diff options
author | merge <null@invalid> | 2009-01-22 13:55:32 +0000 |
---|---|---|
committer | Andy Green <agreen@octopus.localdomain> | 2009-01-22 13:55:32 +0000 |
commit | aa6f5ffbdba45aa8e19e5048648fc6c7b25376d3 (patch) | |
tree | fbb786d0ac6f8a774fd834e9ce951197e60fbffa /drivers/s390 | |
parent | f2d78193eae5dccd3d588d2c8ea0866efc368332 (diff) |
MERGE-via-pending-tracking-hist-MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141
pending-tracking-hist top was MERGE-via-stable-tracking-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040-1232632141 / fdf777a63bcb59e0dfd78bfe2c6242e01f6d4eb9 ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-stable-tracking-hist-MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040
stable-tracking-hist top was MERGE-via-mokopatches-tracking-fix-stray-endmenu-patch-1232632040 / 90463bfd2d5a3c8b52f6e6d71024a00e052b0ced ... parent commitmessage:
From: merge <null@invalid>
MERGE-via-mokopatches-tracking-hist-fix-stray-endmenu-patch
mokopatches-tracking-hist top was fix-stray-endmenu-patch / 3630e0be570de8057e7f8d2fe501ed353cdf34e6 ... parent commitmessage:
From: Andy Green <andy@openmoko.com>
fix-stray-endmenu.patch
Signed-off-by: Andy Green <andy@openmoko.com>
Diffstat (limited to 'drivers/s390')
82 files changed, 2375 insertions, 1895 deletions
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 4f4e7cf105d..d0eae59bc36 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -4,7 +4,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w -obj-y += s390mach.o sysinfo.o s390_rdev.o +obj-y += s390mach.o sysinfo.o obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/ drivers-y += drivers/s390/built-in.o diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 4b76fca64a6..bd591499414 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -336,6 +336,9 @@ static int dasd_state_ready_to_online(struct dasd_device * device) { int rc; + struct gendisk *disk; + struct disk_part_iter piter; + struct hd_struct *part; if (device->discipline->ready_to_online) { rc = device->discipline->ready_to_online(device); @@ -343,8 +346,14 @@ dasd_state_ready_to_online(struct dasd_device * device) return rc; } device->state = DASD_STATE_ONLINE; - if (device->block) + if (device->block) { dasd_schedule_block_bh(device->block); + disk = device->block->bdev->bd_disk; + disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); + while ((part = disk_part_iter_next(&piter))) + kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE); + disk_part_iter_exit(&piter); + } return 0; } @@ -354,6 +363,9 @@ dasd_state_ready_to_online(struct dasd_device * device) static int dasd_state_online_to_ready(struct dasd_device *device) { int rc; + struct gendisk *disk; + struct disk_part_iter piter; + struct hd_struct *part; if (device->discipline->online_to_ready) { rc = device->discipline->online_to_ready(device); @@ -361,6 +373,13 @@ static int dasd_state_online_to_ready(struct dasd_device *device) return rc; } device->state = DASD_STATE_READY; + if (device->block) { + disk = device->block->bdev->bd_disk; + disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); + while ((part = disk_part_iter_next(&piter))) + kobject_uevent(&part_to_dev(part)->kobj, KOBJ_CHANGE); + disk_part_iter_exit(&piter); + } return 0; } @@ -1746,6 +1765,11 @@ restart: goto restart; } + /* log sense for fatal error */ + if (cqr->status == DASD_CQR_FAILED) { + dasd_log_sense(cqr, &cqr->irb); + } + /* First of all call extended error reporting. */ if (dasd_eer_enabled(base) && cqr->status == DASD_CQR_FAILED) { @@ -1893,15 +1917,19 @@ restart_cb: wait_event(dasd_flush_wq, (cqr->status < DASD_CQR_QUEUED)); /* Process finished ERP request. */ if (cqr->refers) { + spin_lock_bh(&block->queue_lock); __dasd_block_process_erp(block, cqr); + spin_unlock_bh(&block->queue_lock); /* restart list_for_xx loop since dasd_process_erp * might remove multiple elements */ goto restart_cb; } /* call the callback function */ + spin_lock_irq(&block->request_queue_lock); cqr->endclk = get_clock(); list_del_init(&cqr->blocklist); __dasd_cleanup_cqr(cqr); + spin_unlock_irq(&block->request_queue_lock); } return rc; } diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index b8f9c00633f..d82aad5224f 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -2621,7 +2621,7 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } } - /* double-check if current erp/cqr was successfull */ + /* double-check if current erp/cqr was successful */ if ((cqr->irb.scsw.cmd.cstat == 0x00) && (cqr->irb.scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 921443b01d1..300e28a531f 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -23,6 +23,7 @@ /* This is ugly... */ #define PRINTK_HEADER "dasd_devmap:" +#define DASD_BUS_ID_SIZE 20 #include "dasd_int.h" @@ -41,7 +42,7 @@ EXPORT_SYMBOL_GPL(dasd_page_cache); */ struct dasd_devmap { struct list_head list; - char bus_id[BUS_ID_SIZE]; + char bus_id[DASD_BUS_ID_SIZE]; unsigned int devindex; unsigned short features; struct dasd_device *device; @@ -94,7 +95,7 @@ dasd_hash_busid(const char *bus_id) int hash, i; hash = 0; - for (i = 0; (i < BUS_ID_SIZE) && *bus_id; i++, bus_id++) + for (i = 0; (i < DASD_BUS_ID_SIZE) && *bus_id; i++, bus_id++) hash += *bus_id; return hash & 0xff; } @@ -205,6 +206,8 @@ dasd_feature_list(char *str, char **endp) features |= DASD_FEATURE_USEDIAG; else if (len == 6 && !strncmp(str, "erplog", 6)) features |= DASD_FEATURE_ERPLOG; + else if (len == 8 && !strncmp(str, "failfast", 8)) + features |= DASD_FEATURE_FAILFAST; else { MESSAGE(KERN_WARNING, "unsupported feature: %*s, " @@ -301,7 +304,7 @@ dasd_parse_range( char *parsestring ) { int from, from_id0, from_id1; int to, to_id0, to_id1; int features, rc; - char bus_id[BUS_ID_SIZE+1], *str; + char bus_id[DASD_BUS_ID_SIZE+1], *str; str = parsestring; rc = dasd_busid(&str, &from_id0, &from_id1, &from); @@ -407,14 +410,14 @@ dasd_add_busid(const char *bus_id, int features) devmap = NULL; hash = dasd_hash_busid(bus_id); list_for_each_entry(tmp, &dasd_hashlists[hash], list) - if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) { + if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { devmap = tmp; break; } if (!devmap) { /* This bus_id is new. */ new->devindex = dasd_max_devindex++; - strncpy(new->bus_id, bus_id, BUS_ID_SIZE); + strncpy(new->bus_id, bus_id, DASD_BUS_ID_SIZE); new->features = features; new->device = NULL; list_add(&new->list, &dasd_hashlists[hash]); @@ -439,7 +442,7 @@ dasd_find_busid(const char *bus_id) devmap = ERR_PTR(-ENODEV); hash = dasd_hash_busid(bus_id); list_for_each_entry(tmp, &dasd_hashlists[hash], list) { - if (strncmp(tmp->bus_id, bus_id, BUS_ID_SIZE) == 0) { + if (strncmp(tmp->bus_id, bus_id, DASD_BUS_ID_SIZE) == 0) { devmap = tmp; break; } @@ -561,7 +564,7 @@ dasd_create_device(struct ccw_device *cdev) } spin_lock_irqsave(get_ccwdev_lock(cdev), flags); - cdev->dev.driver_data = device; + dev_set_drvdata(&cdev->dev, device); spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); return device; @@ -597,7 +600,7 @@ dasd_delete_device(struct dasd_device *device) /* Disconnect dasd_device structure from ccw_device structure. */ spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); - device->cdev->dev.driver_data = NULL; + dev_set_drvdata(&device->cdev->dev, NULL); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); /* @@ -638,7 +641,7 @@ dasd_put_device_wake(struct dasd_device *device) struct dasd_device * dasd_device_from_cdev_locked(struct ccw_device *cdev) { - struct dasd_device *device = cdev->dev.driver_data; + struct dasd_device *device = dev_get_drvdata(&cdev->dev); if (!device) return ERR_PTR(-ENODEV); @@ -666,6 +669,51 @@ dasd_device_from_cdev(struct ccw_device *cdev) */ /* + * failfast controls the behaviour, if no path is available + */ +static ssize_t dasd_ff_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct dasd_devmap *devmap; + int ff_flag; + + devmap = dasd_find_busid(dev->bus_id); + if (!IS_ERR(devmap)) + ff_flag = (devmap->features & DASD_FEATURE_FAILFAST) != 0; + else + ff_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_FAILFAST) != 0; + return snprintf(buf, PAGE_SIZE, ff_flag ? "1\n" : "0\n"); +} + +static ssize_t dasd_ff_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct dasd_devmap *devmap; + int val; + char *endp; + + devmap = dasd_devmap_from_cdev(to_ccwdev(dev)); + if (IS_ERR(devmap)) + return PTR_ERR(devmap); + + val = simple_strtoul(buf, &endp, 0); + if (((endp + 1) < (buf + count)) || (val > 1)) + return -EINVAL; + + spin_lock(&dasd_devmap_lock); + if (val) + devmap->features |= DASD_FEATURE_FAILFAST; + else + devmap->features &= ~DASD_FEATURE_FAILFAST; + if (devmap->device) + devmap->device->features = devmap->features; + spin_unlock(&dasd_devmap_lock); + return count; +} + +static DEVICE_ATTR(failfast, 0644, dasd_ff_show, dasd_ff_store); + +/* * readonly controls the readonly status of a dasd */ static ssize_t @@ -1019,6 +1067,7 @@ static struct attribute * dasd_attrs[] = { &dev_attr_use_diag.attr, &dev_attr_eer_enabled.attr, &dev_attr_erplog.attr, + &dev_attr_failfast.attr, NULL, }; diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 7844461a995..ef2a5695205 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -544,7 +544,8 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev, } cqr->retries = DIAG_MAX_RETRIES; cqr->buildclk = get_clock(); - if (blk_noretry_request(req)) + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = memdev; cqr->memdev = memdev; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 2e60d5f968c..bdb87998f36 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1496,7 +1496,7 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, /* service information message SIM */ - if (irb->esw.esw0.erw.cons && (irb->ecw[27] & DASD_SENSE_BIT_0) && + 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); dasd_schedule_device_bh(device); @@ -1700,7 +1700,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp(struct dasd_device *startdev, recid++; } } - if (blk_noretry_request(req)) + 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; diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 892e2878d61..f8e05ce9862 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -535,8 +535,8 @@ static int dasd_eer_open(struct inode *inp, struct file *filp) eerb->buffer_page_count > INT_MAX / PAGE_SIZE) { kfree(eerb); MESSAGE(KERN_WARNING, "can't open device since module " - "parameter eer_pages is smaller then 1 or" - " bigger then %d", (int)(INT_MAX / PAGE_SIZE)); + "parameter eer_pages is smaller than 1 or" + " bigger than %d", (int)(INT_MAX / PAGE_SIZE)); unlock_kernel(); return -EINVAL; } diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 7d442aeff3d..f1d17602169 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -355,7 +355,8 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev, recid++; } } - if (blk_noretry_request(req)) + if (blk_noretry_request(req) || + block->base->features & DASD_FEATURE_FAILFAST) set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); cqr->startdev = memdev; cqr->memdev = memdev; diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index 05a14536c36..4a39084d9c9 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -199,7 +199,7 @@ struct dasd_ccw_req { #define DASD_CQR_ERROR 0x82 /* request is completed with error */ #define DASD_CQR_CLEAR_PENDING 0x83 /* request is clear pending */ #define DASD_CQR_CLEARED 0x84 /* request was cleared */ -#define DASD_CQR_SUCCESS 0x85 /* request was successfull */ +#define DASD_CQR_SUCCESS 0x85 /* request was successful */ /* per dasd_ccw_req flags */ diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 9088de84b45..bf6fd348f20 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -180,12 +180,12 @@ dasd_calc_metrics(char *page, char **start, off_t off, #ifdef CONFIG_DASD_PROFILE static char * -dasd_statistics_array(char *str, unsigned int *array, int shift) +dasd_statistics_array(char *str, unsigned int *array, int factor) { int i; for (i = 0; i < 32; i++) { - str += sprintf(str, "%7d ", array[i] >> shift); + str += sprintf(str, "%7d ", array[i] / factor); if (i == 15) str += sprintf(str, "\n"); } @@ -202,7 +202,7 @@ dasd_statistics_read(char *page, char **start, off_t off, #ifdef CONFIG_DASD_PROFILE struct dasd_profile_info_t *prof; char *str; - int shift; + int factor; /* check for active profiling */ if (dasd_profile_level == DASD_PROFILE_OFF) { @@ -214,12 +214,14 @@ dasd_statistics_read(char *page, char **start, off_t off, prof = &dasd_global_profile; /* prevent couter 'overflow' on output */ - for (shift = 0; (prof->dasd_io_reqs >> shift) > 9999999; shift++); + for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999; + factor *= 10); str = page; str += sprintf(str, "%d dasd I/O requests\n", prof->dasd_io_reqs); - str += sprintf(str, "with %d sectors(512B each)\n", + str += sprintf(str, "with %u sectors(512B each)\n", prof->dasd_io_sects); + str += sprintf(str, "Scale Factor is %d\n", factor); str += sprintf(str, " __<4 ___8 __16 __32 __64 _128 " " _256 _512 __1k __2k __4k __8k " @@ -230,22 +232,22 @@ dasd_statistics_read(char *page, char **start, off_t off, " __1G __2G __4G " " _>4G\n"); str += sprintf(str, "Histogram of sizes (512B secs)\n"); - str = dasd_statistics_array(str, prof->dasd_io_secs, shift); + str = dasd_statistics_array(str, prof->dasd_io_secs, factor); str += sprintf(str, "Histogram of I/O times (microseconds)\n"); - str = dasd_statistics_array(str, prof->dasd_io_times, shift); + str = dasd_statistics_array(str, prof->dasd_io_times, factor); str += sprintf(str, "Histogram of I/O times per sector\n"); - str = dasd_statistics_array(str, prof->dasd_io_timps, shift); + str = dasd_statistics_array(str, prof->dasd_io_timps, factor); str += sprintf(str, "Histogram of I/O time till ssch\n"); - str = dasd_statistics_array(str, prof->dasd_io_time1, shift); + str = dasd_statistics_array(str, prof->dasd_io_time1, factor); str += sprintf(str, "Histogram of I/O time between ssch and irq\n"); - str = dasd_statistics_array(str, prof->dasd_io_time2, shift); + str = dasd_statistics_array(str, prof->dasd_io_time2, factor); str += sprintf(str, "Histogram of I/O time between ssch " "and irq per sector\n"); - str = dasd_statistics_array(str, prof->dasd_io_time2ps, shift); + str = dasd_statistics_array(str, prof->dasd_io_time2ps, factor); str += sprintf(str, "Histogram of I/O time between irq and end\n"); - str = dasd_statistics_array(str, prof->dasd_io_time3, shift); + str = dasd_statistics_array(str, prof->dasd_io_time3, factor); str += sprintf(str, "# of req in chanq at enqueuing (1..32) \n"); - str = dasd_statistics_array(str, prof->dasd_io_nr_req, shift); + str = dasd_statistics_array(str, prof->dasd_io_nr_req, factor); len = str - page; #else len = sprintf(page, "Statistics are not activated in this kernel\n"); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 63f26a135fe..cfdcf1aed33 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -4,6 +4,9 @@ * Authors: Carsten Otte, Stefan Weinhuber, Gerald Schaefer */ +#define KMSG_COMPONENT "dcssblk" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ctype.h> @@ -15,21 +18,11 @@ #include <asm/io.h> #include <linux/completion.h> #include <linux/interrupt.h> -#include <asm/s390_rdev.h> -//#define DCSSBLK_DEBUG /* Debug messages on/off */ #define DCSSBLK_NAME "dcssblk" #define DCSSBLK_MINORS_PER_DISK 1 #define DCSSBLK_PARM_LEN 400 - -#ifdef DCSSBLK_DEBUG -#define PRINT_DEBUG(x...) printk(KERN_DEBUG DCSSBLK_NAME " debug: " x) -#else -#define PRINT_DEBUG(x...) do {} while (0) -#endif -#define PRINT_INFO(x...) printk(KERN_INFO DCSSBLK_NAME " info: " x) -#define PRINT_WARN(x...) printk(KERN_WARNING DCSSBLK_NAME " warning: " x) -#define PRINT_ERR(x...) printk(KERN_ERR DCSSBLK_NAME " error: " x) +#define DCSS_BUS_ID_SIZE 20 static int dcssblk_open(struct block_device *bdev, fmode_t mode); static int dcssblk_release(struct gendisk *disk, fmode_t mode); @@ -50,7 +43,7 @@ static struct block_device_operations dcssblk_devops = { struct dcssblk_dev_info { struct list_head lh; struct device dev; - char segment_name[BUS_ID_SIZE]; + char segment_name[DCSS_BUS_ID_SIZE]; atomic_t use_count; struct gendisk *gd; unsigned long start; @@ -65,7 +58,7 @@ struct dcssblk_dev_info { struct segment_info { struct list_head lh; - char segment_name[BUS_ID_SIZE]; + char segment_name[DCSS_BUS_ID_SIZE]; unsigned long start; unsigned long end; int segment_type; @@ -261,10 +254,9 @@ dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) /* check continuity */ for (i = 0; i < dev_info->num_of_segments - 1; i++) { if ((sort_list[i].end + 1) != sort_list[i+1].start) { - PRINT_ERR("Segment %s is not contiguous with " - "segment %s\n", - sort_list[i].segment_name, - sort_list[i+1].segment_name); + pr_err("Adjacent DCSSs %s and %s are not " + "contiguous\n", sort_list[i].segment_name, + sort_list[i+1].segment_name); rc = -EINVAL; goto out; } @@ -275,10 +267,10 @@ dcssblk_is_continuous(struct dcssblk_dev_info *dev_info) !(sort_list[i+1].segment_type & SEGMENT_EXCLUSIVE) || (sort_list[i+1].segment_type == SEG_TYPE_ER)) { - PRINT_ERR("Segment %s has different type from " - "segment %s\n", - sort_list[i].segment_name, - sort_list[i+1].segment_name); + pr_err("DCSS %s and DCSS %s have " + "incompatible types\n", + sort_list[i].segment_name, + sort_list[i+1].segment_name); rc = -EINVAL; goto out; } @@ -380,8 +372,9 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch } else if (inbuf[0] == '0') { /* reload segments in exclusive mode */ if (dev_info->segment_type == SEG_TYPE_SC) { - PRINT_ERR("Segment type SC (%s) cannot be loaded in " - "non-shared mode\n", dev_info->segment_name); + pr_err("DCSS %s is of type SC and cannot be " + "loaded as exclusive-writable\n", + dev_info->segment_name); rc = -EINVAL; goto out; } @@ -404,9 +397,8 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch goto out; removeseg: - PRINT_ERR("Could not reload segment(s) of the device %s, removing " - "segment(s) now!\n", - dev_info->segment_name); + pr_err("DCSS device %s is removed after a failed access mode " + "change\n", dev_info->segment_name); temp = entry; list_for_each_entry(entry, &dev_info->seg_list, lh) { if (entry != temp) @@ -454,17 +446,17 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char if (inbuf[0] == '1') { if (atomic_read(&dev_info->use_count) == 0) { // device is idle => we save immediately - PRINT_INFO("Saving segment(s) of the device %s\n", - dev_info->segment_name); + pr_info("All DCSSs that map to device %s are " + "saved\n", dev_info->segment_name); list_for_each_entry(entry, &dev_info->seg_list, lh) { segment_save(entry->segment_name); } } else { // device is busy => we save it when it becomes // idle in dcssblk_release - PRINT_INFO("Device %s is currently busy, segment(s) " - "will be saved when it becomes idle...\n", - dev_info->segment_name); + pr_info("Device %s is in use, its DCSSs will be " + "saved when it becomes idle\n", + dev_info->segment_name); dev_info->save_pending = 1; } } else if (inbuf[0] == '0') { @@ -472,9 +464,9 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char // device is busy & the user wants to undo his save // request dev_info->save_pending = 0; - PRINT_INFO("Pending save for segment(s) of the device " - "%s deactivated\n", - dev_info->segment_name); + pr_info("A pending save request for device %s " + "has been canceled\n", + dev_info->segment_name); } } else { up_write(&dcssblk_devices_sem); @@ -614,9 +606,8 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char seg_byte_size = (dev_info->end - dev_info->start + 1); set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors - PRINT_INFO("Loaded segment(s) %s, size = %lu Byte, " - "capacity = %lu (512 Byte) sectors\n", local_buf, - seg_byte_size, seg_byte_size >> 9); + pr_info("Loaded %s with total size %lu bytes and capacity %lu " + "sectors\n", local_buf, seg_byte_size, seg_byte_size >> 9); dev_info->save_pending = 0; dev_info->is_shared = 1; @@ -744,13 +735,15 @@ dcssblk_remove_store(struct device *dev, struct device_attribute *attr, const ch dev_info = dcssblk_get_device_by_name(local_buf); if (dev_info == NULL) { up_write(&dcssblk_devices_sem); - PRINT_WARN("Device %s is not loaded!\n", local_buf); + pr_warning("Device %s cannot be removed because it is not a " + "known device\n", local_buf); rc = -ENODEV; goto out_buf; } if (atomic_read(&dev_info->use_count) != 0) { up_write(&dcssblk_devices_sem); - PRINT_WARN("Device %s is in use!\n", local_buf); + pr_warning("Device %s cannot be removed while it is in " + "use\n", local_buf); rc = -EBUSY; goto out_buf; } @@ -807,8 +800,8 @@ dcssblk_release(struct gendisk *disk, fmode_t mode) down_write(&dcssblk_devices_sem); if (atomic_dec_and_test(&dev_info->use_count) && (dev_info->save_pending)) { - PRINT_INFO("Device %s became idle and is being saved now\n", - dev_info->segment_name); + pr_info("Device %s has become idle and is being saved " + "now\n", dev_info->segment_name); list_for_each_entry(entry, &dev_info->seg_list, lh) { segment_save(entry->segment_name); } @@ -851,7 +844,8 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio) case SEG_TYPE_SC: /* cannot write to these segments */ if (bio_data_dir(bio) == WRITE) { - PRINT_WARN("rejecting write to ro device %s\n", + pr_warning("Writing to %s failed because it " + "is a read-only device\n", dev_name(&dev_info->dev)); goto fail; } @@ -951,7 +945,7 @@ dcssblk_check_params(void) static void __exit dcssblk_exit(void) { - s390_root_dev_unregister(dcssblk_root_dev); + root_device_unregister(dcssblk_root_dev); unregister_blkdev(dcssblk_major, DCSSBLK_NAME); } @@ -960,22 +954,22 @@ dcssblk_init(void) { int rc; - dcssblk_root_dev = s390_root_dev_register("dcssblk"); + dcssblk_root_dev = root_device_register("dcssblk"); if (IS_ERR(dcssblk_root_dev)) return PTR_ERR(dcssblk_root_dev); rc = device_create_file(dcssblk_root_dev, &dev_attr_add); if (rc) { - s390_root_dev_unregister(dcssblk_root_dev); + root_device_unregister(dcssblk_root_dev); return rc; } rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); if (rc) { - s390_root_dev_unregister(dcssblk_root_dev); + root_device_unregister(dcssblk_root_dev); return rc; } rc = register_blkdev(0, DCSSBLK_NAME); if (rc < 0) { - s390_root_dev_unregister(dcssblk_root_dev); + root_device_unregister(dcssblk_root_dev); return rc; } dcssblk_major = rc; diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 03916989ed2..76814f3e898 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -25,6 +25,9 @@ * generic hard disk support to replace ad-hoc partitioning */ +#define KMSG_COMPONENT "xpram" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/ctype.h> /* isdigit, isxdigit */ @@ -42,12 +45,6 @@ #define XPRAM_DEVS 1 /* one partition */ #define XPRAM_MAX_DEVS 32 /* maximal number of devices (partitions) */ -#define PRINT_DEBUG(x...) printk(KERN_DEBUG XPRAM_NAME " debug:" x) -#define PRINT_INFO(x...) printk(KERN_INFO XPRAM_NAME " info:" x) -#define PRINT_WARN(x...) printk(KERN_WARNING XPRAM_NAME " warning:" x) -#define PRINT_ERR(x...) printk(KERN_ERR XPRAM_NAME " error:" x) - - typedef struct { unsigned int size; /* size of xpram segment in pages */ unsigned int offset; /* start page of xpram segment */ @@ -264,7 +261,7 @@ static int __init xpram_setup_sizes(unsigned long pages) /* Check number of devices. */ if (devs <= 0 || devs > XPRAM_MAX_DEVS) { - PRINT_ERR("invalid number %d of devices\n",devs); + pr_err("%d is not a valid number of XPRAM devices\n",devs); return -EINVAL; } xpram_devs = devs; @@ -295,22 +292,22 @@ static int __init xpram_setup_sizes(unsigned long pages) mem_auto_no++; } - PRINT_INFO(" number of devices (partitions): %d \n", xpram_devs); + pr_info(" number of devices (partitions): %d \n", xpram_devs); for (i = 0; i < xpram_devs; i++) { if (xpram_sizes[i]) - PRINT_INFO(" size of partition %d: %u kB\n", - i, xpram_sizes[i]); + pr_info(" size of partition %d: %u kB\n", + i, xpram_sizes[i]); else - PRINT_INFO(" size of partition %d to be set " - "automatically\n",i); + pr_info(" size of partition %d to be set " + "automatically\n",i); } - PRINT_DEBUG(" memory needed (for sized partitions): %lu kB\n", - mem_needed); - PRINT_DEBUG(" partitions to be sized automatically: %d\n", - mem_auto_no); + pr_info(" memory needed (for sized partitions): %lu kB\n", + mem_needed); + pr_info(" partitions to be sized automatically: %d\n", + mem_auto_no); if (mem_needed > pages * 4) { - PRINT_ERR("Not enough expanded memory available\n"); + pr_err("Not enough expanded memory available\n"); return -EINVAL; } @@ -322,8 +319,8 @@ static int __init xpram_setup_sizes(unsigned long pages) */ if (mem_auto_no) { mem_auto = ((pages - mem_needed / 4) / mem_auto_no) * 4; - PRINT_INFO(" automatically determined " - "partition size: %lu kB\n", mem_auto); + pr_info(" automatically determined " + "partition size: %lu kB\n", mem_auto); for (i = 0; i < xpram_devs; i++) if (xpram_sizes[i] == 0) xpram_sizes[i] = mem_auto; @@ -405,12 +402,12 @@ static int __init xpram_init(void) /* Find out size of expanded memory. */ if (xpram_present() != 0) { - PRINT_WARN("No expanded memory available\n"); + pr_err("No expanded memory available\n"); return -ENODEV; } xpram_pages = xpram_highest_page_index() + 1; - PRINT_INFO(" %u pages expanded memory found (%lu KB).\n", - xpram_pages, (unsigned long) xpram_pages*4); + pr_info(" %u pages expanded memory found (%lu KB).\n", + xpram_pages, (unsigned long) xpram_pages*4); rc = xpram_setup_sizes(xpram_pages); if (rc) return rc; diff --git a/drivers/s390/char/Kconfig b/drivers/s390/char/Kconfig index 643033890e3..0769ced52db 100644 --- a/drivers/s390/char/Kconfig +++ b/drivers/s390/char/Kconfig @@ -100,7 +100,7 @@ comment "S/390 tape interface support" config S390_TAPE_BLOCK bool "Support for tape block devices" - depends on S390_TAPE + depends on S390_TAPE && BLOCK help Select this option if you want to access your channel-attached tape devices using the block device interface. This interface is similar diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 35fd8dfcaaa..97e63cf4694 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -7,6 +7,9 @@ * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> */ +#define KMSG_COMPONENT "monreader" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -24,19 +27,6 @@ #include <asm/ebcdic.h> #include <asm/extmem.h> -//#define MON_DEBUG /* Debug messages on/off */ - -#define MON_NAME "monreader" - -#define P_INFO(x...) printk(KERN_INFO MON_NAME " info: " x) -#define P_ERROR(x...) printk(KERN_ERR MON_NAME " error: " x) -#define P_WARNING(x...) printk(KERN_WARNING MON_NAME " warning: " x) - -#ifdef MON_DEBUG -#define P_DEBUG(x...) printk(KERN_DEBUG MON_NAME " debug: " x) -#else -#define P_DEBUG(x...) do {} while (0) -#endif #define MON_COLLECT_SAMPLE 0x80 #define MON_COLLECT_EVENT 0x40 @@ -172,7 +162,7 @@ static int mon_send_reply(struct mon_msg *monmsg, } else monmsg->replied_msglim = 1; if (rc) { - P_ERROR("read, IUCV reply failed with rc = %i\n\n", rc); + pr_err("Reading monitor data failed with rc=%i\n", rc); return -EIO; } return 0; @@ -251,7 +241,8 @@ static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { struct mon_private *monpriv = path->private; - P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); + pr_err("z/VM *MONITOR system service disconnected with rc=%i\n", + ipuser[0]); iucv_path_sever(path, NULL); atomic_set(&monpriv->iucv_severed, 1); wake_up(&mon_conn_wait_queue); @@ -266,8 +257,7 @@ static void mon_iucv_message_pending(struct iucv_path *path, memcpy(&monpriv->msg_array[monpriv->write_index]->msg, msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { - P_WARNING("IUCV message pending, message limit (%i) reached\n", - MON_MSGLIM); + pr_warning("The read queue for monitor data is full\n"); monpriv->msg_array[monpriv->write_index]->msglim_reached = 1; } monpriv->write_index = (monpriv->write_index + 1) % MON_MSGLIM; @@ -311,8 +301,8 @@ static int mon_open(struct inode *inode, struct file *filp) rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { - P_ERROR("iucv connection to *MONITOR failed with " - "IPUSER SEVER code = %i\n", rc); + pr_err("Connecting to the z/VM *MONITOR system service " + "failed with rc=%i\n", rc); rc = -EIO; goto out_path; } @@ -353,7 +343,8 @@ static int mon_close(struct inode *inode, struct file *filp) */ rc = iucv_path_sever(monpriv->path, user_data_sever); if (rc) - P_ERROR("close, iucv_sever failed with rc = %i\n", rc); + pr_warning("Disconnecting the z/VM *MONITOR system service " + "failed with rc=%i\n", rc); atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); @@ -469,7 +460,8 @@ static int __init mon_init(void) int rc; if (!MACHINE_IS_VM) { - P_ERROR("not running under z/VM, driver not loaded\n"); + pr_err("The z/VM *MONITOR record device driver cannot be " + "loaded without z/VM\n"); return -ENODEV; } @@ -478,7 +470,8 @@ static int __init mon_init(void) */ rc = iucv_register(&monreader_iucv_handler, 1); if (rc) { - P_ERROR("failed to register with iucv driver\n"); + pr_err("The z/VM *MONITOR record device driver failed to " + "register with IUCV\n"); return rc; } @@ -488,8 +481,8 @@ static int __init mon_init(void) goto out_iucv; } if (rc != SEG_TYPE_SC) { - P_ERROR("segment %s has unsupported type, should be SC\n", - mon_dcss_name); + pr_err("The specified *MONITOR DCSS %s does not have the " + "required type SC\n", mon_dcss_name); rc = -EINVAL; goto out_iucv; } diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 4d71aa8c1a7..c7d7483bab9 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -8,6 +8,9 @@ * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> */ +#define KMSG_COMPONENT "monwriter" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/init.h> @@ -64,9 +67,9 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn) rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen); if (rc <= 0) return rc; + pr_err("Writing monitor data failed with rc=%i\n", rc); if (rc == 5) return -EPERM; - printk("DIAG X'DC' error with return code: %i\n", rc); return -EINVAL; } diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index eb5f1b8bc57..50639049641 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -6,6 +6,9 @@ * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> */ +#define KMSG_COMPONENT "sclp_cmd" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/completion.h> #include <linux/init.h> #include <linux/errno.h> @@ -16,9 +19,8 @@ #include <linux/memory.h> #include <asm/chpid.h> #include <asm/sclp.h> -#include "sclp.h" -#define TAG "sclp_cmd: " +#include "sclp.h" #define SCLP_CMDW_READ_SCP_INFO 0x00020001 #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 @@ -169,8 +171,8 @@ static int do_sync_request(sclp_cmdw_t cmd, void *sccb) /* Check response. */ if (request->status != SCLP_REQ_DONE) { - printk(KERN_WARNING TAG "sync request failed " - "(cmd=0x%08x, status=0x%02x)\n", cmd, request->status); + pr_warning("sync request failed (cmd=0x%08x, " + "status=0x%02x)\n", cmd, request->status); rc = -EIO; } out: @@ -224,8 +226,8 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info) if (rc) goto out; if (sccb->header.response_code != 0x0010) { - printk(KERN_WARNING TAG "readcpuinfo failed " - "(response=0x%04x)\n", sccb->header.response_code); + pr_warning("readcpuinfo failed (response=0x%04x)\n", + sccb->header.response_code); rc = -EIO; goto out; } @@ -262,8 +264,9 @@ static int do_cpu_configure(sclp_cmdw_t cmd) case 0x0120: break; default: - printk(KERN_WARNING TAG "configure cpu failed (cmd=0x%08x, " - "response=0x%04x)\n", cmd, sccb->header.response_code); + pr_warning("configure cpu failed (cmd=0x%08x, " + "response=0x%04x)\n", cmd, + sccb->header.response_code); rc = -EIO; break; } @@ -324,6 +327,9 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) case 0x0120: break; default: + pr_warning("assign storage failed (cmd=0x%08x, " + "response=0x%04x, rn=0x%04x)\n", cmd, + sccb->header.response_code, rn); rc = -EIO; break; } @@ -623,9 +629,9 @@ static int do_chp_configure(sclp_cmdw_t cmd) case 0x0450: break; default: - printk(KERN_WARNING TAG "configure channel-path failed " - "(cmd=0x%08x, response=0x%04x)\n", cmd, - sccb->header.response_code); + pr_warning("configure channel-path failed " + "(cmd=0x%08x, response=0x%04x)\n", cmd, + sccb->header.response_code); rc = -EIO; break; } @@ -692,8 +698,8 @@ int sclp_chp_read_info(struct sclp_chp_info *info) if (rc) goto out; if (sccb->header.response_code != 0x0010) { - printk(KERN_WARNING TAG "read channel-path info failed " - "(response=0x%04x)\n", sccb->header.response_code); + pr_warning("read channel-path info failed " + "(response=0x%04x)\n", sccb->header.response_code); rc = -EIO; goto out; } diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 4cebd6ee6d2..b497afe061c 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -5,15 +5,17 @@ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> */ +#define KMSG_COMPONENT "sclp_config" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/init.h> #include <linux/errno.h> #include <linux/cpu.h> #include <linux/sysdev.h> #include <linux/workqueue.h> #include <asm/smp.h> -#include "sclp.h" -#define TAG "sclp_config: " +#include "sclp.h" struct conf_mgm_data { u8 reserved; @@ -31,7 +33,7 @@ static void sclp_cpu_capability_notify(struct work_struct *work) int cpu; struct sys_device *sysdev; - printk(KERN_WARNING TAG "cpu capability changed.\n"); + pr_warning("cpu capability changed.\n"); get_online_cpus(); for_each_online_cpu(cpu) { sysdev = get_cpu_sysdev(cpu); @@ -78,7 +80,7 @@ static int __init sclp_conf_init(void) return rc; if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { - printk(KERN_WARNING TAG "no configuration management.\n"); + pr_warning("no configuration management.\n"); sclp_unregister(&sclp_conf_register); rc = -ENOSYS; } diff --git a/drivers/s390/char/sclp_cpi_sys.c b/drivers/s390/char/sclp_cpi_sys.c index d887bd261d2..62c2647f37f 100644 --- a/drivers/s390/char/sclp_cpi_sys.c +++ b/drivers/s390/char/sclp_cpi_sys.c @@ -7,6 +7,9 @@ * Michael Ernst <mernst@de.ibm.com> */ +#define KMSG_COMPONENT "sclp_cpi" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/kernel.h> #include <linux/init.h> #include <linux/stat.h> @@ -20,6 +23,7 @@ #include <linux/completion.h> #include <asm/ebcdic.h> #include <asm/sclp.h> + #include "sclp.h" #include "sclp_rw.h" #include "sclp_cpi_sys.h" @@ -150,16 +154,16 @@ static int cpi_req(void) wait_for_completion(&completion); if (req->status != SCLP_REQ_DONE) { - printk(KERN_WARNING "cpi: request failed (status=0x%02x)\n", - req->status); + pr_warning("request failed (status=0x%02x)\n", + req->status); rc = -EIO; goto out_free_req; } response = ((struct cpi_sccb *) req->sccb)->header.response_code; if (response != 0x0020) { - printk(KERN_WARNING "cpi: failed with " - "response code 0x%x\n", response); + pr_warning("request failed with response code 0x%x\n", + response); rc = -EIO; } diff --git a/drivers/s390/char/sclp_sdias.c b/drivers/s390/char/sclp_sdias.c index 8b854857ba0..6a1c58dc61a 100644 --- a/drivers/s390/char/sclp_sdias.c +++ b/drivers/s390/char/sclp_sdias.c @@ -5,15 +5,18 @@ * Author(s): Michael Holzheu */ +#define KMSG_COMPONENT "sclp_sdias" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/sched.h> #include <asm/sclp.h> #include <asm/debug.h> #include <asm/ipl.h> + #include "sclp.h" #include "sclp_rw.h" #define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x) -#define ERROR_MSG(x...) printk ( KERN_ALERT "SDIAS: " x ) #define SDIAS_RETRIES 300 #define SDIAS_SLEEP_TICKS 50 @@ -131,7 +134,7 @@ int sclp_sdias_blk_count(void) rc = sdias_sclp_send(&request); if (rc) { - ERROR_MSG("sclp_send failed for get_nr_blocks\n"); + pr_err("sclp_send failed for get_nr_blocks\n"); goto out; } if (sccb.hdr.response_code != 0x0020) { @@ -145,7 +148,8 @@ int sclp_sdias_blk_count(void) rc = sccb.evbuf.blk_cnt; break; default: - ERROR_MSG("SCLP error: %x\n", sccb.evbuf.event_status); + pr_err("SCLP error: %x\n", + sccb.evbuf.event_status); rc = -EIO; goto out; } @@ -201,7 +205,7 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) rc = sdias_sclp_send(&request); if (rc) { - ERROR_MSG("sclp_send failed: %x\n", rc); + pr_err("sclp_send failed: %x\n", rc); goto out; } if (sccb.hdr.response_code != 0x0020) { @@ -219,9 +223,9 @@ int sclp_sdias_copy(void *dest, int start_blk, int nr_blks) case EVSTATE_NO_DATA: TRACE("no data\n"); default: - ERROR_MSG("Error from SCLP while copying hsa. " - "Event status = %x\n", - sccb.evbuf.event_status); + pr_err("Error from SCLP while copying hsa. " + "Event status = %x\n", + sccb.evbuf.event_status); rc = -EIO; } out: diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 9854f19f5e6..a839aa531d7 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -583,23 +583,6 @@ sclp_vt220_chars_in_buffer(struct tty_struct *tty) return count; } -static void -__sclp_vt220_flush_buffer(void) -{ - unsigned long flags; - - sclp_vt220_emit_current(); - spin_lock_irqsave(&sclp_vt220_lock, flags); - if (timer_pending(&sclp_vt220_timer)) - del_timer(&sclp_vt220_timer); - while (sclp_vt220_outqueue_count > 0) { - spin_unlock_irqrestore(&sclp_vt220_lock, flags); - sclp_sync_wait(); - spin_lock_irqsave(&sclp_vt220_lock, flags); - } - spin_unlock_irqrestore(&sclp_vt220_lock, flags); -} - /* * Pass on all buffers to the hardware. Return only when there are no more * buffers pending. @@ -745,6 +728,22 @@ sclp_vt220_con_device(struct console *c, int *index) return sclp_vt220_driver; } +static void __sclp_vt220_flush_buffer(void) +{ + unsigned long flags; + + sclp_vt220_emit_current(); + spin_lock_irqsave(&sclp_vt220_lock, flags); + if (timer_pending(&sclp_vt220_timer)) + del_timer(&sclp_vt220_timer); + while (sclp_vt220_outqueue_count > 0) { + spin_unlock_irqrestore(&sclp_vt220_lock, flags); + sclp_sync_wait(); + spin_lock_irqsave(&sclp_vt220_lock, flags); + } + spin_unlock_irqrestore(&sclp_vt220_lock, flags); +} + static int sclp_vt220_notify(struct notifier_block *self, unsigned long event, void *data) diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 4005c44a404..71605a179d6 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -801,7 +801,7 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) static inline int tape_3590_erp_succeded(struct tape_device *device, struct tape_request *request) { - DBF_EVENT(3, "Error Recovery successfull for %s\n", + DBF_EVENT(3, "Error Recovery successful for %s\n", tape_op_verbose[request->op]); return tape_3590_done(device, request); } diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 09e7d9bf438..a6087cec55b 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -11,12 +11,14 @@ * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS */ +#define KMSG_COMPONENT "vmcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/fs.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/miscdevice.h> #include <linux/module.h> -#include <linux/smp_lock.h> #include <asm/cpcmd.h> #include <asm/debug.h> #include <asm/uaccess.h> @@ -26,8 +28,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Borntraeger <borntraeger@de.ibm.com>"); MODULE_DESCRIPTION("z/VM CP interface"); -#define PRINTK_HEADER "vmcp: " - static debug_info_t *vmcp_debug; static int vmcp_open(struct inode *inode, struct file *file) @@ -41,13 +41,11 @@ static int vmcp_open(struct inode *inode, struct file *file) if (!session) return -ENOMEM; - lock_kernel(); session->bufsize = PAGE_SIZE; session->response = NULL; session->resp_size = 0; mutex_init(&session->mutex); file->private_data = session; - unlock_kernel(); return nonseekable_open(inode, file); } @@ -193,7 +191,8 @@ static int __init vmcp_init(void) int ret; if (!MACHINE_IS_VM) { - PRINT_WARN("z/VM CP interface is only available under z/VM\n"); + pr_warning("The z/VM CP interface device driver cannot be " + "loaded without z/VM\n"); return -ENODEV; } diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 24762727bc2..d8a2289fcb6 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -10,6 +10,10 @@ * Stefan Weinhuber <wein@de.ibm.com> * */ + +#define KMSG_COMPONENT "vmlogrdr" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> @@ -28,8 +32,6 @@ #include <linux/smp_lock.h> #include <linux/string.h> - - MODULE_AUTHOR ("(C) 2004 IBM Corporation by Xenia Tkatschow (xenia@us.ibm.com)\n" " Stefan Weinhuber (wein@de.ibm.com)"); @@ -174,8 +176,7 @@ static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) struct vmlogrdr_priv_t * logptr = path->private; u8 reason = (u8) ipuser[8]; - printk (KERN_ERR "vmlogrdr: connection severed with" - " reason %i\n", reason); + pr_err("vmlogrdr: connection severed with reason %i\n", reason); iucv_path_sever(path, NULL); kfree(path); @@ -333,8 +334,8 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp) if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,1,logptr->autopurge); if (ret) - printk (KERN_WARNING "vmlogrdr: failed to start " - "recording automatically\n"); + pr_warning("vmlogrdr: failed to start " + "recording automatically\n"); } /* create connection to the system service */ @@ -345,9 +346,9 @@ static int vmlogrdr_open (struct inode *inode, struct file *filp) logptr->system_service, NULL, NULL, logptr); if (connect_rc) { - printk (KERN_ERR "vmlogrdr: iucv connection to %s " - "failed with rc %i \n", logptr->system_service, - connect_rc); + pr_err("vmlogrdr: iucv connection to %s " + "failed with rc %i \n", + logptr->system_service, connect_rc); goto out_path; } @@ -388,8 +389,8 @@ static int vmlogrdr_release (struct inode *inode, struct file *filp) if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,0,logptr->autopurge); if (ret) - printk (KERN_WARNING "vmlogrdr: failed to stop " - "recording automatically\n"); + pr_warning("vmlogrdr: failed to stop " + "recording automatically\n"); } logptr->dev_in_use = 0; @@ -426,7 +427,7 @@ static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) buffer = priv->buffer + sizeof(int); } /* - * If the record is bigger then our buffer, we receive only + * If the record is bigger than our buffer, we receive only * a part of it. We can get the rest later. */ if (iucv_data_count > NET_BUFFER_SIZE) @@ -436,7 +437,7 @@ static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) 0, buffer, iucv_data_count, &priv->residual_length); spin_unlock_bh(&priv->priv_lock); - /* An rc of 5 indicates that the record was bigger then + /* An rc of 5 indicates that the record was bigger than * the buffer, which is OK for us. A 9 indicates that the * record was purged befor we could receive it. */ @@ -823,8 +824,7 @@ static int __init vmlogrdr_init(void) dev_t dev; if (! MACHINE_IS_VM) { - printk (KERN_ERR "vmlogrdr: not running under VM, " - "driver not loaded.\n"); + pr_err("not running under VM, driver not loaded.\n"); return -ENODEV; } diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 9020eba620e..5dcef81fc9d 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -8,6 +8,9 @@ * Frank Munzert <munzert@de.ibm.com> */ +#define KMSG_COMPONENT "vmur" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/cdev.h> #include <linux/smp_lock.h> @@ -40,8 +43,6 @@ MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("s390 z/VM virtual unit record device driver"); MODULE_LICENSE("GPL"); -#define PRINTK_HEADER "vmur: " - static dev_t ur_first_dev_maj_min; static struct class *vmur_class; static struct debug_info *vmur_dbf; @@ -987,7 +988,8 @@ static int __init ur_init(void) dev_t dev; if (!MACHINE_IS_VM) { - PRINT_ERR("%s is only available under z/VM.\n", ur_banner); + pr_err("The %s cannot be loaded without z/VM\n", + ur_banner); return -ENODEV; } @@ -1006,7 +1008,8 @@ static int __init ur_init(void) rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur"); if (rc) { - PRINT_ERR("alloc_chrdev_region failed: err = %d\n", rc); + pr_err("Kernel function alloc_chrdev_region failed with " + "error code %d\n", rc); goto fail_unregister_driver; } ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0); @@ -1016,7 +1019,7 @@ static int __init ur_init(void) rc = PTR_ERR(vmur_class); goto fail_unregister_region; } - PRINT_INFO("%s loaded.\n", ur_banner); + pr_info("%s loaded.\n", ur_banner); return 0; fail_unregister_region: @@ -1034,7 +1037,7 @@ static void __exit ur_exit(void) unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS); ccw_driver_unregister(&ur_driver); debug_unregister(vmur_dbf); - PRINT_INFO("%s unloaded.\n", ur_banner); + pr_info("%s unloaded.\n", ur_banner); } module_init(ur_init); diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index 7fd84be1193..eefc6611412 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -9,6 +9,9 @@ * Author(s): Michael Holzheu */ +#define KMSG_COMPONENT "zdump" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/utsname.h> @@ -24,8 +27,6 @@ #include "sclp.h" #define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x) -#define MSG(x...) printk( KERN_ALERT x ) -#define ERROR_MSG(x...) printk ( KERN_ALERT "DUMP: " x ) #define TO_USER 0 #define TO_KERNEL 1 @@ -563,19 +564,19 @@ static int __init sys_info_init(enum arch_id arch) switch (arch) { case ARCH_S390X: - MSG("DETECTED 'S390X (64 bit) OS'\n"); + pr_alert("DETECTED 'S390X (64 bit) OS'\n"); sys_info.sa_base = SAVE_AREA_BASE_S390X; sys_info.sa_size = sizeof(struct save_area_s390x); set_s390x_lc_mask(&sys_info.lc_mask); break; case ARCH_S390: - MSG("DETECTED 'S390 (32 bit) OS'\n"); + pr_alert("DETECTED 'S390 (32 bit) OS'\n"); sys_info.sa_base = SAVE_AREA_BASE_S390; sys_info.sa_size = sizeof(struct save_area_s390); set_s390_lc_mask(&sys_info.lc_mask); break; default: - ERROR_MSG("unknown architecture 0x%x.\n",arch); + pr_alert("0x%x is an unknown architecture.\n",arch); return -EINVAL; } sys_info.arch = arch; @@ -674,7 +675,8 @@ static int __init zcore_init(void) #ifndef __s390x__ if (arch == ARCH_S390X) { - ERROR_MSG("32 bit dumper can't dump 64 bit system!\n"); + pr_alert("The 32-bit dump tool cannot be used for a " + "64-bit system\n"); rc = -EINVAL; goto fail; } diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 2f547b840ef..fe00be3675c 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -9,6 +9,9 @@ * Arnd Bergmann (arndb@de.ibm.com) */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/init.h> #include <linux/vmalloc.h> #include <linux/slab.h> @@ -50,9 +53,10 @@ static int blacklist_range(range_action action, unsigned int from_ssid, { if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) { if (msgtrigger) - printk(KERN_WARNING "cio: Invalid cio_ignore range " - "0.%x.%04x-0.%x.%04x\n", from_ssid, from, - to_ssid, to); + pr_warning("0.%x.%04x to 0.%x.%04x is not a valid " + "range for cio_ignore\n", from_ssid, from, + to_ssid, to); + return 1; } @@ -140,8 +144,8 @@ static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid, rc = 0; out: if (rc && msgtrigger) - printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n", - str); + pr_warning("%s is not a valid device for the cio_ignore " + "kernel parameter\n", str); return rc; } diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 3ac2c2019f5..918e6fce257 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -19,6 +19,8 @@ #include <asm/ccwdev.h> #include <asm/ccwgroup.h> +#define CCW_BUS_ID_SIZE 20 + /* In Linux 2.4, we had a channel device layer called "chandev" * that did all sorts of obscure stuff for networking devices. * This is another driver that serves as a replacement for just @@ -89,15 +91,23 @@ ccwgroup_ungroup_store(struct device *dev, struct device_attribute *attr, const gdev = to_ccwgroupdev(dev); - if (gdev->state != CCWGROUP_OFFLINE) - return -EINVAL; - + /* Prevent concurrent online/offline processing and ungrouping. */ + if (atomic_cmpxchg(&gdev->onoff, 0, 1) != 0) + return -EAGAIN; + if (gdev->state != CCWGROUP_OFFLINE) { + rc = -EINVAL; + goto out; + } /* Note that we cannot unregister the device from one of its * attribute methods, so we have to use this roundabout approach. */ rc = device_schedule_callback(dev, ccwgroup_ungroup_callback); - if (rc) - count = rc; +out: + if (rc) { + /* Release onoff "lock" when ungrouping failed. */ + atomic_set(&gdev->onoff, 0); + return rc; + } return count; } @@ -172,7 +182,7 @@ static int __get_next_bus_id(const char **buf, char *bus_id) len = end - start + 1; end++; } - if (len < BUS_ID_SIZE) { + if (len < CCW_BUS_ID_SIZE) { strlcpy(bus_id, start, len); rc = 0; } else @@ -181,7 +191,7 @@ static int __get_next_bus_id(const char **buf, char *bus_id) return rc; } -static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE]) +static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE]) { int cssid, ssid, devno; @@ -213,7 +223,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, { struct ccwgroup_device *gdev; int rc, i; - char tmp_bus_id[BUS_ID_SIZE]; + char tmp_bus_id[CCW_BUS_ID_SIZE]; const char *curr_buf; gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 29826fdd47b..ebab6ea4659 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -8,6 +8,9 @@ * Arnd Bergmann (arndb@de.ibm.com) */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/slab.h> #include <linux/init.h> @@ -333,6 +336,7 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) struct chp_config_data *data; struct chp_id chpid; int num; + char *events[3] = {"configure", "deconfigure", "cancel deconfigure"}; CIO_CRW_EVENT(4, "chsc: channel-path-configuration notification\n"); if (sei_area->rs != 0) @@ -343,8 +347,8 @@ static void chsc_process_sei_chp_config(struct chsc_sei_area *sei_area) if (!chp_test_bit(data->map, num)) continue; chpid.id = num; - printk(KERN_WARNING "cio: processing configure event %d for " - "chpid %x.%02x\n", data->op, chpid.cssid, chpid.id); + pr_notice("Processing %s for channel path %x.%02x\n", + events[data->op], chpid.cssid, chpid.id); switch (data->op) { case 0: chp_cfg_schedule(chpid, 1); diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index f49f0e502b8..0a2f2edafc0 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c @@ -61,7 +61,7 @@ static void chsc_subchannel_irq(struct subchannel *sch) } private->request = NULL; memcpy(&request->irb, irb, sizeof(*irb)); - stsch(sch->schid, &sch->schib); + cio_update_schib(sch); complete(&request->completion); put_device(&sch->dev); } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 3db2c386546..659f8a79165 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -9,6 +9,9 @@ * Martin Schwidefsky (schwidefsky@de.ibm.com) */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -104,44 +107,6 @@ cio_get_options (struct subchannel *sch) return flags; } -/* - * Use tpi to get a pending interrupt, call the interrupt handler and - * return a pointer to the subchannel structure. - */ -static int -cio_tpi(void) -{ - struct tpi_info *tpi_info; - struct subchannel *sch; - struct irb *irb; - int irq_context; - - tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; - if (tpi (NULL) != 1) - return 0; - irb = (struct irb *) __LC_IRB; - /* Store interrupt response block to lowcore. */ - if (tsch (tpi_info->schid, irb) != 0) - /* Not status pending or not operational. */ - return 1; - sch = (struct subchannel *)(unsigned long)tpi_info->intparm; - if (!sch) - return 1; - irq_context = in_interrupt(); - if (!irq_context) - local_bh_disable(); - irq_enter (); - spin_lock(sch->lock); - memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); - if (sch->driver && sch->driver->irq) - sch->driver->irq(sch); - spin_unlock(sch->lock); - irq_exit (); - if (!irq_context) - _local_bh_enable(); - return 1; -} - static int cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) { @@ -152,11 +117,13 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) else sch->lpm = 0; - stsch (sch->schid, &sch->schib); - CIO_MSG_EVENT(2, "cio_start: 'not oper' status for " "subchannel 0.%x.%04x!\n", sch->schid.ssid, sch->schid.sch_no); + + if (cio_update_schib(sch)) + return -ENODEV; + sprintf(dbf_text, "no%s", dev_name(&sch->dev)); CIO_TRACE_EVENT(0, dbf_text); CIO_HEX_EVENT(0, &sch->schib, sizeof (struct schib)); @@ -354,7 +321,8 @@ cio_cancel (struct subchannel *sch) switch (ccode) { case 0: /* success */ /* Update information in scsw. */ - stsch (sch->schid, &sch->schib); + if (cio_update_schib(sch)) + return -ENODEV; return 0; case 1: /* status pending */ return -EBUSY; @@ -365,30 +333,70 @@ cio_cancel (struct subchannel *sch) } } + +static void cio_apply_config(struct subchannel *sch, struct schib *schib) +{ + schib->pmcw.intparm = sch->config.intparm; + schib->pmcw.mbi = sch->config.mbi; + schib->pmcw.isc = sch->config.isc; + schib->pmcw.ena = sch->config.ena; + schib->pmcw.mme = sch->config.mme; + schib->pmcw.mp = sch->config.mp; + schib->pmcw.csense = sch->config.csense; + schib->pmcw.mbfc = sch->config.mbfc; + if (sch->config.mbfc) + schib->mba = sch->config.mba; +} + +static int cio_check_config(struct subchannel *sch, struct schib *schib) +{ + return (schib->pmcw.intparm == sch->config.intparm) && + (schib->pmcw.mbi == sch->config.mbi) && + (schib->pmcw.isc == sch->config.isc) && + (schib->pmcw.ena == sch->config.ena) && + (schib->pmcw.mme == sch->config.mme) && + (schib->pmcw.mp == sch->config.mp) && + (schib->pmcw.csense == sch->config.csense) && + (schib->pmcw.mbfc == sch->config.mbfc) && + (!sch->config.mbfc || (schib->mba == sch->config.mba)); +} + /* - * Function: cio_modify - * Issues a "Modify Subchannel" on the specified subchannel + * cio_commit_config - apply configuration to the subchannel */ -int -cio_modify (struct subchannel *sch) +int cio_commit_config(struct subchannel *sch) { - int ccode, retry, ret; + struct schib schib; + int ccode, retry, ret = 0; + + if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) + return -ENODEV; - ret = 0; for (retry = 0; retry < 5; retry++) { - ccode = msch_err (sch->schid, &sch->schib); - if (ccode < 0) /* -EIO if msch gets a program check. */ + /* copy desired changes to local schib */ + cio_apply_config(sch, &schib); + ccode = msch_err(sch->schid, &schib); + if (ccode < 0) /* -EIO if msch gets a program check. */ return ccode; switch (ccode) { - case 0: /* successfull */ - return 0; - case 1: /* status pending */ + case 0: /* successful */ + if (stsch(sch->schid, &schib) || + !css_sch_is_valid(&schib)) + return -ENODEV; + if (cio_check_config(sch, &schib)) { + /* commit changes from local schib */ + memcpy(&sch->schib, &schib, sizeof(schib)); + return 0; + } + ret = -EAGAIN; + break; + case 1: /* status pending */ return -EBUSY; - case 2: /* busy */ - udelay (100); /* allow for recovery */ + case 2: /* busy */ + udelay(100); /* allow for recovery */ ret = -EBUSY; break; - case 3: /* not operational */ + case 3: /* not operational */ return -ENODEV; } } @@ -396,6 +404,23 @@ cio_modify (struct subchannel *sch) } /** + * cio_update_schib - Perform stsch and update schib if subchannel is valid. + * @sch: subchannel on which to perform stsch + * Return zero on success, -ENODEV otherwise. + */ +int cio_update_schib(struct subchannel *sch) +{ + struct schib schib; + + if (stsch(sch->schid, &schib) || !css_sch_is_valid(&schib)) + return -ENODEV; + + memcpy(&sch->schib, &schib, sizeof(schib)); + return 0; +} +EXPORT_SYMBOL_GPL(cio_update_schib); + +/** * cio_enable_subchannel - enable a subchannel. * @sch: subchannel to be enabled * @intparm: interruption parameter to set @@ -403,7 +428,6 @@ cio_modify (struct subchannel *sch) int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { char dbf_txt[15]; - int ccode; int retry; int ret; @@ -412,33 +436,27 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) if (sch_is_pseudo_sch(sch)) return -EINVAL; - ccode = stsch (sch->schid, &sch->schib); - if (ccode) + if (cio_update_schib(sch)) return -ENODEV; - for (retry = 5, ret = 0; retry > 0; retry--) { - sch->schib.pmcw.ena = 1; - sch->schib.pmcw.isc = sch->isc; - sch->schib.pmcw.intparm = intparm; - ret = cio_modify(sch); - if (ret == -ENODEV) - break; - if (ret == -EIO) + sch->config.ena = 1; + sch->config.isc = sch->isc; + sch->config.intparm = intparm; + + for (retry = 0; retry < 3; retry++) { + ret = cio_commit_config(sch); + if (ret == -EIO) { /* - * Got a program check in cio_modify. Try without + * Got a program check in msch. Try without * the concurrent sense bit the next time. */ - sch->schib.pmcw.csense = 0; - if (ret == 0) { - stsch (sch->schid, &sch->schib); - if (sch->schib.pmcw.ena) - break; - } - if (ret == -EBUSY) { + sch->config.csense = 0; + } else 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); @@ -453,8 +471,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel); int cio_disable_subchannel(struct subchannel *sch) { char dbf_txt[15]; - int ccode; - int retry; int ret; CIO_TRACE_EVENT (2, "dissch"); @@ -462,8 +478,7 @@ int cio_disable_subchannel(struct subchannel *sch) if (sch_is_pseudo_sch(sch)) return 0; - ccode = stsch (sch->schid, &sch->schib); - if (ccode == 3) /* Not operational. */ + if (cio_update_schib(sch)) return -ENODEV; if (scsw_actl(&sch->schib.scsw) != 0) @@ -473,24 +488,9 @@ int cio_disable_subchannel(struct subchannel *sch) */ return -EBUSY; - for (retry = 5, ret = 0; retry > 0; retry--) { - sch->schib.pmcw.ena = 0; - ret = cio_modify(sch); - if (ret == -ENODEV) - break; - if (ret == -EBUSY) - /* - * The subchannel is busy or status pending. - * We'll disable when the next interrupt was delivered - * via the state machine. - */ - break; - if (ret == 0) { - stsch (sch->schid, &sch->schib); - if (!sch->schib.pmcw.ena) - break; - } - } + sch->config.ena = 0; + ret = cio_commit_config(sch); + sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); return ret; @@ -632,8 +632,8 @@ do_IRQ (struct pt_regs *regs) struct pt_regs *old_regs; old_regs = set_irq_regs(regs); - irq_enter(); s390_idle_check(); + irq_enter(); if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) /* Serve timer interrupts first. */ clock_comparator_work(); @@ -687,6 +687,43 @@ static char console_sch_name[10] = "0.x.xxxx"; static struct io_subchannel_private console_priv; static int console_subchannel_in_use; +/* + * Use tpi to get a pending interrupt, call the interrupt handler and + * return a pointer to the subchannel structure. + */ +static int cio_tpi(void) +{ + struct tpi_info *tpi_info; + struct subchannel *sch; + struct irb *irb; + int irq_context; + + tpi_info = (struct tpi_info *) __LC_SUBCHANNEL_ID; + if (tpi(NULL) != 1) + return 0; + irb = (struct irb *) __LC_IRB; + /* Store interrupt response block to lowcore. */ + if (tsch(tpi_info->schid, irb) != 0) + /* Not status pending or not operational. */ + return 1; + sch = (struct subchannel *)(unsigned long)tpi_info->intparm; + if (!sch) + return 1; + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); + irq_enter(); + spin_lock(sch->lock); + memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); + if (sch->driver && sch->driver->irq) + sch->driver->irq(sch); + spin_unlock(sch->lock); + irq_exit(); + if (!irq_context) + _local_bh_enable(); + return 1; +} + void *cio_get_console_priv(void) { return &console_priv; @@ -780,7 +817,7 @@ cio_probe_console(void) sch_no = cio_get_console_sch_no(); if (sch_no == -1) { console_subchannel_in_use = 0; - printk(KERN_WARNING "cio: No ccw console found!\n"); + pr_warning("No CCW console was found\n"); return ERR_PTR(-ENODEV); } memset(&console_subchannel, 0, sizeof(struct subchannel)); @@ -796,10 +833,9 @@ cio_probe_console(void) * enable console I/O-interrupt subclass */ isc_register(CONSOLE_ISC); - console_subchannel.schib.pmcw.isc = CONSOLE_ISC; - console_subchannel.schib.pmcw.intparm = - (u32)(addr_t)&console_subchannel; - ret = cio_modify(&console_subchannel); + console_subchannel.config.isc = CONSOLE_ISC; + console_subchannel.config.intparm = (u32)(addr_t)&console_subchannel; + ret = cio_commit_config(&console_subchannel); if (ret) { isc_unregister(CONSOLE_ISC); console_subchannel_in_use = 0; @@ -811,8 +847,8 @@ cio_probe_console(void) void cio_release_console(void) { - console_subchannel.schib.pmcw.intparm = 0; - cio_modify(&console_subchannel); + console_subchannel.config.intparm = 0; + cio_commit_config(&console_subchannel); isc_unregister(CONSOLE_ISC); console_subchannel_in_use = 0; } @@ -852,7 +888,8 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) cc = msch(schid, schib); if (cc) return (cc==3?-ENODEV:-EBUSY); - stsch(schid, schib); + if (stsch(schid, schib) || !css_sch_is_valid(schib)) + return -ENODEV; if (!schib->pmcw.ena) return 0; } diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 0fb24784e92..5150fba742a 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h @@ -45,6 +45,19 @@ struct pmcw { /* ... in an operand exception. */ } __attribute__ ((packed)); +/* Target SCHIB configuration. */ +struct schib_config { + u64 mba; + u32 intparm; + u16 mbi; + u32 isc:3; + u32 ena:1; + u32 mme:2; + u32 mp:1; + u32 csense:1; + u32 mbfc:1; +} __attribute__ ((packed)); + /* * subchannel information block */ @@ -82,6 +95,8 @@ struct subchannel { struct device dev; /* entry in device tree */ struct css_driver *driver; void *private; /* private per subchannel type data */ + struct work_struct work; + struct schib_config config; } __attribute__ ((aligned(8))); #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ @@ -100,7 +115,8 @@ extern int cio_start_key (struct subchannel *, struct ccw1 *, __u8, __u8); extern int cio_cancel (struct subchannel *); extern int cio_set_options (struct subchannel *, int); extern int cio_get_options (struct subchannel *); -extern int cio_modify (struct subchannel *); +extern int cio_update_schib(struct subchannel *sch); +extern int cio_commit_config(struct subchannel *sch); int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); int cio_tm_intrg(struct subchannel *sch); diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index a90b28c0be5..dc98b2c6386 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -25,6 +25,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/bootmem.h> #include <linux/device.h> #include <linux/init.h> @@ -185,56 +188,19 @@ static inline void cmf_activate(void *area, unsigned int onoff) static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) { - int ret; - int retry; struct subchannel *sch; - struct schib *schib; sch = to_subchannel(cdev->dev.parent); - schib = &sch->schib; - /* msch can silently fail, so do it again if necessary */ - for (retry = 0; retry < 3; retry++) { - /* prepare schib */ - stsch(sch->schid, schib); - schib->pmcw.mme = mme; - schib->pmcw.mbfc = mbfc; - /* address can be either a block address or a block index */ - if (mbfc) - schib->mba = address; - else - schib->pmcw.mbi = address; - - /* try to submit it */ - switch(ret = msch_err(sch->schid, schib)) { - case 0: - break; - case 1: - case 2: /* in I/O or status pending */ - ret = -EBUSY; - break; - case 3: /* subchannel is no longer valid */ - ret = -ENODEV; - break; - default: /* msch caught an exception */ - ret = -EINVAL; - break; - } - stsch(sch->schid, schib); /* restore the schib */ - - if (ret) - break; - /* check if it worked */ - if (schib->pmcw.mme == mme && - schib->pmcw.mbfc == mbfc && - (mbfc ? (schib->mba == address) - : (schib->pmcw.mbi == address))) - return 0; + sch->config.mme = mme; + sch->config.mbfc = mbfc; + /* address can be either a block address or a block index */ + if (mbfc) + sch->config.mba = address; + else + sch->config.mbi = address; - ret = -EINVAL; - } - - return ret; + return cio_commit_config(sch); } struct set_schib_struct { @@ -338,7 +304,7 @@ static int cmf_copy_block(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); - if (stsch(sch->schid, &sch->schib)) + if (cio_update_schib(sch)) return -ENODEV; if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) { @@ -1359,9 +1325,8 @@ static int __init init_cmf(void) default: return 1; } - - printk(KERN_INFO "cio: Channel measurement facility using %s " - "format (%s)\n", format_string, detect_string); + pr_info("Channel measurement facility initialized using format " + "%s (mode %s)\n", format_string, detect_string); return 0; } diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 76bbb1e74c2..8019288bc6d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -6,6 +6,10 @@ * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) */ + +#define KMSG_COMPONENT "cio" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/device.h> @@ -128,8 +132,8 @@ css_free_subchannel(struct subchannel *sch) { if (sch) { /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); + sch->config.intparm = 0; + cio_commit_config(sch); kfree(sch->lock); kfree(sch); } @@ -844,8 +848,8 @@ out: s390_unregister_crw_handler(CRW_RSC_CSS); chsc_free_sei_area(); kfree(slow_subchannel_set); - printk(KERN_WARNING"cio: failed to initialize css driver (%d)!\n", - ret); + pr_alert("The CSS device driver initialization failed with " + "errno=%d\n", ret); return ret; } diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 4e78c82194b..23d5752349b 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -376,19 +376,23 @@ int ccw_device_set_offline(struct ccw_device *cdev) dev_fsm_event(cdev, DEV_EVENT_NOTOPER); } spin_unlock_irq(cdev->ccwlock); + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); return ret; } spin_unlock_irq(cdev->ccwlock); - if (ret == 0) + if (ret == 0) { wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); - else { + /* Give up reference from ccw_device_set_online(). */ + put_device(&cdev->dev); + } else { CIO_MSG_EVENT(0, "ccw_device_offline returned %d, " "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); cdev->online = 1; } - return ret; + return ret; } /** @@ -411,6 +415,9 @@ int ccw_device_set_online(struct ccw_device *cdev) return -ENODEV; if (cdev->online || !cdev->drv) return -EINVAL; + /* Hold on to an extra reference while device is online. */ + if (!get_device(&cdev->dev)) + return -ENODEV; spin_lock_irq(cdev->ccwlock); ret = ccw_device_online(cdev); @@ -422,10 +429,15 @@ int ccw_device_set_online(struct ccw_device *cdev) "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); return ret; } - if (cdev->private->state != DEV_STATE_ONLINE) + if (cdev->private->state != DEV_STATE_ONLINE) { + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); return -ENODEV; + } if (!cdev->drv->set_online || cdev->drv->set_online(cdev) == 0) { cdev->online = 1; return 0; @@ -440,6 +452,8 @@ int ccw_device_set_online(struct ccw_device *cdev) "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); + /* Give up online reference since onlining failed. */ + put_device(&cdev->dev); return (ret == 0) ? -ENODEV : ret; } @@ -704,6 +718,8 @@ ccw_device_release(struct device *dev) struct ccw_device *cdev; cdev = to_ccwdev(dev); + /* Release reference of parent subchannel. */ + put_device(cdev->dev.parent); kfree(cdev->private); kfree(cdev); } @@ -735,8 +751,8 @@ static int io_subchannel_initialize_dev(struct subchannel *sch, /* Do first half of device_register. */ device_initialize(&cdev->dev); if (!get_device(&sch->dev)) { - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); + /* Release reference from device_initialize(). */ + put_device(&cdev->dev); return -ENODEV; } return 0; @@ -778,37 +794,55 @@ static void sch_attach_disconnected_device(struct subchannel *sch, struct subchannel *other_sch; int ret; - other_sch = to_subchannel(get_device(cdev->dev.parent)); + /* Get reference for new parent. */ + if (!get_device(&sch->dev)) + return; + other_sch = to_subchannel(cdev->dev.parent); + /* Note: device_move() changes cdev->dev.parent */ ret = device_move(&cdev->dev, &sch->dev); if (ret) { CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed " "(ret=%d)!\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); - put_device(&other_sch->dev); + /* Put reference for new parent. */ + put_device(&sch->dev); return; } sch_set_cdev(other_sch, NULL); /* No need to keep a subchannel without ccw device around. */ css_sch_device_unregister(other_sch); - put_device(&other_sch->dev); sch_attach_device(sch, cdev); + /* Put reference for old parent. */ + put_device(&other_sch->dev); } static void sch_attach_orphaned_device(struct subchannel *sch, struct ccw_device *cdev) { int ret; + struct subchannel *pseudo_sch; - /* Try to move the ccw device to its new subchannel. */ + /* Get reference for new parent. */ + if (!get_device(&sch->dev)) + return; + pseudo_sch = to_subchannel(cdev->dev.parent); + /* + * Try to move the ccw device to its new subchannel. + * Note: device_move() changes cdev->dev.parent + */ ret = device_move(&cdev->dev, &sch->dev); if (ret) { CIO_MSG_EVENT(0, "Moving device 0.%x.%04x from orphanage " "failed (ret=%d)!\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); + /* Put reference for new parent. */ + put_device(&sch->dev); return; } sch_attach_device(sch, cdev); + /* Put reference on pseudo subchannel. */ + put_device(&pseudo_sch->dev); } static void sch_create_and_recog_new_device(struct subchannel *sch) @@ -830,9 +864,11 @@ static void sch_create_and_recog_new_device(struct subchannel *sch) spin_lock_irq(sch->lock); sch_set_cdev(sch, NULL); spin_unlock_irq(sch->lock); - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); css_sch_device_unregister(sch); + /* Put reference from io_subchannel_create_ccwdev(). */ + put_device(&sch->dev); + /* Give up initial reference. */ + put_device(&cdev->dev); } } @@ -854,15 +890,20 @@ void ccw_device_move_to_orphanage(struct work_struct *work) dev_id.devno = sch->schib.pmcw.dev; dev_id.ssid = sch->schid.ssid; + /* Increase refcount for pseudo subchannel. */ + get_device(&css->pseudo_subchannel->dev); /* * Move the orphaned ccw device to the orphanage so the replacing * ccw device can take its place on the subchannel. + * Note: device_move() changes cdev->dev.parent */ ret = device_move(&cdev->dev, &css->pseudo_subchannel->dev); if (ret) { CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to orphanage failed " "(ret=%d)!\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); + /* Decrease refcount for pseudo subchannel again. */ + put_device(&css->pseudo_subchannel->dev); return; } cdev->ccwlock = css->pseudo_subchannel->lock; @@ -874,14 +915,24 @@ void ccw_device_move_to_orphanage(struct work_struct *work) replacing_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev); if (replacing_cdev) { sch_attach_disconnected_device(sch, replacing_cdev); + /* Release reference from get_disc_ccwdev_by_dev_id() */ + put_device(&replacing_cdev->dev); + /* Release reference of subchannel from old cdev. */ + put_device(&sch->dev); return; } replacing_cdev = get_orphaned_ccwdev_by_dev_id(css, &dev_id); if (replacing_cdev) { sch_attach_orphaned_device(sch, replacing_cdev); + /* Release reference from get_orphaned_ccwdev_by_dev_id() */ + put_device(&replacing_cdev->dev); + /* Release reference of subchannel from old cdev. */ + put_device(&sch->dev); return; } sch_create_and_recog_new_device(sch); + /* Release reference of subchannel from old cdev. */ + put_device(&sch->dev); } /* @@ -899,6 +950,14 @@ io_subchannel_register(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; sch = to_subchannel(cdev->dev.parent); + /* + * Check if subchannel is still registered. It may have become + * unregistered if a machine check hit us after finishing + * device recognition but before the register work could be + * queued. + */ + if (!device_is_registered(&sch->dev)) + goto out_err; css_update_ssd_info(sch); /* * io_subchannel_register() will also be called after device @@ -906,7 +965,7 @@ io_subchannel_register(struct work_struct *work) * be registered). We need to reprobe since we may now have sense id * information. */ - if (klist_node_attached(&cdev->dev.knode_parent)) { + if (device_is_registered(&cdev->dev)) { if (!cdev->drv) { ret = device_reprobe(&cdev->dev); if (ret) @@ -930,22 +989,19 @@ io_subchannel_register(struct work_struct *work) CIO_MSG_EVENT(0, "Could not register ccw dev 0.%x.%04x: %d\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, ret); - put_device(&cdev->dev); spin_lock_irqsave(sch->lock, flags); sch_set_cdev(sch, NULL); spin_unlock_irqrestore(sch->lock, flags); - kfree (cdev->private); - kfree (cdev); - put_device(&sch->dev); - if (atomic_dec_and_test(&ccw_device_init_count)) - wake_up(&ccw_device_init_wq); - return; + /* Release initial device reference. */ + put_device(&cdev->dev); + goto out_err; } - put_device(&cdev->dev); out: cdev->private->flags.recog_done = 1; - put_device(&sch->dev); wake_up(&cdev->private->wait_q); +out_err: + /* Release reference for workqueue processing. */ + put_device(&cdev->dev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); } @@ -964,8 +1020,8 @@ static void ccw_device_call_sch_unregister(struct work_struct *work) sch = to_subchannel(cdev->dev.parent); css_sch_device_unregister(sch); /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); + sch->config.intparm = 0; + cio_commit_config(sch); /* Release cdev reference for workqueue processing.*/ put_device(&cdev->dev); /* Release subchannel reference for local processing. */ @@ -994,8 +1050,6 @@ io_subchannel_recog_done(struct ccw_device *cdev) PREPARE_WORK(&cdev->private->kick_work, ccw_device_call_sch_unregister); queue_work(slow_path_wq, &cdev->private->kick_work); - /* Release subchannel reference for asynchronous recognition. */ - put_device(&sch->dev); if (atomic_dec_and_test(&ccw_device_init_count)) wake_up(&ccw_device_init_wq); break; @@ -1066,10 +1120,15 @@ static void ccw_device_move_to_sch(struct work_struct *work) priv = container_of(work, struct ccw_device_private, kick_work); sch = priv->sch; cdev = priv->cdev; - former_parent = ccw_device_is_orphan(cdev) ? - NULL : to_subchannel(get_device(cdev->dev.parent)); + former_parent = to_subchannel(cdev->dev.parent); + /* Get reference for new parent. */ + if (!get_device(&sch->dev)) + return; mutex_lock(&sch->reg_mutex); - /* Try to move the ccw device to its new subchannel. */ + /* + * Try to move the ccw device to its new subchannel. + * Note: device_move() changes cdev->dev.parent + */ rc = device_move(&cdev->dev, &sch->dev); mutex_unlock(&sch->reg_mutex); if (rc) { @@ -1079,21 +1138,23 @@ static void ccw_device_move_to_sch(struct work_struct *work) cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, rc); css_sch_device_unregister(sch); + /* Put reference for new parent again. */ + put_device(&sch->dev); goto out; } - if (former_parent) { + if (!sch_is_pseudo_sch(former_parent)) { spin_lock_irq(former_parent->lock); sch_set_cdev(former_parent, NULL); spin_unlock_irq(former_parent->lock); css_sch_device_unregister(former_parent); /* Reset intparm to zeroes. */ - former_parent->schib.pmcw.intparm = 0; - cio_modify(former_parent); + former_parent->config.intparm = 0; + cio_commit_config(former_parent); } sch_attach_device(sch, cdev); out: - if (former_parent) - put_device(&former_parent->dev); + /* Put reference for old parent. */ + put_device(&former_parent->dev); put_device(&cdev->dev); } @@ -1109,6 +1170,15 @@ static void io_subchannel_irq(struct subchannel *sch) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); } +void io_subchannel_init_config(struct subchannel *sch) +{ + memset(&sch->config, 0, sizeof(sch->config)); + sch->config.csense = 1; + /* Use subchannel mp mode when there is more than 1 installed CHPID. */ + if ((sch->schib.pmcw.pim & (sch->schib.pmcw.pim - 1)) != 0) + sch->config.mp = 1; +} + static void io_subchannel_init_fields(struct subchannel *sch) { if (cio_is_console(sch->schid)) @@ -1123,18 +1193,34 @@ static void io_subchannel_init_fields(struct subchannel *sch) sch->schib.pmcw.dev, sch->schid.ssid, sch->schid.sch_no, sch->schib.pmcw.pim, sch->schib.pmcw.pam, sch->schib.pmcw.pom); - /* Initially set up some fields in the pmcw. */ - sch->schib.pmcw.ena = 0; - sch->schib.pmcw.csense = 1; /* concurrent sense */ - if ((sch->lpm & (sch->lpm - 1)) != 0) - sch->schib.pmcw.mp = 1; /* multipath mode */ - /* clean up possible residual cmf stuff */ - sch->schib.pmcw.mme = 0; - sch->schib.pmcw.mbfc = 0; - sch->schib.pmcw.mbi = 0; - sch->schib.mba = 0; + + io_subchannel_init_config(sch); +} + +static void io_subchannel_do_unreg(struct work_struct *work) +{ + struct subchannel *sch; + + sch = container_of(work, struct subchannel, work); + css_sch_device_unregister(sch); + /* Reset intparm to zeroes. */ + sch->config.intparm = 0; + cio_commit_config(sch); + put_device(&sch->dev); +} + +/* Schedule unregister if we have no cdev. */ +static void io_subchannel_schedule_removal(struct subchannel *sch) +{ + get_device(&sch->dev); + INIT_WORK(&sch->work, io_subchannel_do_unreg); + queue_work(slow_path_wq, &sch->work); } +/* + * Note: We always return 0 so that we bind to the device even on error. + * This is needed so that our remove function is called on unregister. + */ static int io_subchannel_probe(struct subchannel *sch) { struct ccw_device *cdev; @@ -1164,9 +1250,8 @@ static int io_subchannel_probe(struct subchannel *sch) ccw_device_register(cdev); /* * Check if the device is already online. If it is - * the reference count needs to be corrected - * (see ccw_device_online and css_init_done for the - * ugly details). + * the reference count needs to be corrected since we + * didn't obtain a reference in ccw_device_set_online. */ if (cdev->private->state != DEV_STATE_NOT_OPER && cdev->private->state != DEV_STATE_OFFLINE && @@ -1175,23 +1260,24 @@ static int io_subchannel_probe(struct subchannel *sch) return 0; } io_subchannel_init_fields(sch); - /* - * First check if a fitting device may be found amongst the - * disconnected devices or in the orphanage. - */ - dev_id.devno = sch->schib.pmcw.dev; - dev_id.ssid = sch->schid.ssid; + rc = cio_commit_config(sch); + if (rc) + goto out_schedule; rc = sysfs_create_group(&sch->dev.kobj, &io_subchannel_attr_group); if (rc) - return rc; + goto out_schedule; /* Allocate I/O subchannel private data. */ sch->private = kzalloc(sizeof(struct io_subchannel_private), GFP_KERNEL | GFP_DMA); - if (!sch->private) { - rc = -ENOMEM; + if (!sch->private) goto out_err; - } + /* + * First check if a fitting device may be found amongst the + * disconnected devices or in the orphanage. + */ + dev_id.devno = sch->schib.pmcw.dev; + dev_id.ssid = sch->schid.ssid; cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); if (!cdev) cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), @@ -1209,24 +1295,21 @@ static int io_subchannel_probe(struct subchannel *sch) return 0; } cdev = io_subchannel_create_ccwdev(sch); - if (IS_ERR(cdev)) { - rc = PTR_ERR(cdev); + if (IS_ERR(cdev)) goto out_err; - } rc = io_subchannel_recog(cdev, sch); if (rc) { spin_lock_irqsave(sch->lock, flags); - sch_set_cdev(sch, NULL); + io_subchannel_recog_done(cdev); spin_unlock_irqrestore(sch->lock, flags); - if (cdev->dev.release) - cdev->dev.release(&cdev->dev); - goto out_err; } return 0; out_err: kfree(sch->private); sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); - return rc; +out_schedule: + io_subchannel_schedule_removal(sch); + return 0; } static int @@ -1271,10 +1354,7 @@ static void io_subchannel_verify(struct subchannel *sch) static int check_for_io_on_path(struct subchannel *sch, int mask) { - int cc; - - cc = stsch(sch->schid, &sch->schib); - if (cc) + if (cio_update_schib(sch)) return 0; if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask) return 1; @@ -1343,15 +1423,13 @@ static int io_subchannel_chp_event(struct subchannel *sch, io_subchannel_verify(sch); break; case CHP_OFFLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; - if (!css_sch_is_valid(&sch->schib)) + if (cio_update_schib(sch)) return -ENODEV; io_subchannel_terminate_path(sch, mask); break; case CHP_ONLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; + if (cio_update_schib(sch)) + return -ENODEV; sch->lpm |= mask & sch->opm; io_subchannel_verify(sch); break; @@ -1606,8 +1684,8 @@ static int io_subchannel_sch_event(struct subchannel *sch, int slow) spin_lock_irqsave(sch->lock, flags); /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); + sch->config.intparm = 0; + cio_commit_config(sch); break; case REPROBE: ccw_device_trigger_reprobe(cdev); @@ -1648,6 +1726,9 @@ static int ccw_device_console_enable(struct ccw_device *cdev, sch->private = cio_get_console_priv(); memset(sch->private, 0, sizeof(struct io_subchannel_private)); io_subchannel_init_fields(sch); + rc = cio_commit_config(sch); + if (rc) + return rc; sch->driver = &io_subchannel_driver; /* Initialize the ccw_device structure. */ cdev->dev.parent= &sch->dev; @@ -1719,7 +1800,7 @@ __ccwdev_check_busid(struct device *dev, void *id) bus_id = id; - return (strncmp(bus_id, dev_name(dev), BUS_ID_SIZE) == 0); + return (strcmp(bus_id, dev_name(dev)) == 0); } @@ -1802,6 +1883,8 @@ ccw_device_remove (struct device *dev) "device 0.%x.%04x\n", ret, cdev->private->dev_id.ssid, cdev->private->dev_id.devno); + /* Give up reference obtained in ccw_device_set_online(). */ + put_device(&cdev->dev); } ccw_device_set_timeout(cdev, 0); cdev->drv = NULL; diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 104ed669db4..0f2e63ea48d 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -76,6 +76,7 @@ extern wait_queue_head_t ccw_device_init_wq; extern atomic_t ccw_device_init_count; void io_subchannel_recog_done(struct ccw_device *cdev); +void io_subchannel_init_config(struct subchannel *sch); int ccw_device_cancel_halt_clear(struct ccw_device *); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 10bc03940fb..8df5eaafc5a 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -140,8 +140,7 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) int ret; sch = to_subchannel(cdev->dev.parent); - ret = stsch(sch->schid, &sch->schib); - if (ret || !sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) return -ENODEV; if (!sch->schib.pmcw.ena) /* Not operational -> done. */ @@ -245,11 +244,13 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) * through ssch() and the path information is up to date. */ old_lpm = sch->lpm; - stsch(sch->schid, &sch->schib); - sch->lpm = sch->schib.pmcw.pam & sch->opm; + /* Check since device may again have become not operational. */ - if (!sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) state = DEV_STATE_NOT_OPER; + else + sch->lpm = sch->schib.pmcw.pam & sch->opm; + if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) /* Force reprobe on all chpids. */ old_lpm = 0; @@ -399,9 +400,6 @@ ccw_device_done(struct ccw_device *cdev, int state) ccw_device_oper_notify(cdev); } wake_up(&cdev->private->wait_q); - - if (css_init_done && state != DEV_STATE_ONLINE) - put_device (&cdev->dev); } static int cmp_pgid(struct pgid *p1, struct pgid *p2) @@ -552,7 +550,11 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) sch = to_subchannel(cdev->dev.parent); /* Update schib - pom may have changed. */ - stsch(sch->schid, &sch->schib); + if (cio_update_schib(sch)) { + cdev->private->flags.donotify = 0; + ccw_device_done(cdev, DEV_STATE_NOT_OPER); + return; + } /* Update lpm with verified path mask. */ sch->lpm = sch->vpm; /* Repeat path verification? */ @@ -611,8 +613,6 @@ ccw_device_online(struct ccw_device *cdev) (cdev->private->state != DEV_STATE_BOXED)) return -EINVAL; sch = to_subchannel(cdev->dev.parent); - if (css_init_done && !get_device(&cdev->dev)) - return -ENODEV; ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); if (ret != 0) { /* Couldn't enable the subchannel for i/o. Sick device. */ @@ -672,7 +672,7 @@ ccw_device_offline(struct ccw_device *cdev) return 0; } sch = to_subchannel(cdev->dev.parent); - if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) return -ENODEV; if (scsw_actl(&sch->schib.scsw) != 0) return -EBUSY; @@ -750,7 +750,10 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) * Since we might not just be coming from an interrupt from the * subchannel we have to update the schib. */ - stsch(sch->schid, &sch->schib); + if (cio_update_schib(sch)) { + ccw_device_verify_done(cdev, -ENODEV); + return; + } if (scsw_actl(&sch->schib.scsw) != 0 || (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || @@ -1016,20 +1019,21 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); /* Update some values. */ - if (stsch(sch->schid, &sch->schib)) - return; - if (!sch->schib.pmcw.dnv) + if (cio_update_schib(sch)) return; /* * The pim, pam, pom values may not be accurate, but they are the best * we have before performing device selection :/ */ sch->lpm = sch->schib.pmcw.pam & sch->opm; - /* Re-set some bits in the pmcw that were lost. */ - sch->schib.pmcw.csense = 1; - sch->schib.pmcw.ena = 0; - if ((sch->lpm & (sch->lpm - 1)) != 0) - sch->schib.pmcw.mp = 1; + /* + * Use the initial configuration since we can't be shure that the old + * paths are valid. + */ + io_subchannel_init_config(sch); + if (cio_commit_config(sch)) + return; + /* We should also udate ssd info, but this has to wait. */ /* Check if this is another device which appeared on the same sch. */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 86bc94eb607..fc5ca1dd52b 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c @@ -504,7 +504,7 @@ ccw_device_verify_start(struct ccw_device *cdev) sch->vpm = 0; /* Get current pam. */ - if (stsch(sch->schid, &sch->schib)) { + if (cio_update_schib(sch)) { ccw_device_verify_done(cdev, -ENODEV); return; } diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index 1b03c5423be..5814dbee241 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -56,7 +56,8 @@ ccw_device_path_notoper(struct ccw_device *cdev) struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); - stsch (sch->schid, &sch->schib); + if (cio_update_schib(sch)) + goto doverify; CIO_MSG_EVENT(0, "%s(0.%x.%04x) - path(s) %02x are " "not operational \n", __func__, @@ -64,6 +65,7 @@ ccw_device_path_notoper(struct ccw_device *cdev) sch->schib.pmcw.pnom); sch->lpm &= ~sch->schib.pmcw.pnom; +doverify: cdev->private->flags.doverify = 1; } diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index e3ea1d5f281..42f2b09631b 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -10,10 +10,10 @@ #include <asm/page.h> #include <asm/schid.h> +#include <asm/debug.h> #include "chsc.h" #define QDIO_BUSY_BIT_PATIENCE 100 /* 100 microseconds */ -#define QDIO_BUSY_BIT_GIVE_UP 2000000 /* 2 seconds = eternity */ #define QDIO_INPUT_THRESHOLD 500 /* 500 microseconds */ /* @@ -111,12 +111,12 @@ static inline int do_sqbs(u64 token, unsigned char state, int queue, } static inline int do_eqbs(u64 token, unsigned char *state, int queue, - int *start, int *count) + int *start, int *count, int ack) { register unsigned long _ccq asm ("0") = *count; register unsigned long _token asm ("1") = token; unsigned long _queuestart = ((unsigned long)queue << 32) | *start; - unsigned long _state = 0; + unsigned long _state = (unsigned long)ack << 63; asm volatile( " .insn rrf,0xB99c0000,%1,%2,0,0" @@ -133,7 +133,7 @@ static inline int do_eqbs(u64 token, unsigned char *state, int queue, static inline int do_sqbs(u64 token, unsigned char state, int queue, int *start, int *count) { return 0; } static inline int do_eqbs(u64 token, unsigned char *state, int queue, - int *start, int *count) { return 0; } + int *start, int *count, int ack) { return 0; } #endif /* CONFIG_64BIT */ struct qdio_irq; @@ -186,20 +186,14 @@ struct qdio_input_q { /* input buffer acknowledgement flag */ int polling; + /* how much sbals are acknowledged with qebsm */ + int ack_count; + /* last time of noticing incoming data */ u64 timestamp; - - /* lock for clearing the acknowledgement */ - spinlock_t lock; }; struct qdio_output_q { - /* failed siga-w attempts*/ - atomic_t busy_siga_counter; - - /* start time of busy condition */ - u64 timestamp; - /* PCIs are enabled for the queue */ int pci_out_enabled; @@ -250,6 +244,7 @@ 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; @@ -300,11 +295,13 @@ struct qdio_irq { struct qdio_q *input_qs[QDIO_MAX_QUEUES_PER_IRQ]; struct qdio_q *output_qs[QDIO_MAX_QUEUES_PER_IRQ]; + debug_info_t *debug_area; struct mutex setup_mutex; }; /* helper functions */ #define queue_type(q) q->irq_ptr->qib.qfmt +#define SCH_NO(q) (q->irq_ptr->schid.sch_no) #define is_thinint_irq(irq) \ (irq->qib.qfmt == QDIO_IQDIO_QFMT || \ @@ -348,10 +345,13 @@ static inline unsigned long long get_usecs(void) ((bufnr + 1) & QDIO_MAX_BUFFERS_MASK) #define add_buf(bufnr, inc) \ ((bufnr + inc) & QDIO_MAX_BUFFERS_MASK) +#define sub_buf(bufnr, dec) \ + ((bufnr - dec) & QDIO_MAX_BUFFERS_MASK) /* prototypes for thin interrupt */ void qdio_sync_after_thinint(struct qdio_q *q); -int get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state); +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); @@ -378,10 +378,15 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, int nr_output_qs); void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr); +int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, + struct subchannel_id *schid, + struct qdio_ssqd_desc *data); int qdio_setup_irq(struct qdio_initialize *init_data); void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, struct ccw_device *cdev); void qdio_release_memory(struct qdio_irq *irq_ptr); +int qdio_setup_create_sysfs(struct ccw_device *cdev); +void qdio_setup_destroy_sysfs(struct ccw_device *cdev); int qdio_setup_init(void); void qdio_setup_exit(void); diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index f05590355be..da7afb04e71 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -14,7 +14,7 @@ #include "qdio.h" debug_info_t *qdio_dbf_setup; -debug_info_t *qdio_dbf_trace; +debug_info_t *qdio_dbf_error; static struct dentry *debugfs_root; #define MAX_DEBUGFS_QUEUES 32 @@ -22,59 +22,33 @@ static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL }; static DEFINE_MUTEX(debugfs_mutex); #define QDIO_DEBUGFS_NAME_LEN 40 -void qdio_allocate_do_dbf(struct qdio_initialize *init_data) +void qdio_allocate_dbf(struct qdio_initialize *init_data, + struct qdio_irq *irq_ptr) { - char dbf_text[20]; - - sprintf(dbf_text, "qfmt:%x", init_data->q_format); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, init_data->adapter_name, 8); - sprintf(dbf_text, "qpff%4x", init_data->qib_param_field_format); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, &init_data->qib_param_field, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->input_slib_elements, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->output_slib_elements, sizeof(void *)); - sprintf(dbf_text, "niq:%4x", init_data->no_input_qs); - QDIO_DBF_TEXT0(0, setup, dbf_text); - sprintf(dbf_text, "noq:%4x", init_data->no_output_qs); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, &init_data->input_handler, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->output_handler, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->int_parm, sizeof(long)); - QDIO_DBF_HEX0(0, setup, &init_data->flags, sizeof(long)); - QDIO_DBF_HEX0(0, setup, &init_data->input_sbal_addr_array, sizeof(void *)); - QDIO_DBF_HEX0(0, setup, &init_data->output_sbal_addr_array, sizeof(void *)); -} - -static void qdio_unregister_dbf_views(void) -{ - if (qdio_dbf_setup) - debug_unregister(qdio_dbf_setup); - if (qdio_dbf_trace) - debug_unregister(qdio_dbf_trace); -} - -static int qdio_register_dbf_views(void) -{ - qdio_dbf_setup = debug_register("qdio_setup", QDIO_DBF_SETUP_PAGES, - QDIO_DBF_SETUP_NR_AREAS, - QDIO_DBF_SETUP_LEN); - if (!qdio_dbf_setup) - goto oom; - debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); - debug_set_level(qdio_dbf_setup, QDIO_DBF_SETUP_LEVEL); - - qdio_dbf_trace = debug_register("qdio_trace", QDIO_DBF_TRACE_PAGES, - QDIO_DBF_TRACE_NR_AREAS, - QDIO_DBF_TRACE_LEN); - if (!qdio_dbf_trace) - goto oom; - debug_register_view(qdio_dbf_trace, &debug_hex_ascii_view); - debug_set_level(qdio_dbf_trace, QDIO_DBF_TRACE_LEVEL); - return 0; -oom: - qdio_unregister_dbf_views(); - return -ENOMEM; + char text[20]; + + DBF_EVENT("qfmt:%1d", init_data->q_format); + DBF_HEX(init_data->adapter_name, 8); + DBF_EVENT("qpff%4x", init_data->qib_param_field_format); + DBF_HEX(&init_data->qib_param_field, sizeof(void *)); + DBF_HEX(&init_data->input_slib_elements, sizeof(void *)); + DBF_HEX(&init_data->output_slib_elements, sizeof(void *)); + DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs, + init_data->no_output_qs); + DBF_HEX(&init_data->input_handler, sizeof(void *)); + DBF_HEX(&init_data->output_handler, sizeof(void *)); + DBF_HEX(&init_data->int_parm, sizeof(long)); + DBF_HEX(&init_data->flags, sizeof(long)); + DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); + DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); + DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); + + /* allocate trace view for the interface */ + snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev)); + irq_ptr->debug_area = debug_register(text, 2, 1, 16); + debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view); + debug_set_level(irq_ptr->debug_area, DBF_WARN); + DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); } static int qstat_show(struct seq_file *m, void *v) @@ -86,16 +60,18 @@ static int qstat_show(struct seq_file *m, void *v) if (!q) return 0; - seq_printf(m, "device state indicator: %d\n", *q->irq_ptr->dsci); + 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, "polling: %d\n", q->u.in.polling); + 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"); qdio_siga_sync_q(q); for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { - get_buf_state(q, i, &state); + get_buf_state(q, i, &state, 0); switch (state) { case SLSB_P_INPUT_NOT_INIT: case SLSB_P_OUTPUT_NOT_INIT: @@ -127,6 +103,7 @@ static int qstat_show(struct seq_file *m, void *v) seq_printf(m, "\n"); } seq_printf(m, "\n"); + seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); return 0; } @@ -192,6 +169,8 @@ static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) q->nr); debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, debugfs_root, q, &debugfs_fops); + if (IS_ERR(debugfs_queues[i])) + debugfs_queues[i] = NULL; } void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) @@ -223,11 +202,24 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd int __init qdio_debug_init(void) { debugfs_root = debugfs_create_dir("qdio_queues", NULL); - return qdio_register_dbf_views(); + + qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); + debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); + debug_set_level(qdio_dbf_setup, DBF_INFO); + DBF_EVENT("dbf created\n"); + + qdio_dbf_error = debug_register("qdio_error", 4, 1, 16); + debug_register_view(qdio_dbf_error, &debug_hex_ascii_view); + debug_set_level(qdio_dbf_error, DBF_INFO); + DBF_ERROR("dbf created\n"); + return 0; } void qdio_debug_exit(void) { debugfs_remove(debugfs_root); - qdio_unregister_dbf_views(); + if (qdio_dbf_setup) + debug_unregister(qdio_dbf_setup); + if (qdio_dbf_error) + debug_unregister(qdio_dbf_error); } diff --git a/drivers/s390/cio/qdio_debug.h b/drivers/s390/cio/qdio_debug.h index 5a4d85b829a..5d70bd162ae 100644 --- a/drivers/s390/cio/qdio_debug.h +++ b/drivers/s390/cio/qdio_debug.h @@ -12,80 +12,72 @@ #include <asm/qdio.h> #include "qdio.h" -#define QDIO_DBF_HEX(ex, name, level, addr, len) \ +/* that gives us 15 characters in the text event views */ +#define QDIO_DBF_LEN 16 + +extern debug_info_t *qdio_dbf_setup; +extern debug_info_t *qdio_dbf_error; + +/* sort out low debug levels early to avoid wasted sprints */ +static inline int qdio_dbf_passes(debug_info_t *dbf_grp, int level) +{ + return (level <= dbf_grp->level); +} + +#define DBF_ERR 3 /* error conditions */ +#define DBF_WARN 4 /* warning conditions */ +#define DBF_INFO 6 /* informational */ + +#undef DBF_EVENT +#undef DBF_ERROR +#undef DBF_DEV_EVENT + +#define DBF_EVENT(text...) \ do { \ - if (ex) \ - debug_exception(qdio_dbf_##name, level, (void *)(addr), len); \ - else \ - debug_event(qdio_dbf_##name, level, (void *)(addr), len); \ + char debug_buffer[QDIO_DBF_LEN]; \ + snprintf(debug_buffer, QDIO_DBF_LEN, text); \ + debug_text_event(qdio_dbf_setup, DBF_ERR, debug_buffer); \ } while (0) -#define QDIO_DBF_TEXT(ex, name, level, text) \ + +#define DBF_HEX(addr, len) \ do { \ - if (ex) \ - debug_text_exception(qdio_dbf_##name, level, text); \ - else \ - debug_text_event(qdio_dbf_##name, level, text); \ + debug_event(qdio_dbf_setup, DBF_ERR, (void*)(addr), len); \ } while (0) -#define QDIO_DBF_HEX0(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 0, addr, len) -#define QDIO_DBF_HEX1(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 1, addr, len) -#define QDIO_DBF_HEX2(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 2, addr, len) - -#ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_HEX3(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 3, addr, len) -#define QDIO_DBF_HEX4(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 4, addr, len) -#define QDIO_DBF_HEX5(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 5, addr, len) -#define QDIO_DBF_HEX6(ex, name, addr, len) QDIO_DBF_HEX(ex, name, 6, addr, len) -#else -#define QDIO_DBF_HEX3(ex, name, addr, len) do {} while (0) -#define QDIO_DBF_HEX4(ex, name, addr, len) do {} while (0) -#define QDIO_DBF_HEX5(ex, name, addr, len) do {} while (0) -#define QDIO_DBF_HEX6(ex, name, addr, len) do {} while (0) -#endif /* CONFIG_QDIO_DEBUG */ - -#define QDIO_DBF_TEXT0(ex, name, text) QDIO_DBF_TEXT(ex, name, 0, text) -#define QDIO_DBF_TEXT1(ex, name, text) QDIO_DBF_TEXT(ex, name, 1, text) -#define QDIO_DBF_TEXT2(ex, name, text) QDIO_DBF_TEXT(ex, name, 2, text) - -#ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_TEXT3(ex, name, text) QDIO_DBF_TEXT(ex, name, 3, text) -#define QDIO_DBF_TEXT4(ex, name, text) QDIO_DBF_TEXT(ex, name, 4, text) -#define QDIO_DBF_TEXT5(ex, name, text) QDIO_DBF_TEXT(ex, name, 5, text) -#define QDIO_DBF_TEXT6(ex, name, text) QDIO_DBF_TEXT(ex, name, 6, text) -#else -#define QDIO_DBF_TEXT3(ex, name, text) do {} while (0) -#define QDIO_DBF_TEXT4(ex, name, text) do {} while (0) -#define QDIO_DBF_TEXT5(ex, name, text) do {} while (0) -#define QDIO_DBF_TEXT6(ex, name, text) do {} while (0) -#endif /* CONFIG_QDIO_DEBUG */ +#define DBF_ERROR(text...) \ + do { \ + char debug_buffer[QDIO_DBF_LEN]; \ + snprintf(debug_buffer, QDIO_DBF_LEN, text); \ + debug_text_event(qdio_dbf_error, DBF_ERR, debug_buffer); \ + } while (0) -/* s390dbf views */ -#define QDIO_DBF_SETUP_LEN 8 -#define QDIO_DBF_SETUP_PAGES 8 -#define QDIO_DBF_SETUP_NR_AREAS 1 +#define DBF_ERROR_HEX(addr, len) \ + do { \ + debug_event(qdio_dbf_error, DBF_ERR, (void*)(addr), len); \ + } while (0) -#define QDIO_DBF_TRACE_LEN 8 -#define QDIO_DBF_TRACE_NR_AREAS 2 -#ifdef CONFIG_QDIO_DEBUG -#define QDIO_DBF_TRACE_PAGES 32 -#define QDIO_DBF_SETUP_LEVEL 6 -#define QDIO_DBF_TRACE_LEVEL 4 -#else /* !CONFIG_QDIO_DEBUG */ -#define QDIO_DBF_TRACE_PAGES 8 -#define QDIO_DBF_SETUP_LEVEL 2 -#define QDIO_DBF_TRACE_LEVEL 2 -#endif /* CONFIG_QDIO_DEBUG */ +#define DBF_DEV_EVENT(level, device, text...) \ + do { \ + char debug_buffer[QDIO_DBF_LEN]; \ + if (qdio_dbf_passes(device->debug_area, level)) { \ + snprintf(debug_buffer, QDIO_DBF_LEN, text); \ + debug_text_event(device->debug_area, level, debug_buffer); \ + } \ + } while (0) -extern debug_info_t *qdio_dbf_setup; -extern debug_info_t *qdio_dbf_trace; +#define DBF_DEV_HEX(level, device, addr, len) \ + do { \ + debug_event(device->debug_area, level, (void*)(addr), len); \ + } while (0) -void qdio_allocate_do_dbf(struct qdio_initialize *init_data); -void debug_print_bstat(struct qdio_q *q); +void qdio_allocate_dbf(struct qdio_initialize *init_data, + struct qdio_irq *irq_ptr); void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev); void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev); int qdio_debug_init(void); void qdio_debug_exit(void); + #endif diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 7c865915199..10cb0f8726e 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -74,7 +74,7 @@ static inline int do_siga_input(struct subchannel_id schid, unsigned int mask) * Note: For IQDC unicast queues only the highest priority queue is processed. */ static inline int do_siga_output(unsigned long schid, unsigned long mask, - u32 *bb, unsigned int fc) + unsigned int *bb, unsigned int fc) { register unsigned long __fc asm("0") = fc; register unsigned long __schid asm("1") = schid; @@ -95,8 +95,6 @@ static inline int do_siga_output(unsigned long schid, unsigned long mask, static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) { - char dbf_text[15]; - /* all done or next buffer state different */ if (ccq == 0 || ccq == 32) return 0; @@ -104,8 +102,7 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) if (ccq == 96 || ccq == 97) return 1; /* notify devices immediately */ - sprintf(dbf_text, "%d", ccq); - QDIO_DBF_TEXT2(1, trace, dbf_text); + DBF_ERROR("%4x ccq:%3d", SCH_NO(q), ccq); return -EIO; } @@ -115,41 +112,45 @@ static inline int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) * @state: state of the extracted buffers * @start: buffer number to start at * @count: count of buffers to examine + * @auto_ack: automatically acknowledge buffers * - * Returns the number of successfull extracted equal buffer states. + * Returns the number of successfully extracted equal buffer states. * Stops processing if a state is different from the last buffers state. */ static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, - int start, int count) + int start, int count, int auto_ack) { unsigned int ccq = 0; int tmp_count = count, tmp_start = start; int nr = q->nr; int rc; - char dbf_text[15]; BUG_ON(!q->irq_ptr->sch_token); + qdio_perf_stat_inc(&perf_stats.debug_eqbs_all); if (!q->is_input_q) nr += q->irq_ptr->nr_input_qs; again: - ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); + ccq = do_eqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count, + auto_ack); rc = qdio_check_ccq(q, ccq); /* At least one buffer was processed, return and extract the remaining * buffers later. */ - if ((ccq == 96) && (count != tmp_count)) + if ((ccq == 96) && (count != tmp_count)) { + qdio_perf_stat_inc(&perf_stats.debug_eqbs_incomplete); return (count - tmp_count); + } + if (rc == 1) { - QDIO_DBF_TEXT5(1, trace, "eqAGAIN"); + DBF_DEV_EVENT(DBF_WARN, q->irq_ptr, "EQBS again:%2d", ccq); goto again; } if (rc < 0) { - QDIO_DBF_TEXT2(1, trace, "eqberr"); - sprintf(dbf_text, "%2x,%2x,%d,%d", count, tmp_count, ccq, nr); - QDIO_DBF_TEXT2(1, trace, dbf_text); + DBF_ERROR("%4x EQBS ERROR", SCH_NO(q)); + DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, 0, -1, -1, q->irq_ptr->int_parm); @@ -176,9 +177,12 @@ static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, int start, int tmp_count = count, tmp_start = start; int nr = q->nr; int rc; - char dbf_text[15]; + + if (!count) + return 0; BUG_ON(!q->irq_ptr->sch_token); + qdio_perf_stat_inc(&perf_stats.debug_sqbs_all); if (!q->is_input_q) nr += q->irq_ptr->nr_input_qs; @@ -186,16 +190,13 @@ again: ccq = do_sqbs(q->irq_ptr->sch_token, state, nr, &tmp_start, &tmp_count); rc = qdio_check_ccq(q, ccq); if (rc == 1) { - QDIO_DBF_TEXT5(1, trace, "sqAGAIN"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "SQBS again:%2d", ccq); + qdio_perf_stat_inc(&perf_stats.debug_sqbs_incomplete); goto again; } if (rc < 0) { - QDIO_DBF_TEXT3(1, trace, "sqberr"); - sprintf(dbf_text, "%2x,%2x", count, tmp_count); - QDIO_DBF_TEXT3(1, trace, dbf_text); - sprintf(dbf_text, "%d,%d", ccq, nr); - QDIO_DBF_TEXT3(1, trace, dbf_text); - + DBF_ERROR("%4x SQBS ERROR", SCH_NO(q)); + DBF_ERROR("%3d%3d%2d", count, tmp_count, nr); q->handler(q->irq_ptr->cdev, QDIO_ERROR_ACTIVATE_CHECK_CONDITION, 0, -1, -1, q->irq_ptr->int_parm); @@ -207,7 +208,8 @@ again: /* returns number of examined buffers and their common state in *state */ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, - unsigned char *state, unsigned int count) + unsigned char *state, unsigned int count, + int auto_ack) { unsigned char __state = 0; int i; @@ -216,7 +218,7 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, BUG_ON(count > QDIO_MAX_BUFFERS_PER_Q); if (is_qebsm(q)) - return qdio_do_eqbs(q, state, bufnr, count); + return qdio_do_eqbs(q, state, bufnr, count, auto_ack); for (i = 0; i < count; i++) { if (!__state) @@ -230,9 +232,9 @@ static inline int get_buf_states(struct qdio_q *q, unsigned int bufnr, } inline int get_buf_state(struct qdio_q *q, unsigned int bufnr, - unsigned char *state) + unsigned char *state, int auto_ack) { - return get_buf_states(q, bufnr, state, 1); + return get_buf_states(q, bufnr, state, 1, auto_ack); } /* wrap-around safe setting of slsb states, returns number of changed buffers */ @@ -282,14 +284,12 @@ static int qdio_siga_sync(struct qdio_q *q, unsigned int output, if (!need_siga_sync(q)) return 0; + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-s:%1d", q->nr); qdio_perf_stat_inc(&perf_stats.siga_sync); cc = do_siga_sync(q->irq_ptr->schid, output, input); - if (cc) { - QDIO_DBF_TEXT4(0, trace, "sigasync"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); - } + if (cc) + DBF_ERROR("%4x SIGA-S:%2d", SCH_NO(q), cc); return cc; } @@ -311,50 +311,37 @@ static inline int qdio_siga_sync_all(struct qdio_q *q) return qdio_siga_sync(q, ~0U, ~0U); } -static inline int qdio_do_siga_output(struct qdio_q *q, unsigned int *busy_bit) +static int qdio_siga_output(struct qdio_q *q, unsigned int *busy_bit) { - unsigned int fc = 0; unsigned long schid; + unsigned int fc = 0; + u64 start_time = 0; + int cc; - if (q->u.out.use_enh_siga) { + if (q->u.out.use_enh_siga) fc = 3; - } - if (!is_qebsm(q)) - schid = *((u32 *)&q->irq_ptr->schid); - else { + + if (is_qebsm(q)) { schid = q->irq_ptr->sch_token; fc |= 0x80; } - return do_siga_output(schid, q->mask, busy_bit, fc); -} - -static int qdio_siga_output(struct qdio_q *q) -{ - int cc; - u32 busy_bit; - u64 start_time = 0; - char dbf_text[15]; - - QDIO_DBF_TEXT5(0, trace, "sigaout"); - QDIO_DBF_HEX5(0, trace, &q, sizeof(void *)); + else + schid = *((u32 *)&q->irq_ptr->schid); - qdio_perf_stat_inc(&perf_stats.siga_out); again: - cc = qdio_do_siga_output(q, &busy_bit); - if (queue_type(q) == QDIO_IQDIO_QFMT && cc == 2 && busy_bit) { - sprintf(dbf_text, "bb%4x%2x", q->irq_ptr->schid.sch_no, q->nr); - QDIO_DBF_TEXT3(0, trace, dbf_text); + cc = do_siga_output(schid, q->mask, busy_bit, fc); - if (!start_time) + /* hipersocket busy condition */ + if (*busy_bit) { + WARN_ON(queue_type(q) != QDIO_IQDIO_QFMT || cc != 2); + + if (!start_time) { start_time = get_usecs(); - else if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) + goto again; + } + if ((get_usecs() - start_time) < QDIO_BUSY_BIT_PATIENCE) goto again; } - - if (cc == 2 && busy_bit) - cc |= QDIO_ERROR_SIGA_BUSY; - if (cc) - QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); return cc; } @@ -362,14 +349,12 @@ static inline int qdio_siga_input(struct qdio_q *q) { int cc; - QDIO_DBF_TEXT4(0, trace, "sigain"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-r:%1d", q->nr); qdio_perf_stat_inc(&perf_stats.siga_in); cc = do_siga_input(q->irq_ptr->schid, q->mask); if (cc) - QDIO_DBF_HEX3(0, trace, &cc, sizeof(int *)); + DBF_ERROR("%4x SIGA-R:%2d", SCH_NO(q), cc); return cc; } @@ -387,35 +372,91 @@ void qdio_sync_after_thinint(struct qdio_q *q) inline void qdio_stop_polling(struct qdio_q *q) { - spin_lock_bh(&q->u.in.lock); - if (!q->u.in.polling) { - spin_unlock_bh(&q->u.in.lock); + if (!q->u.in.polling) return; - } + q->u.in.polling = 0; qdio_perf_stat_inc(&perf_stats.debug_stop_polling); /* show the card that we are not polling anymore */ - set_buf_state(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT); - spin_unlock_bh(&q->u.in.lock); + if (is_qebsm(q)) { + set_buf_states(q, q->last_move_ftc, 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); } -static void announce_buffer_error(struct qdio_q *q) +static void announce_buffer_error(struct qdio_q *q, int count) { - char dbf_text[15]; + q->qdio_error |= QDIO_ERROR_SLSB_STATE; + + /* special handling for no target buffer empty */ + if ((!q->is_input_q && + (q->sbal[q->first_to_check]->element[15].flags & 0xff) == 0x10)) { + qdio_perf_stat_inc(&perf_stats.outbound_target_full); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "OUTFULL FTC:%3d", + q->first_to_check); + return; + } - if (q->is_input_q) - QDIO_DBF_TEXT3(1, trace, "inperr"); - else - QDIO_DBF_TEXT3(0, trace, "outperr"); + DBF_ERROR("%4x BUF ERROR", SCH_NO(q)); + DBF_ERROR((q->is_input_q) ? "IN:%2d" : "OUT:%2d", q->nr); + DBF_ERROR("FTC:%3d C:%3d", q->first_to_check, count); + DBF_ERROR("F14:%2x F15:%2x", + q->sbal[q->first_to_check]->element[14].flags & 0xff, + q->sbal[q->first_to_check]->element[15].flags & 0xff); +} + +static inline void inbound_primed(struct qdio_q *q, int count) +{ + int new; + + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in prim: %3d", count); + + /* for QEBSM the ACK was already set by EQBS */ + if (is_qebsm(q)) { + if (!q->u.in.polling) { + q->u.in.polling = 1; + q->u.in.ack_count = count; + q->last_move_ftc = q->first_to_check; + return; + } + + /* delete the previous ACK's */ + set_buf_states(q, q->last_move_ftc, SLSB_P_INPUT_NOT_INIT, + q->u.in.ack_count); + q->u.in.ack_count = count; + q->last_move_ftc = q->first_to_check; + return; + } + + /* + * ACK the newest buffer. The ACK will be removed in qdio_stop_polling + * or by the next inbound run. + */ + new = add_buf(q->first_to_check, count - 1); + 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); + } + else { + q->u.in.polling = 1; + set_buf_state(q, q->first_to_check, SLSB_P_INPUT_ACK); + } - sprintf(dbf_text, "%x-%x-%x", q->first_to_check, - q->sbal[q->first_to_check]->element[14].flags, - q->sbal[q->first_to_check]->element[15].flags); - QDIO_DBF_TEXT3(1, trace, dbf_text); - QDIO_DBF_HEX2(1, trace, q->sbal[q->first_to_check], 256); + q->last_move_ftc = new; + count--; + if (!count) + return; - q->qdio_error = QDIO_ERROR_SLSB_STATE; + /* + * 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, + count); } static int get_inbound_buffer_frontier(struct qdio_q *q) @@ -424,13 +465,6 @@ static int get_inbound_buffer_frontier(struct qdio_q *q) unsigned char state; /* - * If we still poll don't update last_move_ftc, keep the - * previously ACK buffer there. - */ - if (!q->u.in.polling) - q->last_move_ftc = q->first_to_check; - - /* * Don't check 128 buffers, as otherwise qdio_inbound_q_moved * would return 0. */ @@ -450,34 +484,13 @@ check_next: if (q->first_to_check == stop) goto out; - count = get_buf_states(q, q->first_to_check, &state, count); + count = get_buf_states(q, q->first_to_check, &state, count, 1); if (!count) goto out; switch (state) { case SLSB_P_INPUT_PRIMED: - QDIO_DBF_TEXT5(0, trace, "inptprim"); - - /* - * Only ACK the first buffer. The ACK will be removed in - * qdio_stop_polling. - */ - if (q->u.in.polling) - state = SLSB_P_INPUT_NOT_INIT; - else { - q->u.in.polling = 1; - state = SLSB_P_INPUT_ACK; - } - set_buf_state(q, q->first_to_check, state); - - /* - * Need to change all PRIMED buffers to NOT_INIT, otherwise - * we're loosing initiative in the thinint code. - */ - if (count > 1) - set_buf_states(q, next_buf(q->first_to_check), - SLSB_P_INPUT_NOT_INIT, count - 1); - + inbound_primed(q, count); /* * No siga-sync needed for non-qebsm here, as the inbound queue * will be synced on the next siga-r, resp. @@ -487,7 +500,7 @@ check_next: atomic_sub(count, &q->nr_buf_used); goto check_next; case SLSB_P_INPUT_ERROR: - announce_buffer_error(q); + announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); @@ -495,13 +508,12 @@ check_next: case SLSB_CU_INPUT_EMPTY: case SLSB_P_INPUT_NOT_INIT: case SLSB_P_INPUT_ACK: - QDIO_DBF_TEXT5(0, trace, "inpnipro"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in nop"); break; default: BUG(); } out: - QDIO_DBF_HEX4(0, trace, &q->first_to_check, sizeof(int)); return q->first_to_check; } @@ -515,8 +527,7 @@ int qdio_inbound_q_moved(struct qdio_q *q) if (!need_siga_sync(q) && !pci_out_supported(q)) q->u.in.timestamp = get_usecs(); - QDIO_DBF_TEXT4(0, trace, "inhasmvd"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in moved"); return 1; } else return 0; @@ -524,10 +535,7 @@ int qdio_inbound_q_moved(struct qdio_q *q) static int qdio_inbound_q_done(struct qdio_q *q) { - unsigned char state; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; -#endif + unsigned char state = 0; if (!atomic_read(&q->nr_buf_used)) return 1; @@ -538,7 +546,7 @@ static int qdio_inbound_q_done(struct qdio_q *q) */ qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state); + get_buf_state(q, q->first_to_check, &state, 0); if (state == SLSB_P_INPUT_PRIMED) /* we got something to do */ return 0; @@ -552,20 +560,12 @@ static int qdio_inbound_q_done(struct qdio_q *q) * has (probably) not moved (see qdio_inbound_processing). */ if (get_usecs() > q->u.in.timestamp + QDIO_INPUT_THRESHOLD) { -#ifdef CONFIG_QDIO_DEBUG - QDIO_DBF_TEXT4(0, trace, "inqisdon"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - sprintf(dbf_text, "pf%02x", q->first_to_check); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in done:%3d", + q->first_to_check); return 1; } else { -#ifdef CONFIG_QDIO_DEBUG - QDIO_DBF_TEXT4(0, trace, "inqisntd"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - sprintf(dbf_text, "pf%02x", q->first_to_check); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "in notd:%3d", + q->first_to_check); return 0; } } @@ -573,9 +573,6 @@ static int qdio_inbound_q_done(struct qdio_q *q) void qdio_kick_inbound_handler(struct qdio_q *q) { int count, start, end; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; -#endif qdio_perf_stat_inc(&perf_stats.inbound_handler); @@ -586,10 +583,7 @@ void qdio_kick_inbound_handler(struct qdio_q *q) else count = end + QDIO_MAX_BUFFERS_PER_Q - start; -#ifdef CONFIG_QDIO_DEBUG - sprintf(dbf_text, "s=%2xc=%2x", start, count); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "kih s:%3d c:%3d", start, count); if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; @@ -655,14 +649,14 @@ check_next: if (q->first_to_check == stop) return q->first_to_check; - count = get_buf_states(q, q->first_to_check, &state, count); + count = get_buf_states(q, q->first_to_check, &state, count, 0); if (!count) return q->first_to_check; switch (state) { case SLSB_P_OUTPUT_EMPTY: /* the adapter got it */ - QDIO_DBF_TEXT5(0, trace, "outpempt"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out empty:%1d %3d", q->nr, count); atomic_sub(count, &q->nr_buf_used); q->first_to_check = add_buf(q->first_to_check, count); @@ -674,14 +668,14 @@ check_next: break; goto check_next; case SLSB_P_OUTPUT_ERROR: - announce_buffer_error(q); + announce_buffer_error(q, count); /* process the buffer, the upper layer will take care of it */ q->first_to_check = add_buf(q->first_to_check, count); atomic_sub(count, &q->nr_buf_used); break; case SLSB_CU_OUTPUT_PRIMED: /* the adapter has not fetched the output yet */ - QDIO_DBF_TEXT5(0, trace, "outpprim"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out primed:%1d", q->nr); break; case SLSB_P_OUTPUT_NOT_INIT: case SLSB_P_OUTPUT_HALTED: @@ -706,99 +700,48 @@ static inline int qdio_outbound_q_moved(struct qdio_q *q) if ((bufnr != q->last_move_ftc) || q->qdio_error) { q->last_move_ftc = bufnr; - QDIO_DBF_TEXT4(0, trace, "oqhasmvd"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "out moved:%1d", q->nr); return 1; } else return 0; } -/* - * VM could present us cc=2 and busy bit set on SIGA-write - * during reconfiguration of their Guest LAN (only in iqdio mode, - * otherwise qdio is asynchronous and cc=2 and busy bit there will take - * the queues down immediately). - * - * Therefore qdio_siga_output will try for a short time constantly, - * if such a condition occurs. If it doesn't change, it will - * increase the busy_siga_counter and save the timestamp, and - * schedule the queue for later processing. qdio_outbound_processing - * will check out the counter. If non-zero, it will call qdio_kick_outbound_q - * as often as the value of the counter. This will attempt further SIGA - * instructions. For each successful SIGA, the counter is - * decreased, for failing SIGAs the counter remains the same, after - * all. After some time of no movement, qdio_kick_outbound_q will - * finally fail and reflect corresponding error codes to call - * the upper layer module and have it take the queues down. - * - * Note that this is a change from the original HiperSockets design - * (saying cc=2 and busy bit means take the queues down), but in - * these days Guest LAN didn't exist... excessive cc=2 with busy bit - * conditions will still take the queues down, but the threshold is - * higher due to the Guest LAN environment. - * - * Called from outbound tasklet and do_QDIO handler. - */ static void qdio_kick_outbound_q(struct qdio_q *q) { - int rc; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; - - QDIO_DBF_TEXT5(0, trace, "kickoutq"); - QDIO_DBF_HEX5(0, trace, &q, sizeof(void *)); -#endif /* CONFIG_QDIO_DEBUG */ + unsigned int busy_bit; + int cc; if (!need_siga_out(q)) return; - rc = qdio_siga_output(q); - switch (rc) { + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); + qdio_perf_stat_inc(&perf_stats.siga_out); + + cc = qdio_siga_output(q, &busy_bit); + switch (cc) { case 0: - /* TODO: improve error handling for CC=0 case */ -#ifdef CONFIG_QDIO_DEBUG - if (q->u.out.timestamp) { - QDIO_DBF_TEXT3(0, trace, "cc2reslv"); - sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no, - q->nr, - atomic_read(&q->u.out.busy_siga_counter)); - QDIO_DBF_TEXT3(0, trace, dbf_text); - } -#endif /* CONFIG_QDIO_DEBUG */ - /* went smooth this time, reset timestamp */ - q->u.out.timestamp = 0; break; - /* cc=2 and busy bit */ - case (2 | QDIO_ERROR_SIGA_BUSY): - atomic_inc(&q->u.out.busy_siga_counter); - - /* if the last siga was successful, save timestamp here */ - if (!q->u.out.timestamp) - q->u.out.timestamp = get_usecs(); - - /* if we're in time, don't touch qdio_error */ - if (get_usecs() - q->u.out.timestamp < QDIO_BUSY_BIT_GIVE_UP) { - tasklet_schedule(&q->tasklet); - break; + 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; } - QDIO_DBF_TEXT2(0, trace, "cc2REPRT"); -#ifdef CONFIG_QDIO_DEBUG - sprintf(dbf_text, "%4x%2x%2x", q->irq_ptr->schid.sch_no, q->nr, - atomic_read(&q->u.out.busy_siga_counter)); - QDIO_DBF_TEXT3(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ - default: - /* for plain cc=1, 2 or 3 */ - q->qdio_error = rc; + break; + case 1: + case 3: + DBF_ERROR("%4x SIGA-W:%1d", SCH_NO(q), cc); + q->qdio_error = cc; + break; } } static void qdio_kick_outbound_handler(struct qdio_q *q) { int start, end, count; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; -#endif start = q->first_to_kick; end = q->last_move_ftc; @@ -807,13 +750,8 @@ static void qdio_kick_outbound_handler(struct qdio_q *q) else count = end + QDIO_MAX_BUFFERS_PER_Q - start; -#ifdef CONFIG_QDIO_DEBUG - QDIO_DBF_TEXT4(0, trace, "kickouth"); - QDIO_DBF_HEX4(0, trace, &q, sizeof(void *)); - - sprintf(dbf_text, "s=%2xc=%2x", start, count); - QDIO_DBF_TEXT4(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + 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; @@ -828,22 +766,18 @@ static void qdio_kick_outbound_handler(struct qdio_q *q) static void __qdio_outbound_processing(struct qdio_q *q) { - int siga_attempts; + unsigned long flags; qdio_perf_stat_inc(&perf_stats.tasklet_outbound); - - /* see comment in qdio_kick_outbound_q */ - siga_attempts = atomic_read(&q->u.out.busy_siga_counter); - while (siga_attempts--) { - atomic_dec(&q->u.out.busy_siga_counter); - qdio_kick_outbound_q(q); - } + 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)) tasklet_schedule(&q->tasklet); @@ -908,27 +842,18 @@ void qdio_check_outbound_after_thinint(struct qdio_q *q) static inline void qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) { -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[15]; - - QDIO_DBF_TEXT5(0, trace, "newstate"); - sprintf(dbf_text, "%4x%4x", irq_ptr->schid.sch_no, state); - QDIO_DBF_TEXT5(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "newstate: %1d", state); irq_ptr->state = state; mb(); } -static void qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) +static void qdio_irq_check_sense(struct qdio_irq *irq_ptr, struct irb *irb) { - char dbf_text[15]; - if (irb->esw.esw0.erw.cons) { - sprintf(dbf_text, "sens%4x", schid.sch_no); - QDIO_DBF_TEXT2(1, trace, dbf_text); - QDIO_DBF_HEX0(0, trace, irb, 64); - QDIO_DBF_HEX0(0, trace, irb->ecw, 64); + DBF_ERROR("%4x sense:", irq_ptr->schid.sch_no); + DBF_ERROR_HEX(irb, 64); + DBF_ERROR_HEX(irb->ecw, 64); } } @@ -962,14 +887,10 @@ static void qdio_handle_activate_check(struct ccw_device *cdev, { struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct qdio_q *q; - char dbf_text[15]; - QDIO_DBF_TEXT2(1, trace, "ick2"); - sprintf(dbf_text, "%s", dev_name(&cdev->dev)); - QDIO_DBF_TEXT2(1, trace, dbf_text); - QDIO_DBF_HEX2(0, trace, &intparm, sizeof(int)); - QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int)); - QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int)); + DBF_ERROR("%4x ACT CHECK", irq_ptr->schid.sch_no); + DBF_ERROR("intp :%lx", intparm); + DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); if (irq_ptr->nr_input_qs) { q = irq_ptr->input_qs[0]; @@ -1022,28 +943,29 @@ static void qdio_int_error(struct ccw_device *cdev) } static int qdio_establish_check_errors(struct ccw_device *cdev, int cstat, - int dstat) + int dstat) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; if (cstat || (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { - QDIO_DBF_TEXT2(1, setup, "eq:ckcon"); + DBF_ERROR("EQ:ck con"); goto error; } if (!(dstat & DEV_STAT_DEV_END)) { - QDIO_DBF_TEXT2(1, setup, "eq:no de"); + DBF_ERROR("EQ:no dev"); goto error; } if (dstat & ~(DEV_STAT_CHN_END | DEV_STAT_DEV_END)) { - QDIO_DBF_TEXT2(1, setup, "eq:badio"); + DBF_ERROR("EQ: bad io"); goto error; } return 0; error: - QDIO_DBF_HEX2(0, trace, &cstat, sizeof(int)); - QDIO_DBF_HEX2(0, trace, &dstat, sizeof(int)); + DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no); + DBF_ERROR("ds: %2x cs:%2x", dstat, cstat); + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); return 1; } @@ -1052,12 +974,8 @@ static void qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) { struct qdio_irq *irq_ptr = cdev->private->qdio_data; - char dbf_text[15]; - - sprintf(dbf_text, "qehi%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_TEXT0(0, trace, dbf_text); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq"); if (!qdio_establish_check_errors(cdev, cstat, dstat)) qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED); } @@ -1068,25 +986,21 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, { struct qdio_irq *irq_ptr = cdev->private->qdio_data; int cstat, dstat; - char dbf_text[15]; qdio_perf_stat_inc(&perf_stats.qdio_int); if (!intparm || !irq_ptr) { - sprintf(dbf_text, "qihd%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("qint:%4x", cdev->private->schid.sch_no); return; } if (IS_ERR(irb)) { switch (PTR_ERR(irb)) { case -EIO: - sprintf(dbf_text, "ierr%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x IO error", irq_ptr->schid.sch_no); return; case -ETIMEDOUT: - sprintf(dbf_text, "qtoh%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x IO timeout", irq_ptr->schid.sch_no); qdio_int_error(cdev); return; default: @@ -1094,7 +1008,7 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } } - qdio_irq_check_sense(irq_ptr->schid, irb); + qdio_irq_check_sense(irq_ptr, irb); cstat = irb->scsw.cmd.cstat; dstat = irb->scsw.cmd.dstat; @@ -1129,23 +1043,20 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, /** * qdio_get_ssqd_desc - get qdio subchannel description * @cdev: ccw device to get description for + * @data: where to store the ssqd * - * Returns a pointer to the saved qdio subchannel description, - * or NULL for not setup qdio devices. + * Returns 0 or an error code. The results of the chsc are stored in the + * specified structure. */ -struct qdio_ssqd_desc *qdio_get_ssqd_desc(struct ccw_device *cdev) +int qdio_get_ssqd_desc(struct ccw_device *cdev, + struct qdio_ssqd_desc *data) { - struct qdio_irq *irq_ptr; - char dbf_text[15]; - - sprintf(dbf_text, "qssq%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - irq_ptr = cdev->private->qdio_data; - if (!irq_ptr) - return NULL; + if (!cdev || !cdev->private) + return -EINVAL; - return &irq_ptr->ssqd_desc; + DBF_EVENT("get ssqd:%4x", cdev->private->schid.sch_no); + return qdio_setup_get_ssqd(NULL, &cdev->private->schid, data); } EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); @@ -1159,14 +1070,9 @@ EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); */ int qdio_cleanup(struct ccw_device *cdev, int how) { - struct qdio_irq *irq_ptr; - char dbf_text[15]; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; int rc; - sprintf(dbf_text, "qcln%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; @@ -1199,18 +1105,15 @@ static void qdio_shutdown_queues(struct ccw_device *cdev) */ int qdio_shutdown(struct ccw_device *cdev, int how) { - struct qdio_irq *irq_ptr; + struct qdio_irq *irq_ptr = cdev->private->qdio_data; int rc; unsigned long flags; - char dbf_text[15]; - sprintf(dbf_text, "qshu%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; + DBF_EVENT("qshutdown:%4x", cdev->private->schid.sch_no); + mutex_lock(&irq_ptr->setup_mutex); /* * Subchannel was already shot down. We cannot prevent being called @@ -1234,10 +1137,8 @@ int qdio_shutdown(struct ccw_device *cdev, int how) /* default behaviour is halt */ rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); if (rc) { - sprintf(dbf_text, "sher%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - sprintf(dbf_text, "rc=%d", rc); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_ERROR("%4x SHUTD ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%4d", rc); goto no_cleanup; } @@ -1271,17 +1172,18 @@ EXPORT_SYMBOL_GPL(qdio_shutdown); */ int qdio_free(struct ccw_device *cdev) { - struct qdio_irq *irq_ptr; - char dbf_text[15]; - - sprintf(dbf_text, "qfre%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + struct qdio_irq *irq_ptr = cdev->private->qdio_data; - irq_ptr = cdev->private->qdio_data; if (!irq_ptr) return -ENODEV; + DBF_EVENT("qfree:%4x", cdev->private->schid.sch_no); mutex_lock(&irq_ptr->setup_mutex); + + if (irq_ptr->debug_area != NULL) { + debug_unregister(irq_ptr->debug_area); + irq_ptr->debug_area = NULL; + } cdev->private->qdio_data = NULL; mutex_unlock(&irq_ptr->setup_mutex); @@ -1300,10 +1202,6 @@ EXPORT_SYMBOL_GPL(qdio_free); int qdio_initialize(struct qdio_initialize *init_data) { int rc; - char dbf_text[15]; - - sprintf(dbf_text, "qini%4x", init_data->cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); rc = qdio_allocate(init_data); if (rc) @@ -1323,10 +1221,8 @@ EXPORT_SYMBOL_GPL(qdio_initialize); int qdio_allocate(struct qdio_initialize *init_data) { struct qdio_irq *irq_ptr; - char dbf_text[15]; - sprintf(dbf_text, "qalc%4x", init_data->cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("qallocate:%4x", init_data->cdev->private->schid.sch_no); if ((init_data->no_input_qs && !init_data->input_handler) || (init_data->no_output_qs && !init_data->output_handler)) @@ -1340,16 +1236,13 @@ int qdio_allocate(struct qdio_initialize *init_data) (!init_data->output_sbal_addr_array)) return -EINVAL; - qdio_allocate_do_dbf(init_data); - /* irq_ptr must be in GFP_DMA since it contains ccw1.cda */ irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!irq_ptr) goto out_err; - QDIO_DBF_TEXT0(0, setup, "irq_ptr:"); - QDIO_DBF_HEX0(0, setup, &irq_ptr, sizeof(void *)); mutex_init(&irq_ptr->setup_mutex); + qdio_allocate_dbf(init_data, irq_ptr); /* * Allocate a page for the chsc calls in qdio_establish. @@ -1367,9 +1260,6 @@ int qdio_allocate(struct qdio_initialize *init_data) goto out_rel; WARN_ON((unsigned long)irq_ptr->qdr & 0xfff); - QDIO_DBF_TEXT0(0, setup, "qdr:"); - QDIO_DBF_HEX0(0, setup, &irq_ptr->qdr, sizeof(void *)); - if (qdio_allocate_qs(irq_ptr, init_data->no_input_qs, init_data->no_output_qs)) goto out_rel; @@ -1390,14 +1280,12 @@ EXPORT_SYMBOL_GPL(qdio_allocate); */ int qdio_establish(struct qdio_initialize *init_data) { - char dbf_text[20]; struct qdio_irq *irq_ptr; struct ccw_device *cdev = init_data->cdev; unsigned long saveflags; int rc; - sprintf(dbf_text, "qest%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("qestablish:%4x", cdev->private->schid.sch_no); irq_ptr = cdev->private->qdio_data; if (!irq_ptr) @@ -1427,10 +1315,8 @@ int qdio_establish(struct qdio_initialize *init_data) rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ESTABLISH, 0, 0); if (rc) { - sprintf(dbf_text, "eq:io%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); - sprintf(dbf_text, "eq:rc%4x", rc); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x est IO ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%4x", rc); } spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); @@ -1451,10 +1337,8 @@ int qdio_establish(struct qdio_initialize *init_data) } qdio_setup_ssqd_info(irq_ptr); - sprintf(dbf_text, "qDmmwc%2x", irq_ptr->ssqd_desc.mmwc); - QDIO_DBF_TEXT2(0, setup, dbf_text); - sprintf(dbf_text, "qib ac%2x", irq_ptr->qib.ac); - QDIO_DBF_TEXT2(0, setup, dbf_text); + DBF_EVENT("qDmmwc:%2x", irq_ptr->ssqd_desc.mmwc); + DBF_EVENT("qib ac:%4x", irq_ptr->qib.ac); /* qebsm is now setup if available, initialize buffer states */ qdio_init_buf_states(irq_ptr); @@ -1475,10 +1359,8 @@ int qdio_activate(struct ccw_device *cdev) struct qdio_irq *irq_ptr; int rc; unsigned long saveflags; - char dbf_text[20]; - sprintf(dbf_text, "qact%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("qactivate:%4x", cdev->private->schid.sch_no); irq_ptr = cdev->private->qdio_data; if (!irq_ptr) @@ -1504,10 +1386,8 @@ int qdio_activate(struct ccw_device *cdev) rc = ccw_device_start(cdev, &irq_ptr->ccw, QDIO_DOING_ACTIVATE, 0, DOIO_DENY_PREFETCH); if (rc) { - sprintf(dbf_text, "aq:io%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(1, setup, dbf_text); - sprintf(dbf_text, "aq:rc%4x", rc); - QDIO_DBF_TEXT2(1, setup, dbf_text); + DBF_ERROR("%4x act IO ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%4x", rc); } spin_unlock_irqrestore(get_ccwdev_lock(cdev), saveflags); @@ -1565,23 +1445,38 @@ static inline int buf_in_between(int bufnr, int start, int count) static void handle_inbound(struct qdio_q *q, unsigned int callflags, int bufnr, int count) { - unsigned long flags; - int used, rc; + int used, cc, diff; - /* - * do_QDIO could run in parallel with the queue tasklet so the - * upper-layer programm could empty the ACK'ed buffer here. - * If that happens we must clear the polling flag, otherwise - * qdio_stop_polling() could set the buffer to NOT_INIT after - * it was set to EMPTY which would kill us. - */ - spin_lock_irqsave(&q->u.in.lock, flags); - if (q->u.in.polling) - if (buf_in_between(q->last_move_ftc, bufnr, count)) + if (!q->u.in.polling) + goto set; + + /* protect against stop polling setting an ACK for an emptied slsb */ + if (count == QDIO_MAX_BUFFERS_PER_Q) { + /* overwriting everything, just delete polling status */ + q->u.in.polling = 0; + q->u.in.ack_count = 0; + goto set; + } else if (buf_in_between(q->last_move_ftc, bufnr, count)) { + if (is_qebsm(q)) { + /* partial overwrite, just update last_move_ftc */ + diff = add_buf(bufnr, count); + diff = sub_buf(diff, q->last_move_ftc); + q->u.in.ack_count -= diff; + 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); + } + else + /* the only ACK will be deleted, so stop polling */ q->u.in.polling = 0; + } +set: count = set_buf_states(q, bufnr, SLSB_CU_INPUT_EMPTY, count); - spin_unlock_irqrestore(&q->u.in.lock, flags); used = atomic_add_return(count, &q->nr_buf_used) - count; BUG_ON(used + count > QDIO_MAX_BUFFERS_PER_Q); @@ -1591,9 +1486,9 @@ static void handle_inbound(struct qdio_q *q, unsigned int callflags, return; if (need_siga_in(q)) { - rc = qdio_siga_input(q); - if (rc) - q->qdio_error = rc; + cc = qdio_siga_input(q); + if (cc) + q->qdio_error = cc; } } @@ -1640,6 +1535,10 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, while (count--) qdio_kick_outbound_q(q); } + + /* report CC=2 conditions synchronously */ + if (q->qdio_error) + __qdio_outbound_processing(q); goto out; } @@ -1649,11 +1548,11 @@ static void handle_outbound(struct qdio_q *q, unsigned int callflags, } /* try to fast requeue buffers */ - get_buf_state(q, prev_buf(bufnr), &state); + get_buf_state(q, prev_buf(bufnr), &state, 0); if (state != SLSB_CU_OUTPUT_PRIMED) qdio_kick_outbound_q(q); else { - QDIO_DBF_TEXT5(0, trace, "fast-req"); + DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "fast-req"); qdio_perf_stat_inc(&perf_stats.fast_requeue); } out: @@ -1673,12 +1572,6 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, int q_nr, int bufnr, int count) { struct qdio_irq *irq_ptr; -#ifdef CONFIG_QDIO_DEBUG - char dbf_text[20]; - - sprintf(dbf_text, "doQD%4x", cdev->private->schid.sch_no); - QDIO_DBF_TEXT3(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ if ((bufnr > QDIO_MAX_BUFFERS_PER_Q) || (count > QDIO_MAX_BUFFERS_PER_Q) || @@ -1692,33 +1585,24 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, if (!irq_ptr) return -ENODEV; -#ifdef CONFIG_QDIO_DEBUG if (callflags & QDIO_FLAG_SYNC_INPUT) - QDIO_DBF_HEX3(0, trace, &irq_ptr->input_qs[q_nr], - sizeof(void *)); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO input"); else - QDIO_DBF_HEX3(0, trace, &irq_ptr->output_qs[q_nr], - sizeof(void *)); - - sprintf(dbf_text, "flag%04x", callflags); - QDIO_DBF_TEXT3(0, trace, dbf_text); - sprintf(dbf_text, "qi%02xct%02x", bufnr, count); - QDIO_DBF_TEXT3(0, trace, dbf_text); -#endif /* CONFIG_QDIO_DEBUG */ + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "doQDIO output"); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "q:%1d flag:%4x", q_nr, callflags); + DBF_DEV_EVENT(DBF_INFO, irq_ptr, "buf:%2d cnt:%3d", bufnr, count); if (irq_ptr->state != QDIO_IRQ_STATE_ACTIVE) return -EBUSY; if (callflags & QDIO_FLAG_SYNC_INPUT) - handle_inbound(irq_ptr->input_qs[q_nr], - callflags, bufnr, count); + 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 { - QDIO_DBF_TEXT3(1, trace, "doQD:inv"); + handle_outbound(irq_ptr->output_qs[q_nr], callflags, bufnr, + count); + else return -EINVAL; - } return 0; } EXPORT_SYMBOL_GPL(do_QDIO); diff --git a/drivers/s390/cio/qdio_perf.c b/drivers/s390/cio/qdio_perf.c index ec5c4a41423..136d0f0b1e9 100644 --- a/drivers/s390/cio/qdio_perf.c +++ b/drivers/s390/cio/qdio_perf.c @@ -74,12 +74,20 @@ static int qdio_perf_proc_show(struct seq_file *m, void *v) seq_printf(m, "\n"); seq_printf(m, "Number of fast requeues (outg. SBAL w/o SIGA)\t: %li\n", (long)atomic_long_read(&perf_stats.fast_requeue)); + seq_printf(m, "Number of outbound target full condition\t: %li\n", + (long)atomic_long_read(&perf_stats.outbound_target_full)); seq_printf(m, "Number of outbound tasklet mod_timer calls\t: %li\n", (long)atomic_long_read(&perf_stats.debug_tl_out_timer)); seq_printf(m, "Number of stop polling calls\t\t\t: %li\n", (long)atomic_long_read(&perf_stats.debug_stop_polling)); seq_printf(m, "AI inbound tasklet loops after stop polling\t: %li\n", (long)atomic_long_read(&perf_stats.thinint_inbound_loop2)); + seq_printf(m, "QEBSM EQBS total/incomplete\t\t\t: %li/%li\n", + (long)atomic_long_read(&perf_stats.debug_eqbs_all), + (long)atomic_long_read(&perf_stats.debug_eqbs_incomplete)); + seq_printf(m, "QEBSM SQBS total/incomplete\t\t\t: %li/%li\n", + (long)atomic_long_read(&perf_stats.debug_sqbs_all), + (long)atomic_long_read(&perf_stats.debug_sqbs_incomplete)); seq_printf(m, "\n"); return 0; } diff --git a/drivers/s390/cio/qdio_perf.h b/drivers/s390/cio/qdio_perf.h index 5c406a8b738..7821ac4fa51 100644 --- a/drivers/s390/cio/qdio_perf.h +++ b/drivers/s390/cio/qdio_perf.h @@ -36,10 +36,15 @@ struct qdio_perf_stats { atomic_long_t inbound_handler; atomic_long_t outbound_handler; atomic_long_t fast_requeue; + atomic_long_t outbound_target_full; /* for debugging */ atomic_long_t debug_tl_out_timer; atomic_long_t debug_stop_polling; + atomic_long_t debug_eqbs_all; + atomic_long_t debug_eqbs_incomplete; + atomic_long_t debug_sqbs_all; + atomic_long_t debug_sqbs_incomplete; }; extern struct qdio_perf_stats perf_stats; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index a0b6b46e746..c08356b95bf 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -117,17 +117,16 @@ 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, - void **sbals_array, char *dbf_text, int i) + void **sbals_array, int i) { struct qdio_q *prev; int j; - QDIO_DBF_TEXT0(0, setup, dbf_text); - QDIO_DBF_HEX0(0, setup, &q, sizeof(void *)); - + DBF_HEX(&q, sizeof(void *)); q->sl = (struct sl *)((char *)q->slib + PAGE_SIZE / 2); /* fill in sbal */ @@ -150,31 +149,26 @@ static void setup_storage_lists(struct qdio_q *q, struct qdio_irq *irq_ptr, for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) q->sl->element[j].sbal = (unsigned long)q->sbal[j]; - QDIO_DBF_TEXT2(0, setup, "sl-sb-b0"); - QDIO_DBF_HEX2(0, setup, q->sl, sizeof(void *)); - QDIO_DBF_HEX2(0, setup, &q->slsb, sizeof(void *)); - QDIO_DBF_HEX2(0, setup, q->sbal, sizeof(void *)); + DBF_EVENT("sl-slsb-sbal"); + DBF_HEX(q->sl, sizeof(void *)); + DBF_HEX(&q->slsb, sizeof(void *)); + DBF_HEX(q->sbal, sizeof(void *)); } static void setup_queues(struct qdio_irq *irq_ptr, struct qdio_initialize *qdio_init) { - char dbf_text[20]; struct qdio_q *q; void **input_sbal_array = qdio_init->input_sbal_addr_array; void **output_sbal_array = qdio_init->output_sbal_addr_array; int i; - sprintf(dbf_text, "qset%4x", qdio_init->cdev->private->schid.sch_no); - QDIO_DBF_TEXT0(0, setup, dbf_text); - for_each_input_queue(irq_ptr, q, i) { - sprintf(dbf_text, "in-q%4x", i); + DBF_EVENT("in-q:%1d", i); setup_queues_misc(q, irq_ptr, qdio_init->input_handler, i); q->is_input_q = 1; - spin_lock_init(&q->u.in.lock); - setup_storage_lists(q, irq_ptr, input_sbal_array, dbf_text, i); + setup_storage_lists(q, irq_ptr, input_sbal_array, i); input_sbal_array += QDIO_MAX_BUFFERS_PER_Q; if (is_thinint_irq(irq_ptr)) @@ -186,12 +180,11 @@ static void setup_queues(struct qdio_irq *irq_ptr, } for_each_output_queue(irq_ptr, q, i) { - sprintf(dbf_text, "outq%4x", i); + DBF_EVENT("outq:%1d", i); setup_queues_misc(q, irq_ptr, qdio_init->output_handler, i); q->is_input_q = 0; - setup_storage_lists(q, irq_ptr, output_sbal_array, - dbf_text, i); + setup_storage_lists(q, irq_ptr, output_sbal_array, i); output_sbal_array += QDIO_MAX_BUFFERS_PER_Q; tasklet_init(&q->tasklet, qdio_outbound_processing, @@ -222,8 +215,6 @@ static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac) static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, unsigned long token) { - char dbf_text[15]; - if (!(irq_ptr->qib.rflags & QIB_RFLAGS_ENABLE_QEBSM)) goto no_qebsm; if (!(qdioac & AC1_SC_QEBSM_AVAILABLE) || @@ -232,33 +223,41 @@ static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, irq_ptr->sch_token = token; - QDIO_DBF_TEXT0(0, setup, "V=V:1"); - sprintf(dbf_text, "%8lx", irq_ptr->sch_token); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("V=V:1"); + DBF_EVENT("%8lx", irq_ptr->sch_token); return; no_qebsm: irq_ptr->sch_token = 0; irq_ptr->qib.rflags &= ~QIB_RFLAGS_ENABLE_QEBSM; - QDIO_DBF_TEXT0(0, setup, "noV=V"); + DBF_EVENT("noV=V"); } -static int __get_ssqd_info(struct qdio_irq *irq_ptr) +/* + * If there is a qdio_irq we use the chsc_page and store the information + * in the qdio_irq, otherwise we copy it to the specified structure. + */ +int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, + struct subchannel_id *schid, + struct qdio_ssqd_desc *data) { struct chsc_ssqd_area *ssqd; int rc; - QDIO_DBF_TEXT0(0, setup, "getssqd"); - ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; + DBF_EVENT("getssqd:%4x", schid->sch_no); + if (irq_ptr != NULL) + ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; + else + ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); memset(ssqd, 0, PAGE_SIZE); ssqd->request = (struct chsc_header) { .length = 0x0010, .code = 0x0024, }; - ssqd->first_sch = irq_ptr->schid.sch_no; - ssqd->last_sch = irq_ptr->schid.sch_no; - ssqd->ssid = irq_ptr->schid.ssid; + ssqd->first_sch = schid->sch_no; + ssqd->last_sch = schid->sch_no; + ssqd->ssid = schid->ssid; if (chsc(ssqd)) return -EIO; @@ -268,27 +267,29 @@ static int __get_ssqd_info(struct qdio_irq *irq_ptr) if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || - (ssqd->qdio_ssqd.sch != irq_ptr->schid.sch_no)) + (ssqd->qdio_ssqd.sch != schid->sch_no)) return -EINVAL; - memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, - sizeof(struct qdio_ssqd_desc)); + if (irq_ptr != NULL) + memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, + sizeof(struct qdio_ssqd_desc)); + else { + memcpy(data, &ssqd->qdio_ssqd, + sizeof(struct qdio_ssqd_desc)); + free_page((unsigned long)ssqd); + } return 0; } void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) { unsigned char qdioac; - char dbf_text[15]; int rc; - rc = __get_ssqd_info(irq_ptr); + rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); if (rc) { - QDIO_DBF_TEXT2(0, setup, "ssqdasig"); - sprintf(dbf_text, "schn%4x", irq_ptr->schid.sch_no); - QDIO_DBF_TEXT2(0, setup, dbf_text); - sprintf(dbf_text, "rc:%d", rc); - QDIO_DBF_TEXT2(0, setup, dbf_text); + DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); + DBF_ERROR("rc:%x", rc); /* all flags set, worst case */ qdioac = AC1_SIGA_INPUT_NEEDED | AC1_SIGA_OUTPUT_NEEDED | AC1_SIGA_SYNC_NEEDED; @@ -297,9 +298,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); process_ac_flags(irq_ptr, qdioac); - - sprintf(dbf_text, "qdioac%2x", qdioac); - QDIO_DBF_TEXT2(0, setup, dbf_text); + DBF_EVENT("qdioac:%4x", qdioac); } void qdio_release_memory(struct qdio_irq *irq_ptr) @@ -419,7 +418,7 @@ int qdio_setup_irq(struct qdio_initialize *init_data) /* get qdio commands */ ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_EQUEUE); if (!ciw) { - QDIO_DBF_TEXT2(1, setup, "no eq"); + DBF_ERROR("%4x NO EQ", irq_ptr->schid.sch_no); rc = -EINVAL; goto out_err; } @@ -427,7 +426,7 @@ int qdio_setup_irq(struct qdio_initialize *init_data) ciw = ccw_device_get_ciw(init_data->cdev, CIW_TYPE_AQUEUE); if (!ciw) { - QDIO_DBF_TEXT2(1, setup, "no aq"); + DBF_ERROR("%4x NO AQ", irq_ptr->schid.sch_no); rc = -EINVAL; goto out_err; } @@ -447,56 +446,38 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr, { char s[80]; - sprintf(s, "qdio: %s ", dev_name(&cdev->dev)); - switch (irq_ptr->qib.qfmt) { - case QDIO_QETH_QFMT: - sprintf(s + strlen(s), "OSA "); - break; - case QDIO_ZFCP_QFMT: - sprintf(s + strlen(s), "ZFCP "); - break; - case QDIO_IQDIO_QFMT: - sprintf(s + strlen(s), "HS "); - break; - } - sprintf(s + strlen(s), "on SC %x using ", irq_ptr->schid.sch_no); - sprintf(s + strlen(s), "AI:%d ", is_thinint_irq(irq_ptr)); - sprintf(s + strlen(s), "QEBSM:%d ", (irq_ptr->sch_token) ? 1 : 0); - sprintf(s + strlen(s), "PCI:%d ", - (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0); - sprintf(s + strlen(s), "TDD:%d ", css_general_characteristics.aif_tdd); - sprintf(s + strlen(s), "SIGA:"); - sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.input) ? "R" : " "); - sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.output) ? "W" : " "); - sprintf(s + strlen(s), "%s", (irq_ptr->siga_flag.sync) ? "S" : " "); - sprintf(s + strlen(s), "%s", - (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " "); - sprintf(s + strlen(s), "%s", - (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " "); - sprintf(s + strlen(s), "%s", - (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); - sprintf(s + strlen(s), "\n"); + snprintf(s, 80, "qdio: %s %s on SC %x using " + "AI:%d QEBSM:%d PCI:%d TDD:%d SIGA:%s%s%s%s%s%s\n", + dev_name(&cdev->dev), + (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : + ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), + irq_ptr->schid.sch_no, + is_thinint_irq(irq_ptr), + (irq_ptr->sch_token) ? 1 : 0, + (irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) ? 1 : 0, + css_general_characteristics.aif_tdd, + (irq_ptr->siga_flag.input) ? "R" : " ", + (irq_ptr->siga_flag.output) ? "W" : " ", + (irq_ptr->siga_flag.sync) ? "S" : " ", + (!irq_ptr->siga_flag.no_sync_ti) ? "A" : " ", + (!irq_ptr->siga_flag.no_sync_out_ti) ? "O" : " ", + (!irq_ptr->siga_flag.no_sync_out_pci) ? "P" : " "); printk(KERN_INFO "%s", s); } int __init qdio_setup_init(void) { - char dbf_text[15]; - qdio_q_cache = kmem_cache_create("qdio_q", sizeof(struct qdio_q), 256, 0, NULL); if (!qdio_q_cache) return -ENOMEM; /* Check for OSA/FCP thin interrupts (bit 67). */ - sprintf(dbf_text, "thini%1x", - (css_general_characteristics.aif_osa) ? 1 : 0); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("thinint:%1d", + (css_general_characteristics.aif_osa) ? 1 : 0); /* Check for QEBSM support in general (bit 58). */ - sprintf(dbf_text, "cssQBS:%1x", - (qebsm_possible()) ? 1 : 0); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0); return 0; } diff --git a/drivers/s390/cio/qdio_thinint.c b/drivers/s390/cio/qdio_thinint.c index ea7f6140026..8e90e147b74 100644 --- a/drivers/s390/cio/qdio_thinint.c +++ b/drivers/s390/cio/qdio_thinint.c @@ -125,13 +125,13 @@ void tiqdio_remove_input_queues(struct qdio_irq *irq_ptr) static inline int tiqdio_inbound_q_done(struct qdio_q *q) { - unsigned char state; + unsigned char state = 0; if (!atomic_read(&q->nr_buf_used)) return 1; qdio_siga_sync_q(q); - get_buf_state(q, q->first_to_check, &state); + get_buf_state(q, q->first_to_check, &state, 0); if (state == SLSB_P_INPUT_PRIMED) /* more work coming */ @@ -258,8 +258,6 @@ static void tiqdio_thinint_handler(void *ind, void *drv_data) static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) { struct scssc_area *scssc_area; - char dbf_text[15]; - void *ptr; int rc; scssc_area = (struct scssc_area *)irq_ptr->chsc_page; @@ -294,19 +292,15 @@ static int set_subchannel_ind(struct qdio_irq *irq_ptr, int reset) rc = chsc_error_from_response(scssc_area->response.code); if (rc) { - sprintf(dbf_text, "sidR%4x", scssc_area->response.code); - QDIO_DBF_TEXT1(0, trace, dbf_text); - QDIO_DBF_TEXT1(0, setup, dbf_text); - ptr = &scssc_area->response; - QDIO_DBF_HEX2(1, setup, &ptr, QDIO_DBF_SETUP_LEN); + DBF_ERROR("%4x SSI r:%4x", irq_ptr->schid.sch_no, + scssc_area->response.code); + DBF_ERROR_HEX(&scssc_area->response, sizeof(void *)); return rc; } - QDIO_DBF_TEXT2(0, setup, "setscind"); - QDIO_DBF_HEX2(0, setup, &scssc_area->summary_indicator_addr, - sizeof(unsigned long)); - QDIO_DBF_HEX2(0, setup, &scssc_area->subchannel_indicator_addr, - sizeof(unsigned long)); + DBF_EVENT("setscind"); + DBF_HEX(&scssc_area->summary_indicator_addr, sizeof(unsigned long)); + DBF_HEX(&scssc_area->subchannel_indicator_addr, sizeof(unsigned long)); return 0; } @@ -327,14 +321,11 @@ void tiqdio_free_memory(void) int __init tiqdio_register_thinints(void) { - char dbf_text[20]; - isc_register(QDIO_AIRQ_ISC); tiqdio_alsi = s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL, QDIO_AIRQ_ISC); if (IS_ERR(tiqdio_alsi)) { - sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_alsi)); - QDIO_DBF_TEXT0(0, setup, dbf_text); + DBF_EVENT("RTI:%lx", PTR_ERR(tiqdio_alsi)); tiqdio_alsi = NULL; isc_unregister(QDIO_AIRQ_ISC); return -ENOMEM; @@ -360,7 +351,7 @@ void qdio_setup_thinint(struct qdio_irq *irq_ptr) if (!is_thinint_irq(irq_ptr)) return; irq_ptr->dsci = get_indicator(); - QDIO_DBF_HEX1(0, setup, &irq_ptr->dsci, sizeof(void *)); + DBF_HEX(&irq_ptr->dsci, sizeof(void *)); } void qdio_shutdown_thinint(struct qdio_irq *irq_ptr) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index e3fe6838293..9c148406b98 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -5,6 +5,7 @@ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> * Ralph Wuerthner <rwuerthn@de.ibm.com> + * Felix Beck <felix.beck@de.ibm.com> * * Adjunct processor bus. * @@ -23,6 +24,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define KMSG_COMPONENT "ap" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/delay.h> @@ -32,8 +36,11 @@ #include <linux/notifier.h> #include <linux/kthread.h> #include <linux/mutex.h> -#include <asm/s390_rdev.h> #include <asm/reset.h> +#include <asm/airq.h> +#include <asm/atomic.h> +#include <asm/system.h> +#include <asm/isc.h> #include <linux/hrtimer.h> #include <linux/ktime.h> @@ -46,6 +53,7 @@ static enum hrtimer_restart ap_poll_timeout(struct hrtimer *); static int ap_poll_thread_start(void); static void ap_poll_thread_stop(void); static void ap_request_timeout(unsigned long); +static inline void ap_schedule_poll_timer(void); /* * Module description. @@ -68,7 +76,7 @@ module_param_named(poll_thread, ap_thread_flag, int, 0000); MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); static struct device *ap_root_device = NULL; -static DEFINE_SPINLOCK(ap_device_lock); +static DEFINE_SPINLOCK(ap_device_list_lock); static LIST_HEAD(ap_device_list); /* @@ -80,19 +88,29 @@ static int ap_config_time = AP_CONFIG_TIME; static DECLARE_WORK(ap_config_work, ap_scan_bus); /* - * Tasklet & timer for AP request polling. + * Tasklet & timer for AP request polling and interrupts */ static DECLARE_TASKLET(ap_tasklet, ap_poll_all, 0); static atomic_t ap_poll_requests = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread = NULL; static DEFINE_MUTEX(ap_poll_thread_mutex); +static void *ap_interrupt_indicator; static struct hrtimer ap_poll_timer; /* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ static unsigned long long poll_timeout = 250000; /** + * ap_using_interrupts() - Returns non-zero if interrupt support is + * available. + */ +static inline int ap_using_interrupts(void) +{ + return ap_interrupt_indicator != NULL; +} + +/** * ap_intructions_available() - Test if AP instructions are available. * * Returns 0 if the AP instructions are installed. @@ -113,6 +131,23 @@ static inline int ap_instructions_available(void) } /** + * ap_interrupts_available(): Test if AP interrupts are available. + * + * Returns 1 if AP interrupts are available. + */ +static int ap_interrupts_available(void) +{ + unsigned long long facility_bits[2]; + + if (stfle(facility_bits, 2) <= 1) + return 0; + if (!(facility_bits[0] & (1ULL << 61)) || + !(facility_bits[1] & (1ULL << 62))) + return 0; + return 1; +} + +/** * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number * @queue_depth: Pointer to queue depth value @@ -152,6 +187,80 @@ static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid) return reg1; } +#ifdef CONFIG_64BIT +/** + * ap_queue_interruption_control(): Enable interruption for a specific AP. + * @qid: The AP queue number + * @ind: The notification indicator byte + * + * Returns AP queue status. + */ +static inline struct ap_queue_status +ap_queue_interruption_control(ap_qid_t qid, void *ind) +{ + register unsigned long reg0 asm ("0") = qid | 0x03000000UL; + register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC; + register struct ap_queue_status reg1_out asm ("1"); + register void *reg2 asm ("2") = ind; + asm volatile( + ".long 0xb2af0000" /* PQAP(RAPQ) */ + : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) + : + : "cc" ); + return reg1_out; +} +#endif + +/** + * ap_queue_enable_interruption(): Enable interruption on an AP. + * @qid: The AP queue number + * @ind: the notification indicator byte + * + * Enables interruption on AP queue via ap_queue_interruption_control(). Based + * on the return value it waits a while and tests the AP queue if interrupts + * have been switched on using ap_test_queue(). + */ +static int ap_queue_enable_interruption(ap_qid_t qid, void *ind) +{ +#ifdef CONFIG_64BIT + struct ap_queue_status status; + int t_depth, t_device_type, rc, i; + + rc = -EBUSY; + status = ap_queue_interruption_control(qid, ind); + + for (i = 0; i < AP_MAX_RESET; i++) { + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (status.int_enabled) + return 0; + break; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + break; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_INVALID_ADDRESS: + return -ENODEV; + case AP_RESPONSE_OTHERWISE_CHANGED: + if (status.int_enabled) + return 0; + break; + default: + break; + } + if (i < AP_MAX_RESET - 1) { + udelay(5); + status = ap_test_queue(qid, &t_depth, &t_device_type); + } + } + return rc; +#else + return -EINVAL; +#endif +} + /** * __ap_send(): Send message to adjunct processor queue. * @qid: The AP queue number @@ -295,6 +404,11 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type) case AP_RESPONSE_CHECKSTOPPED: rc = -ENODEV; break; + case AP_RESPONSE_INVALID_ADDRESS: + rc = -ENODEV; + break; + case AP_RESPONSE_OTHERWISE_CHANGED: + break; case AP_RESPONSE_BUSY: break; default: @@ -345,6 +459,15 @@ static int ap_init_queue(ap_qid_t qid) status = ap_test_queue(qid, &dummy, &dummy); } } + if (rc == 0 && ap_using_interrupts()) { + rc = ap_queue_enable_interruption(qid, ap_interrupt_indicator); + /* If interruption mode is supported by the machine, + * but an AP can not be enabled for interruption then + * the AP will be discarded. */ + if (rc) + pr_err("Registering adapter interrupts for " + "AP %d failed\n", AP_QID_DEVICE(qid)); + } return rc; } @@ -397,16 +520,16 @@ static ssize_t ap_hwtype_show(struct device *dev, struct ap_device *ap_dev = to_ap_dev(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type); } -static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); +static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, char *buf) { struct ap_device *ap_dev = to_ap_dev(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth); } -static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); +static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); static ssize_t ap_request_count_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -509,9 +632,9 @@ static int ap_device_probe(struct device *dev) ap_dev->drv = ap_drv; rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; if (!rc) { - spin_lock_bh(&ap_device_lock); + spin_lock_bh(&ap_device_list_lock); list_add(&ap_dev->list, &ap_device_list); - spin_unlock_bh(&ap_device_lock); + spin_unlock_bh(&ap_device_list_lock); } return rc; } @@ -553,9 +676,9 @@ static int ap_device_remove(struct device *dev) ap_flush_queue(ap_dev); del_timer_sync(&ap_dev->timeout); - spin_lock_bh(&ap_device_lock); + spin_lock_bh(&ap_device_list_lock); list_del_init(&ap_dev->list); - spin_unlock_bh(&ap_device_lock); + spin_unlock_bh(&ap_device_list_lock); if (ap_drv->remove) ap_drv->remove(ap_dev); spin_lock_bh(&ap_dev->lock); @@ -599,6 +722,14 @@ static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); } +static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", + ap_using_interrupts() ? 1 : 0); +} + +static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL); + static ssize_t ap_config_time_store(struct bus_type *bus, const char *buf, size_t count) { @@ -653,7 +784,8 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, ktime_t hr_time; /* 120 seconds = maximum poll interval */ - if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000) + if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || + time > 120000000000ULL) return -EINVAL; poll_timeout = time; hr_time = ktime_set(0, poll_timeout); @@ -672,6 +804,7 @@ static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_config_time, &bus_attr_poll_thread, + &bus_attr_ap_interrupts, &bus_attr_poll_timeout, NULL, }; @@ -814,6 +947,11 @@ out: return rc; } +static void ap_interrupt_handler(void *unused1, void *unused2) +{ + tasklet_schedule(&ap_tasklet); +} + /** * __ap_scan_bus(): Scan the AP bus. * @dev: Pointer to device @@ -928,6 +1066,8 @@ ap_config_timeout(unsigned long ptr) */ static inline void ap_schedule_poll_timer(void) { + if (ap_using_interrupts()) + return; if (hrtimer_is_queued(&ap_poll_timer)) return; hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout), @@ -1181,7 +1321,7 @@ static void ap_reset(struct ap_device *ap_dev) ap_dev->unregistered = 1; } -static int __ap_poll_all(struct ap_device *ap_dev, unsigned long *flags) +static int __ap_poll_device(struct ap_device *ap_dev, unsigned long *flags) { spin_lock(&ap_dev->lock); if (!ap_dev->unregistered) { @@ -1207,13 +1347,19 @@ static void ap_poll_all(unsigned long dummy) unsigned long flags; struct ap_device *ap_dev; + /* Reset the indicator if interrupts are used. Thus new interrupts can + * be received. Doing it in the beginning of the tasklet is therefor + * important that no requests on any AP get lost. + */ + if (ap_using_interrupts()) + xchg((u8 *)ap_interrupt_indicator, 0); do { flags = 0; - spin_lock(&ap_device_lock); + spin_lock(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { - __ap_poll_all(ap_dev, &flags); + __ap_poll_device(ap_dev, &flags); } - spin_unlock(&ap_device_lock); + spin_unlock(&ap_device_list_lock); } while (flags & 1); if (flags & 2) ap_schedule_poll_timer(); @@ -1253,11 +1399,11 @@ static int ap_poll_thread(void *data) remove_wait_queue(&ap_poll_wait, &wait); flags = 0; - spin_lock_bh(&ap_device_lock); + spin_lock_bh(&ap_device_list_lock); list_for_each_entry(ap_dev, &ap_device_list, list) { - __ap_poll_all(ap_dev, &flags); + __ap_poll_device(ap_dev, &flags); } - spin_unlock_bh(&ap_device_lock); + spin_unlock_bh(&ap_device_list_lock); } set_current_state(TASK_RUNNING); remove_wait_queue(&ap_poll_wait, &wait); @@ -1268,6 +1414,8 @@ static int ap_poll_thread_start(void) { int rc; + if (ap_using_interrupts()) + return 0; mutex_lock(&ap_poll_thread_mutex); if (!ap_poll_kthread) { ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); @@ -1301,8 +1449,12 @@ static void ap_request_timeout(unsigned long data) { struct ap_device *ap_dev = (struct ap_device *) data; - if (ap_dev->reset == AP_RESET_ARMED) + if (ap_dev->reset == AP_RESET_ARMED) { ap_dev->reset = AP_RESET_DO; + + if (ap_using_interrupts()) + tasklet_schedule(&ap_tasklet); + } } static void ap_reset_domain(void) @@ -1337,14 +1489,25 @@ int __init ap_module_init(void) int rc, i; if (ap_domain_index < -1 || ap_domain_index >= AP_DOMAINS) { - printk(KERN_WARNING "Invalid param: domain = %d. " - " Not loading.\n", ap_domain_index); + pr_warning("%d is not a valid cryptographic domain\n", + ap_domain_index); return -EINVAL; } if (ap_instructions_available() != 0) { - printk(KERN_WARNING "AP instructions not installed.\n"); + pr_warning("The hardware system does not support " + "AP instructions\n"); return -ENODEV; } + if (ap_interrupts_available()) { + isc_register(AP_ISC); + ap_interrupt_indicator = s390_register_adapter_interrupt( + &ap_interrupt_handler, NULL, AP_ISC); + if (IS_ERR(ap_interrupt_indicator)) { + ap_interrupt_indicator = NULL; + isc_unregister(AP_ISC); + } + } + register_reset_call(&ap_reset_call); /* Create /sys/bus/ap. */ @@ -1358,7 +1521,7 @@ int __init ap_module_init(void) } /* Create /sys/devices/ap. */ - ap_root_device = s390_root_dev_register("ap"); + ap_root_device = root_device_register("ap"); rc = IS_ERR(ap_root_device) ? PTR_ERR(ap_root_device) : 0; if (rc) goto out_bus; @@ -1401,13 +1564,17 @@ out_work: hrtimer_cancel(&ap_poll_timer); destroy_workqueue(ap_work_queue); out_root: - s390_root_dev_unregister(ap_root_device); + root_device_unregister(ap_root_device); out_bus: while (i--) bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); bus_unregister(&ap_bus_type); out: unregister_reset_call(&ap_reset_call); + if (ap_using_interrupts()) { + s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); + isc_unregister(AP_ISC); + } return rc; } @@ -1432,7 +1599,7 @@ void ap_module_exit(void) hrtimer_cancel(&ap_poll_timer); destroy_workqueue(ap_work_queue); tasklet_kill(&ap_tasklet); - s390_root_dev_unregister(ap_root_device); + root_device_unregister(ap_root_device); while ((dev = bus_find_device(&ap_bus_type, NULL, NULL, __ap_match_all))) { @@ -1443,6 +1610,10 @@ void ap_module_exit(void) bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); bus_unregister(&ap_bus_type); unregister_reset_call(&ap_reset_call); + if (ap_using_interrupts()) { + s390_unregister_adapter_interrupt(ap_interrupt_indicator, AP_ISC); + isc_unregister(AP_ISC); + } } #ifndef CONFIG_ZCRYPT_MONOLITHIC diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 446378b308f..a3536224180 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -5,6 +5,7 @@ * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> * Martin Schwidefsky <schwidefsky@de.ibm.com> * Ralph Wuerthner <rwuerthn@de.ibm.com> + * Felix Beck <felix.beck@de.ibm.com> * * Adjunct processor bus header file. * @@ -67,7 +68,8 @@ struct ap_queue_status { unsigned int queue_empty : 1; unsigned int replies_waiting : 1; unsigned int queue_full : 1; - unsigned int pad1 : 5; + unsigned int pad1 : 4; + unsigned int int_enabled : 1; unsigned int response_code : 8; unsigned int pad2 : 16; }; @@ -78,6 +80,8 @@ struct ap_queue_status { #define AP_RESPONSE_DECONFIGURED 0x03 #define AP_RESPONSE_CHECKSTOPPED 0x04 #define AP_RESPONSE_BUSY 0x05 +#define AP_RESPONSE_INVALID_ADDRESS 0x06 +#define AP_RESPONSE_OTHERWISE_CHANGED 0x07 #define AP_RESPONSE_Q_FULL 0x10 #define AP_RESPONSE_NO_PENDING_REPLY 0x10 #define AP_RESPONSE_INDEX_TOO_BIG 0x11 diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 54f4cbc3be9..326ea08f67c 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -264,17 +264,21 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct type80_hdr *t80h = reply->message; + struct type80_hdr *t80h; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t80h->type == TYPE80_RSP_CODE) { + goto out; + } + t80h = reply->message; + if (t80h->type == TYPE80_RSP_CODE) { length = min(CEX2A_MAX_RESPONSE_SIZE, (int) t80h->len); memcpy(msg->message, reply->message, length); } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete((struct completion *) msg->private); } diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 12da4815ba8..17ba81b58c7 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c @@ -247,17 +247,21 @@ static void zcrypt_pcica_receive(struct ap_device *ap_dev, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct type84_hdr *t84h = reply->message; + struct type84_hdr *t84h; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t84h->code == TYPE84_RSP_CODE) { + goto out; + } + t84h = reply->message; + if (t84h->code == TYPE84_RSP_CODE) { length = min(PCICA_MAX_RESPONSE_SIZE, (int) t84h->len); memcpy(msg->message, reply->message, length); } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete((struct completion *) msg->private); } diff --git a/drivers/s390/crypto/zcrypt_pcicc.c b/drivers/s390/crypto/zcrypt_pcicc.c index 779952cb19f..f4b0c479543 100644 --- a/drivers/s390/crypto/zcrypt_pcicc.c +++ b/drivers/s390/crypto/zcrypt_pcicc.c @@ -447,19 +447,23 @@ static void zcrypt_pcicc_receive(struct ap_device *ap_dev, .type = TYPE82_RSP_CODE, .reply_code = REP82_ERROR_MACHINE_FAILURE, }; - struct type86_reply *t86r = reply->message; + struct type86_reply *t86r; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t86r->hdr.type == TYPE86_RSP_CODE && + goto out; + } + t86r = reply->message; + if (t86r->hdr.type == TYPE86_RSP_CODE && t86r->cprb.cprb_ver_id == 0x01) { length = sizeof(struct type86_reply) + t86r->length - 2; length = min(PCICC_MAX_RESPONSE_SIZE, length); memcpy(msg->message, reply->message, length); } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete((struct completion *) msg->private); } diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index d8ad36f8154..e7a1e22e77a 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -635,13 +635,16 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, }; struct response_type *resp_type = (struct response_type *) msg->private; - struct type86x_reply *t86r = reply->message; + struct type86x_reply *t86r; int length; /* Copy the reply message to the request message buffer. */ - if (IS_ERR(reply)) + if (IS_ERR(reply)) { memcpy(msg->message, &error_reply, sizeof(error_reply)); - else if (t86r->hdr.type == TYPE86_RSP_CODE && + goto out; + } + t86r = reply->message; + if (t86r->hdr.type == TYPE86_RSP_CODE && t86r->cprbx.cprb_ver_id == 0x02) { switch (resp_type->type) { case PCIXCC_RESPONSE_TYPE_ICA: @@ -660,6 +663,7 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, } } else memcpy(msg->message, reply->message, sizeof error_reply); +out: complete(&(resp_type->work)); } diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c index ff4a6931bb8..cbc8566fab7 100644 --- a/drivers/s390/kvm/kvm_virtio.c +++ b/drivers/s390/kvm/kvm_virtio.c @@ -24,7 +24,6 @@ #include <asm/kvm_virtio.h> #include <asm/setup.h> #include <asm/s390_ext.h> -#include <asm/s390_rdev.h> #define VIRTIO_SUBCODE_64 0x0D00 @@ -188,11 +187,13 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, config = kvm_vq_config(kdev->desc)+index; err = vmem_add_mapping(config->address, - vring_size(config->num, PAGE_SIZE)); + vring_size(config->num, + KVM_S390_VIRTIO_RING_ALIGN)); if (err) goto out; - vq = vring_new_virtqueue(config->num, vdev, (void *) config->address, + vq = vring_new_virtqueue(config->num, KVM_S390_VIRTIO_RING_ALIGN, + vdev, (void *) config->address, kvm_notify, callback); if (!vq) { err = -ENOMEM; @@ -209,7 +210,8 @@ static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, return vq; unmap: vmem_remove_mapping(config->address, - vring_size(config->num, PAGE_SIZE)); + vring_size(config->num, + KVM_S390_VIRTIO_RING_ALIGN)); out: return ERR_PTR(err); } @@ -220,7 +222,8 @@ static void kvm_del_vq(struct virtqueue *vq) vring_del_virtqueue(vq); vmem_remove_mapping(config->address, - vring_size(config->num, PAGE_SIZE)); + vring_size(config->num, + KVM_S390_VIRTIO_RING_ALIGN)); } /* @@ -295,13 +298,29 @@ static void scan_devices(void) */ static void kvm_extint_handler(u16 code) { - void *data = (void *) *(long *) __LC_PFAULT_INTPARM; - u16 subcode = S390_lowcore.cpu_addr; + struct virtqueue *vq; + u16 subcode; + int config_changed; + subcode = S390_lowcore.cpu_addr; if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) return; - vring_interrupt(0, data); + /* The LSB might be overloaded, we have to mask it */ + vq = (struct virtqueue *) ((*(long *) __LC_PFAULT_INTPARM) & ~1UL); + + /* We use the LSB of extparam, to decide, if this interrupt is a config + * change or a "standard" interrupt */ + config_changed = (*(int *) __LC_EXT_PARAMS & 1); + + if (config_changed) { + struct virtio_driver *drv; + drv = container_of(vq->vdev->dev.driver, + struct virtio_driver, driver); + if (drv->config_changed) + drv->config_changed(vq->vdev); + } else + vring_interrupt(0, vq); } /* @@ -315,20 +334,20 @@ static int __init kvm_devices_init(void) if (!MACHINE_IS_KVM) return -ENODEV; - kvm_root = s390_root_dev_register("kvm_s390"); + kvm_root = root_device_register("kvm_s390"); if (IS_ERR(kvm_root)) { rc = PTR_ERR(kvm_root); printk(KERN_ERR "Could not register kvm_s390 root device"); return rc; } - rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE); + rc = vmem_add_mapping(real_memory_size, PAGE_SIZE); if (rc) { - s390_root_dev_unregister(kvm_root); + root_device_unregister(kvm_root); return rc; } - kvm_devices = (void *) PFN_PHYS(max_pfn); + kvm_devices = (void *) real_memory_size; ctl_set_bit(0, 9); register_external_interrupt(0x2603, kvm_extint_handler); diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c index 42776550acf..f29c7086fc1 100644 --- a/drivers/s390/net/ctcm_fsms.c +++ b/drivers/s390/net/ctcm_fsms.c @@ -13,6 +13,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -190,21 +193,22 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg); void ctcm_ccw_check_rc(struct channel *ch, int rc, char *msg) { CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, - "%s(%s): %s: %04x\n", - CTCM_FUNTAIL, ch->id, msg, rc); + "%s(%s): %s: %04x\n", + CTCM_FUNTAIL, ch->id, msg, rc); switch (rc) { case -EBUSY: - ctcm_pr_warn("%s (%s): Busy !\n", ch->id, msg); + pr_info("%s: The communication peer is busy\n", + ch->id); fsm_event(ch->fsm, CTC_EVENT_IO_EBUSY, ch); break; case -ENODEV: - ctcm_pr_emerg("%s (%s): Invalid device called for IO\n", - ch->id, msg); + pr_err("%s: The specified target device is not valid\n", + ch->id); fsm_event(ch->fsm, CTC_EVENT_IO_ENODEV, ch); break; default: - ctcm_pr_emerg("%s (%s): Unknown error in do_IO %04x\n", - ch->id, msg, rc); + pr_err("An I/O operation resulted in error %04x\n", + rc); fsm_event(ch->fsm, CTC_EVENT_IO_UNKNOWN, ch); } } @@ -886,8 +890,15 @@ static void ctcm_chx_rxiniterr(fsm_instance *fi, int event, void *arg) fsm_newstate(fi, CTC_STATE_RXERR); fsm_event(priv->fsm, DEV_EVENT_RXDOWN, dev); } - } else - ctcm_pr_warn("%s: Error during RX init handshake\n", dev->name); + } else { + CTCM_DBF_TEXT_(ERROR, CTC_DBF_ERROR, + "%s(%s): %s in %s", CTCM_FUNTAIL, ch->id, + ctc_ch_event_names[event], fsm_getstate_str(fi)); + + dev_warn(&dev->dev, + "Initialization failed with RX/TX init handshake " + "error %s\n", ctc_ch_event_names[event]); + } } /** @@ -969,7 +980,9 @@ static void ctcm_chx_txiniterr(fsm_instance *fi, int event, void *arg) "%s(%s): %s in %s", CTCM_FUNTAIL, ch->id, ctc_ch_event_names[event], fsm_getstate_str(fi)); - ctcm_pr_warn("%s: Error during TX init handshake\n", dev->name); + dev_warn(&dev->dev, + "Initialization failed with RX/TX init handshake " + "error %s\n", ctc_ch_event_names[event]); } } @@ -2101,14 +2114,11 @@ static void dev_action_restart(fsm_instance *fi, int event, void *arg) CTCMY_DBF_DEV_NAME(TRACE, dev, ""); if (IS_MPC(priv)) { - ctcm_pr_info("ctcm: %s Restarting Device and " - "MPC Group in 5 seconds\n", - dev->name); restart_timer = CTCM_TIME_1_SEC; } else { - ctcm_pr_info("%s: Restarting\n", dev->name); restart_timer = CTCM_TIME_5_SEC; } + dev_info(&dev->dev, "Restarting device\n"); dev_action_stop(fi, event, arg); fsm_event(priv->fsm, DEV_EVENT_STOP, dev); @@ -2150,16 +2160,16 @@ static void dev_action_chup(fsm_instance *fi, int event, void *arg) case DEV_STATE_STARTWAIT_RX: if (event == DEV_EVENT_RXUP) { fsm_newstate(fi, DEV_STATE_RUNNING); - ctcm_pr_info("%s: connected with remote side\n", - dev->name); + dev_info(&dev->dev, + "Connected with remote side\n"); ctcm_clear_busy(dev); } break; case DEV_STATE_STARTWAIT_TX: if (event == DEV_EVENT_TXUP) { fsm_newstate(fi, DEV_STATE_RUNNING); - ctcm_pr_info("%s: connected with remote side\n", - dev->name); + dev_info(&dev->dev, + "Connected with remote side\n"); ctcm_clear_busy(dev); } break; diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index a4e29836a2a..2678573bece 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c @@ -21,6 +21,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -281,14 +284,16 @@ static long ctcm_check_irb_error(struct ccw_device *cdev, struct irb *irb) switch (PTR_ERR(irb)) { case -EIO: - ctcm_pr_warn("i/o-error on device %s\n", dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "An I/O-error occurred on the CTCM device\n"); break; case -ETIMEDOUT: - ctcm_pr_warn("timeout on device %s\n", dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "An adapter hardware operation timed out\n"); break; default: - ctcm_pr_warn("unknown error %ld on device %s\n", - PTR_ERR(irb), dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "An error occurred on the adapter hardware\n"); } return PTR_ERR(irb); } @@ -309,15 +314,17 @@ static inline void ccw_unit_check(struct channel *ch, __u8 sense) if (sense & SNS0_INTERVENTION_REQ) { if (sense & 0x01) { if (ch->sense_rc != 0x01) { - ctcm_pr_debug("%s: Interface disc. or Sel. " - "reset (remote)\n", ch->id); + pr_notice( + "%s: The communication peer has " + "disconnected\n", ch->id); ch->sense_rc = 0x01; } fsm_event(ch->fsm, CTC_EVENT_UC_RCRESET, ch); } else { if (ch->sense_rc != SNS0_INTERVENTION_REQ) { - ctcm_pr_debug("%s: System reset (remote)\n", - ch->id); + pr_notice( + "%s: The remote operating system is " + "not available\n", ch->id); ch->sense_rc = SNS0_INTERVENTION_REQ; } fsm_event(ch->fsm, CTC_EVENT_UC_RSRESET, ch); @@ -1194,8 +1201,11 @@ static void ctcm_irq_handler(struct ccw_device *cdev, /* Check for unsolicited interrupts. */ if (cgdev == NULL) { - ctcm_pr_warn("ctcm: Got unsolicited irq: c-%02x d-%02x\n", - cstat, dstat); + CTCM_DBF_TEXT_(TRACE, CTC_DBF_ERROR, + "%s(%s) unsolicited irq: c-%02x d-%02x\n", + CTCM_FUNTAIL, dev_name(&cdev->dev), cstat, dstat); + dev_warn(&cdev->dev, + "The adapter received a non-specific IRQ\n"); return; } @@ -1207,31 +1217,34 @@ static void ctcm_irq_handler(struct ccw_device *cdev, else if (priv->channel[WRITE]->cdev == cdev) ch = priv->channel[WRITE]; else { - ctcm_pr_err("ctcm: Can't determine channel for interrupt, " - "device %s\n", dev_name(&cdev->dev)); + dev_err(&cdev->dev, + "%s: Internal error: Can't determine channel for " + "interrupt device %s\n", + __func__, dev_name(&cdev->dev)); + /* Explain: inconsistent internal structures */ return; } dev = ch->netdev; if (dev == NULL) { - ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n", - __func__, dev_name(&cdev->dev), ch); + dev_err(&cdev->dev, + "%s Internal error: net_device is NULL, ch = 0x%p\n", + __func__, ch); + /* Explain: inconsistent internal structures */ return; } - CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, - "%s(%s): int. for %s: cstat=%02x dstat=%02x", - CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat); - /* Copy interruption response block. */ memcpy(ch->irb, irb, sizeof(struct irb)); + /* Issue error message and return on subchannel error code */ if (irb->scsw.cmd.cstat) { - /* Check for good subchannel return code, otherwise error message */ fsm_event(ch->fsm, CTC_EVENT_SC_UNKNOWN, ch); - ctcm_pr_warn("%s: subchannel check for dev: %s - %02x %02x\n", - dev->name, ch->id, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN, + "%s(%s): sub-ch check %s: cs=%02x ds=%02x", + CTCM_FUNTAIL, dev->name, ch->id, cstat, dstat); + dev_warn(&cdev->dev, + "A check occurred on the subchannel\n"); return; } @@ -1239,7 +1252,7 @@ static void ctcm_irq_handler(struct ccw_device *cdev, if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { if ((irb->ecw[0] & ch->sense_rc) == 0) /* print it only once */ - CTCM_DBF_TEXT_(TRACE, CTC_DBF_INFO, + CTCM_DBF_TEXT_(TRACE, CTC_DBF_WARN, "%s(%s): sense=%02x, ds=%02x", CTCM_FUNTAIL, ch->id, irb->ecw[0], dstat); ccw_unit_check(ch, irb->ecw[0]); @@ -1574,6 +1587,11 @@ static int ctcm_new_device(struct ccwgroup_device *cgdev) strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); + dev_info(&dev->dev, + "setup OK : r/w = %s/%s, protocol : %d\n", + priv->channel[READ]->id, + priv->channel[WRITE]->id, priv->protocol); + CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, "setup(%s) OK : r/w = %s/%s, protocol : %d", dev->name, priv->channel[READ]->id, @@ -1687,7 +1705,7 @@ static void __exit ctcm_exit(void) { unregister_cu3088_discipline(&ctcm_group_driver); ctcm_unregister_dbf_views(); - ctcm_pr_info("CTCM driver unloaded\n"); + pr_info("CTCM driver unloaded\n"); } /* @@ -1695,7 +1713,7 @@ static void __exit ctcm_exit(void) */ static void print_banner(void) { - printk(KERN_INFO "CTCM driver initialized\n"); + pr_info("CTCM driver initialized\n"); } /** @@ -1717,8 +1735,8 @@ static int __init ctcm_init(void) ret = register_cu3088_discipline(&ctcm_group_driver); if (ret) { ctcm_unregister_dbf_views(); - ctcm_pr_crit("ctcm_init failed with register_cu3088_discipline " - "(rc = %d)\n", ret); + pr_err("%s / register_cu3088_discipline failed, ret = %d\n", + __func__, ret); return ret; } print_banner(); diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h index d77cce3fe4d..d925e732b7d 100644 --- a/drivers/s390/net/ctcm_main.h +++ b/drivers/s390/net/ctcm_main.h @@ -41,12 +41,6 @@ #define LOG_FLAG_NOMEM 8 #define ctcm_pr_debug(fmt, arg...) printk(KERN_DEBUG fmt, ##arg) -#define ctcm_pr_info(fmt, arg...) printk(KERN_INFO fmt, ##arg) -#define ctcm_pr_notice(fmt, arg...) printk(KERN_NOTICE fmt, ##arg) -#define ctcm_pr_warn(fmt, arg...) printk(KERN_WARNING fmt, ##arg) -#define ctcm_pr_emerg(fmt, arg...) printk(KERN_EMERG fmt, ##arg) -#define ctcm_pr_err(fmt, arg...) printk(KERN_ERR fmt, ##arg) -#define ctcm_pr_crit(fmt, arg...) printk(KERN_CRIT fmt, ##arg) #define CTCM_PR_DEBUG(fmt, arg...) \ do { \ diff --git a/drivers/s390/net/ctcm_mpc.c b/drivers/s390/net/ctcm_mpc.c index 19f5d5ed85e..3db5f846bbf 100644 --- a/drivers/s390/net/ctcm_mpc.c +++ b/drivers/s390/net/ctcm_mpc.c @@ -19,6 +19,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> @@ -386,7 +389,7 @@ int ctc_mpc_alloc_channel(int port_num, void (*callback)(int, int)) if (grp->allocchan_callback_retries < 4) { if (grp->allochanfunc) grp->allochanfunc(grp->port_num, - grp->group_max_buflen); + grp->group_max_buflen); } else { /* there are problems...bail out */ /* there may be a state mismatch so restart */ @@ -1232,8 +1235,9 @@ done: dev_kfree_skb_any(pskb); if (sendrc == NET_RX_DROP) { - printk(KERN_WARNING "%s %s() NETWORK BACKLOG EXCEEDED" - " - PACKET DROPPED\n", dev->name, __func__); + dev_warn(&dev->dev, + "The network backlog for %s is exceeded, " + "package dropped\n", __func__); fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); } @@ -1670,10 +1674,11 @@ static int mpc_validate_xid(struct mpcg_info *mpcginfo) CTCM_FUNTAIL, ch->id); } } - done: if (rc) { - ctcm_pr_info("ctcmpc : %s() failed\n", __func__); + dev_warn(&dev->dev, + "The XID used in the MPC protocol is not valid, " + "rc = %d\n", rc); priv->xid->xid2_flag2 = 0x40; grp->saved_xid2->xid2_flag2 = 0x40; } diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c index bb2d13721d3..8452bb052d6 100644 --- a/drivers/s390/net/ctcm_sysfs.c +++ b/drivers/s390/net/ctcm_sysfs.c @@ -10,6 +10,9 @@ #undef DEBUGDATA #undef DEBUGCCW +#define KMSG_COMPONENT "ctcm" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/sysfs.h> #include "ctcm_main.h" diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c index f4a32375c03..48383459e99 100644 --- a/drivers/s390/net/cu3088.c +++ b/drivers/s390/net/cu3088.c @@ -25,7 +25,6 @@ #include <linux/module.h> #include <linux/err.h> -#include <asm/s390_rdev.h> #include <asm/ccwdev.h> #include <asm/ccwgroup.h> @@ -120,12 +119,12 @@ cu3088_init (void) { int rc; - cu3088_root_dev = s390_root_dev_register("cu3088"); + cu3088_root_dev = root_device_register("cu3088"); if (IS_ERR(cu3088_root_dev)) return PTR_ERR(cu3088_root_dev); rc = ccw_driver_register(&cu3088_driver); if (rc) - s390_root_dev_unregister(cu3088_root_dev); + root_device_unregister(cu3088_root_dev); return rc; } @@ -134,7 +133,7 @@ static void __exit cu3088_exit (void) { ccw_driver_unregister(&cu3088_driver); - s390_root_dev_unregister(cu3088_root_dev); + root_device_unregister(cu3088_root_dev); } MODULE_DEVICE_TABLE(ccw,cu3088_ids); diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 0825be87e5a..acca6678cb2 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -26,6 +26,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define KMSG_COMPONENT "lcs" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/if.h> #include <linux/netdevice.h> @@ -54,8 +57,6 @@ #error Cannot compile lcs.c without some net devices switched on. #endif -#define PRINTK_HEADER " lcs: " - /** * initialization string for output */ @@ -96,7 +97,7 @@ lcs_register_debug_facility(void) lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8); lcs_dbf_trace = debug_register("lcs_trace", 4, 1, 8); if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) { - PRINT_ERR("Not enough memory for debug facility.\n"); + pr_err("Not enough memory for debug facility.\n"); lcs_unregister_debug_facility(); return -ENOMEM; } @@ -503,7 +504,9 @@ lcs_start_channel(struct lcs_channel *channel) if (rc) { LCS_DBF_TEXT_(4,trace,"essh%s", dev_name(&channel->ccwdev->dev)); - PRINT_ERR("Error in starting channel, rc=%d!\n", rc); + dev_err(&channel->ccwdev->dev, + "Starting an LCS device resulted in an error," + " rc=%d!\n", rc); } return rc; } @@ -640,7 +643,9 @@ __lcs_resume_channel(struct lcs_channel *channel) if (rc) { LCS_DBF_TEXT_(4, trace, "ersc%s", dev_name(&channel->ccwdev->dev)); - PRINT_ERR("Error in lcs_resume_channel: rc=%d\n",rc); + dev_err(&channel->ccwdev->dev, + "Sending data from the LCS device to the LAN failed" + " with rc=%d\n",rc); } else channel->state = LCS_CH_STATE_RUNNING; return rc; @@ -1086,7 +1091,7 @@ lcs_check_multicast_support(struct lcs_card *card) cmd->cmd.lcs_qipassist.num_ip_pairs = 1; rc = lcs_send_lancmd(card, buffer, __lcs_check_multicast_cb); if (rc != 0) { - PRINT_ERR("Query IPAssist failed. Assuming unsupported!\n"); + pr_err("Query IPAssist failed. Assuming unsupported!\n"); return -EOPNOTSUPP; } if (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) @@ -1119,8 +1124,8 @@ list_modified: rc = lcs_send_setipm(card, ipm); spin_lock_irqsave(&card->ipm_lock, flags); if (rc) { - PRINT_INFO("Adding multicast address failed. " - "Table possibly full!\n"); + pr_info("Adding multicast address failed." + " Table possibly full!\n"); /* store ipm in failed list -> will be added * to ipm_list again, so a retry will be done * during the next call of this function */ @@ -1231,8 +1236,8 @@ lcs_set_mc_addresses(struct lcs_card *card, struct in_device *in4_dev) ipm = (struct lcs_ipm_list *) kzalloc(sizeof(struct lcs_ipm_list), GFP_ATOMIC); if (ipm == NULL) { - PRINT_INFO("Not enough memory to add " - "new multicast entry!\n"); + pr_info("Not enough memory to add" + " new multicast entry!\n"); break; } memcpy(&ipm->ipm.mac_addr, buf, LCS_MAC_LENGTH); @@ -1290,7 +1295,7 @@ lcs_set_multicast_list(struct net_device *dev) struct lcs_card *card; LCS_DBF_TEXT(4, trace, "setmulti"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) schedule_work(&card->kernel_thread_starter); @@ -1306,18 +1311,21 @@ lcs_check_irb_error(struct ccw_device *cdev, struct irb *irb) switch (PTR_ERR(irb)) { case -EIO: - PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev)); + dev_warn(&cdev->dev, + "An I/O-error occurred on the LCS device\n"); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT_(2, trace, " rc%d", -EIO); break; case -ETIMEDOUT: - PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev)); + dev_warn(&cdev->dev, + "A command timed out on the LCS device\n"); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT_(2, trace, " rc%d", -ETIMEDOUT); break; default: - PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), - dev_name(&cdev->dev)); + dev_warn(&cdev->dev, + "An error occurred on the LCS device, rc=%ld\n", + PTR_ERR(irb)); LCS_DBF_TEXT(2, trace, "ckirberr"); LCS_DBF_TEXT(2, trace, " rc???"); } @@ -1403,8 +1411,10 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* Check for channel and device errors presented */ rc = lcs_get_problem(cdev, irb); if (rc || (dstat & DEV_STAT_UNIT_EXCEP)) { - PRINT_WARN("check on device %s, dstat=0x%X, cstat=0x%X \n", - dev_name(&cdev->dev), dstat, cstat); + dev_warn(&cdev->dev, + "The LCS device stopped because of an error," + " dstat=0x%X, cstat=0x%X \n", + dstat, cstat); if (rc) { channel->state = LCS_CH_STATE_ERROR; } @@ -1607,7 +1617,7 @@ lcs_start_xmit(struct sk_buff *skb, struct net_device *dev) int rc; LCS_DBF_TEXT(5, trace, "pktxmit"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; rc = __lcs_start_xmit(card, skb, dev); return rc; } @@ -1761,8 +1771,8 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) lcs_schedule_recovery(card); break; case LCS_CMD_STOPLAN: - PRINT_WARN("Stoplan for %s initiated by LGW.\n", - card->dev->name); + pr_warning("Stoplan for %s initiated by LGW.\n", + card->dev->name); if (card->dev) netif_carrier_off(card->dev); break; @@ -1790,7 +1800,8 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len) skb = dev_alloc_skb(skb_len); if (skb == NULL) { - PRINT_ERR("LCS: alloc_skb failed for device=%s\n", + dev_err(&card->dev->dev, + " Allocating a socket buffer to interface %s failed\n", card->dev->name); card->stats.rx_dropped++; return; @@ -1863,7 +1874,7 @@ lcs_getstats(struct net_device *dev) struct lcs_card *card; LCS_DBF_TEXT(4, trace, "netstats"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; return &card->stats; } @@ -1878,7 +1889,7 @@ lcs_stop_device(struct net_device *dev) int rc; LCS_DBF_TEXT(2, trace, "stopdev"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; netif_carrier_off(dev); netif_tx_disable(dev); dev->flags &= ~IFF_UP; @@ -1886,7 +1897,8 @@ lcs_stop_device(struct net_device *dev) (card->write.state != LCS_CH_STATE_RUNNING)); rc = lcs_stopcard(card); if (rc) - PRINT_ERR("Try it again!\n "); + dev_err(&card->dev->dev, + " Shutting down the LCS device failed\n "); return rc; } @@ -1901,11 +1913,11 @@ lcs_open_device(struct net_device *dev) int rc; LCS_DBF_TEXT(2, trace, "opendev"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; /* initialize statistics */ rc = lcs_detect(card); if (rc) { - PRINT_ERR("LCS:Error in opening device!\n"); + pr_err("Error in opening device!\n"); } else { dev->flags |= IFF_UP; @@ -2113,8 +2125,9 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) rc = lcs_detect(card); if (rc) { LCS_DBF_TEXT(2, setup, "dtctfail"); - PRINT_WARN("Detection of LCS card failed with return code " - "%d (0x%x)\n", rc, rc); + dev_err(&card->dev->dev, + "Detecting a network adapter for LCS devices" + " failed with rc=%d (0x%x)\n", rc, rc); lcs_stopcard(card); goto out; } @@ -2144,13 +2157,13 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) #endif default: LCS_DBF_TEXT(3, setup, "errinit"); - PRINT_ERR("LCS: Initialization failed\n"); + pr_err(" Initialization failed\n"); goto out; } if (!dev) goto out; card->dev = dev; - card->dev->priv = card; + card->dev->ml_priv = card; card->dev->open = lcs_open_device; card->dev->stop = lcs_stop_device; card->dev->hard_start_xmit = lcs_start_xmit; @@ -2176,13 +2189,13 @@ netdev_out: goto out; /* Print out supported assists: IPv6 */ - PRINT_INFO("LCS device %s %s IPv6 support\n", card->dev->name, - (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? - "with" : "without"); + pr_info("LCS device %s %s IPv6 support\n", card->dev->name, + (card->ip_assists_supported & LCS_IPASS_IPV6_SUPPORT) ? + "with" : "without"); /* Print out supported assist: Multicast */ - PRINT_INFO("LCS device %s %s Multicast support\n", card->dev->name, - (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? - "with" : "without"); + pr_info("LCS device %s %s Multicast support\n", card->dev->name, + (card->ip_assists_supported & LCS_IPASS_MULTICAST_SUPPORT) ? + "with" : "without"); return 0; out: @@ -2248,15 +2261,16 @@ lcs_recovery(void *ptr) return 0; LCS_DBF_TEXT(4, trace, "recover2"); gdev = card->gdev; - PRINT_WARN("Recovery of device %s started...\n", dev_name(&gdev->dev)); + dev_warn(&gdev->dev, + "A recovery process has been started for the LCS device\n"); rc = __lcs_shutdown_device(gdev, 1); rc = lcs_new_device(gdev); if (!rc) - PRINT_INFO("Device %s successfully recovered!\n", - card->dev->name); + pr_info("Device %s successfully recovered!\n", + card->dev->name); else - PRINT_INFO("Device %s could not be recovered!\n", - card->dev->name); + pr_info("Device %s could not be recovered!\n", + card->dev->name); lcs_clear_thread_running_bit(card, LCS_RECOVERY_THREAD); return 0; } @@ -2308,17 +2322,17 @@ __init lcs_init_module(void) { int rc; - PRINT_INFO("Loading %s\n",version); + pr_info("Loading %s\n", version); rc = lcs_register_debug_facility(); LCS_DBF_TEXT(0, setup, "lcsinit"); if (rc) { - PRINT_ERR("Initialization failed\n"); + pr_err("Initialization failed\n"); return rc; } rc = register_cu3088_discipline(&lcs_group_driver); if (rc) { - PRINT_ERR("Initialization failed\n"); + pr_err("Initialization failed\n"); return rc; } return 0; @@ -2331,7 +2345,7 @@ __init lcs_init_module(void) static void __exit lcs_cleanup_module(void) { - PRINT_INFO("Terminating lcs module.\n"); + pr_info("Terminating lcs module.\n"); LCS_DBF_TEXT(0, trace, "cleanup"); unregister_cu3088_discipline(&lcs_group_driver); lcs_unregister_debug_facility(); diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 0fea51e34b5..930e2fc2a01 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -31,6 +31,9 @@ * */ +#define KMSG_COMPONENT "netiucv" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #undef DEBUG #include <linux/module.h> @@ -846,7 +849,8 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg) fsm_deltimer(&conn->timer); iucv_path_sever(conn->path, NULL); - PRINT_INFO("%s: Remote dropped connection\n", netdev->name); + dev_info(privptr->dev, "The peer interface of the IUCV device" + " has closed the connection\n"); IUCV_DBF_TEXT(data, 2, "conn_action_connsever: Remote dropped connection\n"); fsm_newstate(fi, CONN_STATE_STARTWAIT); @@ -856,13 +860,15 @@ static void conn_action_connsever(fsm_instance *fi, int event, void *arg) static void conn_action_start(fsm_instance *fi, int event, void *arg) { struct iucv_connection *conn = arg; + struct net_device *netdev = conn->netdev; + struct netiucv_priv *privptr = netdev_priv(netdev); int rc; IUCV_DBF_TEXT(trace, 3, __func__); fsm_newstate(fi, CONN_STATE_STARTWAIT); IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n", - conn->netdev->name, conn->userid); + netdev->name, conn->userid); /* * We must set the state before calling iucv_connect because the @@ -876,41 +882,45 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) NULL, iucvMagic, conn); switch (rc) { case 0: - conn->netdev->tx_queue_len = conn->path->msglim; + netdev->tx_queue_len = conn->path->msglim; fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, CONN_EVENT_TIMER, conn); return; case 11: - PRINT_INFO("%s: User %s is currently not available.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); + dev_warn(privptr->dev, + "The IUCV device failed to connect to z/VM guest %s\n", + netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); break; case 12: - PRINT_INFO("%s: User %s is currently not ready.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); + dev_warn(privptr->dev, + "The IUCV device failed to connect to the peer on z/VM" + " guest %s\n", netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_STARTWAIT); break; case 13: - PRINT_WARN("%s: Too many IUCV connections.\n", - conn->netdev->name); + dev_err(privptr->dev, + "Connecting the IUCV device would exceed the maximum" + " number of IUCV connections\n"); fsm_newstate(fi, CONN_STATE_CONNERR); break; case 14: - PRINT_WARN("%s: User %s has too many IUCV connections.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); + dev_err(privptr->dev, + "z/VM guest %s has too many IUCV connections" + " to connect with the IUCV device\n", + netiucv_printname(conn->userid)); fsm_newstate(fi, CONN_STATE_CONNERR); break; case 15: - PRINT_WARN("%s: No IUCV authorization in CP directory.\n", - conn->netdev->name); + dev_err(privptr->dev, + "The IUCV device cannot connect to a z/VM guest with no" + " IUCV authorization\n"); fsm_newstate(fi, CONN_STATE_CONNERR); break; default: - PRINT_WARN("%s: iucv_connect returned error %d\n", - conn->netdev->name, rc); + dev_err(privptr->dev, + "Connecting the IUCV device failed with error %d\n", + rc); fsm_newstate(fi, CONN_STATE_CONNERR); break; } @@ -1059,8 +1069,9 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) switch (fsm_getstate(fi)) { case DEV_STATE_STARTWAIT: fsm_newstate(fi, DEV_STATE_RUNNING); - PRINT_INFO("%s: connected with remote side %s\n", - dev->name, privptr->conn->userid); + dev_info(privptr->dev, + "The IUCV device has been connected" + " successfully to %s\n", privptr->conn->userid); IUCV_DBF_TEXT(setup, 3, "connection is up and running\n"); break; @@ -1982,6 +1993,8 @@ static ssize_t conn_write(struct device_driver *drv, if (rc) goto out_unreg; + dev_info(priv->dev, "The IUCV interface to %s has been" + " established successfully\n", netiucv_printname(username)); return count; @@ -2027,10 +2040,9 @@ static ssize_t remove_write (struct device_driver *drv, continue; read_unlock_bh(&iucv_connection_rwlock); if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN("netiucv: net device %s active with peer " - "%s\n", ndev->name, priv->conn->userid); - PRINT_WARN("netiucv: %s cannot be removed\n", - ndev->name); + dev_warn(dev, "The IUCV device is connected" + " to %s and cannot be removed\n", + priv->conn->userid); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); return -EPERM; } @@ -2062,7 +2074,7 @@ static struct attribute_group *netiucv_drv_attr_groups[] = { static void netiucv_banner(void) { - PRINT_INFO("NETIUCV driver initialized\n"); + pr_info("driver initialized\n"); } static void __exit netiucv_exit(void) @@ -2088,7 +2100,7 @@ static void __exit netiucv_exit(void) iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); - PRINT_INFO("NETIUCV driver unloaded\n"); + pr_info("driver unloaded\n"); return; } diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index af6d6045851..e0c45574b0c 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -31,11 +31,10 @@ #include <asm/qdio.h> #include <asm/ccwdev.h> #include <asm/ccwgroup.h> +#include <asm/sysinfo.h> #include "qeth_core_mpc.h" -#define KMSG_COMPONENT "qeth" - /** * Debug Facility stuff */ @@ -74,11 +73,6 @@ struct qeth_dbf_info { #define QETH_DBF_TEXT_(name, level, text...) \ qeth_dbf_longtext(QETH_DBF_##name, level, text) -/** - * some more debug stuff - */ -#define PRINTK_HEADER "qeth: " - #define SENSE_COMMAND_REJECT_BYTE 0 #define SENSE_COMMAND_REJECT_FLAG 0x80 #define SENSE_RESETTING_EVENT_BYTE 1 @@ -649,7 +643,6 @@ struct qeth_card_options { int macaddr_mode; int fake_broadcast; int add_hhlen; - int fake_ll; int layer2; enum qeth_large_send_types large_send; int performance_stats; @@ -733,6 +726,7 @@ struct qeth_card { struct qeth_osn_info osn_info; struct qeth_discipline discipline; atomic_t force_alloc_skb; + struct service_level qeth_service_level; }; struct qeth_card_list_struct { diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 52d26592c72..d1b5bebea7f 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -8,6 +8,9 @@ * Frank Blaschka <frank.blaschka@de.ibm.com> */ +#define KMSG_COMPONENT "qeth" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/string.h> @@ -21,7 +24,6 @@ #include <asm/ebcdic.h> #include <asm/io.h> -#include <asm/s390_rdev.h> #include "qeth_core.h" #include "qeth_core_offl.h" @@ -284,8 +286,15 @@ int qeth_set_large_send(struct qeth_card *card, card->options.large_send = type; switch (card->options.large_send) { case QETH_LARGE_SEND_EDDP: - card->dev->features |= NETIF_F_TSO | NETIF_F_SG | + if (card->info.type != QETH_CARD_TYPE_IQD) { + card->dev->features |= NETIF_F_TSO | NETIF_F_SG | NETIF_F_HW_CSUM; + } else { + card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | + NETIF_F_HW_CSUM); + card->options.large_send = QETH_LARGE_SEND_NO; + rc = -EOPNOTSUPP; + } break; case QETH_LARGE_SEND_TSO: if (qeth_is_supported(card, IPA_OUTBOUND_TSO)) { @@ -319,7 +328,10 @@ static int qeth_issue_next_read(struct qeth_card *card) return -EIO; iob = qeth_get_buffer(&card->read); if (!iob) { - PRINT_WARN("issue_next_read failed: no iob available!\n"); + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s issue_next_read failed: no iob " + "available\n", dev_name(&card->gdev->dev)); return -ENOMEM; } qeth_setup_ccw(&card->read, iob->data, QETH_BUFSIZE); @@ -327,7 +339,8 @@ static int qeth_issue_next_read(struct qeth_card *card) rc = ccw_device_start(card->read.ccwdev, &card->read.ccw, (addr_t) iob, 0, 0); if (rc) { - PRINT_ERR("Error in starting next read ccw! rc=%i\n", rc); + QETH_DBF_MESSAGE(2, "%s error in starting next read ccw! " + "rc=%i\n", dev_name(&card->gdev->dev), rc); atomic_set(&card->read.irq_pending, 0); qeth_schedule_recovery(card); wake_up(&card->wait_q); @@ -393,10 +406,9 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, } else { switch (cmd->hdr.command) { case IPA_CMD_STOPLAN: - PRINT_WARN("Link failure on %s (CHPID 0x%X) - " - "there is a network problem or " - "someone pulled the cable or " - "disabled the port.\n", + dev_warn(&card->gdev->dev, + "The link for interface %s on CHPID" + " 0x%X failed\n", QETH_CARD_IFNAME(card), card->info.chpid); card->lan_online = 0; @@ -404,9 +416,9 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, netif_carrier_off(card->dev); return NULL; case IPA_CMD_STARTLAN: - PRINT_INFO("Link reestablished on %s " - "(CHPID 0x%X). Scheduling " - "IP address reset.\n", + dev_info(&card->gdev->dev, + "The link for %s on CHPID 0x%X has" + " been restored\n", QETH_CARD_IFNAME(card), card->info.chpid); netif_carrier_on(card->dev); @@ -458,7 +470,7 @@ static int qeth_check_idx_response(unsigned char *buffer) QETH_DBF_HEX(CTRL, 2, buffer, QETH_DBF_CTRL_LEN); if ((buffer[2] & 0xc0) == 0xc0) { - PRINT_WARN("received an IDX TERMINATE " + QETH_DBF_MESSAGE(2, "received an IDX TERMINATE " "with cause code 0x%02x%s\n", buffer[4], ((buffer[4] == 0x22) ? @@ -566,6 +578,10 @@ static void qeth_send_control_data_cb(struct qeth_channel *channel, card = CARD_FROM_CDEV(channel->ccwdev); if (qeth_check_idx_response(iob->data)) { qeth_clear_ipacmd_list(card); + if (((iob->data[2] & 0xc0) == 0xc0) && iob->data[4] == 0xf6) + dev_err(&card->gdev->dev, + "The qeth device is not configured " + "for the OSI layer required by z/VM\n"); qeth_schedule_recovery(card); goto out; } @@ -744,8 +760,10 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb) SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | SCHN_STAT_PROT_CHECK | SCHN_STAT_PROG_CHECK)) { QETH_DBF_TEXT(TRACE, 2, "CGENCHK"); - PRINT_WARN("check on device %s, dstat=x%x, cstat=x%x ", - dev_name(&cdev->dev), dstat, cstat); + dev_warn(&cdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s check on device dstat=x%x, cstat=x%x ", + dev_name(&cdev->dev), dstat, cstat); print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET, 16, 1, irb, 64, 1); return 1; @@ -784,12 +802,14 @@ static long __qeth_check_irb_error(struct ccw_device *cdev, switch (PTR_ERR(irb)) { case -EIO: - PRINT_WARN("i/o-error on device %s\n", dev_name(&cdev->dev)); + QETH_DBF_MESSAGE(2, "%s i/o-error on device\n", + dev_name(&cdev->dev)); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT_(TRACE, 2, " rc%d", -EIO); break; case -ETIMEDOUT: - PRINT_WARN("timeout on device %s\n", dev_name(&cdev->dev)); + dev_warn(&cdev->dev, "A hardware operation timed out" + " on the device\n"); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT_(TRACE, 2, " rc%d", -ETIMEDOUT); if (intparm == QETH_RCD_PARM) { @@ -802,8 +822,8 @@ static long __qeth_check_irb_error(struct ccw_device *cdev, } break; default: - PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb), - dev_name(&cdev->dev)); + QETH_DBF_MESSAGE(2, "%s unknown error %ld on device\n", + dev_name(&cdev->dev), PTR_ERR(irb)); QETH_DBF_TEXT(TRACE, 2, "ckirberr"); QETH_DBF_TEXT(TRACE, 2, " rc???"); } @@ -869,10 +889,12 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, (dstat & DEV_STAT_UNIT_CHECK) || (cstat)) { if (irb->esw.esw0.erw.cons) { - /* TODO: we should make this s390dbf */ - PRINT_WARN("sense data available on channel %s.\n", - CHANNEL_ID(channel)); - PRINT_WARN(" cstat 0x%X\n dstat 0x%X\n", cstat, dstat); + dev_warn(&channel->ccwdev->dev, + "The qeth device driver failed to recover " + "an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s sense data available. cstat " + "0x%X dstat 0x%X\n", + dev_name(&channel->ccwdev->dev), cstat, dstat); print_hex_dump(KERN_WARNING, "qeth: irb ", DUMP_PREFIX_OFFSET, 16, 1, irb, 32, 1); print_hex_dump(KERN_WARNING, "qeth: sense data ", @@ -1060,7 +1082,6 @@ static void qeth_set_intial_options(struct qeth_card *card) card->options.macaddr_mode = QETH_TR_MACADDR_NONCANONICAL; card->options.fake_broadcast = 0; card->options.add_hhlen = DEFAULT_ADD_HHLEN; - card->options.fake_ll = 0; card->options.performance_stats = 0; card->options.rx_sg_cb = QETH_RX_SG_CB; } @@ -1138,6 +1159,14 @@ static int qeth_setup_card(struct qeth_card *card) return 0; } +static void qeth_core_sl_print(struct seq_file *m, struct service_level *slr) +{ + struct qeth_card *card = container_of(slr, struct qeth_card, + qeth_service_level); + seq_printf(m, "qeth: %s firmware level %s\n", CARD_BUS_ID(card), + card->info.mcl_level); +} + static struct qeth_card *qeth_alloc_card(void) { struct qeth_card *card; @@ -1157,6 +1186,8 @@ static struct qeth_card *qeth_alloc_card(void) return NULL; } card->options.layer2 = -1; + card->qeth_service_level.seq_print = qeth_core_sl_print; + register_service_level(&card->qeth_service_level); return card; } @@ -1175,8 +1206,8 @@ static int qeth_determine_card_type(struct qeth_card *card) card->qdio.no_out_queues = known_devices[i][8]; card->info.is_multicast_different = known_devices[i][9]; if (qeth_is_1920_device(card)) { - PRINT_INFO("Priority Queueing not able " - "due to hardware limitations!\n"); + dev_info(&card->gdev->dev, + "Priority Queueing not supported\n"); card->qdio.no_out_queues = 1; card->qdio.default_out_queue = 0; } @@ -1185,7 +1216,8 @@ static int qeth_determine_card_type(struct qeth_card *card) i++; } card->info.type = QETH_CARD_TYPE_UNKNOWN; - PRINT_ERR("unknown card type on device %s\n", CARD_BUS_ID(card)); + dev_err(&card->gdev->dev, "The adapter hardware is of an " + "unknown type\n"); return -ENOENT; } @@ -1368,8 +1400,8 @@ static int qeth_get_unitaddr(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "getunit"); rc = qeth_read_conf_data(card, (void **) &prcd, &length); if (rc) { - PRINT_ERR("qeth_read_conf_data for device %s returned %i\n", - CARD_DDEV_ID(card), rc); + QETH_DBF_MESSAGE(2, "%s qeth_read_conf_data returned %i\n", + dev_name(&card->gdev->dev), rc); return rc; } card->info.chpid = prcd[30]; @@ -1519,7 +1551,10 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, if (rc == -ERESTARTSYS) return rc; if (channel->state != CH_STATE_ACTIVATING) { - PRINT_WARN("IDX activate timed out!\n"); + dev_warn(&channel->ccwdev->dev, "The qeth device driver" + " failed to recover an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n", + dev_name(&channel->ccwdev->dev)); QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); qeth_clear_cmd_buffers(channel); return -ETIME; @@ -1552,20 +1587,21 @@ static void qeth_idx_write_cb(struct qeth_channel *channel, if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) - PRINT_ERR("IDX_ACTIVATE on write channel device %s: " - "adapter exclusively used by another host\n", - CARD_WDEV_ID(card)); + dev_err(&card->write.ccwdev->dev, + "The adapter is used exclusively by another " + "host\n"); else - PRINT_ERR("IDX_ACTIVATE on write channel device %s: " - "negative reply\n", CARD_WDEV_ID(card)); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel:" + " negative reply\n", + dev_name(&card->write.ccwdev->dev)); goto out; } memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) { - PRINT_WARN("IDX_ACTIVATE on write channel device %s: " - "function level mismatch " - "(sent: 0x%x, received: 0x%x)\n", - CARD_WDEV_ID(card), card->info.func_level, temp); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on write channel: " + "function level mismatch (sent: 0x%x, received: " + "0x%x)\n", dev_name(&card->write.ccwdev->dev), + card->info.func_level, temp); goto out; } channel->state = CH_STATE_UP; @@ -1591,12 +1627,13 @@ static void qeth_idx_read_cb(struct qeth_channel *channel, if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) - PRINT_ERR("IDX_ACTIVATE on read channel device %s: " - "adapter exclusively used by another host\n", - CARD_RDEV_ID(card)); + dev_err(&card->write.ccwdev->dev, + "The adapter is used exclusively by another " + "host\n"); else - PRINT_ERR("IDX_ACTIVATE on read channel device %s: " - "negative reply\n", CARD_RDEV_ID(card)); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel:" + " negative reply\n", + dev_name(&card->read.ccwdev->dev)); goto out; } @@ -1610,9 +1647,10 @@ static void qeth_idx_read_cb(struct qeth_channel *channel, memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); if (temp != qeth_peer_func_level(card->info.func_level)) { - PRINT_WARN("IDX_ACTIVATE on read channel device %s: function " - "level mismatch (sent: 0x%x, received: 0x%x)\n", - CARD_RDEV_ID(card), card->info.func_level, temp); + QETH_DBF_MESSAGE(2, "%s IDX_ACTIVATE on read channel: function " + "level mismatch (sent: 0x%x, received: 0x%x)\n", + dev_name(&card->read.ccwdev->dev), + card->info.func_level, temp); goto out; } memcpy(&card->token.issuer_rm_r, @@ -1653,6 +1691,7 @@ int qeth_send_control_data(struct qeth_card *card, int len, unsigned long flags; struct qeth_reply *reply = NULL; unsigned long timeout; + struct qeth_ipa_cmd *cmd; QETH_DBF_TEXT(TRACE, 2, "sendctl"); @@ -1686,8 +1725,9 @@ int qeth_send_control_data(struct qeth_card *card, int len, (addr_t) iob, 0, 0); spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); if (rc) { - PRINT_WARN("qeth_send_control_data: " - "ccw_device_start rc = %i\n", rc); + QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: " + "ccw_device_start rc = %i\n", + dev_name(&card->write.ccwdev->dev), rc); QETH_DBF_TEXT_(TRACE, 2, " err%d", rc); spin_lock_irqsave(&card->lock, flags); list_del_init(&reply->list); @@ -1698,17 +1738,34 @@ int qeth_send_control_data(struct qeth_card *card, int len, wake_up(&card->wait_q); return rc; } - while (!atomic_read(&reply->received)) { - if (time_after(jiffies, timeout)) { - spin_lock_irqsave(&reply->card->lock, flags); - list_del_init(&reply->list); - spin_unlock_irqrestore(&reply->card->lock, flags); - reply->rc = -ETIME; - atomic_inc(&reply->received); - wake_up(&reply->wait_q); - } - cpu_relax(); - }; + + /* we have only one long running ipassist, since we can ensure + process context of this command we can sleep */ + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + if ((cmd->hdr.command == IPA_CMD_SETIP) && + (cmd->hdr.prot_version == QETH_PROT_IPV4)) { + if (!wait_event_timeout(reply->wait_q, + atomic_read(&reply->received), timeout)) + goto time_err; + } else { + while (!atomic_read(&reply->received)) { + if (time_after(jiffies, timeout)) + goto time_err; + cpu_relax(); + }; + } + + rc = reply->rc; + qeth_put_reply(reply); + return rc; + +time_err: + spin_lock_irqsave(&reply->card->lock, flags); + list_del_init(&reply->list); + spin_unlock_irqrestore(&reply->card->lock, flags); + reply->rc = -ETIME; + atomic_inc(&reply->received); + wake_up(&reply->wait_q); rc = reply->rc; qeth_put_reply(reply); return rc; @@ -2170,11 +2227,8 @@ static void qeth_print_status_with_portname(struct qeth_card *card) dbf_text[i] = (char) _ebcasc[(__u8) dbf_text[i]]; dbf_text[8] = 0; - PRINT_INFO("Device %s/%s/%s is a%s card%s%s%s\n" + dev_info(&card->gdev->dev, "Device is a%s card%s%s%s\n" "with link type %s (portname: %s)\n", - CARD_RDEV_ID(card), - CARD_WDEV_ID(card), - CARD_DDEV_ID(card), qeth_get_cardname(card), (card->info.mcl_level[0]) ? " (level: " : "", (card->info.mcl_level[0]) ? card->info.mcl_level : "", @@ -2187,23 +2241,17 @@ static void qeth_print_status_with_portname(struct qeth_card *card) static void qeth_print_status_no_portname(struct qeth_card *card) { if (card->info.portname[0]) - PRINT_INFO("Device %s/%s/%s is a%s " + dev_info(&card->gdev->dev, "Device is a%s " "card%s%s%s\nwith link type %s " "(no portname needed by interface).\n", - CARD_RDEV_ID(card), - CARD_WDEV_ID(card), - CARD_DDEV_ID(card), qeth_get_cardname(card), (card->info.mcl_level[0]) ? " (level: " : "", (card->info.mcl_level[0]) ? card->info.mcl_level : "", (card->info.mcl_level[0]) ? ")" : "", qeth_get_cardname_short(card)); else - PRINT_INFO("Device %s/%s/%s is a%s " + dev_info(&card->gdev->dev, "Device is a%s " "card%s%s%s\nwith link type %s.\n", - CARD_RDEV_ID(card), - CARD_WDEV_ID(card), - CARD_DDEV_ID(card), qeth_get_cardname(card), (card->info.mcl_level[0]) ? " (level: " : "", (card->info.mcl_level[0]) ? card->info.mcl_level : "", @@ -2229,7 +2277,8 @@ void qeth_print_status_message(struct qeth_card *card) } /* fallthrough */ case QETH_CARD_TYPE_IQD: - if (card->info.guestlan) { + if ((card->info.guestlan) || + (card->info.mcl_level[0] & 0x80)) { card->info.mcl_level[0] = (char) _ebcasc[(__u8) card->info.mcl_level[0]]; card->info.mcl_level[1] = (char) _ebcasc[(__u8) @@ -2325,7 +2374,6 @@ static int qeth_init_input_buffer(struct qeth_card *card, * the QETH_IN_BUF_REQUEUE_THRESHOLD we should never run out off * buffers */ - BUG_ON(!pool_entry); buf->pool_entry = pool_entry; for (i = 0; i < QETH_MAX_BUFFER_ELEMENTS(card); ++i) { @@ -2630,9 +2678,8 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index) qeth_get_micros() - card->perf_stats.inbound_do_qdio_start_time; if (rc) { - PRINT_WARN("qeth_queue_input_buffer's do_QDIO " - "return %i (device %s).\n", - rc, CARD_DDEV_ID(card)); + dev_warn(&card->gdev->dev, + "QDIO reported an error, rc=%i\n", rc); QETH_DBF_TEXT(TRACE, 2, "qinberr"); QETH_DBF_TEXT_(TRACE, 2, "%s", CARD_BUS_ID(card)); } @@ -3730,6 +3777,7 @@ static void qeth_core_free_card(struct qeth_card *card) free_netdev(card->dev); kfree(card->ip_tbd_list); qeth_free_qdio_buffers(card); + unregister_service_level(&card->qeth_service_level); kfree(card); } @@ -3757,7 +3805,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev, int qeth_core_hardsetup_card(struct qeth_card *card) { - struct qdio_ssqd_desc *qdio_ssqd; + struct qdio_ssqd_desc *ssqd; int retries = 3; int mpno = 0; int rc; @@ -3766,7 +3814,8 @@ int qeth_core_hardsetup_card(struct qeth_card *card) atomic_set(&card->force_alloc_skb, 0); retry: if (retries < 3) { - PRINT_WARN("Retrying to do IDX activates.\n"); + QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n", + dev_name(&card->gdev->dev)); ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_RDEV(card)); @@ -3792,9 +3841,16 @@ retry: return rc; } - qdio_ssqd = qdio_get_ssqd_desc(CARD_DDEV(card)); - if (qdio_ssqd) - mpno = qdio_ssqd->pcnt; + ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL); + if (!ssqd) { + rc = -ENOMEM; + goto out; + } + rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd); + if (rc == 0) + mpno = ssqd->pcnt; + kfree(ssqd); + if (mpno) mpno = min(mpno - 1, QETH_MAX_PORTNO); if (card->info.portno > mpno) { @@ -3834,7 +3890,10 @@ retry: } return 0; out: - PRINT_ERR("Initialization in hardsetup failed! rc=%d\n", rc); + dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " + "an error on the device\n"); + QETH_DBF_MESSAGE(2, "%s Initialization in hardsetup failed! rc=%d\n", + dev_name(&card->gdev->dev), rc); return rc; } EXPORT_SYMBOL_GPL(qeth_core_hardsetup_card); @@ -4054,8 +4113,8 @@ int qeth_core_load_discipline(struct qeth_card *card, break; } if (!card->discipline.ccwgdriver) { - PRINT_ERR("Support for discipline %d not present\n", - discipline); + dev_err(&card->gdev->dev, "There is no kernel module to " + "support discipline %d\n", discipline); rc = -EINVAL; } return rc; @@ -4448,7 +4507,7 @@ static int __init qeth_core_init(void) { int rc; - PRINT_INFO("loading core functions\n"); + pr_info("loading core functions\n"); INIT_LIST_HEAD(&qeth_core_card_list.list); rwlock_init(&qeth_core_card_list.rwlock); @@ -4465,7 +4524,7 @@ static int __init qeth_core_init(void) &driver_attr_group); if (rc) goto driver_err; - qeth_core_root_dev = s390_root_dev_register("qeth"); + qeth_core_root_dev = root_device_register("qeth"); rc = IS_ERR(qeth_core_root_dev) ? PTR_ERR(qeth_core_root_dev) : 0; if (rc) goto register_err; @@ -4479,7 +4538,7 @@ static int __init qeth_core_init(void) return 0; slab_err: - s390_root_dev_unregister(qeth_core_root_dev); + root_device_unregister(qeth_core_root_dev); register_err: driver_remove_file(&qeth_core_ccwgroup_driver.driver, &driver_attr_group); @@ -4488,22 +4547,23 @@ driver_err: ccwgroup_err: ccw_driver_unregister(&qeth_ccw_driver); ccw_err: + QETH_DBF_MESSAGE(2, "Initialization failed with code %d\n", rc); qeth_unregister_dbf_views(); out_err: - PRINT_ERR("Initialization failed with code %d\n", rc); + pr_err("Initializing the qeth device driver failed\n"); return rc; } static void __exit qeth_core_exit(void) { - s390_root_dev_unregister(qeth_core_root_dev); + root_device_unregister(qeth_core_root_dev); driver_remove_file(&qeth_core_ccwgroup_driver.driver, &driver_attr_group); ccwgroup_driver_unregister(&qeth_core_ccwgroup_driver); ccw_driver_unregister(&qeth_ccw_driver); kmem_cache_destroy(qeth_core_header_cache); qeth_unregister_dbf_views(); - PRINT_INFO("core functions removed\n"); + pr_info("core functions removed\n"); } module_init(qeth_core_init); diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c index 452874e8974..4080126ca48 100644 --- a/drivers/s390/net/qeth_core_offl.c +++ b/drivers/s390/net/qeth_core_offl.c @@ -350,7 +350,7 @@ static __wsum qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr, eddp->thl + data_len, IPPROTO_TCP, 0); /* compute checksum of tcp header */ - return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum); + return csum_partial(&eddp->th, eddp->thl, phcsum); } static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, @@ -362,12 +362,12 @@ static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, QETH_DBF_TEXT(TRACE, 5, "eddpckt6"); eddp->th.tcp.h.check = 0; /* compute pseudo header checksum */ - phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr, + phcsum = csum_partial(&eddp->nh.ip6.h.saddr, sizeof(struct in6_addr), 0); - phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr, + phcsum = csum_partial(&eddp->nh.ip6.h.daddr, sizeof(struct in6_addr), phcsum); proto = htonl(IPPROTO_TCP); - phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum); + phcsum = csum_partial(&proto, sizeof(u32), phcsum); return phcsum; } diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 1b1e80336d2..07ab8a5c1c4 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -8,6 +8,9 @@ * Frank Blaschka <frank.blaschka@de.ibm.com> */ +#define KMSG_COMPONENT "qeth" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/string.h> @@ -17,8 +20,6 @@ #include <linux/mii.h> #include <linux/ip.h> -#include <asm/s390_rdev.h> - #include "qeth_core.h" #include "qeth_core_offl.h" @@ -131,17 +132,13 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, mac = &cmd->data.setdelmac.mac[0]; /* MAC already registered, needed in couple/uncouple case */ if (cmd->hdr.return_code == 0x2005) { - QETH_DBF_MESSAGE(2, "Group MAC %02x:%02x:%02x:%02x:%02x:%02x " - "already existing on %s \n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card)); + QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", + mac, QETH_CARD_IFNAME(card)); cmd->hdr.return_code = 0; } if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not set group MAC " - "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card), cmd->hdr.return_code); + QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %x\n", + mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); return 0; } @@ -163,10 +160,8 @@ static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; mac = &cmd->data.setdelmac.mac[0]; if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not delete group MAC " - "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card), cmd->hdr.return_code); + QETH_DBF_MESSAGE(2, "Could not delete group MAC %pM on %s: %x\n", + mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); return 0; } @@ -503,12 +498,13 @@ static int qeth_l2_send_setmac_cb(struct qeth_card *card, card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED; memcpy(card->dev->dev_addr, cmd->data.setdelmac.mac, OSA_ADDR_LEN); - PRINT_INFO("MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " - "successfully registered on device %s\n", - card->dev->dev_addr[0], card->dev->dev_addr[1], - card->dev->dev_addr[2], card->dev->dev_addr[3], - card->dev->dev_addr[4], card->dev->dev_addr[5], - card->dev->name); + dev_info(&card->gdev->dev, + "MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x " + "successfully registered on device %s\n", + card->dev->dev_addr[0], card->dev->dev_addr[1], + card->dev->dev_addr[2], card->dev->dev_addr[3], + card->dev->dev_addr[4], card->dev->dev_addr[5], + card->dev->name); } return 0; } @@ -920,6 +916,21 @@ static struct ethtool_ops qeth_l2_osn_ops = { .get_drvinfo = qeth_core_get_drvinfo, }; +static const struct net_device_ops qeth_l2_netdev_ops = { + .ndo_open = qeth_l2_open, + .ndo_stop = qeth_l2_stop, + .ndo_get_stats = qeth_get_stats, + .ndo_start_xmit = qeth_l2_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qeth_l2_set_multicast_list, + .ndo_do_ioctl = qeth_l2_do_ioctl, + .ndo_set_mac_address = qeth_l2_set_mac_address, + .ndo_change_mtu = qeth_change_mtu, + .ndo_vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid, + .ndo_tx_timeout = qeth_tx_timeout, +}; + static int qeth_l2_setup_netdev(struct qeth_card *card) { switch (card->info.type) { @@ -941,19 +952,9 @@ static int qeth_l2_setup_netdev(struct qeth_card *card) return -ENODEV; card->dev->ml_priv = card; - card->dev->tx_timeout = &qeth_tx_timeout; card->dev->watchdog_timeo = QETH_TX_TIMEOUT; - card->dev->open = qeth_l2_open; - card->dev->stop = qeth_l2_stop; - card->dev->hard_start_xmit = qeth_l2_hard_start_xmit; - card->dev->do_ioctl = qeth_l2_do_ioctl; - card->dev->get_stats = qeth_get_stats; - card->dev->change_mtu = qeth_change_mtu; - card->dev->set_multicast_list = qeth_l2_set_multicast_list; - card->dev->vlan_rx_kill_vid = qeth_l2_vlan_rx_kill_vid; - card->dev->vlan_rx_add_vid = qeth_l2_vlan_rx_add_vid; - card->dev->set_mac_address = qeth_l2_set_mac_address; card->dev->mtu = card->info.initial_mtu; + card->dev->netdev_ops = &qeth_l2_netdev_ops; if (card->info.type != QETH_CARD_TYPE_OSN) SET_ETHTOOL_OPS(card->dev, &qeth_l2_ethtool_ops); else @@ -1015,9 +1016,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) if (rc) { QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); if (rc == 0xe080) { - PRINT_WARN("LAN on card %s if offline! " - "Waiting for STARTLAN from card.\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "The LAN is offline\n"); card->lan_online = 0; } return rc; @@ -1117,8 +1117,8 @@ static int qeth_l2_recover(void *ptr) if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) return 0; QETH_DBF_TEXT(TRACE, 2, "recover2"); - PRINT_WARN("Recovery of device %s started ...\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "A recovery process has been started for the device\n"); card->use_hard_stop = 1; __qeth_l2_set_offline(card->gdev, 1); rc = __qeth_l2_set_online(card->gdev, 1); @@ -1126,27 +1126,29 @@ static int qeth_l2_recover(void *ptr) qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); if (!rc) - PRINT_INFO("Device %s successfully recovered!\n", - CARD_BUS_ID(card)); + dev_info(&card->gdev->dev, + "Device successfully recovered!\n"); else { - rtnl_lock(); - dev_close(card->dev); - rtnl_unlock(); - PRINT_INFO("Device %s could not be recovered!\n", - CARD_BUS_ID(card)); + if (card->dev) { + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); + } + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); } return 0; } static int __init qeth_l2_init(void) { - PRINT_INFO("register layer 2 discipline\n"); + pr_info("register layer 2 discipline\n"); return 0; } static void __exit qeth_l2_exit(void) { - PRINT_INFO("unregister layer 2 discipline\n"); + pr_info("unregister layer 2 discipline\n"); } static void qeth_l2_shutdown(struct ccwgroup_device *gdev) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index ed59fedd592..3d04920b9bb 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -8,6 +8,9 @@ * Frank Blaschka <frank.blaschka@de.ibm.com> */ +#define KMSG_COMPONENT "qeth" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/string.h> @@ -23,8 +26,6 @@ #include <net/ip.h> #include <net/arp.h> -#include <asm/s390_rdev.h> - #include "qeth_l3.h" #include "qeth_core_offl.h" @@ -917,8 +918,8 @@ static int qeth_l3_register_addr_entry(struct qeth_card *card, if (rc) { QETH_DBF_TEXT(TRACE, 2, "FAILED"); qeth_l3_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf); - PRINT_WARN("Could not register IP address %s (rc=0x%x/%d)\n", - buf, rc, rc); + dev_warn(&card->gdev->dev, + "Registering IP address %s failed\n", buf); } return rc; } @@ -1029,24 +1030,22 @@ static int qeth_l3_setadapter_parms(struct qeth_card *card) QETH_DBF_TEXT(SETUP, 2, "setadprm"); if (!qeth_is_supported(card, IPA_SETADAPTERPARMS)) { - PRINT_WARN("set adapter parameters not supported " - "on device %s.\n", - CARD_BUS_ID(card)); + dev_info(&card->gdev->dev, + "set adapter parameters not supported.\n"); QETH_DBF_TEXT(SETUP, 2, " notsupp"); return 0; } rc = qeth_query_setadapterparms(card); if (rc) { - PRINT_WARN("couldn't set adapter parameters on device %s: " - "x%x\n", CARD_BUS_ID(card), rc); + QETH_DBF_MESSAGE(2, "%s couldn't set adapter parameters: " + "0x%x\n", card->gdev->dev.bus_id, rc); return rc; } if (qeth_adp_supported(card, IPA_SETADP_ALTER_MAC_ADDRESS)) { rc = qeth_setadpparms_change_macaddr(card); if (rc) - PRINT_WARN("couldn't get MAC address on " - "device %s: x%x\n", - CARD_BUS_ID(card), rc); + dev_warn(&card->gdev->dev, "Reading the adapter MAC" + " address failed\n"); } if ((card->info.link_type == QETH_LINK_TYPE_HSTR) || @@ -1160,16 +1159,17 @@ static int qeth_l3_start_ipa_arp_processing(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "ipaarp"); if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { - PRINT_WARN("ARP processing not supported " - "on %s!\n", QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "ARP processing not supported on %s!\n", + QETH_CARD_IFNAME(card)); return 0; } rc = qeth_l3_send_simple_setassparms(card, IPA_ARP_PROCESSING, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start ARP processing " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting ARP processing support for %s failed\n", + QETH_CARD_IFNAME(card)); } return rc; } @@ -1181,19 +1181,21 @@ static int qeth_l3_start_ipa_ip_fragmentation(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "ipaipfrg"); if (!qeth_is_supported(card, IPA_IP_FRAGMENTATION)) { - PRINT_INFO("Hardware IP fragmentation not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Hardware IP fragmentation not supported on %s\n", + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_IP_FRAGMENTATION, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start Hardware IP fragmentation " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting IP fragmentation support for %s failed\n", + QETH_CARD_IFNAME(card)); } else - PRINT_INFO("Hardware IP fragmentation enabled \n"); + dev_info(&card->gdev->dev, + "Hardware IP fragmentation enabled \n"); return rc; } @@ -1203,21 +1205,19 @@ static int qeth_l3_start_ipa_source_mac(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "stsrcmac"); - if (!card->options.fake_ll) - return -EOPNOTSUPP; - if (!qeth_is_supported(card, IPA_SOURCE_MAC)) { - PRINT_INFO("Inbound source address not " - "supported on %s\n", QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Inbound source MAC-address not supported on %s\n", + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_SOURCE_MAC, IPA_CMD_ASS_START, 0); if (rc) - PRINT_WARN("Could not start inbound source " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting source MAC-address support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } @@ -1228,19 +1228,19 @@ static int qeth_l3_start_ipa_vlan(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "strtvlan"); if (!qeth_is_supported(card, IPA_FULL_VLAN)) { - PRINT_WARN("VLAN not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "VLAN not supported on %s\n", QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_VLAN_PRIO, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start vlan " - "assist on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting VLAN support for %s failed\n", + QETH_CARD_IFNAME(card)); } else { - PRINT_INFO("VLAN enabled \n"); + dev_info(&card->gdev->dev, "VLAN enabled\n"); } return rc; } @@ -1252,19 +1252,20 @@ static int qeth_l3_start_ipa_multicast(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "stmcast"); if (!qeth_is_supported(card, IPA_MULTICASTING)) { - PRINT_WARN("Multicast not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Multicast not supported on %s\n", + QETH_CARD_IFNAME(card)); return -EOPNOTSUPP; } rc = qeth_l3_send_simple_setassparms(card, IPA_MULTICASTING, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not start multicast " - "assist on %s: rc=%i\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Starting multicast support for %s failed\n", + QETH_CARD_IFNAME(card)); } else { - PRINT_INFO("Multicast enabled\n"); + dev_info(&card->gdev->dev, "Multicast enabled\n"); card->dev->flags |= IFF_MULTICAST; } return rc; @@ -1315,36 +1316,37 @@ static int qeth_l3_softsetup_ipv6(struct qeth_card *card) rc = qeth_l3_query_ipassists(card, QETH_PROT_IPV6); if (rc) { - PRINT_ERR("IPv6 query ipassist failed on %s\n", - QETH_CARD_IFNAME(card)); + dev_err(&card->gdev->dev, + "Activating IPv6 support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms(card, IPA_IPV6, IPA_CMD_ASS_START, 3); if (rc) { - PRINT_WARN("IPv6 start assist (version 4) failed " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_err(&card->gdev->dev, + "Activating IPv6 support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_IPV6, IPA_CMD_ASS_START); if (rc) { - PRINT_WARN("IPV6 start assist (version 6) failed " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_err(&card->gdev->dev, + "Activating IPv6 support for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms_ipv6(card, IPA_PASSTHRU, IPA_CMD_ASS_START); if (rc) { - PRINT_WARN("Could not enable passthrough " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Enabling the passthrough mode for %s failed\n", + QETH_CARD_IFNAME(card)); return rc; } out: - PRINT_INFO("IPV6 enabled \n"); + dev_info(&card->gdev->dev, "IPV6 enabled\n"); return 0; } #endif @@ -1356,8 +1358,8 @@ static int qeth_l3_start_ipa_ipv6(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "strtipv6"); if (!qeth_is_supported(card, IPA_IPV6)) { - PRINT_WARN("IPv6 not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "IPv6 not supported on %s\n", QETH_CARD_IFNAME(card)); return 0; } #ifdef CONFIG_QETH_IPV6 @@ -1373,34 +1375,35 @@ static int qeth_l3_start_ipa_broadcast(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "stbrdcst"); card->info.broadcast_capable = 0; if (!qeth_is_supported(card, IPA_FILTERING)) { - PRINT_WARN("Broadcast not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Broadcast not supported on %s\n", + QETH_CARD_IFNAME(card)); rc = -EOPNOTSUPP; goto out; } rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Could not enable broadcasting filtering " - "on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Enabling broadcast filtering for " + "%s failed\n", QETH_CARD_IFNAME(card)); goto out; } rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, IPA_CMD_ASS_CONFIGURE, 1); if (rc) { - PRINT_WARN("Could not set up broadcast filtering on %s: 0x%x\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, + "Setting up broadcast filtering for %s failed\n", + QETH_CARD_IFNAME(card)); goto out; } card->info.broadcast_capable = QETH_BROADCAST_WITH_ECHO; - PRINT_INFO("Broadcast enabled \n"); + dev_info(&card->gdev->dev, "Broadcast enabled\n"); rc = qeth_l3_send_simple_setassparms(card, IPA_FILTERING, IPA_CMD_ASS_ENABLE, 1); if (rc) { - PRINT_WARN("Could not set up broadcast echo filtering on " - "%s: 0x%x\n", QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Setting up broadcast echo " + "filtering for %s failed\n", QETH_CARD_IFNAME(card)); goto out; } card->info.broadcast_capable = QETH_BROADCAST_WITHOUT_ECHO; @@ -1419,18 +1422,18 @@ static int qeth_l3_send_checksum_command(struct qeth_card *card) rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_START, 0); if (rc) { - PRINT_WARN("Starting Inbound HW Checksumming failed on %s: " - "0x%x,\ncontinuing using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Starting HW checksumming for %s " + "failed, using SW checksumming\n", + QETH_CARD_IFNAME(card)); return rc; } rc = qeth_l3_send_simple_setassparms(card, IPA_INBOUND_CHECKSUM, IPA_CMD_ASS_ENABLE, card->info.csum_mask); if (rc) { - PRINT_WARN("Enabling Inbound HW Checksumming failed on %s: " - "0x%x,\ncontinuing using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Enabling HW checksumming for %s " + "failed, using SW checksumming\n", + QETH_CARD_IFNAME(card)); return rc; } return 0; @@ -1443,26 +1446,30 @@ static int qeth_l3_start_ipa_checksum(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "strtcsum"); if (card->options.checksum_type == NO_CHECKSUMMING) { - PRINT_WARN("Using no checksumming on %s.\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Using no checksumming on %s.\n", + QETH_CARD_IFNAME(card)); return 0; } if (card->options.checksum_type == SW_CHECKSUMMING) { - PRINT_WARN("Using SW checksumming on %s.\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Using SW checksumming on %s.\n", + QETH_CARD_IFNAME(card)); return 0; } if (!qeth_is_supported(card, IPA_INBOUND_CHECKSUM)) { - PRINT_WARN("Inbound HW Checksumming not " - "supported on %s,\ncontinuing " - "using Inbound SW Checksumming\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Inbound HW Checksumming not " + "supported on %s,\ncontinuing " + "using Inbound SW Checksumming\n", + QETH_CARD_IFNAME(card)); card->options.checksum_type = SW_CHECKSUMMING; return 0; } rc = qeth_l3_send_checksum_command(card); if (!rc) - PRINT_INFO("HW Checksumming (inbound) enabled \n"); + dev_info(&card->gdev->dev, + "HW Checksumming (inbound) enabled\n"); return rc; } @@ -1474,18 +1481,20 @@ static int qeth_l3_start_ipa_tso(struct qeth_card *card) QETH_DBF_TEXT(TRACE, 3, "sttso"); if (!qeth_is_supported(card, IPA_OUTBOUND_TSO)) { - PRINT_WARN("Outbound TSO not supported on %s\n", - QETH_CARD_IFNAME(card)); + dev_info(&card->gdev->dev, + "Outbound TSO not supported on %s\n", + QETH_CARD_IFNAME(card)); rc = -EOPNOTSUPP; } else { rc = qeth_l3_send_simple_setassparms(card, IPA_OUTBOUND_TSO, IPA_CMD_ASS_START, 0); if (rc) - PRINT_WARN("Could not start outbound TSO " - "assist on %s: rc=%i\n", - QETH_CARD_IFNAME(card), rc); + dev_warn(&card->gdev->dev, "Starting outbound TCP " + "segmentation offload for %s failed\n", + QETH_CARD_IFNAME(card)); else - PRINT_INFO("Outbound TSO enabled\n"); + dev_info(&card->gdev->dev, + "Outbound TSO enabled\n"); } if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)) { card->options.large_send = QETH_LARGE_SEND_NO; @@ -1578,12 +1587,8 @@ static int qeth_l3_get_unique_id_cb(struct qeth_card *card, else { card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED | UNIQUE_ID_NOT_BY_CARD; - PRINT_WARN("couldn't get a unique id from the card on device " - "%s (result=x%x), using default id. ipv6 " - "autoconfig on other lpars may lead to duplicate " - "ip addresses. please use manually " - "configured ones.\n", - CARD_BUS_ID(card), cmd->hdr.return_code); + dev_warn(&card->gdev->dev, "The network adapter failed to " + "generate a unique ID\n"); } return 0; } @@ -1824,28 +1829,6 @@ static void qeth_l3_vlan_rx_register(struct net_device *dev, static void qeth_l3_vlan_rx_add_vid(struct net_device *dev, unsigned short vid) { - struct net_device *vlandev; - struct qeth_card *card = dev->ml_priv; - struct in_device *in_dev; - - if (card->info.type == QETH_CARD_TYPE_IQD) - return; - - vlandev = vlan_group_get_device(card->vlangrp, vid); - vlandev->neigh_setup = qeth_l3_neigh_setup; - - in_dev = in_dev_get(vlandev); -#ifdef CONFIG_SYSCTL - neigh_sysctl_unregister(in_dev->arp_parms); -#endif - neigh_parms_release(&arp_tbl, in_dev->arp_parms); - - in_dev->arp_parms = neigh_parms_alloc(vlandev, &arp_tbl); -#ifdef CONFIG_SYSCTL - neigh_sysctl_register(vlandev, in_dev->arp_parms, NET_IPV4, - NET_IPV4_NEIGH, "ipv4", NULL, NULL); -#endif - in_dev_put(in_dev); return; } @@ -1911,8 +1894,13 @@ static inline __u16 qeth_l3_rebuild_skb(struct qeth_card *card, memcpy(tg_addr, card->dev->dev_addr, card->dev->addr_len); } - card->dev->header_ops->create(skb, card->dev, prot, tg_addr, - "FAKELL", card->dev->addr_len); + if (hdr->hdr.l3.ext_flags & QETH_HDR_EXT_SRC_MAC_ADDR) + card->dev->header_ops->create(skb, card->dev, prot, + tg_addr, &hdr->hdr.l3.dest_addr[2], + card->dev->addr_len); + else + card->dev->header_ops->create(skb, card->dev, prot, + tg_addr, "FAKELL", card->dev->addr_len); } #ifdef CONFIG_TR @@ -2070,9 +2058,11 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) if (recovery_mode) qeth_l3_stop(card->dev); else { - rtnl_lock(); - dev_close(card->dev); - rtnl_unlock(); + if (card->dev) { + rtnl_lock(); + dev_close(card->dev); + rtnl_unlock(); + } } if (!card->use_hard_stop) { rc = qeth_send_stoplan(card); @@ -2904,6 +2894,37 @@ qeth_l3_neigh_setup(struct net_device *dev, struct neigh_parms *np) return 0; } +static const struct net_device_ops qeth_l3_netdev_ops = { + .ndo_open = qeth_l3_open, + .ndo_stop = qeth_l3_stop, + .ndo_get_stats = qeth_get_stats, + .ndo_start_xmit = qeth_l3_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qeth_l3_set_multicast_list, + .ndo_do_ioctl = qeth_l3_do_ioctl, + .ndo_change_mtu = qeth_change_mtu, + .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, + .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, + .ndo_tx_timeout = qeth_tx_timeout, +}; + +static const struct net_device_ops qeth_l3_osa_netdev_ops = { + .ndo_open = qeth_l3_open, + .ndo_stop = qeth_l3_stop, + .ndo_get_stats = qeth_get_stats, + .ndo_start_xmit = qeth_l3_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = qeth_l3_set_multicast_list, + .ndo_do_ioctl = qeth_l3_do_ioctl, + .ndo_change_mtu = qeth_change_mtu, + .ndo_vlan_rx_register = qeth_l3_vlan_rx_register, + .ndo_vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid, + .ndo_tx_timeout = qeth_tx_timeout, + .ndo_neigh_setup = qeth_l3_neigh_setup, +}; + static int qeth_l3_setup_netdev(struct qeth_card *card) { if (card->info.type == QETH_CARD_TYPE_OSAE) { @@ -2914,11 +2935,12 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) #endif if (!card->dev) return -ENODEV; + card->dev->netdev_ops = &qeth_l3_netdev_ops; } else { card->dev = alloc_etherdev(0); if (!card->dev) return -ENODEV; - card->dev->neigh_setup = qeth_l3_neigh_setup; + card->dev->netdev_ops = &qeth_l3_osa_netdev_ops; /*IPv6 address autoconfiguration stuff*/ qeth_l3_get_unique_id(card); @@ -2931,25 +2953,14 @@ static int qeth_l3_setup_netdev(struct qeth_card *card) if (!card->dev) return -ENODEV; card->dev->flags |= IFF_NOARP; + card->dev->netdev_ops = &qeth_l3_netdev_ops; qeth_l3_iqd_read_initial_mac(card); } else return -ENODEV; - card->dev->hard_start_xmit = qeth_l3_hard_start_xmit; card->dev->ml_priv = card; - card->dev->tx_timeout = &qeth_tx_timeout; card->dev->watchdog_timeo = QETH_TX_TIMEOUT; - card->dev->open = qeth_l3_open; - card->dev->stop = qeth_l3_stop; - card->dev->do_ioctl = qeth_l3_do_ioctl; - card->dev->get_stats = qeth_get_stats; - card->dev->change_mtu = qeth_change_mtu; - card->dev->set_multicast_list = qeth_l3_set_multicast_list; - card->dev->vlan_rx_register = qeth_l3_vlan_rx_register; - card->dev->vlan_rx_add_vid = qeth_l3_vlan_rx_add_vid; - card->dev->vlan_rx_kill_vid = qeth_l3_vlan_rx_kill_vid; card->dev->mtu = card->info.initial_mtu; - card->dev->set_mac_address = NULL; SET_ETHTOOL_OPS(card->dev, &qeth_l3_ethtool_ops); card->dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | @@ -3086,9 +3097,8 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) if (rc) { QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); if (rc == 0xe080) { - PRINT_WARN("LAN on card %s if offline! " - "Waiting for STARTLAN from card.\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "The LAN is offline\n"); card->lan_online = 0; } return rc; @@ -3194,8 +3204,8 @@ static int qeth_l3_recover(void *ptr) if (!qeth_do_run_thread(card, QETH_RECOVER_THREAD)) return 0; QETH_DBF_TEXT(TRACE, 2, "recover2"); - PRINT_WARN("Recovery of device %s started ...\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, + "A recovery process has been started for the device\n"); card->use_hard_stop = 1; __qeth_l3_set_offline(card->gdev, 1); rc = __qeth_l3_set_online(card->gdev, 1); @@ -3203,14 +3213,14 @@ static int qeth_l3_recover(void *ptr) qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD); qeth_clear_thread_running_bit(card, QETH_RECOVER_THREAD); if (!rc) - PRINT_INFO("Device %s successfully recovered!\n", - CARD_BUS_ID(card)); + dev_info(&card->gdev->dev, + "Device successfully recovered!\n"); else { rtnl_lock(); dev_close(card->dev); rtnl_unlock(); - PRINT_INFO("Device %s could not be recovered!\n", - CARD_BUS_ID(card)); + dev_warn(&card->gdev->dev, "The qeth device driver " + "failed to recover an error on the device\n"); } return 0; } @@ -3344,7 +3354,7 @@ static int qeth_l3_register_notifiers(void) return rc; } #else - PRINT_WARN("layer 3 discipline no IPv6 support\n"); + pr_warning("There is no IPv6 support for the layer 3 discipline\n"); #endif return 0; } @@ -3363,7 +3373,7 @@ static int __init qeth_l3_init(void) { int rc = 0; - PRINT_INFO("register layer 3 discipline\n"); + pr_info("register layer 3 discipline\n"); rc = qeth_l3_register_notifiers(); return rc; } @@ -3371,7 +3381,7 @@ static int __init qeth_l3_init(void) static void __exit qeth_l3_exit(void) { qeth_l3_unregister_notifiers(); - PRINT_INFO("unregister layer 3 discipline\n"); + pr_info("unregister layer 3 discipline\n"); } module_init(qeth_l3_init); diff --git a/drivers/s390/s390_rdev.c b/drivers/s390/s390_rdev.c deleted file mode 100644 index 64371c05a3b..00000000000 --- a/drivers/s390/s390_rdev.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * drivers/s390/s390_rdev.c - * s390 root device - * - * Copyright (C) 2002, 2005 IBM Deutschland Entwicklung GmbH, - * IBM Corporation - * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) - * Carsten Otte (cotte@de.ibm.com) - */ - -#include <linux/slab.h> -#include <linux/err.h> -#include <linux/device.h> -#include <asm/s390_rdev.h> - -static void -s390_root_dev_release(struct device *dev) -{ - kfree(dev); -} - -struct device * -s390_root_dev_register(const char *name) -{ - struct device *dev; - int ret; - - if (!strlen(name)) - return ERR_PTR(-EINVAL); - dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!dev) - return ERR_PTR(-ENOMEM); - dev_set_name(dev, name); - dev->release = s390_root_dev_release; - ret = device_register(dev); - if (ret) { - kfree(dev); - return ERR_PTR(ret); - } - return dev; -} - -void -s390_root_dev_unregister(struct device *dev) -{ - if (dev) - device_unregister(dev); -} - -EXPORT_SYMBOL(s390_root_dev_register); -EXPORT_SYMBOL(s390_root_dev_unregister); diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 834e9ee7e93..92b0417f8e1 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -18,6 +18,7 @@ #include <asm/etr.h> #include <asm/lowcore.h> #include <asm/cio.h> +#include <asm/cpu.h> #include "s390mach.h" static struct semaphore m_sem; @@ -369,6 +370,8 @@ s390_do_machine_check(struct pt_regs *regs) lockdep_off(); + s390_idle_check(); + mci = (struct mci *) &S390_lowcore.mcck_interruption_code; mcck = &__get_cpu_var(cpu_mcck); umode = user_mode(regs); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 3b56220fb90..8af7dfbe022 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -25,16 +25,21 @@ * Sven Schuetz */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/miscdevice.h> +#include <linux/seq_file.h> #include "zfcp_ext.h" -static char *device; +#define ZFCP_BUS_ID_SIZE 20 MODULE_AUTHOR("IBM Deutschland Entwicklung GmbH - linux390@de.ibm.com"); MODULE_DESCRIPTION("FCP HBA driver"); MODULE_LICENSE("GPL"); -module_param(device, charp, 0400); +static char *init_device; +module_param_named(device, init_device, charp, 0400); MODULE_PARM_DESC(device, "specify initial device"); static int zfcp_reqlist_alloc(struct zfcp_adapter *adapter) @@ -67,46 +72,7 @@ int zfcp_reqlist_isempty(struct zfcp_adapter *adapter) return 1; } -static int __init zfcp_device_setup(char *devstr) -{ - char *token; - char *str; - - if (!devstr) - return 0; - - /* duplicate devstr and keep the original for sysfs presentation*/ - str = kmalloc(strlen(devstr) + 1, GFP_KERNEL); - if (!str) - return 0; - - strcpy(str, devstr); - - token = strsep(&str, ","); - if (!token || strlen(token) >= BUS_ID_SIZE) - goto err_out; - strncpy(zfcp_data.init_busid, token, BUS_ID_SIZE); - - token = strsep(&str, ","); - if (!token || strict_strtoull(token, 0, - (unsigned long long *) &zfcp_data.init_wwpn)) - goto err_out; - - token = strsep(&str, ","); - if (!token || strict_strtoull(token, 0, - (unsigned long long *) &zfcp_data.init_fcp_lun)) - goto err_out; - - kfree(str); - return 1; - - err_out: - kfree(str); - pr_err("zfcp: %s is not a valid SCSI device\n", devstr); - return 0; -} - -static void __init zfcp_init_device_configure(void) +static void __init zfcp_init_device_configure(char *busid, u64 wwpn, u64 lun) { struct zfcp_adapter *adapter; struct zfcp_port *port; @@ -114,17 +80,17 @@ static void __init zfcp_init_device_configure(void) down(&zfcp_data.config_sema); read_lock_irq(&zfcp_data.config_lock); - adapter = zfcp_get_adapter_by_busid(zfcp_data.init_busid); + adapter = zfcp_get_adapter_by_busid(busid); if (adapter) zfcp_adapter_get(adapter); read_unlock_irq(&zfcp_data.config_lock); if (!adapter) goto out_adapter; - port = zfcp_port_enqueue(adapter, zfcp_data.init_wwpn, 0, 0); + port = zfcp_port_enqueue(adapter, wwpn, 0, 0); if (IS_ERR(port)) goto out_port; - unit = zfcp_unit_enqueue(port, zfcp_data.init_fcp_lun); + unit = zfcp_unit_enqueue(port, lun); if (IS_ERR(unit)) goto out_unit; up(&zfcp_data.config_sema); @@ -154,6 +120,42 @@ static struct kmem_cache *zfcp_cache_create(int size, char *name) return kmem_cache_create(name , size, align, 0, NULL); } +static void __init zfcp_init_device_setup(char *devstr) +{ + char *token; + char *str; + char busid[ZFCP_BUS_ID_SIZE]; + u64 wwpn, lun; + + /* duplicate devstr and keep the original for sysfs presentation*/ + str = kmalloc(strlen(devstr) + 1, GFP_KERNEL); + if (!str) + return; + + strcpy(str, devstr); + + token = strsep(&str, ","); + if (!token || strlen(token) >= ZFCP_BUS_ID_SIZE) + goto err_out; + strncpy(busid, token, ZFCP_BUS_ID_SIZE); + + token = strsep(&str, ","); + if (!token || strict_strtoull(token, 0, (unsigned long long *) &wwpn)) + goto err_out; + + token = strsep(&str, ","); + if (!token || strict_strtoull(token, 0, (unsigned long long *) &lun)) + goto err_out; + + kfree(str); + zfcp_init_device_configure(busid, wwpn, lun); + return; + + err_out: + kfree(str); + pr_err("%s is not a valid SCSI device\n", devstr); +} + static int __init zfcp_module_init(void) { int retval = -ENOMEM; @@ -175,7 +177,6 @@ static int __init zfcp_module_init(void) zfcp_data.work_queue = create_singlethread_workqueue("zfcp_wq"); - INIT_LIST_HEAD(&zfcp_data.adapter_list_head); sema_init(&zfcp_data.config_sema, 1); rwlock_init(&zfcp_data.config_lock); @@ -186,21 +187,20 @@ static int __init zfcp_module_init(void) retval = misc_register(&zfcp_cfdc_misc); if (retval) { - pr_err("zfcp: Registering the misc device zfcp_cfdc failed\n"); + pr_err("Registering the misc device zfcp_cfdc failed\n"); goto out_misc; } retval = zfcp_ccw_register(); if (retval) { - pr_err("zfcp: The zfcp device driver could not register with " + pr_err("The zfcp device driver could not register with " "the common I/O layer\n"); goto out_ccw_register; } - if (zfcp_device_setup(device)) - zfcp_init_device_configure(); - - goto out; + if (init_device) + zfcp_init_device_setup(init_device); + return 0; out_ccw_register: misc_deregister(&zfcp_cfdc_misc); @@ -436,6 +436,16 @@ static void _zfcp_status_read_scheduler(struct work_struct *work) stat_work)); } +static void zfcp_print_sl(struct seq_file *m, struct service_level *sl) +{ + struct zfcp_adapter *adapter = + container_of(sl, struct zfcp_adapter, service_level); + + seq_printf(m, "zfcp: %s microcode level %x\n", + dev_name(&adapter->ccw_device->dev), + adapter->fsf_lic_version); +} + /** * zfcp_adapter_enqueue - enqueue a new adapter to the list * @ccw_device: pointer to the struct cc_device @@ -500,6 +510,8 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler); INIT_WORK(&adapter->scan_work, _zfcp_scan_ports_later); + adapter->service_level.seq_print = zfcp_print_sl; + /* mark adapter unusable as long as sysfs registration is not complete */ atomic_set_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); @@ -509,14 +521,11 @@ int zfcp_adapter_enqueue(struct ccw_device *ccw_device) &zfcp_sysfs_adapter_attrs)) goto sysfs_failed; - write_lock_irq(&zfcp_data.config_lock); atomic_clear_mask(ZFCP_STATUS_COMMON_REMOVE, &adapter->status); - list_add_tail(&adapter->list, &zfcp_data.adapter_list_head); - write_unlock_irq(&zfcp_data.config_lock); - zfcp_fc_nameserver_init(adapter); - return 0; + if (!zfcp_adapter_scsi_register(adapter)) + return 0; sysfs_failed: zfcp_adapter_debug_unregister(adapter); @@ -555,14 +564,7 @@ void zfcp_adapter_dequeue(struct zfcp_adapter *adapter) return; zfcp_adapter_debug_unregister(adapter); - - /* remove specified adapter data structure from list */ - write_lock_irq(&zfcp_data.config_lock); - list_del(&adapter->list); - write_unlock_irq(&zfcp_data.config_lock); - zfcp_qdio_free(adapter); - zfcp_free_low_mem_buffers(adapter); kfree(adapter->req_list); kfree(adapter->fc_stats); @@ -610,7 +612,8 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, atomic_set_mask(status | ZFCP_STATUS_COMMON_REMOVE, &port->status); atomic_set(&port->refcount, 0); - dev_set_name(&port->sysfs_device, "0x%016llx", wwpn); + dev_set_name(&port->sysfs_device, "0x%016llx", + (unsigned long long)wwpn); port->sysfs_device.parent = &adapter->ccw_device->dev; port->sysfs_device.release = zfcp_sysfs_port_release; diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index b04038c7478..285881f0764 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" /** @@ -103,10 +106,6 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) if (retval) goto out; - retval = zfcp_adapter_scsi_register(adapter); - if (retval) - goto out_scsi_register; - /* initialize request counter */ BUG_ON(!zfcp_reqlist_isempty(adapter)); adapter->req_no = 0; @@ -116,10 +115,10 @@ static int zfcp_ccw_set_online(struct ccw_device *ccw_device) zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, 85, NULL); zfcp_erp_wait(adapter); - goto out; + up(&zfcp_data.config_sema); + flush_work(&adapter->scan_work); + return 0; - out_scsi_register: - zfcp_erp_thread_kill(adapter); out: up(&zfcp_data.config_sema); return retval; diff --git a/drivers/s390/scsi/zfcp_cfdc.c b/drivers/s390/scsi/zfcp_cfdc.c index ec2abceca6d..10cbfd172a2 100644 --- a/drivers/s390/scsi/zfcp_cfdc.c +++ b/drivers/s390/scsi/zfcp_cfdc.c @@ -7,6 +7,9 @@ * Copyright IBM Corporation 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/types.h> #include <linux/miscdevice.h> #include <asm/ccwdev.h> @@ -82,20 +85,9 @@ static int zfcp_cfdc_copy_to_user(void __user *user_buffer, static struct zfcp_adapter *zfcp_cfdc_get_adapter(u32 devno) { - struct zfcp_adapter *adapter = NULL, *cur_adapter; - struct ccw_dev_id dev_id; - - read_lock_irq(&zfcp_data.config_lock); - list_for_each_entry(cur_adapter, &zfcp_data.adapter_list_head, list) { - ccw_device_get_id(cur_adapter->ccw_device, &dev_id); - if (dev_id.devno == devno) { - adapter = cur_adapter; - zfcp_adapter_get(adapter); - break; - } - } - read_unlock_irq(&zfcp_data.config_lock); - return adapter; + char busid[9]; + snprintf(busid, sizeof(busid), "0.0.%04x", devno); + return zfcp_get_adapter_by_busid(busid); } static int zfcp_cfdc_set_fsf(struct zfcp_fsf_cfdc *fsf_cfdc, int command) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 060f5f2352e..cb6df609953 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/ctype.h> #include <asm/debug.h> #include "zfcp_ext.h" @@ -30,7 +33,7 @@ static void zfcp_dbf_hexdump(debug_info_t *dbf, void *to, int to_len, dump->offset = offset; dump->size = min(from_len - offset, room); memcpy(dump->data, from + offset, dump->size); - debug_event(dbf, level, dump, dump->size); + debug_event(dbf, level, dump, dump->size + sizeof(*dump)); } } @@ -108,7 +111,7 @@ static int zfcp_dbf_view_header(debug_info_t *id, struct debug_view *view, t.tv_sec, t.tv_nsec); zfcp_dbf_out(&p, "cpu", "%02i", entry->id.fields.cpuid); } else { - zfcp_dbf_outd(&p, NULL, dump->data, dump->size, dump->offset, + zfcp_dbf_outd(&p, "", dump->data, dump->size, dump->offset, dump->total_size); if ((dump->offset + dump->size) == dump->total_size) p += sprintf(p, "\n"); @@ -366,6 +369,7 @@ static void zfcp_hba_dbf_view_response(char **p, break; zfcp_dbf_out(p, "scsi_cmnd", "0x%0Lx", r->u.fcp.cmnd); zfcp_dbf_out(p, "scsi_serial", "0x%016Lx", r->u.fcp.serial); + p += sprintf(*p, "\n"); break; case FSF_QTCB_OPEN_PORT_WITH_DID: @@ -465,7 +469,8 @@ static int zfcp_hba_dbf_view_format(debug_info_t *id, struct debug_view *view, else if (strncmp(r->tag, "berr", ZFCP_DBF_TAG_SIZE) == 0) zfcp_hba_dbf_view_berr(&p, &r->u.berr); - p += sprintf(p, "\n"); + if (strncmp(r->tag, "resp", ZFCP_DBF_TAG_SIZE) != 0) + p += sprintf(p, "\n"); return p - out_buf; } @@ -517,7 +522,7 @@ static const char *zfcp_rec_dbf_ids[] = { [29] = "link down", [30] = "link up status read", [31] = "open port failed", - [32] = "open port failed", + [32] = "", [33] = "close port", [34] = "open unit failed", [35] = "exclusive open unit failed", @@ -880,6 +885,7 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) struct ct_hdr *hdr = sg_virt(ct->req); struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; struct zfcp_san_dbf_record_ct_request *oct = &r->u.ct_req; + int level = 3; unsigned long flags; spin_lock_irqsave(&adapter->san_dbf_lock, flags); @@ -896,9 +902,10 @@ void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) oct->options = hdr->options; oct->max_res_size = hdr->max_res_size; oct->len = min((int)ct->req->length - (int)sizeof(struct ct_hdr), - ZFCP_DBF_CT_PAYLOAD); - memcpy(oct->payload, (void *)hdr + sizeof(struct ct_hdr), oct->len); - debug_event(adapter->san_dbf, 3, r, sizeof(*r)); + ZFCP_DBF_SAN_MAX_PAYLOAD); + debug_event(adapter->san_dbf, level, r, sizeof(*r)); + zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level, + (void *)hdr + sizeof(struct ct_hdr), oct->len); spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } @@ -914,6 +921,7 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) struct ct_hdr *hdr = sg_virt(ct->resp); struct zfcp_san_dbf_record *r = &adapter->san_dbf_buf; struct zfcp_san_dbf_record_ct_response *rct = &r->u.ct_resp; + int level = 3; unsigned long flags; spin_lock_irqsave(&adapter->san_dbf_lock, flags); @@ -928,10 +936,12 @@ void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) rct->reason_code = hdr->reason_code; rct->expl = hdr->reason_code_expl; rct->vendor_unique = hdr->vendor_unique; + rct->max_res_size = hdr->max_res_size; rct->len = min((int)ct->resp->length - (int)sizeof(struct ct_hdr), - ZFCP_DBF_CT_PAYLOAD); - memcpy(rct->payload, (void *)hdr + sizeof(struct ct_hdr), rct->len); - debug_event(adapter->san_dbf, 3, r, sizeof(*r)); + ZFCP_DBF_SAN_MAX_PAYLOAD); + debug_event(adapter->san_dbf, level, r, sizeof(*r)); + zfcp_dbf_hexdump(adapter->san_dbf, r, sizeof(*r), level, + (void *)hdr + sizeof(struct ct_hdr), rct->len); spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } @@ -954,7 +964,7 @@ static void zfcp_san_dbf_event_els(const char *tag, int level, rec->u.els.ls_code = ls_code; debug_event(adapter->san_dbf, level, rec, sizeof(*rec)); zfcp_dbf_hexdump(adapter->san_dbf, rec, sizeof(*rec), level, - buffer, min(buflen, ZFCP_DBF_ELS_MAX_PAYLOAD)); + buffer, min(buflen, ZFCP_DBF_SAN_MAX_PAYLOAD)); spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } @@ -1008,8 +1018,6 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, char *out_buf, const char *in_buf) { struct zfcp_san_dbf_record *r = (struct zfcp_san_dbf_record *)in_buf; - char *buffer = NULL; - int buflen = 0, total = 0; char *p = out_buf; if (strncmp(r->tag, "dump", ZFCP_DBF_TAG_SIZE) == 0) @@ -1029,9 +1037,6 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "gs_subtype", "0x%02x", ct->gs_subtype); zfcp_dbf_out(&p, "options", "0x%02x", ct->options); zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); - total = ct->len; - buffer = ct->payload; - buflen = min(total, ZFCP_DBF_CT_PAYLOAD); } else if (strncmp(r->tag, "rctc", ZFCP_DBF_TAG_SIZE) == 0) { struct zfcp_san_dbf_record_ct_response *ct = &r->u.ct_resp; zfcp_dbf_out(&p, "cmd_rsp_code", "0x%04x", ct->cmd_rsp_code); @@ -1039,23 +1044,13 @@ static int zfcp_san_dbf_view_format(debug_info_t *id, struct debug_view *view, zfcp_dbf_out(&p, "reason_code", "0x%02x", ct->reason_code); zfcp_dbf_out(&p, "reason_code_expl", "0x%02x", ct->expl); zfcp_dbf_out(&p, "vendor_unique", "0x%02x", ct->vendor_unique); - total = ct->len; - buffer = ct->payload; - buflen = min(total, ZFCP_DBF_CT_PAYLOAD); + zfcp_dbf_out(&p, "max_res_size", "0x%04x", ct->max_res_size); } else if (strncmp(r->tag, "oels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "rels", ZFCP_DBF_TAG_SIZE) == 0 || strncmp(r->tag, "iels", ZFCP_DBF_TAG_SIZE) == 0) { struct zfcp_san_dbf_record_els *els = &r->u.els; zfcp_dbf_out(&p, "ls_code", "0x%02x", els->ls_code); - total = els->len; - buffer = els->payload; - buflen = min(total, ZFCP_DBF_ELS_PAYLOAD); } - - zfcp_dbf_outd(&p, "payload", buffer, buflen, 0, total); - if (buflen == total) - p += sprintf(p, "\n"); - return p - out_buf; } @@ -1256,7 +1251,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) char dbf_name[DEBUG_MAX_NAME_LEN]; /* debug feature area which records recovery activity */ - sprintf(dbf_name, "zfcp_%s_rec", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_rec", dev_name(&adapter->ccw_device->dev)); adapter->rec_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_rec_dbf_record)); if (!adapter->rec_dbf) @@ -1266,7 +1261,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->rec_dbf, 3); /* debug feature area which records HBA (FSF and QDIO) conditions */ - sprintf(dbf_name, "zfcp_%s_hba", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_hba", dev_name(&adapter->ccw_device->dev)); adapter->hba_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_hba_dbf_record)); if (!adapter->hba_dbf) @@ -1276,7 +1271,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->hba_dbf, 3); /* debug feature area which records SAN command failures and recovery */ - sprintf(dbf_name, "zfcp_%s_san", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_san", dev_name(&adapter->ccw_device->dev)); adapter->san_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_san_dbf_record)); if (!adapter->san_dbf) @@ -1286,7 +1281,7 @@ int zfcp_adapter_debug_register(struct zfcp_adapter *adapter) debug_set_level(adapter->san_dbf, 6); /* debug feature area which records SCSI command failures and recovery */ - sprintf(dbf_name, "zfcp_%s_scsi", zfcp_get_busid_by_adapter(adapter)); + sprintf(dbf_name, "zfcp_%s_scsi", dev_name(&adapter->ccw_device->dev)); adapter->scsi_dbf = debug_register(dbf_name, dbfsize, 1, sizeof(struct zfcp_scsi_dbf_record)); if (!adapter->scsi_dbf) diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index e8f450801fe..74998ff88e5 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -163,8 +163,6 @@ struct zfcp_san_dbf_record_ct_request { u8 options; u16 max_res_size; u32 len; -#define ZFCP_DBF_CT_PAYLOAD 24 - u8 payload[ZFCP_DBF_CT_PAYLOAD]; } __attribute__ ((packed)); struct zfcp_san_dbf_record_ct_response { @@ -173,16 +171,13 @@ struct zfcp_san_dbf_record_ct_response { u8 reason_code; u8 expl; u8 vendor_unique; + u16 max_res_size; u32 len; - u8 payload[ZFCP_DBF_CT_PAYLOAD]; } __attribute__ ((packed)); struct zfcp_san_dbf_record_els { u8 ls_code; u32 len; -#define ZFCP_DBF_ELS_PAYLOAD 32 -#define ZFCP_DBF_ELS_MAX_PAYLOAD 1024 - u8 payload[ZFCP_DBF_ELS_PAYLOAD]; } __attribute__ ((packed)); struct zfcp_san_dbf_record { @@ -196,6 +191,8 @@ struct zfcp_san_dbf_record { struct zfcp_san_dbf_record_ct_response ct_resp; struct zfcp_san_dbf_record_els els; } u; +#define ZFCP_DBF_SAN_MAX_PAYLOAD 1024 + u8 payload[32]; } __attribute__ ((packed)); struct zfcp_scsi_dbf_record { diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 9ce4c75bd19..510662783a6 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -33,6 +33,7 @@ #include <asm/qdio.h> #include <asm/debug.h> #include <asm/ebcdic.h> +#include <asm/sysinfo.h> #include "zfcp_dbf.h" #include "zfcp_fsf.h" @@ -158,20 +159,6 @@ struct fcp_rscn_element { u32 nport_did:24; } __attribute__((packed)); -#define ZFCP_PORT_ADDRESS 0x0 -#define ZFCP_AREA_ADDRESS 0x1 -#define ZFCP_DOMAIN_ADDRESS 0x2 -#define ZFCP_FABRIC_ADDRESS 0x3 - -#define ZFCP_PORTS_RANGE_PORT 0xFFFFFF -#define ZFCP_PORTS_RANGE_AREA 0xFFFF00 -#define ZFCP_PORTS_RANGE_DOMAIN 0xFF0000 -#define ZFCP_PORTS_RANGE_FABRIC 0x000000 - -#define ZFCP_NO_PORTS_PER_AREA 0x100 -#define ZFCP_NO_PORTS_PER_DOMAIN 0x10000 -#define ZFCP_NO_PORTS_PER_FABRIC 0x1000000 - /* see fc-ph */ struct fcp_logo { u32 command; @@ -210,7 +197,6 @@ struct zfcp_ls_adisc { #define ZFCP_CT_UNABLE_TO_PERFORM_CMD 0x09 #define ZFCP_CT_GID_PN 0x0121 #define ZFCP_CT_GPN_FT 0x0172 -#define ZFCP_CT_MAX_SIZE 0x1020 #define ZFCP_CT_ACCEPT 0x8002 #define ZFCP_CT_REJECT 0x8001 @@ -257,7 +243,6 @@ struct zfcp_ls_adisc { /* remote port status */ #define ZFCP_STATUS_PORT_PHYS_OPEN 0x00000001 -#define ZFCP_STATUS_PORT_DID_DID 0x00000002 #define ZFCP_STATUS_PORT_PHYS_CLOSING 0x00000004 #define ZFCP_STATUS_PORT_NO_WWPN 0x00000008 #define ZFCP_STATUS_PORT_INVALID_WWPN 0x00000020 @@ -339,8 +324,6 @@ struct ct_iu_gid_pn_resp { * @wka_port: port where the request is sent to * @req: scatter-gather list for request * @resp: scatter-gather list for response - * @req_count: number of elements in request scatter-gather list - * @resp_count: number of elements in response scatter-gather list * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function * @timeout: FSF timeout for this request @@ -351,8 +334,6 @@ struct zfcp_send_ct { struct zfcp_wka_port *wka_port; struct scatterlist *req; struct scatterlist *resp; - unsigned int req_count; - unsigned int resp_count; void (*handler)(unsigned long); unsigned long handler_data; int timeout; @@ -377,8 +358,6 @@ struct zfcp_gid_pn_data { * @d_id: destiniation id of port where request is sent to * @req: scatter-gather list for request * @resp: scatter-gather list for response - * @req_count: number of elements in request scatter-gather list - * @resp_count: number of elements in response scatter-gather list * @handler: handler function (called for response to the request) * @handler_data: data passed to handler function * @completion: completion for synchronization purposes @@ -391,8 +370,6 @@ struct zfcp_send_els { u32 d_id; struct scatterlist *req; struct scatterlist *resp; - unsigned int req_count; - unsigned int resp_count; void (*handler)(unsigned long); unsigned long handler_data; struct completion *completion; @@ -450,7 +427,6 @@ struct zfcp_latencies { }; struct zfcp_adapter { - struct list_head list; /* list of adapters */ atomic_t refcount; /* reference count */ wait_queue_head_t remove_wq; /* can be used to wait for refcount drop to zero */ @@ -515,6 +491,7 @@ struct zfcp_adapter { struct fsf_qtcb_bottom_port *stats_reset_data; unsigned long stats_reset; struct work_struct scan_work; + struct service_level service_level; atomic_t qdio_outb_full; /* queue full incidents */ }; @@ -591,16 +568,11 @@ struct zfcp_fsf_req { struct zfcp_data { struct scsi_host_template scsi_host_template; struct scsi_transport_template *scsi_transport_template; - struct list_head adapter_list_head; /* head of adapter list */ rwlock_t config_lock; /* serialises changes to adapter/port/unit lists */ struct semaphore config_sema; /* serialises configuration changes */ - atomic_t loglevel; /* current loglevel */ - char init_busid[20]; - u64 init_wwpn; - u64 init_fcp_lun; struct kmem_cache *fsf_req_qtcb_cache; struct kmem_cache *sr_buffer_cache; struct kmem_cache *gid_pn_cache; @@ -621,8 +593,6 @@ struct zfcp_fsf_req_qtcb { #define ZFCP_SET 0x00000100 #define ZFCP_CLEAR 0x00000200 -#define zfcp_get_busid_by_adapter(adapter) (dev_name(&adapter->ccw_device->dev)) - /* * Helper functions for request ID management. */ diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 9040f738ff3..387a3af528a 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" #define ZFCP_MAX_ERPS 3 @@ -472,6 +475,7 @@ static void zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *act) ZFCP_STATUS_ERP_TIMEDOUT)) { act->fsf_req->status |= ZFCP_STATUS_FSFREQ_DISMISSED; zfcp_rec_dbf_event_action(142, act); + act->fsf_req->erp_action = NULL; } if (act->status & ZFCP_STATUS_ERP_TIMEDOUT) zfcp_rec_dbf_event_action(143, act); @@ -719,7 +723,6 @@ static int zfcp_erp_adapter_strategy_generic(struct zfcp_erp_action *act, goto failed_openfcp; atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &act->adapter->status); - schedule_work(&act->adapter->scan_work); return ZFCP_ERP_SUCCEEDED; @@ -837,7 +840,6 @@ static int zfcp_erp_open_ptp_port(struct zfcp_erp_action *act) return ZFCP_ERP_FAILED; } port->d_id = adapter->peer_d_id; - atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); return zfcp_erp_port_strategy_open_port(act); } @@ -868,12 +870,12 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) case ZFCP_ERP_STEP_PORT_CLOSING: if (fc_host_port_type(adapter->scsi_host) == FC_PORTTYPE_PTP) return zfcp_erp_open_ptp_port(act); - if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { + if (!port->d_id) { queue_work(zfcp_data.work_queue, &port->gid_pn_work); return ZFCP_ERP_CONTINUES; } case ZFCP_ERP_STEP_NAMESERVER_LOOKUP: - if (!(p_status & ZFCP_STATUS_PORT_DID_DID)) { + if (!port->d_id) { if (p_status & (ZFCP_STATUS_PORT_INVALID_WWPN)) { zfcp_erp_port_failed(port, 26, NULL); return ZFCP_ERP_EXIT; @@ -885,7 +887,7 @@ static int zfcp_erp_port_strategy_open_common(struct zfcp_erp_action *act) case ZFCP_ERP_STEP_PORT_OPENING: /* D_ID might have changed during open */ if (p_status & ZFCP_STATUS_COMMON_OPEN) { - if (p_status & ZFCP_STATUS_PORT_DID_DID) + if (port->d_id) return ZFCP_ERP_SUCCEEDED; else { act->step = ZFCP_ERP_STEP_PORT_CLOSING; @@ -1185,7 +1187,9 @@ static void zfcp_erp_scsi_scan(struct work_struct *work) container_of(work, struct zfcp_erp_add_work, work); struct zfcp_unit *unit = p->unit; struct fc_rport *rport = unit->port->rport; - scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, + + if (rport && rport->port_state == FC_PORTSTATE_ONLINE) + scsi_scan_target(&rport->dev, 0, rport->scsi_target_id, scsilun_to_int((struct scsi_lun *)&unit->fcp_lun), 0); atomic_clear_mask(ZFCP_STATUS_UNIT_SCSI_WORK_PENDING, &unit->status); zfcp_unit_put(unit); @@ -1279,8 +1283,13 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - if (result != ZFCP_ERP_SUCCEEDED) + if (result != ZFCP_ERP_SUCCEEDED) { + unregister_service_level(&adapter->service_level); zfcp_erp_rports_del(adapter); + } else { + register_service_level(&adapter->service_level); + schedule_work(&adapter->scan_work); + } zfcp_adapter_put(adapter); break; } @@ -1375,6 +1384,7 @@ static int zfcp_erp_thread(void *data) struct list_head *next; struct zfcp_erp_action *act; unsigned long flags; + int ignore; daemonize("zfcperp%s", dev_name(&adapter->ccw_device->dev)); /* Block all signals */ @@ -1397,7 +1407,7 @@ static int zfcp_erp_thread(void *data) } zfcp_rec_dbf_event_thread_lock(4, adapter); - down_interruptible(&adapter->erp_ready_sem); + ignore = down_interruptible(&adapter->erp_ready_sem); zfcp_rec_dbf_event_thread_lock(5, adapter); } diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 1a7c80a77ff..eabdfe24456 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -6,8 +6,25 @@ * Copyright IBM Corporation 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" +enum rscn_address_format { + RSCN_PORT_ADDRESS = 0x0, + RSCN_AREA_ADDRESS = 0x1, + RSCN_DOMAIN_ADDRESS = 0x2, + RSCN_FABRIC_ADDRESS = 0x3, +}; + +static u32 rscn_range_mask[] = { + [RSCN_PORT_ADDRESS] = 0xFFFFFF, + [RSCN_AREA_ADDRESS] = 0xFFFF00, + [RSCN_DOMAIN_ADDRESS] = 0xFF0000, + [RSCN_FABRIC_ADDRESS] = 0x000000, +}; + struct ct_iu_gpn_ft_req { struct ct_hdr header; u8 flags; @@ -23,9 +40,12 @@ struct gpn_ft_resp_acc { u64 wwpn; } __attribute__ ((packed)); -#define ZFCP_GPN_FT_ENTRIES ((PAGE_SIZE - sizeof(struct ct_hdr)) \ - / sizeof(struct gpn_ft_resp_acc)) +#define ZFCP_CT_SIZE_ONE_PAGE (PAGE_SIZE - sizeof(struct ct_hdr)) +#define ZFCP_GPN_FT_ENTRIES (ZFCP_CT_SIZE_ONE_PAGE \ + / sizeof(struct gpn_ft_resp_acc)) #define ZFCP_GPN_FT_BUFFERS 4 +#define ZFCP_GPN_FT_MAX_SIZE (ZFCP_GPN_FT_BUFFERS * PAGE_SIZE \ + - sizeof(struct ct_hdr)) #define ZFCP_GPN_FT_MAX_ENTRIES ZFCP_GPN_FT_BUFFERS * (ZFCP_GPN_FT_ENTRIES + 1) struct ct_iu_gpn_ft_resp { @@ -50,7 +70,8 @@ static int zfcp_wka_port_get(struct zfcp_wka_port *wka_port) if (mutex_lock_interruptible(&wka_port->mutex)) return -ERESTARTSYS; - if (wka_port->status != ZFCP_WKA_PORT_ONLINE) { + if (wka_port->status == ZFCP_WKA_PORT_OFFLINE || + wka_port->status == ZFCP_WKA_PORT_CLOSING) { wka_port->status = ZFCP_WKA_PORT_OPENING; if (zfcp_fsf_open_wka_port(wka_port)) wka_port->status = ZFCP_WKA_PORT_OFFLINE; @@ -125,8 +146,7 @@ static void _zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req, u32 range, read_lock_irqsave(&zfcp_data.config_lock, flags); list_for_each_entry(port, &fsf_req->adapter->port_list_head, list) { - /* FIXME: ZFCP_STATUS_PORT_DID_DID check is racy */ - if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_DID_DID)) + if (!(atomic_read(&port->status) & ZFCP_STATUS_PORT_PHYS_OPEN)) /* Try to connect to unused ports anyway. */ zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, @@ -157,22 +177,7 @@ static void zfcp_fc_incoming_rscn(struct zfcp_fsf_req *fsf_req) for (i = 1; i < no_entries; i++) { /* skip head and start with 1st element */ fcp_rscn_element++; - switch (fcp_rscn_element->addr_format) { - case ZFCP_PORT_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_PORT; - break; - case ZFCP_AREA_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_AREA; - break; - case ZFCP_DOMAIN_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_DOMAIN; - break; - case ZFCP_FABRIC_ADDRESS: - range_mask = ZFCP_PORTS_RANGE_FABRIC; - break; - default: - continue; - } + range_mask = rscn_range_mask[fcp_rscn_element->addr_format]; _zfcp_fc_incoming_rscn(fsf_req, range_mask, fcp_rscn_element); } schedule_work(&fsf_req->adapter->scan_work); @@ -263,7 +268,6 @@ static void zfcp_fc_ns_gid_pn_eval(unsigned long data) return; /* looks like a valid d_id */ port->d_id = ct_iu_resp->d_id & ZFCP_DID_MASK; - atomic_set_mask(ZFCP_STATUS_PORT_DID_DID, &port->status); } int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, @@ -281,8 +285,6 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, gid_pn->ct.timeout = ZFCP_NS_GID_PN_TIMEOUT; gid_pn->ct.req = &gid_pn->req; gid_pn->ct.resp = &gid_pn->resp; - gid_pn->ct.req_count = 1; - gid_pn->ct.resp_count = 1; sg_init_one(&gid_pn->req, &gid_pn->ct_iu_req, sizeof(struct ct_iu_gid_pn_req)); sg_init_one(&gid_pn->resp, &gid_pn->ct_iu_resp, @@ -294,7 +296,7 @@ int static zfcp_fc_ns_gid_pn_request(struct zfcp_erp_action *erp_action, gid_pn->ct_iu_req.header.gs_subtype = ZFCP_CT_NAME_SERVER; gid_pn->ct_iu_req.header.options = ZFCP_CT_SYNCHRONOUS; gid_pn->ct_iu_req.header.cmd_rsp_code = ZFCP_CT_GID_PN; - gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_MAX_SIZE; + gid_pn->ct_iu_req.header.max_res_size = ZFCP_CT_SIZE_ONE_PAGE / 4; gid_pn->ct_iu_req.wwpn = erp_action->port->wwpn; init_completion(&compl_rec.done); @@ -404,8 +406,6 @@ static int zfcp_fc_adisc(struct zfcp_port *port) sg_init_one(adisc->els.resp, &adisc->ls_adisc_acc, sizeof(struct zfcp_ls_adisc)); - adisc->els.req_count = 1; - adisc->els.resp_count = 1; adisc->els.adapter = adapter; adisc->els.port = port; adisc->els.d_id = port->d_id; @@ -445,17 +445,17 @@ void zfcp_test_link(struct zfcp_port *port) zfcp_erp_port_forced_reopen(port, 0, 65, NULL); } -static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft) +static void zfcp_free_sg_env(struct zfcp_gpn_ft *gpn_ft, int buf_num) { struct scatterlist *sg = &gpn_ft->sg_req; kfree(sg_virt(sg)); /* free request buffer */ - zfcp_sg_free_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS); + zfcp_sg_free_table(gpn_ft->sg_resp, buf_num); kfree(gpn_ft); } -static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) +static struct zfcp_gpn_ft *zfcp_alloc_sg_env(int buf_num) { struct zfcp_gpn_ft *gpn_ft; struct ct_iu_gpn_ft_req *req; @@ -472,8 +472,8 @@ static struct zfcp_gpn_ft *zfcp_alloc_sg_env(void) } sg_init_one(&gpn_ft->sg_req, req, sizeof(*req)); - if (zfcp_sg_setup_table(gpn_ft->sg_resp, ZFCP_GPN_FT_BUFFERS)) { - zfcp_free_sg_env(gpn_ft); + if (zfcp_sg_setup_table(gpn_ft->sg_resp, buf_num)) { + zfcp_free_sg_env(gpn_ft, buf_num); gpn_ft = NULL; } out: @@ -482,7 +482,8 @@ out: static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, - struct zfcp_adapter *adapter) + struct zfcp_adapter *adapter, + int max_bytes) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct ct_iu_gpn_ft_req *req = sg_virt(&gpn_ft->sg_req); @@ -495,8 +496,7 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, req->header.gs_subtype = ZFCP_CT_NAME_SERVER; req->header.options = ZFCP_CT_SYNCHRONOUS; req->header.cmd_rsp_code = ZFCP_CT_GPN_FT; - req->header.max_res_size = (sizeof(struct gpn_ft_resp_acc) * - (ZFCP_GPN_FT_MAX_ENTRIES - 1)) >> 2; + req->header.max_res_size = max_bytes / 4; req->flags = 0; req->domain_id_scope = 0; req->area_id_scope = 0; @@ -509,8 +509,6 @@ static int zfcp_scan_issue_gpn_ft(struct zfcp_gpn_ft *gpn_ft, ct->timeout = 10; ct->req = &gpn_ft->sg_req; ct->resp = gpn_ft->sg_resp; - ct->req_count = 1; - ct->resp_count = ZFCP_GPN_FT_BUFFERS; init_completion(&compl_rec.done); compl_rec.handler = NULL; @@ -537,7 +535,7 @@ static void zfcp_validate_port(struct zfcp_port *port) zfcp_port_dequeue(port); } -static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) +static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft, int max_entries) { struct zfcp_send_ct *ct = &gpn_ft->ct; struct scatterlist *sg = gpn_ft->sg_resp; @@ -557,13 +555,17 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) return -EIO; } - if (hdr->max_res_size) + if (hdr->max_res_size) { + dev_warn(&adapter->ccw_device->dev, + "The name server reported %d words residual data\n", + hdr->max_res_size); return -E2BIG; + } down(&zfcp_data.config_sema); /* first entry is the header */ - for (x = 1; x < ZFCP_GPN_FT_MAX_ENTRIES && !last; x++) { + for (x = 1; x < max_entries && !last; x++) { if (x % (ZFCP_GPN_FT_ENTRIES + 1)) acc++; else @@ -586,7 +588,6 @@ static int zfcp_scan_eval_gpn_ft(struct zfcp_gpn_ft *gpn_ft) } port = zfcp_port_enqueue(adapter, acc->wwpn, - ZFCP_STATUS_PORT_DID_DID | ZFCP_STATUS_COMMON_NOESC, d_id); if (IS_ERR(port)) ret = PTR_ERR(port); @@ -609,8 +610,13 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) { int ret, i; struct zfcp_gpn_ft *gpn_ft; + int chain, max_entries, buf_num, max_bytes; + + chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS; + buf_num = chain ? ZFCP_GPN_FT_BUFFERS : 1; + max_entries = chain ? ZFCP_GPN_FT_MAX_ENTRIES : ZFCP_GPN_FT_ENTRIES; + max_bytes = chain ? ZFCP_GPN_FT_MAX_SIZE : ZFCP_CT_SIZE_ONE_PAGE; - zfcp_erp_wait(adapter); /* wait until adapter is finished with ERP */ if (fc_host_port_type(adapter->scsi_host) != FC_PORTTYPE_NPORT) return 0; @@ -618,23 +624,23 @@ int zfcp_scan_ports(struct zfcp_adapter *adapter) if (ret) return ret; - gpn_ft = zfcp_alloc_sg_env(); + gpn_ft = zfcp_alloc_sg_env(buf_num); if (!gpn_ft) { ret = -ENOMEM; goto out; } for (i = 0; i < 3; i++) { - ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter); + ret = zfcp_scan_issue_gpn_ft(gpn_ft, adapter, max_bytes); if (!ret) { - ret = zfcp_scan_eval_gpn_ft(gpn_ft); + ret = zfcp_scan_eval_gpn_ft(gpn_ft, max_entries); if (ret == -EAGAIN) ssleep(1); else break; } } - zfcp_free_sg_env(gpn_ft); + zfcp_free_sg_env(gpn_ft, buf_num); out: zfcp_wka_port_put(&adapter->nsp); return ret; diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 5ae1d497e5e..e6416f8541b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include <linux/blktrace_api.h> #include "zfcp_ext.h" @@ -641,38 +644,38 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) } } -static int zfcp_fsf_sbal_check(struct zfcp_adapter *adapter) +static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter) { - struct zfcp_qdio_queue *req_q = &adapter->req_q; - - spin_lock_bh(&adapter->req_q_lock); - if (atomic_read(&req_q->count)) + if (atomic_read(&adapter->req_q.count) > 0) return 1; - spin_unlock_bh(&adapter->req_q_lock); + atomic_inc(&adapter->qdio_outb_full); return 0; } -static int zfcp_fsf_sbal_available(struct zfcp_adapter *adapter) -{ - unsigned int count = atomic_read(&adapter->req_q.count); - if (!count) - atomic_inc(&adapter->qdio_outb_full); - return count > 0; -} - static int zfcp_fsf_req_sbal_get(struct zfcp_adapter *adapter) + __releases(&adapter->req_q_lock) + __acquires(&adapter->req_q_lock) { + struct zfcp_qdio_queue *req_q = &adapter->req_q; long ret; + if (atomic_read(&req_q->count) <= -REQUEST_LIST_SIZE) + return -EIO; + if (atomic_read(&req_q->count) > 0) + return 0; + + atomic_dec(&req_q->count); spin_unlock_bh(&adapter->req_q_lock); ret = wait_event_interruptible_timeout(adapter->request_wq, - zfcp_fsf_sbal_check(adapter), 5 * HZ); + atomic_read(&req_q->count) >= 0, + 5 * HZ); + spin_lock_bh(&adapter->req_q_lock); + atomic_inc(&req_q->count); + if (ret > 0) return 0; if (!ret) atomic_inc(&adapter->qdio_outb_full); - - spin_lock_bh(&adapter->req_q_lock); return -EIO; } @@ -683,6 +686,7 @@ static struct zfcp_fsf_req *zfcp_fsf_alloc_noqtcb(mempool_t *pool) if (!req) return NULL; memset(req, 0, sizeof(*req)); + req->pool = pool; return req; } @@ -769,28 +773,24 @@ static struct zfcp_fsf_req *zfcp_fsf_req_create(struct zfcp_adapter *adapter, static int zfcp_fsf_req_send(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; - struct zfcp_qdio_queue *req_q = &adapter->req_q; + unsigned long flags; int idx; /* put allocated FSF request into hash table */ - spin_lock(&adapter->req_list_lock); + spin_lock_irqsave(&adapter->req_list_lock, flags); idx = zfcp_reqlist_hash(req->req_id); list_add_tail(&req->list, &adapter->req_list[idx]); - spin_unlock(&adapter->req_list_lock); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); - req->qdio_outb_usage = atomic_read(&req_q->count); + req->qdio_outb_usage = atomic_read(&adapter->req_q.count); req->issued = get_clock(); if (zfcp_qdio_send(req)) { - /* Queues are down..... */ del_timer(&req->timer); - spin_lock(&adapter->req_list_lock); - zfcp_reqlist_remove(adapter, req); - spin_unlock(&adapter->req_list_lock); - /* undo changes in request queue made for this request */ - atomic_add(req->sbal_number, &req_q->count); - req_q->first -= req->sbal_number; - req_q->first += QDIO_MAX_BUFFERS_PER_Q; - req_q->first %= QDIO_MAX_BUFFERS_PER_Q; /* wrap */ + spin_lock_irqsave(&adapter->req_list_lock, flags); + /* lookup request again, list might have changed */ + if (zfcp_reqlist_find_safe(adapter, req)) + zfcp_reqlist_remove(adapter, req); + spin_unlock_irqrestore(&adapter->req_list_lock, flags); zfcp_erp_adapter_reopen(adapter, 0, 116, req); return -EIO; } @@ -933,8 +933,10 @@ struct zfcp_fsf_req *zfcp_fsf_abort_fcp_command(unsigned long old_req_id, goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_ABORT_FCP_CMND, req_flags, adapter->pool.fsf_req_abort); - if (IS_ERR(req)) + if (IS_ERR(req)) { + req = NULL; goto out; + } if (unlikely(!(atomic_read(&unit->status) & ZFCP_STATUS_COMMON_UNBLOCKED))) @@ -1011,12 +1013,29 @@ skip_fsfstatus: send_ct->handler(send_ct->handler_data); } -static int zfcp_fsf_setup_sbals(struct zfcp_fsf_req *req, - struct scatterlist *sg_req, - struct scatterlist *sg_resp, int max_sbals) +static int zfcp_fsf_setup_ct_els_sbals(struct zfcp_fsf_req *req, + struct scatterlist *sg_req, + struct scatterlist *sg_resp, + int max_sbals) { + struct qdio_buffer_element *sbale = zfcp_qdio_sbale_req(req); + u32 feat = req->adapter->adapter_features; int bytes; + if (!(feat & FSF_FEATURE_ELS_CT_CHAINED_SBALS)) { + if (sg_req->length > PAGE_SIZE || sg_resp->length > PAGE_SIZE || + !sg_is_last(sg_req) || !sg_is_last(sg_resp)) + return -EOPNOTSUPP; + + sbale[0].flags |= SBAL_FLAGS0_TYPE_WRITE_READ; + sbale[2].addr = sg_virt(sg_req); + sbale[2].length = sg_req->length; + sbale[3].addr = sg_virt(sg_resp); + sbale[3].length = sg_resp->length; + sbale[3].flags |= SBAL_FLAGS_LAST_ENTRY; + return 0; + } + bytes = zfcp_qdio_sbals_from_sg(req, SBAL_FLAGS0_TYPE_WRITE_READ, sg_req, max_sbals); if (bytes <= 0) @@ -1058,8 +1077,8 @@ int zfcp_fsf_send_ct(struct zfcp_send_ct *ct, mempool_t *pool, goto out; } - ret = zfcp_fsf_setup_sbals(req, ct->req, ct->resp, - FSF_MAX_SBALS_PER_REQ); + ret = zfcp_fsf_setup_ct_els_sbals(req, ct->req, ct->resp, + FSF_MAX_SBALS_PER_REQ); if (ret) goto failed_send; @@ -1169,7 +1188,7 @@ int zfcp_fsf_send_els(struct zfcp_send_els *els) goto out; } - ret = zfcp_fsf_setup_sbals(req, els->req, els->resp, 2); + ret = zfcp_fsf_setup_ct_els_sbals(req, els->req, els->resp, 2); if (ret) goto failed_send; @@ -1404,13 +1423,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) switch (header->fsf_status_qual.word[0]) { case FSF_SQ_INVOKE_LINK_TEST_PROCEDURE: case FSF_SQ_ULP_DEPENDENT_ERP_REQUIRED: - req->status |= ZFCP_STATUS_FSFREQ_ERROR; - break; case FSF_SQ_NO_RETRY_POSSIBLE: - dev_warn(&req->adapter->ccw_device->dev, - "Remote port 0x%016Lx could not be opened\n", - (unsigned long long)port->wwpn); - zfcp_erp_port_failed(port, 32, req); req->status |= ZFCP_STATUS_FSFREQ_ERROR; break; } @@ -1438,10 +1451,10 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) * Alternately, an ADISC/PDISC ELS should suffice, as well. */ plogi = (struct fsf_plogi *) req->qtcb->bottom.support.els; - if (req->qtcb->bottom.support.els1_length >= sizeof(*plogi)) { + if (req->qtcb->bottom.support.els1_length >= + FSF_PLOGI_MIN_LEN) { if (plogi->serv_param.wwpn != port->wwpn) - atomic_clear_mask(ZFCP_STATUS_PORT_DID_DID, - &port->status); + port->d_id = 0; else { port->wwnn = plogi->serv_param.wwnn; zfcp_fc_plogi_evaluate(port, plogi); @@ -1587,6 +1600,7 @@ static void zfcp_fsf_open_wka_port_handler(struct zfcp_fsf_req *req) wka_port->status = ZFCP_WKA_PORT_OFFLINE; break; case FSF_PORT_ALREADY_OPEN: + break; case FSF_GOOD: wka_port->handle = header->port_handle; wka_port->status = ZFCP_WKA_PORT_ONLINE; @@ -1904,7 +1918,7 @@ static void zfcp_fsf_open_unit_handler(struct zfcp_fsf_req *req) dev_err(&adapter->ccw_device->dev, "Shared read-write access not " "supported (unit 0x%016Lx, port " - "0x%016Lx\n)", + "0x%016Lx)\n", (unsigned long long)unit->fcp_lun, (unsigned long long)unit->port->wwpn); zfcp_erp_unit_failed(unit, 36, req); @@ -2116,18 +2130,21 @@ static inline void zfcp_fsf_trace_latency(struct zfcp_fsf_req *fsf_req) static void zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *req) { - struct scsi_cmnd *scpnt = req->data; + struct scsi_cmnd *scpnt; struct fcp_rsp_iu *fcp_rsp_iu = (struct fcp_rsp_iu *) &(req->qtcb->bottom.io.fcp_rsp); u32 sns_len; char *fcp_rsp_info = (unsigned char *) &fcp_rsp_iu[1]; unsigned long flags; - if (unlikely(!scpnt)) - return; - read_lock_irqsave(&req->adapter->abort_lock, flags); + scpnt = req->data; + if (unlikely(!scpnt)) { + read_unlock_irqrestore(&req->adapter->abort_lock, flags); + return; + } + if (unlikely(req->status & ZFCP_STATUS_FSFREQ_ABORTED)) { set_host_byte(scpnt, DID_SOFT_ERROR); set_driver_byte(scpnt, SUGGEST_RETRY); @@ -2445,8 +2462,10 @@ struct zfcp_fsf_req *zfcp_fsf_send_fcp_ctm(struct zfcp_adapter *adapter, goto out; req = zfcp_fsf_req_create(adapter, FSF_QTCB_FCP_CMND, req_flags, adapter->pool.fsf_req_scsi); - if (IS_ERR(req)) + if (IS_ERR(req)) { + req = NULL; goto out; + } req->status |= ZFCP_STATUS_FSFREQ_TASK_MANAGEMENT; req->data = unit; diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index fa2a3178061..8bb20025234 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -164,6 +164,7 @@ #define FSF_FEATURE_LUN_SHARING 0x00000004 #define FSF_FEATURE_NOTIFICATION_LOST 0x00000008 #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 +#define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 #define FSF_FEATURE_UPDATE_ALERT 0x00000100 #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 @@ -322,6 +323,7 @@ struct fsf_nport_serv_param { u8 vendor_version_level[16]; } __attribute__ ((packed)); +#define FSF_PLOGI_MIN_LEN 112 struct fsf_plogi { u32 code; struct fsf_nport_serv_param serv_param; diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 664752f90b2..33e0a206a0a 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" /* FIXME(tune): free space should be one max. SBAL chain plus what? */ @@ -109,7 +112,7 @@ static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, * corruption and must stop the machine immediatly. */ panic("error: unknown request id (%lx) on adapter %s.\n", - req_id, zfcp_get_busid_by_adapter(adapter)); + req_id, dev_name(&adapter->ccw_device->dev)); zfcp_reqlist_remove(adapter, fsf_req); spin_unlock_irqrestore(&adapter->req_list_lock, flags); @@ -389,7 +392,7 @@ int zfcp_qdio_allocate(struct zfcp_adapter *adapter) init_data->cdev = adapter->ccw_device; init_data->q_format = QDIO_ZFCP_QFMT; - memcpy(init_data->adapter_name, zfcp_get_busid_by_adapter(adapter), 8); + memcpy(init_data->adapter_name, dev_name(&adapter->ccw_device->dev), 8); ASCEBC(init_data->adapter_name, 8); init_data->qib_param_field_format = 0; init_data->qib_param_field = NULL; diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index ca8f85f3dad..9dc42a68fbd 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2002, 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" #include <asm/atomic.h> @@ -24,14 +27,10 @@ char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) static void zfcp_scsi_slave_destroy(struct scsi_device *sdpnt) { struct zfcp_unit *unit = (struct zfcp_unit *) sdpnt->hostdata; - WARN_ON(!unit); - if (unit) { - atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); - sdpnt->hostdata = NULL; - unit->device = NULL; - zfcp_erp_unit_failed(unit, 12, NULL); - zfcp_unit_put(unit); - } + atomic_clear_mask(ZFCP_STATUS_UNIT_REGISTERED, &unit->status); + unit->device = NULL; + zfcp_erp_unit_failed(unit, 12, NULL); + zfcp_unit_put(unit); } static int zfcp_scsi_slave_configure(struct scsi_device *sdp) @@ -92,7 +91,7 @@ static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, ret = zfcp_fsf_send_fcp_command_task(adapter, unit, scpnt, 0, ZFCP_REQ_AUTO_CLEANUP); if (unlikely(ret == -EBUSY)) - zfcp_scsi_command_fail(scpnt, DID_NO_CONNECT); + return SCSI_MLQUEUE_DEVICE_BUSY; else if (unlikely(ret < 0)) return SCSI_MLQUEUE_HOST_BUSY; diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index ca9293ba176..899af2b45b1 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -6,6 +6,9 @@ * Copyright IBM Corporation 2008 */ +#define KMSG_COMPONENT "zfcp" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + #include "zfcp_ext.h" #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index c3e4ab07b9c..0eea9078138 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c @@ -1,17 +1,21 @@ /* * drivers/s390/sysinfo.c * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) + * Copyright IBM Corp. 2001, 2008 + * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com) + * Martin Schwidefsky <schwidefsky@de.ibm.com> */ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/module.h> #include <asm/ebcdic.h> #include <asm/sysinfo.h> +#include <asm/cpcmd.h> /* Sigh, math-emu. Don't ask. */ #include <asm/sfp-util.h> @@ -271,6 +275,125 @@ static __init int create_proc_sysinfo(void) __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; |