diff --git a/[refs] b/[refs] index d23405586a7f..32159d44f841 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: b7f80afa28866c257876c272d6c013e0dbed3c31 +refs/heads/master: 4f9c16ccfa26691dbb9a5d9e7d5098eb934ccdbe diff --git a/trunk/Documentation/ABI/testing/sysfs-block b/trunk/Documentation/ABI/testing/sysfs-block index 44f52a4f5903..4bd9ea539129 100644 --- a/trunk/Documentation/ABI/testing/sysfs-block +++ b/trunk/Documentation/ABI/testing/sysfs-block @@ -26,37 +26,3 @@ Description: I/O statistics of partition . The format is the same as the above-written /sys/block//stat format. - - -What: /sys/block//integrity/format -Date: June 2008 -Contact: Martin K. Petersen -Description: - Metadata format for integrity capable block device. - E.g. T10-DIF-TYPE1-CRC. - - -What: /sys/block//integrity/read_verify -Date: June 2008 -Contact: Martin K. Petersen -Description: - Indicates whether the block layer should verify the - integrity of read requests serviced by devices that - support sending integrity metadata. - - -What: /sys/block//integrity/tag_size -Date: June 2008 -Contact: Martin K. Petersen -Description: - Number of bytes of integrity tag space available per - 512 bytes of data. - - -What: /sys/block//integrity/write_generate -Date: June 2008 -Contact: Martin K. Petersen -Description: - Indicates whether the block layer should automatically - generate checksums for write requests bound for - devices that support receiving integrity metadata. diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-css b/trunk/Documentation/ABI/testing/sysfs-bus-css deleted file mode 100644 index b585ec258a08..000000000000 --- a/trunk/Documentation/ABI/testing/sysfs-bus-css +++ /dev/null @@ -1,35 +0,0 @@ -What: /sys/bus/css/devices/.../type -Date: March 2008 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the subchannel type, as reported by the hardware. - This attribute is present for all subchannel types. - -What: /sys/bus/css/devices/.../modalias -Date: March 2008 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the module alias as reported with uevents. - It is of the format css:t and present for all - subchannel types. - -What: /sys/bus/css/drivers/io_subchannel/.../chpids -Date: December 2002 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the ids of the channel paths used by this - subchannel, as reported by the channel subsystem - during subchannel recognition. - Note: This is an I/O-subchannel specific attribute. -Users: s390-tools, HAL - -What: /sys/bus/css/drivers/io_subchannel/.../pimpampom -Date: December 2002 -Contact: Cornelia Huck - linux-s390@vger.kernel.org -Description: Contains the PIM/PAM/POM values, as reported by the - channel subsystem when last queried by the common I/O - layer (this implies that this attribute is not neccessarily - in sync with the values current in the channel subsystem). - Note: This is an I/O-subchannel specific attribute. -Users: s390-tools, HAL diff --git a/trunk/Documentation/block/data-integrity.txt b/trunk/Documentation/block/data-integrity.txt deleted file mode 100644 index e9dc8d86adc7..000000000000 --- a/trunk/Documentation/block/data-integrity.txt +++ /dev/null @@ -1,327 +0,0 @@ ----------------------------------------------------------------------- -1. INTRODUCTION - -Modern filesystems feature checksumming of data and metadata to -protect against data corruption. However, the detection of the -corruption is done at read time which could potentially be months -after the data was written. At that point the original data that the -application tried to write is most likely lost. - -The solution is to ensure that the disk is actually storing what the -application meant it to. Recent additions to both the SCSI family -protocols (SBC Data Integrity Field, SCC protection proposal) as well -as SATA/T13 (External Path Protection) try to remedy this by adding -support for appending integrity metadata to an I/O. The integrity -metadata (or protection information in SCSI terminology) includes a -checksum for each sector as well as an incrementing counter that -ensures the individual sectors are written in the right order. And -for some protection schemes also that the I/O is written to the right -place on disk. - -Current storage controllers and devices implement various protective -measures, for instance checksumming and scrubbing. But these -technologies are working in their own isolated domains or at best -between adjacent nodes in the I/O path. The interesting thing about -DIF and the other integrity extensions is that the protection format -is well defined and every node in the I/O path can verify the -integrity of the I/O and reject it if corruption is detected. This -allows not only corruption prevention but also isolation of the point -of failure. - ----------------------------------------------------------------------- -2. THE DATA INTEGRITY EXTENSIONS - -As written, the protocol extensions only protect the path between -controller and storage device. However, many controllers actually -allow the operating system to interact with the integrity metadata -(IMD). We have been working with several FC/SAS HBA vendors to enable -the protection information to be transferred to and from their -controllers. - -The SCSI Data Integrity Field works by appending 8 bytes of protection -information to each sector. The data + integrity metadata is stored -in 520 byte sectors on disk. Data + IMD are interleaved when -transferred between the controller and target. The T13 proposal is -similar. - -Because it is highly inconvenient for operating systems to deal with -520 (and 4104) byte sectors, we approached several HBA vendors and -encouraged them to allow separation of the data and integrity metadata -scatter-gather lists. - -The controller will interleave the buffers on write and split them on -read. This means that the Linux can DMA the data buffers to and from -host memory without changes to the page cache. - -Also, the 16-bit CRC checksum mandated by both the SCSI and SATA specs -is somewhat heavy to compute in software. Benchmarks found that -calculating this checksum had a significant impact on system -performance for a number of workloads. Some controllers allow a -lighter-weight checksum to be used when interfacing with the operating -system. Emulex, for instance, supports the TCP/IP checksum instead. -The IP checksum received from the OS is converted to the 16-bit CRC -when writing and vice versa. This allows the integrity metadata to be -generated by Linux or the application at very low cost (comparable to -software RAID5). - -The IP checksum is weaker than the CRC in terms of detecting bit -errors. However, the strength is really in the separation of the data -buffers and the integrity metadata. These two distinct buffers much -match up for an I/O to complete. - -The separation of the data and integrity metadata buffers as well as -the choice in checksums is referred to as the Data Integrity -Extensions. As these extensions are outside the scope of the protocol -bodies (T10, T13), Oracle and its partners are trying to standardize -them within the Storage Networking Industry Association. - ----------------------------------------------------------------------- -3. KERNEL CHANGES - -The data integrity framework in Linux enables protection information -to be pinned to I/Os and sent to/received from controllers that -support it. - -The advantage to the integrity extensions in SCSI and SATA is that -they enable us to protect the entire path from application to storage -device. However, at the same time this is also the biggest -disadvantage. It means that the protection information must be in a -format that can be understood by the disk. - -Generally Linux/POSIX applications are agnostic to the intricacies of -the storage devices they are accessing. The virtual filesystem switch -and the block layer make things like hardware sector size and -transport protocols completely transparent to the application. - -However, this level of detail is required when preparing the -protection information to send to a disk. Consequently, the very -concept of an end-to-end protection scheme is a layering violation. -It is completely unreasonable for an application to be aware whether -it is accessing a SCSI or SATA disk. - -The data integrity support implemented in Linux attempts to hide this -from the application. As far as the application (and to some extent -the kernel) is concerned, the integrity metadata is opaque information -that's attached to the I/O. - -The current implementation allows the block layer to automatically -generate the protection information for any I/O. Eventually the -intent is to move the integrity metadata calculation to userspace for -user data. Metadata and other I/O that originates within the kernel -will still use the automatic generation interface. - -Some storage devices allow each hardware sector to be tagged with a -16-bit value. The owner of this tag space is the owner of the block -device. I.e. the filesystem in most cases. The filesystem can use -this extra space to tag sectors as they see fit. Because the tag -space is limited, the block interface allows tagging bigger chunks by -way of interleaving. This way, 8*16 bits of information can be -attached to a typical 4KB filesystem block. - -This also means that applications such as fsck and mkfs will need -access to manipulate the tags from user space. A passthrough -interface for this is being worked on. - - ----------------------------------------------------------------------- -4. BLOCK LAYER IMPLEMENTATION DETAILS - -4.1 BIO - -The data integrity patches add a new field to struct bio when -CONFIG_BLK_DEV_INTEGRITY is enabled. bio->bi_integrity is a pointer -to a struct bip which contains the bio integrity payload. Essentially -a bip is a trimmed down struct bio which holds a bio_vec containing -the integrity metadata and the required housekeeping information (bvec -pool, vector count, etc.) - -A kernel subsystem can enable data integrity protection on a bio by -calling bio_integrity_alloc(bio). This will allocate and attach the -bip to the bio. - -Individual pages containing integrity metadata can subsequently be -attached using bio_integrity_add_page(). - -bio_free() will automatically free the bip. - - -4.2 BLOCK DEVICE - -Because the format of the protection data is tied to the physical -disk, each block device has been extended with a block integrity -profile (struct blk_integrity). This optional profile is registered -with the block layer using blk_integrity_register(). - -The profile contains callback functions for generating and verifying -the protection data, as well as getting and setting application tags. -The profile also contains a few constants to aid in completing, -merging and splitting the integrity metadata. - -Layered block devices will need to pick a profile that's appropriate -for all subdevices. blk_integrity_compare() can help with that. DM -and MD linear, RAID0 and RAID1 are currently supported. RAID4/5/6 -will require extra work due to the application tag. - - ----------------------------------------------------------------------- -5.0 BLOCK LAYER INTEGRITY API - -5.1 NORMAL FILESYSTEM - - The normal filesystem is unaware that the underlying block device - is capable of sending/receiving integrity metadata. The IMD will - be automatically generated by the block layer at submit_bio() time - in case of a WRITE. A READ request will cause the I/O integrity - to be verified upon completion. - - IMD generation and verification can be toggled using the - - /sys/block//integrity/write_generate - - and - - /sys/block//integrity/read_verify - - flags. - - -5.2 INTEGRITY-AWARE FILESYSTEM - - A filesystem that is integrity-aware can prepare I/Os with IMD - attached. It can also use the application tag space if this is - supported by the block device. - - - int bdev_integrity_enabled(block_device, int rw); - - bdev_integrity_enabled() will return 1 if the block device - supports integrity metadata transfer for the data direction - specified in 'rw'. - - bdev_integrity_enabled() honors the write_generate and - read_verify flags in sysfs and will respond accordingly. - - - int bio_integrity_prep(bio); - - To generate IMD for WRITE and to set up buffers for READ, the - filesystem must call bio_integrity_prep(bio). - - Prior to calling this function, the bio data direction and start - sector must be set, and the bio should have all data pages - added. It is up to the caller to ensure that the bio does not - change while I/O is in progress. - - bio_integrity_prep() should only be called if - bio_integrity_enabled() returned 1. - - - int bio_integrity_tag_size(bio); - - If the filesystem wants to use the application tag space it will - first have to find out how much storage space is available. - Because tag space is generally limited (usually 2 bytes per - sector regardless of sector size), the integrity framework - supports interleaving the information between the sectors in an - I/O. - - Filesystems can call bio_integrity_tag_size(bio) to find out how - many bytes of storage are available for that particular bio. - - Another option is bdev_get_tag_size(block_device) which will - return the number of available bytes per hardware sector. - - - int bio_integrity_set_tag(bio, void *tag_buf, len); - - After a successful return from bio_integrity_prep(), - bio_integrity_set_tag() can be used to attach an opaque tag - buffer to a bio. Obviously this only makes sense if the I/O is - a WRITE. - - - int bio_integrity_get_tag(bio, void *tag_buf, len); - - Similarly, at READ I/O completion time the filesystem can - retrieve the tag buffer using bio_integrity_get_tag(). - - -6.3 PASSING EXISTING INTEGRITY METADATA - - Filesystems that either generate their own integrity metadata or - are capable of transferring IMD from user space can use the - following calls: - - - struct bip * bio_integrity_alloc(bio, gfp_mask, nr_pages); - - Allocates the bio integrity payload and hangs it off of the bio. - nr_pages indicate how many pages of protection data need to be - stored in the integrity bio_vec list (similar to bio_alloc()). - - The integrity payload will be freed at bio_free() time. - - - int bio_integrity_add_page(bio, page, len, offset); - - Attaches a page containing integrity metadata to an existing - bio. The bio must have an existing bip, - i.e. bio_integrity_alloc() must have been called. For a WRITE, - the integrity metadata in the pages must be in a format - understood by the target device with the notable exception that - the sector numbers will be remapped as the request traverses the - I/O stack. This implies that the pages added using this call - will be modified during I/O! The first reference tag in the - integrity metadata must have a value of bip->bip_sector. - - Pages can be added using bio_integrity_add_page() as long as - there is room in the bip bio_vec array (nr_pages). - - Upon completion of a READ operation, the attached pages will - contain the integrity metadata received from the storage device. - It is up to the receiver to process them and verify data - integrity upon completion. - - -6.4 REGISTERING A BLOCK DEVICE AS CAPABLE OF EXCHANGING INTEGRITY - METADATA - - To enable integrity exchange on a block device the gendisk must be - registered as capable: - - int blk_integrity_register(gendisk, blk_integrity); - - The blk_integrity struct is a template and should contain the - following: - - static struct blk_integrity my_profile = { - .name = "STANDARDSBODY-TYPE-VARIANT-CSUM", - .generate_fn = my_generate_fn, - .verify_fn = my_verify_fn, - .get_tag_fn = my_get_tag_fn, - .set_tag_fn = my_set_tag_fn, - .tuple_size = sizeof(struct my_tuple_size), - .tag_size = , - }; - - 'name' is a text string which will be visible in sysfs. This is - part of the userland API so chose it carefully and never change - it. The format is standards body-type-variant. - E.g. T10-DIF-TYPE1-IP or T13-EPP-0-CRC. - - 'generate_fn' generates appropriate integrity metadata (for WRITE). - - 'verify_fn' verifies that the data buffer matches the integrity - metadata. - - 'tuple_size' must be set to match the size of the integrity - metadata per sector. I.e. 8 for DIF and EPP. - - 'tag_size' must be set to identify how many bytes of tag space - are available per hardware sector. For DIF this is either 2 or - 0 depending on the value of the Control Mode Page ATO bit. - - See 6.2 for a description of get_tag_fn and set_tag_fn. - ----------------------------------------------------------------------- -2007-12-24 Martin K. Petersen diff --git a/trunk/Documentation/ioctl-number.txt b/trunk/Documentation/ioctl-number.txt index 3bb5f466a90d..240ce7a56c40 100644 --- a/trunk/Documentation/ioctl-number.txt +++ b/trunk/Documentation/ioctl-number.txt @@ -117,7 +117,6 @@ Code Seq# Include File Comments 'c' 00-7F linux/comstats.h conflict! 'c' 00-7F linux/coda.h conflict! -'c' 80-9F asm-s390/chsc.h 'd' 00-FF linux/char/drm/drm/h conflict! 'd' 00-DF linux/video_decoder.h conflict! 'd' F0-FF linux/digi1.h diff --git a/trunk/arch/s390/Kconfig b/trunk/arch/s390/Kconfig index 5dc8f8028d52..107e492cb47e 100644 --- a/trunk/arch/s390/Kconfig +++ b/trunk/arch/s390/Kconfig @@ -146,7 +146,6 @@ config MATHEMU config COMPAT bool "Kernel support for 31 bit emulation" depends on 64BIT - select COMPAT_BINFMT_ELF help Select this option if you want to enable your system kernel to handle system-calls from ELF binaries for 31 bit ESA. This option @@ -313,10 +312,6 @@ config ARCH_SPARSEMEM_DEFAULT config ARCH_SELECT_MEMORY_MODEL def_bool y -config ARCH_ENABLE_MEMORY_HOTPLUG - def_bool y - depends on SPARSEMEM - source "mm/Kconfig" comment "I/O subsystem configuration" @@ -349,22 +344,6 @@ config QDIO_DEBUG If unsure, say N. -config CHSC_SCH - tristate "Support for CHSC subchannels" - help - This driver allows usage of CHSC subchannels. A CHSC subchannel - is usually present on LPAR only. - The driver creates a device /dev/chsc, which may be used to - obtain I/O configuration information about the machine and - to issue asynchronous chsc commands (DANGEROUS). - You will usually only want to use this interface on a special - LPAR designated for system management. - - To compile this driver as a module, choose M here: the - module will be called chsc_sch. - - If unsure, say N. - comment "Misc" config IPL diff --git a/trunk/arch/s390/appldata/appldata.h b/trunk/arch/s390/appldata/appldata.h index 17a2636fec0a..db3ae8505103 100644 --- a/trunk/arch/s390/appldata/appldata.h +++ b/trunk/arch/s390/appldata/appldata.h @@ -3,11 +3,13 @@ * * Definitions and interface for Linux - z/VM Monitor Stream. * - * Copyright IBM Corp. 2003, 2008 + * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer */ +//#define APPLDATA_DEBUG /* Debug messages on/off */ + #define APPLDATA_MAX_REC_SIZE 4024 /* Maximum size of the */ /* data buffer */ #define APPLDATA_MAX_PROCS 100 @@ -30,6 +32,12 @@ #define P_ERROR(x...) printk(KERN_ERR MY_PRINT_NAME " error: " x) #define P_WARNING(x...) printk(KERN_WARNING MY_PRINT_NAME " status: " x) +#ifdef APPLDATA_DEBUG +#define P_DEBUG(x...) printk(KERN_DEBUG MY_PRINT_NAME " debug: " x) +#else +#define P_DEBUG(x...) do {} while (0) +#endif + struct appldata_ops { struct list_head list; struct ctl_table_header *sysctl_header; diff --git a/trunk/arch/s390/appldata/appldata_base.c b/trunk/arch/s390/appldata/appldata_base.c index 9cb3d92447a3..ad40729bec3d 100644 --- a/trunk/arch/s390/appldata/appldata_base.c +++ b/trunk/arch/s390/appldata/appldata_base.c @@ -5,7 +5,7 @@ * Exports appldata_register_ops() and appldata_unregister_ops() for the * data gathering modules. * - * Copyright IBM Corp. 2003, 2008 + * Copyright (C) 2003,2006 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer */ @@ -108,6 +108,9 @@ static LIST_HEAD(appldata_ops_list); */ static void appldata_timer_function(unsigned long data) { + P_DEBUG(" -= Timer =-\n"); + P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(), + atomic_read(&appldata_expire_count)); if (atomic_dec_and_test(&appldata_expire_count)) { atomic_set(&appldata_expire_count, num_online_cpus()); queue_work(appldata_wq, (struct work_struct *) data); @@ -125,11 +128,14 @@ static void appldata_work_fn(struct work_struct *work) struct appldata_ops *ops; int i; + P_DEBUG(" -= Work Queue =-\n"); i = 0; get_online_cpus(); spin_lock(&appldata_ops_lock); list_for_each(lh, &appldata_ops_list) { ops = list_entry(lh, struct appldata_ops, list); + P_DEBUG("list_for_each loop: %i) active = %u, name = %s\n", + ++i, ops->active, ops->name); if (ops->active == 1) { ops->callback(ops->data); } @@ -206,6 +212,7 @@ __appldata_vtimer_setup(int cmd) 0, 1); } appldata_timer_active = 1; + P_INFO("Monitoring timer started.\n"); break; case APPLDATA_DEL_TIMER: for_each_online_cpu(i) @@ -214,6 +221,7 @@ __appldata_vtimer_setup(int cmd) break; appldata_timer_active = 0; atomic_set(&appldata_expire_count, num_online_cpus()); + P_INFO("Monitoring timer stopped.\n"); break; case APPLDATA_MOD_TIMER: per_cpu_interval = (u64) (appldata_interval*1000 / @@ -305,8 +313,10 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, } interval = 0; sscanf(buf, "%i", &interval); - if (interval <= 0) + if (interval <= 0) { + P_ERROR("Timer CPU interval has to be > 0!\n"); return -EINVAL; + } get_online_cpus(); spin_lock(&appldata_timer_lock); @@ -314,6 +324,9 @@ appldata_interval_handler(ctl_table *ctl, int write, struct file *filp, __appldata_vtimer_setup(APPLDATA_MOD_TIMER); spin_unlock(&appldata_timer_lock); put_online_cpus(); + + P_INFO("Monitoring CPU interval set to %u milliseconds.\n", + interval); out: *lenp = len; *ppos += len; @@ -393,16 +406,23 @@ appldata_generic_handler(ctl_table *ctl, int write, struct file *filp, P_ERROR("START DIAG 0xDC for %s failed, " "return code: %d\n", ops->name, rc); module_put(ops->owner); - } else + } else { + P_INFO("Monitoring %s data enabled, " + "DIAG 0xDC started.\n", ops->name); ops->active = 1; + } } else if ((buf[0] == '0') && (ops->active == 1)) { ops->active = 0; rc = appldata_diag(ops->record_nr, APPLDATA_STOP_REC, (unsigned long) ops->data, ops->size, ops->mod_lvl); - if (rc != 0) + if (rc != 0) { P_ERROR("STOP DIAG 0xDC for %s failed, " "return code: %d\n", ops->name, rc); + } else { + P_INFO("Monitoring %s data disabled, " + "DIAG 0xDC stopped.\n", ops->name); + } module_put(ops->owner); } spin_unlock(&appldata_ops_lock); @@ -448,6 +468,7 @@ int appldata_register_ops(struct appldata_ops *ops) ops->sysctl_header = register_sysctl_table(ops->ctl_table); if (!ops->sysctl_header) goto out; + P_INFO("%s-ops registered!\n", ops->name); return 0; out: spin_lock(&appldata_ops_lock); @@ -469,6 +490,7 @@ void appldata_unregister_ops(struct appldata_ops *ops) spin_unlock(&appldata_ops_lock); unregister_sysctl_table(ops->sysctl_header); kfree(ops->ctl_table); + P_INFO("%s-ops unregistered!\n", ops->name); } /********************** module-ops management **************************/ @@ -531,9 +553,14 @@ static int __init appldata_init(void) { int i; + P_DEBUG("sizeof(parameter_list) = %lu\n", + sizeof(struct appldata_parameter_list)); + appldata_wq = create_singlethread_workqueue("appldata"); - if (!appldata_wq) + if (!appldata_wq) { + P_ERROR("Could not create work queue\n"); return -ENOMEM; + } get_online_cpus(); for_each_online_cpu(i) @@ -544,6 +571,8 @@ static int __init appldata_init(void) register_hotcpu_notifier(&appldata_nb); appldata_sysctl_header = register_sysctl_table(appldata_dir_table); + + P_DEBUG("Base interface initialized.\n"); return 0; } @@ -555,9 +584,7 @@ EXPORT_SYMBOL_GPL(appldata_register_ops); EXPORT_SYMBOL_GPL(appldata_unregister_ops); EXPORT_SYMBOL_GPL(appldata_diag); -#ifdef CONFIG_SWAP EXPORT_SYMBOL_GPL(si_swapinfo); -#endif EXPORT_SYMBOL_GPL(nr_threads); EXPORT_SYMBOL_GPL(nr_running); EXPORT_SYMBOL_GPL(nr_iowait); diff --git a/trunk/arch/s390/appldata/appldata_mem.c b/trunk/arch/s390/appldata/appldata_mem.c index 3ed56b7d1b2f..51181ccdb87b 100644 --- a/trunk/arch/s390/appldata/appldata_mem.c +++ b/trunk/arch/s390/appldata/appldata_mem.c @@ -14,13 +14,14 @@ #include #include #include +#include #include #include -#include #include "appldata.h" +#define MY_PRINT_NAME "appldata_mem" /* for debug messages, etc. */ #define P2K(x) ((x) << (PAGE_SHIFT - 10)) /* Converts #Pages to KB */ /* @@ -69,6 +70,30 @@ static struct appldata_mem_data { } __attribute__((packed)) appldata_mem_data; +static inline void appldata_debug_print(struct appldata_mem_data *mem_data) +{ + P_DEBUG("--- MEM - RECORD ---\n"); + P_DEBUG("pgpgin = %8lu KB\n", mem_data->pgpgin); + P_DEBUG("pgpgout = %8lu KB\n", mem_data->pgpgout); + P_DEBUG("pswpin = %8lu Pages\n", mem_data->pswpin); + P_DEBUG("pswpout = %8lu Pages\n", mem_data->pswpout); + P_DEBUG("pgalloc = %8lu \n", mem_data->pgalloc); + P_DEBUG("pgfault = %8lu \n", mem_data->pgfault); + P_DEBUG("pgmajfault = %8lu \n", mem_data->pgmajfault); + P_DEBUG("sharedram = %8lu KB\n", mem_data->sharedram); + P_DEBUG("totalram = %8lu KB\n", mem_data->totalram); + P_DEBUG("freeram = %8lu KB\n", mem_data->freeram); + P_DEBUG("totalhigh = %8lu KB\n", mem_data->totalhigh); + P_DEBUG("freehigh = %8lu KB\n", mem_data->freehigh); + P_DEBUG("bufferram = %8lu KB\n", mem_data->bufferram); + P_DEBUG("cached = %8lu KB\n", mem_data->cached); + P_DEBUG("totalswap = %8lu KB\n", mem_data->totalswap); + P_DEBUG("freeswap = %8lu KB\n", mem_data->freeswap); + P_DEBUG("sync_count_1 = %u\n", mem_data->sync_count_1); + P_DEBUG("sync_count_2 = %u\n", mem_data->sync_count_2); + P_DEBUG("timestamp = %lX\n", mem_data->timestamp); +} + /* * appldata_get_mem_data() * @@ -115,6 +140,9 @@ static void appldata_get_mem_data(void *data) mem_data->timestamp = get_clock(); mem_data->sync_count_2++; +#ifdef APPLDATA_DEBUG + appldata_debug_print(mem_data); +#endif } @@ -136,7 +164,17 @@ static struct appldata_ops ops = { */ static int __init appldata_mem_init(void) { - return appldata_register_ops(&ops); + int rc; + + P_DEBUG("sizeof(mem) = %lu\n", sizeof(struct appldata_mem_data)); + + rc = appldata_register_ops(&ops); + if (rc != 0) { + P_ERROR("Error registering ops, rc = %i\n", rc); + } else { + P_DEBUG("%s-ops registered!\n", ops.name); + } + return rc; } /* @@ -147,6 +185,7 @@ static int __init appldata_mem_init(void) static void __exit appldata_mem_exit(void) { appldata_unregister_ops(&ops); + P_DEBUG("%s-ops unregistered!\n", ops.name); } diff --git a/trunk/arch/s390/appldata/appldata_net_sum.c b/trunk/arch/s390/appldata/appldata_net_sum.c index 3b746556e1a3..4d8344336001 100644 --- a/trunk/arch/s390/appldata/appldata_net_sum.c +++ b/trunk/arch/s390/appldata/appldata_net_sum.c @@ -21,6 +21,9 @@ #include "appldata.h" +#define MY_PRINT_NAME "appldata_net_sum" /* for debug messages, etc. */ + + /* * Network data * @@ -57,6 +60,26 @@ static struct appldata_net_sum_data { } __attribute__((packed)) appldata_net_sum_data; +static inline void appldata_print_debug(struct appldata_net_sum_data *net_data) +{ + P_DEBUG("--- NET - RECORD ---\n"); + + P_DEBUG("nr_interfaces = %u\n", net_data->nr_interfaces); + P_DEBUG("rx_packets = %8lu\n", net_data->rx_packets); + P_DEBUG("tx_packets = %8lu\n", net_data->tx_packets); + P_DEBUG("rx_bytes = %8lu\n", net_data->rx_bytes); + P_DEBUG("tx_bytes = %8lu\n", net_data->tx_bytes); + P_DEBUG("rx_errors = %8lu\n", net_data->rx_errors); + P_DEBUG("tx_errors = %8lu\n", net_data->tx_errors); + P_DEBUG("rx_dropped = %8lu\n", net_data->rx_dropped); + P_DEBUG("tx_dropped = %8lu\n", net_data->tx_dropped); + P_DEBUG("collisions = %8lu\n", net_data->collisions); + + P_DEBUG("sync_count_1 = %u\n", net_data->sync_count_1); + P_DEBUG("sync_count_2 = %u\n", net_data->sync_count_2); + P_DEBUG("timestamp = %lX\n", net_data->timestamp); +} + /* * appldata_get_net_sum_data() * @@ -112,6 +135,9 @@ static void appldata_get_net_sum_data(void *data) net_data->timestamp = get_clock(); net_data->sync_count_2++; +#ifdef APPLDATA_DEBUG + appldata_print_debug(net_data); +#endif } @@ -133,7 +159,17 @@ static struct appldata_ops ops = { */ static int __init appldata_net_init(void) { - return appldata_register_ops(&ops); + int rc; + + P_DEBUG("sizeof(net) = %lu\n", sizeof(struct appldata_net_sum_data)); + + rc = appldata_register_ops(&ops); + if (rc != 0) { + P_ERROR("Error registering ops, rc = %i\n", rc); + } else { + P_DEBUG("%s-ops registered!\n", ops.name); + } + return rc; } /* @@ -144,6 +180,7 @@ static int __init appldata_net_init(void) static void __exit appldata_net_exit(void) { appldata_unregister_ops(&ops); + P_DEBUG("%s-ops unregistered!\n", ops.name); } diff --git a/trunk/arch/s390/appldata/appldata_os.c b/trunk/arch/s390/appldata/appldata_os.c index eb44f9f8ab91..6b3eafe10453 100644 --- a/trunk/arch/s390/appldata/appldata_os.c +++ b/trunk/arch/s390/appldata/appldata_os.c @@ -89,6 +89,44 @@ static struct appldata_ops ops = { }; +static inline void appldata_print_debug(struct appldata_os_data *os_data) +{ + int a0, a1, a2, i; + + P_DEBUG("--- OS - RECORD ---\n"); + P_DEBUG("nr_threads = %u\n", os_data->nr_threads); + P_DEBUG("nr_running = %u\n", os_data->nr_running); + P_DEBUG("nr_iowait = %u\n", os_data->nr_iowait); + P_DEBUG("avenrun(int) = %8x / %8x / %8x\n", os_data->avenrun[0], + os_data->avenrun[1], os_data->avenrun[2]); + a0 = os_data->avenrun[0]; + a1 = os_data->avenrun[1]; + a2 = os_data->avenrun[2]; + P_DEBUG("avenrun(float) = %d.%02d / %d.%02d / %d.%02d\n", + LOAD_INT(a0), LOAD_FRAC(a0), LOAD_INT(a1), LOAD_FRAC(a1), + LOAD_INT(a2), LOAD_FRAC(a2)); + + P_DEBUG("nr_cpus = %u\n", os_data->nr_cpus); + for (i = 0; i < os_data->nr_cpus; i++) { + P_DEBUG("cpu%u : user = %u, nice = %u, system = %u, " + "idle = %u, irq = %u, softirq = %u, iowait = %u, " + "steal = %u\n", + os_data->os_cpu[i].cpu_id, + os_data->os_cpu[i].per_cpu_user, + os_data->os_cpu[i].per_cpu_nice, + os_data->os_cpu[i].per_cpu_system, + os_data->os_cpu[i].per_cpu_idle, + os_data->os_cpu[i].per_cpu_irq, + os_data->os_cpu[i].per_cpu_softirq, + os_data->os_cpu[i].per_cpu_iowait, + os_data->os_cpu[i].per_cpu_steal); + } + + P_DEBUG("sync_count_1 = %u\n", os_data->sync_count_1); + P_DEBUG("sync_count_2 = %u\n", os_data->sync_count_2); + P_DEBUG("timestamp = %lX\n", os_data->timestamp); +} + /* * appldata_get_os_data() * @@ -142,10 +180,13 @@ static void appldata_get_os_data(void *data) APPLDATA_START_INTERVAL_REC, (unsigned long) ops.data, new_size, ops.mod_lvl); - if (rc != 0) + if (rc != 0) { P_ERROR("os: START NEW DIAG 0xDC failed, " "return code: %d, new size = %i\n", rc, new_size); + P_INFO("os: stopping old record now\n"); + } else + P_INFO("os: new record size = %i\n", new_size); rc = appldata_diag(APPLDATA_RECORD_OS_ID, APPLDATA_STOP_REC, @@ -163,6 +204,9 @@ static void appldata_get_os_data(void *data) } os_data->timestamp = get_clock(); os_data->sync_count_2++; +#ifdef APPLDATA_DEBUG + appldata_print_debug(os_data); +#endif } @@ -183,9 +227,12 @@ static int __init appldata_os_init(void) rc = -ENOMEM; goto out; } + P_DEBUG("max. sizeof(os) = %i, sizeof(os_cpu) = %lu\n", max_size, + sizeof(struct appldata_os_per_cpu)); appldata_os_data = kzalloc(max_size, GFP_DMA); if (appldata_os_data == NULL) { + P_ERROR("No memory for %s!\n", ops.name); rc = -ENOMEM; goto out; } @@ -193,12 +240,17 @@ static int __init appldata_os_init(void) appldata_os_data->per_cpu_size = sizeof(struct appldata_os_per_cpu); appldata_os_data->cpu_offset = offsetof(struct appldata_os_data, os_cpu); + P_DEBUG("cpu offset = %u\n", appldata_os_data->cpu_offset); ops.data = appldata_os_data; ops.callback = &appldata_get_os_data; rc = appldata_register_ops(&ops); - if (rc != 0) + if (rc != 0) { + P_ERROR("Error registering ops, rc = %i\n", rc); kfree(appldata_os_data); + } else { + P_DEBUG("%s-ops registered!\n", ops.name); + } out: return rc; } @@ -212,6 +264,7 @@ static void __exit appldata_os_exit(void) { appldata_unregister_ops(&ops); kfree(appldata_os_data); + P_DEBUG("%s-ops unregistered!\n", ops.name); } diff --git a/trunk/arch/s390/crypto/prng.c b/trunk/arch/s390/crypto/prng.c index 6a4300b3ff52..0cfefddd8375 100644 --- a/trunk/arch/s390/crypto/prng.c +++ b/trunk/arch/s390/crypto/prng.c @@ -185,8 +185,11 @@ static int __init prng_init(void) prng_seed(16); ret = misc_register(&prng_dev); - if (ret) + if (ret) { + printk(KERN_WARNING + "Could not register misc device for PRNG.\n"); goto out_buf; + } return 0; out_buf: diff --git a/trunk/arch/s390/hypfs/inode.c b/trunk/arch/s390/hypfs/inode.c index 7383781f3e6a..4b010ff814c9 100644 --- a/trunk/arch/s390/hypfs/inode.c +++ b/trunk/arch/s390/hypfs/inode.c @@ -150,24 +150,33 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t offset) { char *data; - ssize_t ret; + size_t len; struct file *filp = iocb->ki_filp; /* XXX: temporary */ char __user *buf = iov[0].iov_base; size_t count = iov[0].iov_len; - if (nr_segs != 1) - return -EINVAL; + if (nr_segs != 1) { + count = -EINVAL; + goto out; + } data = filp->private_data; - ret = simple_read_from_buffer(buf, count, &offset, data, strlen(data)); - if (ret <= 0) - return ret; - - iocb->ki_pos += ret; + len = strlen(data); + if (offset > len) { + count = 0; + goto out; + } + if (count > len - offset) + count = len - offset; + if (copy_to_user(buf, data + offset, count)) { + count = -EFAULT; + goto out; + } + iocb->ki_pos += count; file_accessed(filp); - - return ret; +out: + return count; } static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t offset) diff --git a/trunk/arch/s390/kernel/Makefile b/trunk/arch/s390/kernel/Makefile index 50f657e77344..6302f5082588 100644 --- a/trunk/arch/s390/kernel/Makefile +++ b/trunk/arch/s390/kernel/Makefile @@ -7,14 +7,9 @@ # CFLAGS_smp.o := -Wno-nonnull -# -# Pass UTS_MACHINE for user_regset definition -# -CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' - obj-y := bitmap.o traps.o time.o process.o base.o early.o \ setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ - s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o + s390_ext.o debug.o irq.o ipl.o dis.o diag.o obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) @@ -28,7 +23,7 @@ obj-$(CONFIG_AUDIT) += audit.o compat-obj-$(CONFIG_AUDIT) += compat_audit.o obj-$(CONFIG_COMPAT) += compat_linux.o compat_signal.o \ compat_wrapper.o compat_exec_domain.o \ - $(compat-obj-y) + binfmt_elf32.o $(compat-obj-y) obj-$(CONFIG_VIRT_TIMER) += vtime.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/trunk/arch/s390/kernel/binfmt_elf32.c b/trunk/arch/s390/kernel/binfmt_elf32.c new file mode 100644 index 000000000000..3e1c315b736d --- /dev/null +++ b/trunk/arch/s390/kernel/binfmt_elf32.c @@ -0,0 +1,214 @@ +/* + * Support for 32-bit Linux for S390 ELF binaries. + * + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Gerhard Tonn (ton@de.ibm.com) + * + * Heavily inspired by the 32-bit Sparc compat code which is + * Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com) + * Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz) + */ + +#define __ASMS390_ELF_H + +#include + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_S390 + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) \ + (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ + && (x)->e_ident[EI_CLASS] == ELF_CLASS) + +/* ELF register definitions */ +#define NUM_GPRS 16 +#define NUM_FPRS 16 +#define NUM_ACRS 16 + +/* For SVR4/S390 the function pointer to be registered with `atexit` is + passed in R14. */ +#define ELF_PLAT_INIT(_r, load_addr) \ + do { \ + _r->gprs[14] = 0; \ + } while(0) + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) + +/* Wow, the "main" arch needs arch dependent functions too.. :) */ + +/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is + now struct_user_regs, they are different) */ + +#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs32(regs, &pr_reg); + +#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs32(tsk, regs) + +#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs) + +/* This yields a mask that user programs can use to figure out what + instruction set this CPU supports. */ + +#define ELF_HWCAP (0) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. + + For the moment, we have only optimizations for the Intel generations, + but that could change... */ + +#define ELF_PLATFORM (NULL) + +#define SET_PERSONALITY(ex, ibcs2) \ +do { \ + if (ibcs2) \ + set_personality(PER_SVR4); \ + else if (current->personality != PER_LINUX32) \ + set_personality(PER_LINUX); \ + set_thread_flag(TIF_31BIT); \ +} while (0) + +#include "compat_linux.h" + +typedef _s390_fp_regs32 elf_fpregset_t; + +typedef struct +{ + + _psw_t32 psw; + __u32 gprs[__NUM_GPRS]; + __u32 acrs[__NUM_ACRS]; + __u32 orig_gpr2; +} s390_regs32; +typedef s390_regs32 elf_gregset_t; + +static inline int dump_regs32(struct pt_regs *ptregs, elf_gregset_t *regs) +{ + int i; + + memcpy(®s->psw.mask, &ptregs->psw.mask, 4); + memcpy(®s->psw.addr, (char *)&ptregs->psw.addr + 4, 4); + for (i = 0; i < NUM_GPRS; i++) + regs->gprs[i] = ptregs->gprs[i]; + save_access_regs(regs->acrs); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +static inline int dump_task_regs32(struct task_struct *tsk, elf_gregset_t *regs) +{ + struct pt_regs *ptregs = task_pt_regs(tsk); + int i; + + memcpy(®s->psw.mask, &ptregs->psw.mask, 4); + memcpy(®s->psw.addr, (char *)&ptregs->psw.addr + 4, 4); + for (i = 0; i < NUM_GPRS; i++) + regs->gprs[i] = ptregs->gprs[i]; + memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs)); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +{ + if (tsk == current) + save_fp_regs((s390_fp_regs *) fpregs); + else + memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t)); + return 1; +} + +#include +#include +#include +#include +#include +#include + +#define elf_prstatus elf_prstatus32 +struct elf_prstatus32 +{ + struct elf_siginfo pr_info; /* Info associated with signal */ + short pr_cursig; /* Current signal */ + u32 pr_sigpend; /* Set of pending signals */ + u32 pr_sighold; /* Set of held signals */ + pid_t pr_pid; + pid_t pr_ppid; + pid_t pr_pgrp; + pid_t pr_sid; + struct compat_timeval pr_utime; /* User time */ + struct compat_timeval pr_stime; /* System time */ + struct compat_timeval pr_cutime; /* Cumulative user time */ + struct compat_timeval pr_cstime; /* Cumulative system time */ + elf_gregset_t pr_reg; /* GP registers */ + int pr_fpvalid; /* True if math co-processor being used. */ +}; + +#define elf_prpsinfo elf_prpsinfo32 +struct elf_prpsinfo32 +{ + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + u32 pr_flag; /* flags */ + u16 pr_uid; + u16 pr_gid; + pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; + +#include + +/* +#define init_elf_binfmt init_elf32_binfmt +*/ + +#undef start_thread +#define start_thread start_thread31 + +static inline void start_thread31(struct pt_regs *regs, unsigned long new_psw, + unsigned long new_stackp) +{ + set_fs(USER_DS); + regs->psw.mask = psw_user32_bits; + regs->psw.addr = new_psw; + regs->gprs[15] = new_stackp; + crst_table_downgrade(current->mm, 1UL << 31); +} + +MODULE_DESCRIPTION("Binary format loader for compatibility with 32bit Linux for S390 binaries," + " Copyright 2000 IBM Corporation"); +MODULE_AUTHOR("Gerhard Tonn "); + +#undef MODULE_DESCRIPTION +#undef MODULE_AUTHOR + +#undef cputime_to_timeval +#define cputime_to_timeval cputime_to_compat_timeval +static inline void +cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) +{ + value->tv_usec = cputime % 1000000; + value->tv_sec = cputime / 1000000; +} + +#include "../../../fs/binfmt_elf.c" + diff --git a/trunk/arch/s390/kernel/compat_ptrace.h b/trunk/arch/s390/kernel/compat_ptrace.h index cde81fa64f89..419aef913ee1 100644 --- a/trunk/arch/s390/kernel/compat_ptrace.h +++ b/trunk/arch/s390/kernel/compat_ptrace.h @@ -1,7 +1,7 @@ #ifndef _PTRACE32_H #define _PTRACE32_H -#include "compat_linux.h" /* needed for psw_compat_t */ +#include "compat_linux.h" /* needed for _psw_t32 */ typedef struct { __u32 cr[3]; @@ -38,7 +38,7 @@ typedef struct { struct user_regs_struct32 { - psw_compat_t psw; + _psw_t32 psw; u32 gprs[NUM_GPRS]; u32 acrs[NUM_ACRS]; u32 orig_gpr2; diff --git a/trunk/arch/s390/kernel/debug.c b/trunk/arch/s390/kernel/debug.c index d80fcd4a7fe1..c93d1296cc0a 100644 --- a/trunk/arch/s390/kernel/debug.c +++ b/trunk/arch/s390/kernel/debug.c @@ -1079,6 +1079,7 @@ __init debug_init(void) s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table); mutex_lock(&debug_mutex); debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL); + printk(KERN_INFO "debug: Initialization complete\n"); initialized = 1; mutex_unlock(&debug_mutex); @@ -1192,6 +1193,7 @@ debug_get_uint(char *buf) for(; isspace(*buf); buf++); rc = simple_strtoul(buf, &buf, 10); if(*buf){ + printk("debug: no integer specified!\n"); rc = -EINVAL; } return rc; @@ -1338,12 +1340,19 @@ static void debug_flush(debug_info_t* id, int area) memset(id->areas[i][j], 0, PAGE_SIZE); } } + printk(KERN_INFO "debug: %s: all areas flushed\n",id->name); } else if(area >= 0 && area < id->nr_areas) { id->active_entries[area] = 0; id->active_pages[area] = 0; for(i = 0; i < id->pages_per_area; i++) { memset(id->areas[area][i],0,PAGE_SIZE); } + printk(KERN_INFO "debug: %s: area %i has been flushed\n", + id->name, area); + } else { + printk(KERN_INFO + "debug: %s: area %i cannot be flushed (range: %i - %i)\n", + id->name, area, 0, id->nr_areas-1); } spin_unlock_irqrestore(&id->lock,flags); } diff --git a/trunk/arch/s390/kernel/early.c b/trunk/arch/s390/kernel/early.c index 2a2ca268b1dd..d0e09684b9ce 100644 --- a/trunk/arch/s390/kernel/early.c +++ b/trunk/arch/s390/kernel/early.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -27,40 +26,12 @@ /* * Create a Kernel NSS if the SAVESYS= parameter is defined */ -#define DEFSYS_CMD_SIZE 128 +#define DEFSYS_CMD_SIZE 96 #define SAVESYS_CMD_SIZE 32 char kernel_nss_name[NSS_NAME_SIZE + 1]; -static void __init setup_boot_command_line(void); - - #ifdef CONFIG_SHARED_KERNEL -int __init savesys_ipl_nss(char *cmd, const int cmdlen); - -asm( - " .section .init.text,\"ax\",@progbits\n" - " .align 4\n" - " .type savesys_ipl_nss, @function\n" - "savesys_ipl_nss:\n" -#ifdef CONFIG_64BIT - " stmg 6,15,48(15)\n" - " lgr 14,3\n" - " sam31\n" - " diag 2,14,0x8\n" - " sam64\n" - " lgr 2,14\n" - " lmg 6,15,48(15)\n" -#else - " stm 6,15,24(15)\n" - " lr 14,3\n" - " diag 2,14,0x8\n" - " lr 2,14\n" - " lm 6,15,24(15)\n" -#endif - " br 14\n" - " .size savesys_ipl_nss, .-savesys_ipl_nss\n"); - static noinline __init void create_kernel_nss(void) { unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; @@ -68,7 +39,6 @@ static noinline __init void create_kernel_nss(void) unsigned int sinitrd_pfn, einitrd_pfn; #endif int response; - size_t len; char *savesys_ptr; char upper_command_line[COMMAND_LINE_SIZE]; char defsys_cmd[DEFSYS_CMD_SIZE]; @@ -79,8 +49,8 @@ static noinline __init void create_kernel_nss(void) return; /* Convert COMMAND_LINE to upper case */ - for (i = 0; i < strlen(boot_command_line); i++) - upper_command_line[i] = toupper(boot_command_line[i]); + for (i = 0; i < strlen(COMMAND_LINE); i++) + upper_command_line[i] = toupper(COMMAND_LINE[i]); savesys_ptr = strstr(upper_command_line, "SAVESYS="); @@ -113,8 +83,7 @@ static noinline __init void create_kernel_nss(void) } #endif - sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13", - defsys_cmd, min_size); + sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size); sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", kernel_nss_name, kernel_nss_name); @@ -125,24 +94,13 @@ static noinline __init void create_kernel_nss(void) return; } - len = strlen(savesys_cmd); - ASCEBC(savesys_cmd, len); - response = savesys_ipl_nss(savesys_cmd, len); + __cpcmd(savesys_cmd, NULL, 0, &response); - /* On success: response is equal to the command size, - * max SAVESYS_CMD_SIZE - * On error: response contains the numeric portion of cp error message. - * for SAVESYS it will be >= 263 - */ - if (response > SAVESYS_CMD_SIZE) { + if (response != strlen(savesys_cmd)) { kernel_nss_name[0] = '\0'; return; } - /* re-setup boot command line with new ipl vm parms */ - ipl_update_parameters(); - setup_boot_command_line(); - ipl_flags = IPL_NSS_VALID; } @@ -183,11 +141,109 @@ static noinline __init void detect_machine_type(void) if (cpuinfo->cpu_id.version == 0xff) machine_flags |= MACHINE_FLAG_VM; + /* Running on a P/390 ? */ + if (cpuinfo->cpu_id.machine == 0x7490) + machine_flags |= MACHINE_FLAG_P390; + /* Running under KVM ? */ if (cpuinfo->cpu_id.version == 0xfe) machine_flags |= MACHINE_FLAG_KVM; } +#ifdef CONFIG_64BIT +static noinline __init int memory_fast_detect(void) +{ + unsigned long val0 = 0; + unsigned long val1 = 0xc; + int ret = -ENOSYS; + + if (ipl_flags & IPL_NSS_VALID) + return -ENOSYS; + + asm volatile( + " diag %1,%2,0x260\n" + "0: lhi %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc"); + + if (ret || val0 != val1) + return -ENOSYS; + + memory_chunk[0].size = val0 + 1; + return 0; +} +#else +static inline int memory_fast_detect(void) +{ + return -ENOSYS; +} +#endif + +static inline __init unsigned long __tprot(unsigned long addr) +{ + int cc = -1; + + asm volatile( + " tprot 0(%1),0\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (cc) : "a" (addr) : "cc"); + return (unsigned long)cc; +} + +/* Checking memory in 128KB increments. */ +#define CHUNK_INCR (1UL << 17) +#define ADDR2G (1UL << 31) + +static noinline __init void find_memory_chunks(unsigned long memsize) +{ + unsigned long addr = 0, old_addr = 0; + unsigned long old_cc = CHUNK_READ_WRITE; + unsigned long cc; + int chunk = 0; + + while (chunk < MEMORY_CHUNKS) { + cc = __tprot(addr); + while (cc == old_cc) { + addr += CHUNK_INCR; + if (memsize && addr >= memsize) + break; +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + cc = __tprot(addr); + } + + if (old_addr != addr && + (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) { + memory_chunk[chunk].addr = old_addr; + memory_chunk[chunk].size = addr - old_addr; + memory_chunk[chunk].type = old_cc; + chunk++; + } + + old_addr = addr; + old_cc = cc; + +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + /* + * Finish memory detection at the first hole + * if storage size is unknown. + */ + if (cc == -1UL && !memsize) + break; + if (memsize && addr >= memsize) + break; + } +} + static __init void early_pgm_check_handler(void) { unsigned long addr; @@ -324,61 +380,23 @@ static __init void detect_machine_facilities(void) #endif } -static __init void rescue_initrd(void) -{ -#ifdef CONFIG_BLK_DEV_INITRD - /* - * Move the initrd right behind the bss section in case it starts - * within the bss section. So we don't overwrite it when the bss - * section gets cleared. - */ - if (!INITRD_START || !INITRD_SIZE) - return; - if (INITRD_START >= (unsigned long) __bss_stop) - return; - memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE); - INITRD_START = (unsigned long) __bss_stop; -#endif -} - -/* Set up boot command line */ -static void __init setup_boot_command_line(void) -{ - char *parm = NULL; - - /* copy arch command line */ - strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE); - boot_command_line[ARCH_COMMAND_LINE_SIZE - 1] = 0; - - /* append IPL PARM data to the boot command line */ - if (MACHINE_IS_VM) { - parm = boot_command_line + strlen(boot_command_line); - *parm++ = ' '; - get_ipl_vmparm(parm); - if (parm[0] == '=') - memmove(boot_command_line, parm + 1, strlen(parm)); - } -} - - /* * Save ipl parameters, clear bss memory, initialize storage keys * and create a kernel NSS at startup if the SAVESYS= parm is defined */ void __init startup_init(void) { + unsigned long long memsize; + ipl_save_parameters(); - rescue_initrd(); clear_bss_section(); init_kernel_storage_key(); lockdep_init(); lockdep_off(); - sort_main_extable(); - setup_lowcore_early(); detect_machine_type(); - ipl_update_parameters(); - setup_boot_command_line(); create_kernel_nss(); + sort_main_extable(); + setup_lowcore_early(); detect_mvpg(); detect_ieee(); detect_csp(); @@ -386,7 +404,18 @@ void __init startup_init(void) detect_diag44(); detect_machine_facilities(); setup_hpage(); + sclp_read_info_early(); sclp_facilities_detect(); - detect_memory_layout(memory_chunk); + memsize = sclp_memory_detect(); +#ifndef CONFIG_64BIT + /* + * Can't deal with more than 2G in 31 bit addressing mode, so + * limit the value in order to avoid strange side effects. + */ + if (memsize > ADDR2G) + memsize = ADDR2G; +#endif + if (memory_fast_detect() < 0) + find_memory_chunks((unsigned long) memsize); lockdep_on(); } diff --git a/trunk/arch/s390/kernel/ipl.c b/trunk/arch/s390/kernel/ipl.c index 54b2779b5e2f..532542447d66 100644 --- a/trunk/arch/s390/kernel/ipl.c +++ b/trunk/arch/s390/kernel/ipl.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -23,7 +22,6 @@ #include #include #include -#include #define IPL_PARM_BLOCK_VERSION 0 @@ -123,7 +121,6 @@ enum ipl_method { REIPL_METHOD_FCP_RO_VM, REIPL_METHOD_FCP_DUMP, REIPL_METHOD_NSS, - REIPL_METHOD_NSS_DIAG, REIPL_METHOD_DEFAULT, }; @@ -137,15 +134,14 @@ enum dump_method { static int diag308_set_works = 0; -static struct ipl_parameter_block ipl_block; - static int reipl_capabilities = IPL_TYPE_UNKNOWN; static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN; static enum ipl_method reipl_method = REIPL_METHOD_DEFAULT; static struct ipl_parameter_block *reipl_block_fcp; static struct ipl_parameter_block *reipl_block_ccw; -static struct ipl_parameter_block *reipl_block_nss; + +static char reipl_nss_name[NSS_NAME_SIZE + 1]; static int dump_capabilities = DUMP_TYPE_NONE; static enum dump_type dump_type = DUMP_TYPE_NONE; @@ -267,56 +263,6 @@ static ssize_t ipl_type_show(struct kobject *kobj, struct kobj_attribute *attr, static struct kobj_attribute sys_ipl_type_attr = __ATTR_RO(ipl_type); -/* VM IPL PARM routines */ -static void reipl_get_ascii_vmparm(char *dest, - const struct ipl_parameter_block *ipb) -{ - int i; - int len = 0; - char has_lowercase = 0; - - if ((ipb->ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID) && - (ipb->ipl_info.ccw.vm_parm_len > 0)) { - - len = ipb->ipl_info.ccw.vm_parm_len; - memcpy(dest, ipb->ipl_info.ccw.vm_parm, len); - /* If at least one character is lowercase, we assume mixed - * case; otherwise we convert everything to lowercase. - */ - for (i = 0; i < len; i++) - if ((dest[i] > 0x80 && dest[i] < 0x8a) || /* a-i */ - (dest[i] > 0x90 && dest[i] < 0x9a) || /* j-r */ - (dest[i] > 0xa1 && dest[i] < 0xaa)) { /* s-z */ - has_lowercase = 1; - break; - } - if (!has_lowercase) - EBC_TOLOWER(dest, len); - EBCASC(dest, len); - } - dest[len] = 0; -} - -void get_ipl_vmparm(char *dest) -{ - if (diag308_set_works && (ipl_block.hdr.pbt == DIAG308_IPL_TYPE_CCW)) - reipl_get_ascii_vmparm(dest, &ipl_block); - else - dest[0] = 0; -} - -static ssize_t ipl_vm_parm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - char parm[DIAG308_VMPARM_SIZE + 1] = {}; - - get_ipl_vmparm(parm); - return sprintf(page, "%s\n", parm); -} - -static struct kobj_attribute sys_ipl_vm_parm_attr = - __ATTR(parm, S_IRUGO, ipl_vm_parm_show, NULL); - static ssize_t sys_ipl_device_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { @@ -339,8 +285,14 @@ static struct kobj_attribute sys_ipl_device_attr = static ssize_t ipl_parameter_read(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t off, size_t count) { - return memory_read_from_buffer(buf, count, &off, IPL_PARMBLOCK_START, - IPL_PARMBLOCK_SIZE); + unsigned int size = IPL_PARMBLOCK_SIZE; + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, (void *)IPL_PARMBLOCK_START + off, count); + return count; } static struct bin_attribute ipl_parameter_attr = { @@ -358,7 +310,12 @@ static ssize_t ipl_scp_data_read(struct kobject *kobj, struct bin_attribute *att unsigned int size = IPL_PARMBLOCK_START->ipl_info.fcp.scp_data_len; void *scp_data = &IPL_PARMBLOCK_START->ipl_info.fcp.scp_data; - return memory_read_from_buffer(buf, count, &off, scp_data, size); + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, scp_data + off, count); + return count; } static struct bin_attribute ipl_scp_data_attr = { @@ -413,27 +370,15 @@ static ssize_t ipl_ccw_loadparm_show(struct kobject *kobj, static struct kobj_attribute sys_ipl_ccw_loadparm_attr = __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); -static struct attribute *ipl_ccw_attrs_vm[] = { +static struct attribute *ipl_ccw_attrs[] = { &sys_ipl_type_attr.attr, &sys_ipl_device_attr.attr, &sys_ipl_ccw_loadparm_attr.attr, - &sys_ipl_vm_parm_attr.attr, NULL, }; -static struct attribute *ipl_ccw_attrs_lpar[] = { - &sys_ipl_type_attr.attr, - &sys_ipl_device_attr.attr, - &sys_ipl_ccw_loadparm_attr.attr, - NULL, -}; - -static struct attribute_group ipl_ccw_attr_group_vm = { - .attrs = ipl_ccw_attrs_vm, -}; - -static struct attribute_group ipl_ccw_attr_group_lpar = { - .attrs = ipl_ccw_attrs_lpar +static struct attribute_group ipl_ccw_attr_group = { + .attrs = ipl_ccw_attrs, }; /* NSS ipl device attributes */ @@ -443,8 +388,6 @@ DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name); static struct attribute *ipl_nss_attrs[] = { &sys_ipl_type_attr.attr, &sys_ipl_nss_name_attr.attr, - &sys_ipl_ccw_loadparm_attr.attr, - &sys_ipl_vm_parm_attr.attr, NULL, }; @@ -507,12 +450,7 @@ static int __init ipl_init(void) } switch (ipl_info.type) { case IPL_TYPE_CCW: - if (MACHINE_IS_VM) - rc = sysfs_create_group(&ipl_kset->kobj, - &ipl_ccw_attr_group_vm); - else - rc = sysfs_create_group(&ipl_kset->kobj, - &ipl_ccw_attr_group_lpar); + rc = sysfs_create_group(&ipl_kset->kobj, &ipl_ccw_attr_group); break; case IPL_TYPE_FCP: case IPL_TYPE_FCP_DUMP: @@ -543,83 +481,6 @@ static struct shutdown_action __refdata ipl_action = { * reipl shutdown action: Reboot Linux on shutdown. */ -/* VM IPL PARM attributes */ -static ssize_t reipl_generic_vmparm_show(struct ipl_parameter_block *ipb, - char *page) -{ - char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; - - reipl_get_ascii_vmparm(vmparm, ipb); - return sprintf(page, "%s\n", vmparm); -} - -static ssize_t reipl_generic_vmparm_store(struct ipl_parameter_block *ipb, - size_t vmparm_max, - const char *buf, size_t len) -{ - int i, ip_len; - - /* ignore trailing newline */ - ip_len = len; - if ((len > 0) && (buf[len - 1] == '\n')) - ip_len--; - - if (ip_len > vmparm_max) - return -EINVAL; - - /* parm is used to store kernel options, check for common chars */ - for (i = 0; i < ip_len; i++) - if (!(isalnum(buf[i]) || isascii(buf[i]) || isprint(buf[i]))) - return -EINVAL; - - memset(ipb->ipl_info.ccw.vm_parm, 0, DIAG308_VMPARM_SIZE); - ipb->ipl_info.ccw.vm_parm_len = ip_len; - if (ip_len > 0) { - ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID; - memcpy(ipb->ipl_info.ccw.vm_parm, buf, ip_len); - ASCEBC(ipb->ipl_info.ccw.vm_parm, ip_len); - } else { - ipb->ipl_info.ccw.vm_flags &= ~DIAG308_VM_FLAGS_VP_VALID; - } - - return len; -} - -/* NSS wrapper */ -static ssize_t reipl_nss_vmparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_vmparm_show(reipl_block_nss, page); -} - -static ssize_t reipl_nss_vmparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_vmparm_store(reipl_block_nss, 56, buf, len); -} - -/* CCW wrapper */ -static ssize_t reipl_ccw_vmparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_vmparm_show(reipl_block_ccw, page); -} - -static ssize_t reipl_ccw_vmparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_vmparm_store(reipl_block_ccw, 64, buf, len); -} - -static struct kobj_attribute sys_reipl_nss_vmparm_attr = - __ATTR(parm, S_IRUGO | S_IWUSR, reipl_nss_vmparm_show, - reipl_nss_vmparm_store); -static struct kobj_attribute sys_reipl_ccw_vmparm_attr = - __ATTR(parm, S_IRUGO | S_IWUSR, reipl_ccw_vmparm_show, - reipl_ccw_vmparm_store); - /* FCP reipl device attributes */ DEFINE_IPL_ATTR_RW(reipl_fcp, wwpn, "0x%016llx\n", "%016llx\n", @@ -652,26 +513,27 @@ static struct attribute_group reipl_fcp_attr_group = { DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", reipl_block_ccw->ipl_info.ccw.devno); -static void reipl_get_ascii_loadparm(char *loadparm, - struct ipl_parameter_block *ibp) +static void reipl_get_ascii_loadparm(char *loadparm) { - memcpy(loadparm, ibp->ipl_info.ccw.load_parm, LOADPARM_LEN); + memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, + LOADPARM_LEN); EBCASC(loadparm, LOADPARM_LEN); loadparm[LOADPARM_LEN] = 0; strstrip(loadparm); } -static ssize_t reipl_generic_loadparm_show(struct ipl_parameter_block *ipb, - char *page) +static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, + struct kobj_attribute *attr, char *page) { char buf[LOADPARM_LEN + 1]; - reipl_get_ascii_loadparm(buf, ipb); + reipl_get_ascii_loadparm(buf); return sprintf(page, "%s\n", buf); } -static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, - const char *buf, size_t len) +static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t len) { int i, lp_len; @@ -690,128 +552,35 @@ static ssize_t reipl_generic_loadparm_store(struct ipl_parameter_block *ipb, return -EINVAL; } /* initialize loadparm with blanks */ - memset(ipb->ipl_info.ccw.load_parm, ' ', LOADPARM_LEN); + memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); /* copy and convert to ebcdic */ - memcpy(ipb->ipl_info.ccw.load_parm, buf, lp_len); - ASCEBC(ipb->ipl_info.ccw.load_parm, LOADPARM_LEN); + memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); + ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); return len; } -/* NSS wrapper */ -static ssize_t reipl_nss_loadparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_loadparm_show(reipl_block_nss, page); -} - -static ssize_t reipl_nss_loadparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_loadparm_store(reipl_block_nss, buf, len); -} - -/* CCW wrapper */ -static ssize_t reipl_ccw_loadparm_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - return reipl_generic_loadparm_show(reipl_block_ccw, page); -} - -static ssize_t reipl_ccw_loadparm_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - return reipl_generic_loadparm_store(reipl_block_ccw, buf, len); -} - static struct kobj_attribute sys_reipl_ccw_loadparm_attr = - __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_ccw_loadparm_show, - reipl_ccw_loadparm_store); + __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, + reipl_ccw_loadparm_store); -static struct attribute *reipl_ccw_attrs_vm[] = { +static struct attribute *reipl_ccw_attrs[] = { &sys_reipl_ccw_device_attr.attr, &sys_reipl_ccw_loadparm_attr.attr, - &sys_reipl_ccw_vmparm_attr.attr, NULL, }; -static struct attribute *reipl_ccw_attrs_lpar[] = { - &sys_reipl_ccw_device_attr.attr, - &sys_reipl_ccw_loadparm_attr.attr, - NULL, -}; - -static struct attribute_group reipl_ccw_attr_group_vm = { - .name = IPL_CCW_STR, - .attrs = reipl_ccw_attrs_vm, -}; - -static struct attribute_group reipl_ccw_attr_group_lpar = { +static struct attribute_group reipl_ccw_attr_group = { .name = IPL_CCW_STR, - .attrs = reipl_ccw_attrs_lpar, + .attrs = reipl_ccw_attrs, }; /* NSS reipl device attributes */ -static void reipl_get_ascii_nss_name(char *dst, - struct ipl_parameter_block *ipb) -{ - memcpy(dst, ipb->ipl_info.ccw.nss_name, NSS_NAME_SIZE); - EBCASC(dst, NSS_NAME_SIZE); - dst[NSS_NAME_SIZE] = 0; -} - -static ssize_t reipl_nss_name_show(struct kobject *kobj, - struct kobj_attribute *attr, char *page) -{ - char nss_name[NSS_NAME_SIZE + 1] = {}; - reipl_get_ascii_nss_name(nss_name, reipl_block_nss); - return sprintf(page, "%s\n", nss_name); -} - -static ssize_t reipl_nss_name_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t len) -{ - int nss_len; - - /* ignore trailing newline */ - nss_len = len; - if ((len > 0) && (buf[len - 1] == '\n')) - nss_len--; - - if (nss_len > NSS_NAME_SIZE) - return -EINVAL; - - memset(reipl_block_nss->ipl_info.ccw.nss_name, 0x40, NSS_NAME_SIZE); - if (nss_len > 0) { - reipl_block_nss->ipl_info.ccw.vm_flags |= - DIAG308_VM_FLAGS_NSS_VALID; - memcpy(reipl_block_nss->ipl_info.ccw.nss_name, buf, nss_len); - ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, nss_len); - EBC_TOUPPER(reipl_block_nss->ipl_info.ccw.nss_name, nss_len); - } else { - reipl_block_nss->ipl_info.ccw.vm_flags &= - ~DIAG308_VM_FLAGS_NSS_VALID; - } - - return len; -} - -static struct kobj_attribute sys_reipl_nss_name_attr = - __ATTR(name, S_IRUGO | S_IWUSR, reipl_nss_name_show, - reipl_nss_name_store); - -static struct kobj_attribute sys_reipl_nss_loadparm_attr = - __ATTR(loadparm, S_IRUGO | S_IWUSR, reipl_nss_loadparm_show, - reipl_nss_loadparm_store); +DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name); static struct attribute *reipl_nss_attrs[] = { &sys_reipl_nss_name_attr.attr, - &sys_reipl_nss_loadparm_attr.attr, - &sys_reipl_nss_vmparm_attr.attr, NULL, }; @@ -848,10 +617,7 @@ static int reipl_set_type(enum ipl_type type) reipl_method = REIPL_METHOD_FCP_DUMP; break; case IPL_TYPE_NSS: - if (diag308_set_works) - reipl_method = REIPL_METHOD_NSS_DIAG; - else - reipl_method = REIPL_METHOD_NSS; + reipl_method = REIPL_METHOD_NSS; break; case IPL_TYPE_UNKNOWN: reipl_method = REIPL_METHOD_DEFAULT; @@ -889,38 +655,11 @@ static struct kobj_attribute reipl_type_attr = static struct kset *reipl_kset; -static void get_ipl_string(char *dst, struct ipl_parameter_block *ipb, - const enum ipl_method m) -{ - char loadparm[LOADPARM_LEN + 1] = {}; - char vmparm[DIAG308_VMPARM_SIZE + 1] = {}; - char nss_name[NSS_NAME_SIZE + 1] = {}; - size_t pos = 0; - - reipl_get_ascii_loadparm(loadparm, ipb); - reipl_get_ascii_nss_name(nss_name, ipb); - reipl_get_ascii_vmparm(vmparm, ipb); - - switch (m) { - case REIPL_METHOD_CCW_VM: - pos = sprintf(dst, "IPL %X CLEAR", ipb->ipl_info.ccw.devno); - break; - case REIPL_METHOD_NSS: - pos = sprintf(dst, "IPL %s", nss_name); - break; - default: - break; - } - if (strlen(loadparm) > 0) - pos += sprintf(dst + pos, " LOADPARM '%s'", loadparm); - if (strlen(vmparm) > 0) - sprintf(dst + pos, " PARM %s", vmparm); -} - static void reipl_run(struct shutdown_trigger *trigger) { struct ccw_dev_id devid; - static char buf[128]; + static char buf[100]; + char loadparm[LOADPARM_LEN + 1]; switch (reipl_method) { case REIPL_METHOD_CCW_CIO: @@ -929,7 +668,13 @@ static void reipl_run(struct shutdown_trigger *trigger) reipl_ccw_dev(&devid); break; case REIPL_METHOD_CCW_VM: - get_ipl_string(buf, reipl_block_ccw, REIPL_METHOD_CCW_VM); + reipl_get_ascii_loadparm(loadparm); + if (strlen(loadparm) == 0) + sprintf(buf, "IPL %X CLEAR", + reipl_block_ccw->ipl_info.ccw.devno); + else + sprintf(buf, "IPL %X CLEAR LOADPARM '%s'", + reipl_block_ccw->ipl_info.ccw.devno, loadparm); __cpcmd(buf, NULL, 0, NULL); break; case REIPL_METHOD_CCW_DIAG: @@ -946,12 +691,8 @@ static void reipl_run(struct shutdown_trigger *trigger) case REIPL_METHOD_FCP_RO_VM: __cpcmd("IPL", NULL, 0, NULL); break; - case REIPL_METHOD_NSS_DIAG: - diag308(DIAG308_SET, reipl_block_nss); - diag308(DIAG308_IPL, NULL); - break; case REIPL_METHOD_NSS: - get_ipl_string(buf, reipl_block_nss, REIPL_METHOD_NSS); + sprintf(buf, "IPL %s", reipl_nss_name); __cpcmd(buf, NULL, 0, NULL); break; case REIPL_METHOD_DEFAULT: @@ -966,36 +707,16 @@ static void reipl_run(struct shutdown_trigger *trigger) disabled_wait((unsigned long) __builtin_return_address(0)); } -static void reipl_block_ccw_init(struct ipl_parameter_block *ipb) +static void __init reipl_probe(void) { - ipb->hdr.len = IPL_PARM_BLK_CCW_LEN; - ipb->hdr.version = IPL_PARM_BLOCK_VERSION; - ipb->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; - ipb->hdr.pbt = DIAG308_IPL_TYPE_CCW; -} + void *buffer; -static void reipl_block_ccw_fill_parms(struct ipl_parameter_block *ipb) -{ - /* LOADPARM */ - /* check if read scp info worked and set loadparm */ - if (sclp_ipl_info.is_valid) - memcpy(ipb->ipl_info.ccw.load_parm, - &sclp_ipl_info.loadparm, LOADPARM_LEN); - else - /* read scp info failed: set empty loadparm (EBCDIC blanks) */ - memset(ipb->ipl_info.ccw.load_parm, 0x40, LOADPARM_LEN); - ipb->hdr.flags = DIAG308_FLAGS_LP_VALID; - - /* VM PARM */ - if (MACHINE_IS_VM && diag308_set_works && - (ipl_block.ipl_info.ccw.vm_flags & DIAG308_VM_FLAGS_VP_VALID)) { - - ipb->ipl_info.ccw.vm_flags |= DIAG308_VM_FLAGS_VP_VALID; - ipb->ipl_info.ccw.vm_parm_len = - ipl_block.ipl_info.ccw.vm_parm_len; - memcpy(ipb->ipl_info.ccw.vm_parm, - ipl_block.ipl_info.ccw.vm_parm, DIAG308_VMPARM_SIZE); - } + buffer = (void *) get_zeroed_page(GFP_KERNEL); + if (!buffer) + return; + if (diag308(DIAG308_STORE, buffer) == DIAG308_RC_OK) + diag308_set_works = 1; + free_page((unsigned long)buffer); } static int __init reipl_nss_init(void) @@ -1004,31 +725,10 @@ static int __init reipl_nss_init(void) if (!MACHINE_IS_VM) return 0; - - reipl_block_nss = (void *) get_zeroed_page(GFP_KERNEL); - if (!reipl_block_nss) - return -ENOMEM; - - if (!diag308_set_works) - sys_reipl_nss_vmparm_attr.attr.mode = S_IRUGO; - rc = sysfs_create_group(&reipl_kset->kobj, &reipl_nss_attr_group); if (rc) return rc; - - reipl_block_ccw_init(reipl_block_nss); - if (ipl_info.type == IPL_TYPE_NSS) { - memset(reipl_block_nss->ipl_info.ccw.nss_name, - ' ', NSS_NAME_SIZE); - memcpy(reipl_block_nss->ipl_info.ccw.nss_name, - kernel_nss_name, strlen(kernel_nss_name)); - ASCEBC(reipl_block_nss->ipl_info.ccw.nss_name, NSS_NAME_SIZE); - reipl_block_nss->ipl_info.ccw.vm_flags |= - DIAG308_VM_FLAGS_NSS_VALID; - - reipl_block_ccw_fill_parms(reipl_block_nss); - } - + strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1); reipl_capabilities |= IPL_TYPE_NSS; return 0; } @@ -1040,27 +740,28 @@ static int __init reipl_ccw_init(void) reipl_block_ccw = (void *) get_zeroed_page(GFP_KERNEL); if (!reipl_block_ccw) return -ENOMEM; - - if (MACHINE_IS_VM) { - if (!diag308_set_works) - sys_reipl_ccw_vmparm_attr.attr.mode = S_IRUGO; - rc = sysfs_create_group(&reipl_kset->kobj, - &reipl_ccw_attr_group_vm); - } else { - if(!diag308_set_works) - sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; - rc = sysfs_create_group(&reipl_kset->kobj, - &reipl_ccw_attr_group_lpar); - } - if (rc) + rc = sysfs_create_group(&reipl_kset->kobj, &reipl_ccw_attr_group); + if (rc) { + free_page((unsigned long)reipl_block_ccw); return rc; - - reipl_block_ccw_init(reipl_block_ccw); - if (ipl_info.type == IPL_TYPE_CCW) { - reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; - reipl_block_ccw_fill_parms(reipl_block_ccw); } - + reipl_block_ccw->hdr.len = IPL_PARM_BLK_CCW_LEN; + reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; + reipl_block_ccw->hdr.blk0_len = IPL_PARM_BLK0_CCW_LEN; + reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; + reipl_block_ccw->hdr.flags = DIAG308_FLAGS_LP_VALID; + /* check if read scp info worked and set loadparm */ + if (sclp_ipl_info.is_valid) + memcpy(reipl_block_ccw->ipl_info.ccw.load_param, + &sclp_ipl_info.loadparm, LOADPARM_LEN); + else + /* read scp info failed: set empty loadparm (EBCDIC blanks) */ + memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, + LOADPARM_LEN); + if (!MACHINE_IS_VM && !diag308_set_works) + sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; + if (ipl_info.type == IPL_TYPE_CCW) + reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; reipl_capabilities |= IPL_TYPE_CCW; return 0; } @@ -1597,6 +1298,7 @@ static void __init shutdown_actions_init(void) static int __init s390_ipl_init(void) { + reipl_probe(); sclp_get_ipl_info(&sclp_ipl_info); shutdown_actions_init(); shutdown_triggers_init(); @@ -1703,12 +1405,6 @@ void __init setup_ipl(void) atomic_notifier_chain_register(&panic_notifier_list, &on_panic_nb); } -void __init ipl_update_parameters(void) -{ - if (diag308(DIAG308_STORE, &ipl_block) == DIAG308_RC_OK) - diag308_set_works = 1; -} - void __init ipl_save_parameters(void) { struct cio_iplinfo iplinfo; diff --git a/trunk/arch/s390/kernel/kprobes.c b/trunk/arch/s390/kernel/kprobes.c index 288ad490a6dd..ed04d1372d5d 100644 --- a/trunk/arch/s390/kernel/kprobes.c +++ b/trunk/arch/s390/kernel/kprobes.c @@ -41,8 +41,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) if (is_prohibited_opcode((kprobe_opcode_t *) p->addr)) return -EINVAL; - if ((unsigned long)p->addr & 0x01) + if ((unsigned long)p->addr & 0x01) { + printk("Attempt to register kprobe at an unaligned address\n"); return -EINVAL; + } /* Use the get_insn_slot() facility for correctness */ if (!(p->ainsn.insn = get_insn_slot())) diff --git a/trunk/arch/s390/kernel/machine_kexec.c b/trunk/arch/s390/kernel/machine_kexec.c index 131d7ee8b416..3c77dd36994c 100644 --- a/trunk/arch/s390/kernel/machine_kexec.c +++ b/trunk/arch/s390/kernel/machine_kexec.c @@ -52,6 +52,7 @@ void machine_kexec_cleanup(struct kimage *image) void machine_shutdown(void) { + printk(KERN_INFO "kexec: machine_shutdown called\n"); } void machine_kexec(struct kimage *image) diff --git a/trunk/arch/s390/kernel/mem_detect.c b/trunk/arch/s390/kernel/mem_detect.c deleted file mode 100644 index 18ed7abe16c5..000000000000 --- a/trunk/arch/s390/kernel/mem_detect.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright IBM Corp. 2008 - * Author(s): Heiko Carstens - */ - -#include -#include -#include -#include -#include - -static int memory_fast_detect(struct mem_chunk *chunk) -{ - unsigned long val0 = 0; - unsigned long val1 = 0xc; - int rc = -EOPNOTSUPP; - - if (ipl_flags & IPL_NSS_VALID) - return -EOPNOTSUPP; - asm volatile( - " diag %1,%2,0x260\n" - "0: lhi %0,0\n" - "1:\n" - EX_TABLE(0b,1b) - : "+d" (rc), "+d" (val0), "+d" (val1) : : "cc"); - - if (rc || val0 != val1) - return -EOPNOTSUPP; - chunk->size = val0 + 1; - return 0; -} - -static inline int tprot(unsigned long addr) -{ - int rc = -EFAULT; - - asm volatile( - " tprot 0(%1),0\n" - "0: ipm %0\n" - " srl %0,28\n" - "1:\n" - EX_TABLE(0b,1b) - : "+d" (rc) : "a" (addr) : "cc"); - return rc; -} - -#define ADDR2G (1ULL << 31) - -static void find_memory_chunks(struct mem_chunk chunk[]) -{ - unsigned long long memsize, rnmax, rzm; - unsigned long addr = 0, size; - int i = 0, type; - - rzm = sclp_get_rzm(); - rnmax = sclp_get_rnmax(); - memsize = rzm * rnmax; - if (!rzm) - rzm = 1ULL << 17; - if (sizeof(long) == 4) { - rzm = min(ADDR2G, rzm); - memsize = memsize ? min(ADDR2G, memsize) : ADDR2G; - } - do { - size = 0; - type = tprot(addr); - do { - size += rzm; - if (memsize && addr + size >= memsize) - break; - } while (type == tprot(addr + size)); - if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { - chunk[i].addr = addr; - chunk[i].size = size; - chunk[i].type = type; - i++; - } - addr += size; - } while (addr < memsize && i < MEMORY_CHUNKS); -} - -void detect_memory_layout(struct mem_chunk chunk[]) -{ - unsigned long flags, cr0; - - memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk)); - if (memory_fast_detect(&chunk[0]) == 0) - return; - /* Disable IRQs, DAT and low address protection so tprot does the - * right thing and we don't get scheduled away with low address - * protection disabled. - */ - flags = __raw_local_irq_stnsm(0xf8); - __ctl_store(cr0, 0, 0); - __ctl_clear_bit(0, 28); - find_memory_chunks(chunk); - __ctl_load(cr0, 0, 0); - __raw_local_irq_ssm(flags); -} -EXPORT_SYMBOL(detect_memory_layout); diff --git a/trunk/arch/s390/kernel/process.c b/trunk/arch/s390/kernel/process.c index 85defd01d293..7920861109d2 100644 --- a/trunk/arch/s390/kernel/process.c +++ b/trunk/arch/s390/kernel/process.c @@ -75,19 +75,46 @@ unsigned long thread_saved_pc(struct task_struct *tsk) return sf->gprs[8]; } +/* + * Need to know about CPUs going idle? + */ +static ATOMIC_NOTIFIER_HEAD(idle_chain); DEFINE_PER_CPU(struct s390_idle_data, s390_idle); +int register_idle_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_register(&idle_chain, nb); +} +EXPORT_SYMBOL(register_idle_notifier); + +int unregister_idle_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&idle_chain, nb); +} +EXPORT_SYMBOL(unregister_idle_notifier); + static int s390_idle_enter(void) { struct s390_idle_data *idle; + int nr_calls = 0; + void *hcpu; + int rc; + hcpu = (void *)(long)smp_processor_id(); + rc = __atomic_notifier_call_chain(&idle_chain, S390_CPU_IDLE, hcpu, -1, + &nr_calls); + if (rc == NOTIFY_BAD) { + nr_calls--; + __atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, + hcpu, nr_calls, NULL); + return rc; + } idle = &__get_cpu_var(s390_idle); spin_lock(&idle->lock); idle->idle_count++; idle->in_idle = 1; idle->idle_enter = get_clock(); spin_unlock(&idle->lock); - vtime_stop_cpu_timer(); return NOTIFY_OK; } @@ -95,12 +122,13 @@ void s390_idle_leave(void) { struct s390_idle_data *idle; - vtime_start_cpu_timer(); idle = &__get_cpu_var(s390_idle); spin_lock(&idle->lock); idle->idle_time += get_clock() - idle->idle_enter; idle->in_idle = 0; spin_unlock(&idle->lock); + atomic_notifier_call_chain(&idle_chain, S390_CPU_NOT_IDLE, + (void *)(long) smp_processor_id()); } extern void s390_handle_mcck(void); diff --git a/trunk/arch/s390/kernel/ptrace.c b/trunk/arch/s390/kernel/ptrace.c index 2815bfe348a6..35827b9bd4d1 100644 --- a/trunk/arch/s390/kernel/ptrace.c +++ b/trunk/arch/s390/kernel/ptrace.c @@ -33,8 +33,6 @@ #include #include #include -#include -#include #include #include @@ -49,11 +47,6 @@ #include "compat_ptrace.h" #endif -enum s390_regset { - REGSET_GENERAL, - REGSET_FP, -}; - static void FixPerRegisters(struct task_struct *task) { @@ -133,10 +126,24 @@ ptrace_disable(struct task_struct *child) * struct user contain pad bytes that should be read as zeroes. * Lovely... */ -static unsigned long __peek_user(struct task_struct *child, addr_t addr) +static int +peek_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; - addr_t offset, tmp; + addr_t offset, tmp, mask; + + /* + * Stupid gdb peeks/pokes the access registers in 64 bit with + * an alignment of 4. Programmers from hell... + */ + mask = __ADDR_MASK; +#ifdef CONFIG_64BIT + if (addr >= (addr_t) &dummy->regs.acrs && + addr < (addr_t) &dummy->regs.orig_gpr2) + mask = 3; +#endif + if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) + return -EIO; if (addr < (addr_t) &dummy->regs.acrs) { /* @@ -190,18 +197,24 @@ static unsigned long __peek_user(struct task_struct *child, addr_t addr) } else tmp = 0; - return tmp; + return put_user(tmp, (addr_t __user *) data); } +/* + * Write a word to the user area of a process at location addr. This + * operation does have an additional problem compared to peek_user. + * Stores to the program status word and on the floating point + * control register needs to get checked for validity. + */ static int -peek_user(struct task_struct *child, addr_t addr, addr_t data) +poke_user(struct task_struct *child, addr_t addr, addr_t data) { struct user *dummy = NULL; - addr_t tmp, mask; + addr_t offset, mask; /* * Stupid gdb peeks/pokes the access registers in 64 bit with - * an alignment of 4. Programmers from hell... + * an alignment of 4. Programmers from hell indeed... */ mask = __ADDR_MASK; #ifdef CONFIG_64BIT @@ -212,21 +225,6 @@ peek_user(struct task_struct *child, addr_t addr, addr_t data) if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) return -EIO; - tmp = __peek_user(child, addr); - return put_user(tmp, (addr_t __user *) data); -} - -/* - * Write a word to the user area of a process at location addr. This - * operation does have an additional problem compared to peek_user. - * Stores to the program status word and on the floating point - * control register needs to get checked for validity. - */ -static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user *dummy = NULL; - addr_t offset; - if (addr < (addr_t) &dummy->regs.acrs) { /* * psw and gprs are stored on the stack @@ -294,28 +292,6 @@ static int __poke_user(struct task_struct *child, addr_t addr, addr_t data) return 0; } -static int -poke_user(struct task_struct *child, addr_t addr, addr_t data) -{ - struct user *dummy = NULL; - addr_t mask; - - /* - * Stupid gdb peeks/pokes the access registers in 64 bit with - * an alignment of 4. Programmers from hell indeed... - */ - mask = __ADDR_MASK; -#ifdef CONFIG_64BIT - if (addr >= (addr_t) &dummy->regs.acrs && - addr < (addr_t) &dummy->regs.orig_gpr2) - mask = 3; -#endif - if ((addr & mask) || addr > sizeof(struct user) - __ADDR_MASK) - return -EIO; - - return __poke_user(child, addr, data); -} - long arch_ptrace(struct task_struct *child, long request, long addr, long data) { ptrace_area parea; @@ -391,13 +367,18 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) /* * Same as peek_user but for a 31 bit program. */ -static u32 __peek_user_compat(struct task_struct *child, addr_t addr) +static int +peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data) { struct user32 *dummy32 = NULL; per_struct32 *dummy_per32 = NULL; addr_t offset; __u32 tmp; + if (!test_thread_flag(TIF_31BIT) || + (addr & 3) || addr > sizeof(struct user) - 3) + return -EIO; + if (addr < (addr_t) &dummy32->regs.acrs) { /* * psw and gprs are stored on the stack @@ -454,32 +435,25 @@ static u32 __peek_user_compat(struct task_struct *child, addr_t addr) } else tmp = 0; - return tmp; -} - -static int peek_user_compat(struct task_struct *child, - addr_t addr, addr_t data) -{ - __u32 tmp; - - if (!test_thread_flag(TIF_31BIT) || - (addr & 3) || addr > sizeof(struct user) - 3) - return -EIO; - - tmp = __peek_user_compat(child, addr); return put_user(tmp, (__u32 __user *) data); } /* * Same as poke_user but for a 31 bit program. */ -static int __poke_user_compat(struct task_struct *child, - addr_t addr, addr_t data) +static int +poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data) { struct user32 *dummy32 = NULL; per_struct32 *dummy_per32 = NULL; - __u32 tmp = (__u32) data; addr_t offset; + __u32 tmp; + + if (!test_thread_flag(TIF_31BIT) || + (addr & 3) || addr > sizeof(struct user32) - 3) + return -EIO; + + tmp = (__u32) data; if (addr < (addr_t) &dummy32->regs.acrs) { /* @@ -554,16 +528,6 @@ static int __poke_user_compat(struct task_struct *child, return 0; } -static int poke_user_compat(struct task_struct *child, - addr_t addr, addr_t data) -{ - if (!test_thread_flag(TIF_31BIT) || - (addr & 3) || addr > sizeof(struct user32) - 3) - return -EIO; - - return __poke_user_compat(child, addr, data); -} - long compat_arch_ptrace(struct task_struct *child, compat_long_t request, compat_ulong_t caddr, compat_ulong_t cdata) { @@ -575,11 +539,11 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, switch (request) { case PTRACE_PEEKUSR: /* read the word at location addr in the USER area. */ - return peek_user_compat(child, addr, data); + return peek_user_emu31(child, addr, data); case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ - return poke_user_compat(child, addr, data); + return poke_user_emu31(child, addr, data); case PTRACE_PEEKUSR_AREA: case PTRACE_POKEUSR_AREA: @@ -591,13 +555,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, copied = 0; while (copied < parea.len) { if (request == PTRACE_PEEKUSR_AREA) - ret = peek_user_compat(child, addr, data); + ret = peek_user_emu31(child, addr, data); else { __u32 utmp; if (get_user(utmp, (__u32 __force __user *) data)) return -EFAULT; - ret = poke_user_compat(child, addr, utmp); + ret = poke_user_emu31(child, addr, utmp); } if (ret) return ret; @@ -646,240 +610,3 @@ syscall_trace(struct pt_regs *regs, int entryexit) regs->gprs[2], regs->orig_gpr2, regs->gprs[3], regs->gprs[4], regs->gprs[5]); } - -/* - * user_regset definitions. - */ - -static int s390_regs_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - unsigned long *k = kbuf; - while (count > 0) { - *k++ = __peek_user(target, pos); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - unsigned long __user *u = ubuf; - while (count > 0) { - if (__put_user(__peek_user(target, pos), u++)) - return -EFAULT; - count -= sizeof(*u); - pos += sizeof(*u); - } - } - return 0; -} - -static int s390_regs_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int rc = 0; - - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - const unsigned long *k = kbuf; - while (count > 0 && !rc) { - rc = __poke_user(target, pos, *k++); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - const unsigned long __user *u = ubuf; - while (count > 0 && !rc) { - unsigned long word; - rc = __get_user(word, u++); - if (rc) - break; - rc = __poke_user(target, pos, word); - count -= sizeof(*u); - pos += sizeof(*u); - } - } - - if (rc == 0 && target == current) - restore_access_regs(target->thread.acrs); - - return rc; -} - -static int s390_fpregs_get(struct task_struct *target, - const struct user_regset *regset, unsigned int pos, - unsigned int count, void *kbuf, void __user *ubuf) -{ - if (target == current) - save_fp_regs(&target->thread.fp_regs); - - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, - &target->thread.fp_regs, 0, -1); -} - -static int s390_fpregs_set(struct task_struct *target, - const struct user_regset *regset, unsigned int pos, - unsigned int count, const void *kbuf, - const void __user *ubuf) -{ - int rc = 0; - - if (target == current) - save_fp_regs(&target->thread.fp_regs); - - /* If setting FPC, must validate it first. */ - if (count > 0 && pos < offsetof(s390_fp_regs, fprs)) { - u32 fpc[2] = { target->thread.fp_regs.fpc, 0 }; - rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &fpc, - 0, offsetof(s390_fp_regs, fprs)); - if (rc) - return rc; - if ((fpc[0] & ~FPC_VALID_MASK) != 0 || fpc[1] != 0) - return -EINVAL; - target->thread.fp_regs.fpc = fpc[0]; - } - - if (rc == 0 && count > 0) - rc = user_regset_copyin(&pos, &count, &kbuf, &ubuf, - target->thread.fp_regs.fprs, - offsetof(s390_fp_regs, fprs), -1); - - if (rc == 0 && target == current) - restore_fp_regs(&target->thread.fp_regs); - - return rc; -} - -static const struct user_regset s390_regsets[] = { - [REGSET_GENERAL] = { - .core_note_type = NT_PRSTATUS, - .n = sizeof(s390_regs) / sizeof(long), - .size = sizeof(long), - .align = sizeof(long), - .get = s390_regs_get, - .set = s390_regs_set, - }, - [REGSET_FP] = { - .core_note_type = NT_PRFPREG, - .n = sizeof(s390_fp_regs) / sizeof(long), - .size = sizeof(long), - .align = sizeof(long), - .get = s390_fpregs_get, - .set = s390_fpregs_set, - }, -}; - -static const struct user_regset_view user_s390_view = { - .name = UTS_MACHINE, - .e_machine = EM_S390, - .regsets = s390_regsets, - .n = ARRAY_SIZE(s390_regsets) -}; - -#ifdef CONFIG_COMPAT -static int s390_compat_regs_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - compat_ulong_t *k = kbuf; - while (count > 0) { - *k++ = __peek_user_compat(target, pos); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - compat_ulong_t __user *u = ubuf; - while (count > 0) { - if (__put_user(__peek_user_compat(target, pos), u++)) - return -EFAULT; - count -= sizeof(*u); - pos += sizeof(*u); - } - } - return 0; -} - -static int s390_compat_regs_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int rc = 0; - - if (target == current) - save_access_regs(target->thread.acrs); - - if (kbuf) { - const compat_ulong_t *k = kbuf; - while (count > 0 && !rc) { - rc = __poke_user_compat(target, pos, *k++); - count -= sizeof(*k); - pos += sizeof(*k); - } - } else { - const compat_ulong_t __user *u = ubuf; - while (count > 0 && !rc) { - compat_ulong_t word; - rc = __get_user(word, u++); - if (rc) - break; - rc = __poke_user_compat(target, pos, word); - count -= sizeof(*u); - pos += sizeof(*u); - } - } - - if (rc == 0 && target == current) - restore_access_regs(target->thread.acrs); - - return rc; -} - -static const struct user_regset s390_compat_regsets[] = { - [REGSET_GENERAL] = { - .core_note_type = NT_PRSTATUS, - .n = sizeof(s390_compat_regs) / sizeof(compat_long_t), - .size = sizeof(compat_long_t), - .align = sizeof(compat_long_t), - .get = s390_compat_regs_get, - .set = s390_compat_regs_set, - }, - [REGSET_FP] = { - .core_note_type = NT_PRFPREG, - .n = sizeof(s390_fp_regs) / sizeof(compat_long_t), - .size = sizeof(compat_long_t), - .align = sizeof(compat_long_t), - .get = s390_fpregs_get, - .set = s390_fpregs_set, - }, -}; - -static const struct user_regset_view user_s390_compat_view = { - .name = "s390", - .e_machine = EM_S390, - .regsets = s390_compat_regsets, - .n = ARRAY_SIZE(s390_compat_regsets) -}; -#endif - -const struct user_regset_view *task_user_regset_view(struct task_struct *task) -{ -#ifdef CONFIG_COMPAT - if (test_tsk_thread_flag(task, TIF_31BIT)) - return &user_s390_compat_view; -#endif - return &user_s390_view; -} diff --git a/trunk/arch/s390/kernel/setup.c b/trunk/arch/s390/kernel/setup.c index b358e18273b0..2bc70b6e876a 100644 --- a/trunk/arch/s390/kernel/setup.c +++ b/trunk/arch/s390/kernel/setup.c @@ -77,7 +77,7 @@ unsigned long machine_flags; unsigned long elf_hwcap = 0; char elf_platform[ELF_PLATFORM_SIZE]; -struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; +struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS]; volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ static unsigned long __initdata memory_end; @@ -205,6 +205,12 @@ static void __init conmode_default(void) SET_CONSOLE_SCLP; #endif } + } else if (MACHINE_IS_P390) { +#if defined(CONFIG_TN3215_CONSOLE) + SET_CONSOLE_3215; +#elif defined(CONFIG_TN3270_CONSOLE) + SET_CONSOLE_3270; +#endif } else { #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; @@ -215,17 +221,18 @@ static void __init conmode_default(void) #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE) static void __init setup_zfcpdump(unsigned int console_devno) { - static char str[41]; + static char str[64]; if (ipl_info.type != IPL_TYPE_FCP_DUMP) return; if (console_devno != -1) - sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x", + sprintf(str, "cio_ignore=all,!0.0.%04x,!0.0.%04x", ipl_info.data.fcp.dev_id.devno, console_devno); else - sprintf(str, " cio_ignore=all,!0.0.%04x", + sprintf(str, "cio_ignore=all,!0.0.%04x", ipl_info.data.fcp.dev_id.devno); - strcat(boot_command_line, str); + strcat(COMMAND_LINE, " "); + strcat(COMMAND_LINE, str); console_loglevel = 2; } #else @@ -282,6 +289,32 @@ static int __init early_parse_mem(char *p) } early_param("mem", early_parse_mem); +/* + * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes + */ +static int __init early_parse_ipldelay(char *p) +{ + unsigned long delay = 0; + + delay = simple_strtoul(p, &p, 0); + + switch (*p) { + case 's': + case 'S': + delay *= 1000000; + break; + case 'm': + case 'M': + delay *= 60 * 1000000; + } + + /* now wait for the requested amount of time */ + udelay(delay); + + return 0; +} +early_param("ipldelay", early_parse_ipldelay); + #ifdef CONFIG_S390_SWITCH_AMODE #ifdef CONFIG_PGSTE unsigned int switch_amode = 1; @@ -771,9 +804,11 @@ setup_arch(char **cmdline_p) printk("We are running native (64 bit mode)\n"); #endif /* CONFIG_64BIT */ - /* Have one command line that is parsed and saved in /proc/cmdline */ - /* boot_command_line has been already set up in early.c */ - *cmdline_p = boot_command_line; + /* Save unparsed command line copy for /proc/cmdline */ + strlcpy(boot_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + + *cmdline_p = COMMAND_LINE; + *(*cmdline_p + COMMAND_LINE_SIZE - 1) = '\0'; ROOT_DEV = Root_RAM0; diff --git a/trunk/arch/s390/kernel/time.c b/trunk/arch/s390/kernel/time.c index 7418bebb547f..7aec676fefd5 100644 --- a/trunk/arch/s390/kernel/time.c +++ b/trunk/arch/s390/kernel/time.c @@ -3,7 +3,7 @@ * Time of day based timer functions. * * S390 version - * Copyright IBM Corp. 1999, 2008 + * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Hartmut Penner (hp@de.ibm.com), * Martin Schwidefsky (schwidefsky@de.ibm.com), * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -163,7 +162,7 @@ void init_cpu_timer(void) /* Enable clock comparator timer interrupt. */ __ctl_set_bit(0,11); - /* Always allow the timing alert external interrupt. */ + /* Always allow ETR external interrupts, even without an ETR. */ __ctl_set_bit(0, 4); } @@ -171,21 +170,8 @@ static void clock_comparator_interrupt(__u16 code) { } -static void etr_timing_alert(struct etr_irq_parm *); -static void stp_timing_alert(struct stp_irq_parm *); - -static void timing_alert_interrupt(__u16 code) -{ - if (S390_lowcore.ext_params & 0x00c40000) - etr_timing_alert((struct etr_irq_parm *) - &S390_lowcore.ext_params); - if (S390_lowcore.ext_params & 0x00038000) - stp_timing_alert((struct stp_irq_parm *) - &S390_lowcore.ext_params); -} - static void etr_reset(void); -static void stp_reset(void); +static void etr_ext_handler(__u16); /* * Get the TOD clock running. @@ -195,7 +181,6 @@ static u64 __init reset_tod_clock(void) u64 time; etr_reset(); - stp_reset(); if (store_clock(&time) == 0) return time; /* TOD clock not running. Set the clock to Unix Epoch. */ @@ -246,9 +231,8 @@ void __init time_init(void) if (clocksource_register(&clocksource_tod) != 0) panic("Could not register TOD clock source"); - /* request the timing alert external interrupt */ - if (register_early_external_interrupt(0x1406, - timing_alert_interrupt, + /* request the etr external interrupt */ + if (register_early_external_interrupt(0x1406, etr_ext_handler, &ext_int_etr_cc) != 0) panic("Couldn't request external interrupt 0x1406"); @@ -260,113 +244,11 @@ void __init time_init(void) #endif } -/* - * The time is "clock". old is what we think the time is. - * Adjust the value by a multiple of jiffies and add the delta to ntp. - * "delay" is an approximation how long the synchronization took. If - * the time correction is positive, then "delay" is subtracted from - * the time difference and only the remaining part is passed to ntp. - */ -static unsigned long long adjust_time(unsigned long long old, - unsigned long long clock, - unsigned long long delay) -{ - unsigned long long delta, ticks; - struct timex adjust; - - if (clock > old) { - /* It is later than we thought. */ - delta = ticks = clock - old; - delta = ticks = (delta < delay) ? 0 : delta - delay; - delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - adjust.offset = ticks * (1000000 / HZ); - } else { - /* It is earlier than we thought. */ - delta = ticks = old - clock; - delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); - delta = -delta; - adjust.offset = -ticks * (1000000 / HZ); - } - jiffies_timer_cc += delta; - if (adjust.offset != 0) { - printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", - adjust.offset); - adjust.modes = ADJ_OFFSET_SINGLESHOT; - do_adjtimex(&adjust); - } - return delta; -} - -static DEFINE_PER_CPU(atomic_t, clock_sync_word); -static unsigned long clock_sync_flags; - -#define CLOCK_SYNC_HAS_ETR 0 -#define CLOCK_SYNC_HAS_STP 1 -#define CLOCK_SYNC_ETR 2 -#define CLOCK_SYNC_STP 3 - -/* - * The synchronous get_clock function. It will write the current clock - * value to the clock pointer and return 0 if the clock is in sync with - * the external time source. If the clock mode is local it will return - * -ENOSYS and -EAGAIN if the clock is not in sync with the external - * reference. - */ -int get_sync_clock(unsigned long long *clock) -{ - atomic_t *sw_ptr; - unsigned int sw0, sw1; - - sw_ptr = &get_cpu_var(clock_sync_word); - sw0 = atomic_read(sw_ptr); - *clock = get_clock(); - sw1 = atomic_read(sw_ptr); - put_cpu_var(clock_sync_sync); - if (sw0 == sw1 && (sw0 & 0x80000000U)) - /* Success: time is in sync. */ - return 0; - if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags) && - !test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) - return -ENOSYS; - if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags) && - !test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return -EACCES; - return -EAGAIN; -} -EXPORT_SYMBOL(get_sync_clock); - -/* - * Make get_sync_clock return -EAGAIN. - */ -static void disable_sync_clock(void *dummy) -{ - atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word); - /* - * Clear the in-sync bit 2^31. All get_sync_clock calls will - * fail until the sync bit is turned back on. In addition - * increase the "sequence" counter to avoid the race of an - * etr event and the complete recovery against get_sync_clock. - */ - atomic_clear_mask(0x80000000, sw_ptr); - atomic_inc(sw_ptr); -} - -/* - * Make get_sync_clock return 0 again. - * Needs to be called from a context disabled for preemption. - */ -static void enable_sync_clock(void) -{ - atomic_t *sw_ptr = &__get_cpu_var(clock_sync_word); - atomic_set_mask(0x80000000, sw_ptr); -} - /* * External Time Reference (ETR) code. */ static int etr_port0_online; static int etr_port1_online; -static int etr_steai_available; static int __init early_parse_etr(char *p) { @@ -391,6 +273,12 @@ enum etr_event { ETR_EVENT_UPDATE, }; +enum etr_flags { + ETR_FLAG_ENOSYS, + ETR_FLAG_EACCES, + ETR_FLAG_STEAI, +}; + /* * Valid bit combinations of the eacr register are (x = don't care): * e0 e1 dp p0 p1 ea es sl @@ -417,17 +305,73 @@ enum etr_event { */ static struct etr_eacr etr_eacr; static u64 etr_tolec; /* time of last eacr update */ +static unsigned long etr_flags; static struct etr_aib etr_port0; static int etr_port0_uptodate; static struct etr_aib etr_port1; static int etr_port1_uptodate; static unsigned long etr_events; static struct timer_list etr_timer; +static DEFINE_PER_CPU(atomic_t, etr_sync_word); static void etr_timeout(unsigned long dummy); static void etr_work_fn(struct work_struct *work); static DECLARE_WORK(etr_work, etr_work_fn); +/* + * The etr get_clock function. It will write the current clock value + * to the clock pointer and return 0 if the clock is in sync with the + * external time source. If the clock mode is local it will return + * -ENOSYS and -EAGAIN if the clock is not in sync with the external + * reference. This function is what ETR is all about.. + */ +int get_sync_clock(unsigned long long *clock) +{ + atomic_t *sw_ptr; + unsigned int sw0, sw1; + + sw_ptr = &get_cpu_var(etr_sync_word); + sw0 = atomic_read(sw_ptr); + *clock = get_clock(); + sw1 = atomic_read(sw_ptr); + put_cpu_var(etr_sync_sync); + if (sw0 == sw1 && (sw0 & 0x80000000U)) + /* Success: time is in sync. */ + return 0; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; + if (test_bit(ETR_FLAG_EACCES, &etr_flags)) + return -EACCES; + return -EAGAIN; +} +EXPORT_SYMBOL(get_sync_clock); + +/* + * Make get_sync_clock return -EAGAIN. + */ +static void etr_disable_sync_clock(void *dummy) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + /* + * Clear the in-sync bit 2^31. All get_sync_clock calls will + * fail until the sync bit is turned back on. In addition + * increase the "sequence" counter to avoid the race of an + * etr event and the complete recovery against get_sync_clock. + */ + atomic_clear_mask(0x80000000, sw_ptr); + atomic_inc(sw_ptr); +} + +/* + * Make get_sync_clock return 0 again. + * Needs to be called from a context disabled for preemption. + */ +static void etr_enable_sync_clock(void) +{ + atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word); + atomic_set_mask(0x80000000, sw_ptr); +} + /* * Reset ETR attachment. */ @@ -437,13 +381,15 @@ static void etr_reset(void) .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0, .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0, .es = 0, .sl = 0 }; - if (etr_setr(&etr_eacr) == 0) { + if (etr_setr(&etr_eacr) == 0) etr_tolec = get_clock(); - set_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags); - } else if (etr_port0_online || etr_port1_online) { - printk(KERN_WARNING "Running on non ETR capable " - "machine, only local mode available.\n"); - etr_port0_online = etr_port1_online = 0; + else { + set_bit(ETR_FLAG_ENOSYS, &etr_flags); + if (etr_port0_online || etr_port1_online) { + printk(KERN_WARNING "Running on non ETR capable " + "machine, only local mode available.\n"); + etr_port0_online = etr_port1_online = 0; + } } } @@ -451,12 +397,14 @@ static int __init etr_init(void) { struct etr_aib aib; - if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags)) + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) return 0; /* Check if this machine has the steai instruction. */ if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) - etr_steai_available = 1; + set_bit(ETR_FLAG_STEAI, &etr_flags); setup_timer(&etr_timer, etr_timeout, 0UL); + if (!etr_port0_online && !etr_port1_online) + set_bit(ETR_FLAG_EACCES, &etr_flags); if (etr_port0_online) { set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); schedule_work(&etr_work); @@ -487,8 +435,7 @@ void etr_switch_to_local(void) { if (!etr_eacr.sl) return; - if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); schedule_work(&etr_work); } @@ -503,21 +450,23 @@ void etr_sync_check(void) { if (!etr_eacr.es) return; - if (test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); schedule_work(&etr_work); } /* - * ETR timing alert. There are two causes: + * ETR external interrupt. There are two causes: * 1) port state change, check the usability of the port * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the * sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3) * or ETR-data word 4 (edf4) has changed. */ -static void etr_timing_alert(struct etr_irq_parm *intparm) +static void etr_ext_handler(__u16 code) { + struct etr_interruption_parameter *intparm = + (struct etr_interruption_parameter *) &S390_lowcore.ext_params; + if (intparm->pc0) /* ETR port 0 state change. */ set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); @@ -642,23 +591,58 @@ static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p) return 1; } -struct clock_sync_data { +/* + * The time is "clock". old is what we think the time is. + * Adjust the value by a multiple of jiffies and add the delta to ntp. + * "delay" is an approximation how long the synchronization took. If + * the time correction is positive, then "delay" is subtracted from + * the time difference and only the remaining part is passed to ntp. + */ +static unsigned long long etr_adjust_time(unsigned long long old, + unsigned long long clock, + unsigned long long delay) +{ + unsigned long long delta, ticks; + struct timex adjust; + + if (clock > old) { + /* It is later than we thought. */ + delta = ticks = clock - old; + delta = ticks = (delta < delay) ? 0 : delta - delay; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + adjust.offset = ticks * (1000000 / HZ); + } else { + /* It is earlier than we thought. */ + delta = ticks = old - clock; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + delta = -delta; + adjust.offset = -ticks * (1000000 / HZ); + } + jiffies_timer_cc += delta; + if (adjust.offset != 0) { + printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", + adjust.offset); + adjust.modes = ADJ_OFFSET_SINGLESHOT; + do_adjtimex(&adjust); + } + return delta; +} + +static struct { int in_sync; unsigned long long fixup_cc; -}; +} etr_sync; -static void clock_sync_cpu_start(void *dummy) +static void etr_sync_cpu_start(void *dummy) { - struct clock_sync_data *sync = dummy; - - enable_sync_clock(); + etr_enable_sync_clock(); /* * This looks like a busy wait loop but it isn't. etr_sync_cpus * is called on all other cpus while the TOD clocks is stopped. * __udelay will stop the cpu on an enabled wait psw until the * TOD is running again. */ - while (sync->in_sync == 0) { + while (etr_sync.in_sync == 0) { __udelay(1); /* * A different cpu changes *in_sync. Therefore use @@ -666,17 +650,17 @@ static void clock_sync_cpu_start(void *dummy) */ barrier(); } - if (sync->in_sync != 1) + if (etr_sync.in_sync != 1) /* Didn't work. Clear per-cpu in sync bit again. */ - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); /* * This round of TOD syncing is done. Set the clock comparator * to the next tick and let the processor continue. */ - fixup_clock_comparator(sync->fixup_cc); + fixup_clock_comparator(etr_sync.fixup_cc); } -static void clock_sync_cpu_end(void *dummy) +static void etr_sync_cpu_end(void *dummy) { } @@ -688,7 +672,6 @@ static void clock_sync_cpu_end(void *dummy) static int etr_sync_clock(struct etr_aib *aib, int port) { struct etr_aib *sync_port; - struct clock_sync_data etr_sync; unsigned long long clock, old_clock, delay, delta; int follows; int rc; @@ -707,9 +690,9 @@ static int etr_sync_clock(struct etr_aib *aib, int port) */ memset(&etr_sync, 0, sizeof(etr_sync)); preempt_disable(); - smp_call_function(clock_sync_cpu_start, &etr_sync, 0, 0); + smp_call_function(etr_sync_cpu_start, NULL, 0, 0); local_irq_disable(); - enable_sync_clock(); + etr_enable_sync_clock(); /* Set clock to next OTE. */ __ctl_set_bit(14, 21); @@ -724,13 +707,13 @@ static int etr_sync_clock(struct etr_aib *aib, int port) /* Adjust Linux timing variables. */ delay = (unsigned long long) (aib->edf2.etv - sync_port->edf2.etv) << 32; - delta = adjust_time(old_clock, clock, delay); + delta = etr_adjust_time(old_clock, clock, delay); etr_sync.fixup_cc = delta; fixup_clock_comparator(delta); /* Verify that the clock is properly set. */ if (!etr_aib_follows(sync_port, aib, port)) { /* Didn't work. */ - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); etr_sync.in_sync = -EAGAIN; rc = -EAGAIN; } else { @@ -741,12 +724,12 @@ static int etr_sync_clock(struct etr_aib *aib, int port) /* Could not set the clock ?!? */ __ctl_clear_bit(0, 29); __ctl_clear_bit(14, 21); - disable_sync_clock(NULL); + etr_disable_sync_clock(NULL); etr_sync.in_sync = -EAGAIN; rc = -EAGAIN; } local_irq_enable(); - smp_call_function(clock_sync_cpu_end, NULL, 0, 0); + smp_call_function(etr_sync_cpu_end,NULL,0,0); preempt_enable(); return rc; } @@ -849,7 +832,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, * Do not try to get the alternate port aib if the clock * is not in sync yet. */ - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags) && !eacr.es) + if (!eacr.es) return eacr; /* @@ -857,7 +840,7 @@ static struct etr_eacr etr_handle_update(struct etr_aib *aib, * the other port immediately. If only stetr is available the * data-port bit toggle has to be used. */ - if (etr_steai_available) { + if (test_bit(ETR_FLAG_STEAI, &etr_flags)) { if (eacr.p0 && !etr_port0_uptodate) { etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0); etr_port0_uptodate = 1; @@ -926,10 +909,10 @@ static void etr_work_fn(struct work_struct *work) if (!eacr.ea) { /* Both ports offline. Reset everything. */ eacr.dp = eacr.es = eacr.sl = 0; - on_each_cpu(disable_sync_clock, NULL, 0, 1); + on_each_cpu(etr_disable_sync_clock, NULL, 0, 1); del_timer_sync(&etr_timer); etr_update_eacr(eacr); - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); + set_bit(ETR_FLAG_EACCES, &etr_flags); return; } @@ -970,6 +953,7 @@ static void etr_work_fn(struct work_struct *work) eacr.e1 = 1; sync_port = (etr_port0_uptodate && etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) { eacr.sl = 0; eacr.e0 = 0; @@ -978,6 +962,7 @@ static void etr_work_fn(struct work_struct *work) eacr.es = 0; sync_port = (etr_port1_uptodate && etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) { eacr.sl = 1; eacr.e0 = 1; @@ -991,6 +976,7 @@ static void etr_work_fn(struct work_struct *work) eacr.e1 = 1; sync_port = (etr_port0_uptodate && etr_port_valid(&etr_port0, 0)) ? 0 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) { eacr.sl = 1; eacr.e0 = 0; @@ -999,22 +985,19 @@ static void etr_work_fn(struct work_struct *work) eacr.es = 0; sync_port = (etr_port1_uptodate && etr_port_valid(&etr_port1, 1)) ? 1 : -1; + clear_bit(ETR_FLAG_EACCES, &etr_flags); } else { /* Both ports not usable. */ eacr.es = eacr.sl = 0; sync_port = -1; - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); + set_bit(ETR_FLAG_EACCES, &etr_flags); } - if (!test_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - eacr.es = 0; - /* * If the clock is in sync just update the eacr and return. * If there is no valid sync port wait for a port update. */ - if (test_bit(CLOCK_SYNC_STP, &clock_sync_flags) || - eacr.es || sync_port < 0) { + if (eacr.es || sync_port < 0) { etr_update_eacr(eacr); etr_set_tolec_timeout(now); return; @@ -1035,13 +1018,11 @@ static void etr_work_fn(struct work_struct *work) * and set up a timer to try again after 0.5 seconds */ etr_update_eacr(eacr); - set_bit(CLOCK_SYNC_ETR, &clock_sync_flags); if (now < etr_tolec + (1600000 << 12) || etr_sync_clock(&aib, sync_port) != 0) { /* Sync failed. Try again in 1/2 second. */ eacr.es = 0; etr_update_eacr(eacr); - clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); etr_set_sync_timeout(); } else etr_set_tolec_timeout(now); @@ -1116,8 +1097,8 @@ static ssize_t etr_online_store(struct sys_device *dev, value = simple_strtoul(buf, NULL, 0); if (value != 0 && value != 1) return -EINVAL; - if (!test_bit(CLOCK_SYNC_HAS_ETR, &clock_sync_flags)) - return -EOPNOTSUPP; + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; if (dev == &etr_port0_dev) { if (etr_port0_online == value) return count; /* Nothing to do. */ @@ -1311,318 +1292,3 @@ static int __init etr_init_sysfs(void) } device_initcall(etr_init_sysfs); - -/* - * Server Time Protocol (STP) code. - */ -static int stp_online; -static struct stp_sstpi stp_info; -static void *stp_page; - -static void stp_work_fn(struct work_struct *work); -static DECLARE_WORK(stp_work, stp_work_fn); - -static int __init early_parse_stp(char *p) -{ - if (strncmp(p, "off", 3) == 0) - stp_online = 0; - else if (strncmp(p, "on", 2) == 0) - stp_online = 1; - return 0; -} -early_param("stp", early_parse_stp); - -/* - * Reset STP attachment. - */ -static void stp_reset(void) -{ - int rc; - - stp_page = alloc_bootmem_pages(PAGE_SIZE); - rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); - if (rc == 1) - set_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags); - else if (stp_online) { - printk(KERN_WARNING "Running on non STP capable machine.\n"); - free_bootmem((unsigned long) stp_page, PAGE_SIZE); - stp_page = NULL; - stp_online = 0; - } -} - -static int __init stp_init(void) -{ - if (test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags) && stp_online) - schedule_work(&stp_work); - return 0; -} - -arch_initcall(stp_init); - -/* - * STP timing alert. There are three causes: - * 1) timing status change - * 2) link availability change - * 3) time control parameter change - * In all three cases we are only interested in the clock source state. - * If a STP clock source is now available use it. - */ -static void stp_timing_alert(struct stp_irq_parm *intparm) -{ - if (intparm->tsc || intparm->lac || intparm->tcpc) - schedule_work(&stp_work); -} - -/* - * STP sync check machine check. This is called when the timing state - * changes from the synchronized state to the unsynchronized state. - * After a STP sync check the clock is not in sync. The machine check - * is broadcasted to all cpus at the same time. - */ -void stp_sync_check(void) -{ - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return; - disable_sync_clock(NULL); - schedule_work(&stp_work); -} - -/* - * STP island condition machine check. This is called when an attached - * server attempts to communicate over an STP link and the servers - * have matching CTN ids and have a valid stratum-1 configuration - * but the configurations do not match. - */ -void stp_island_check(void) -{ - if (!test_bit(CLOCK_SYNC_STP, &clock_sync_flags)) - return; - disable_sync_clock(NULL); - schedule_work(&stp_work); -} - -/* - * STP tasklet. Check for the STP state and take over the clock - * synchronization if the STP clock source is usable. - */ -static void stp_work_fn(struct work_struct *work) -{ - struct clock_sync_data stp_sync; - unsigned long long old_clock, delta; - int rc; - - if (!stp_online) { - chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); - return; - } - - rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); - if (rc) - return; - - rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); - if (rc || stp_info.c == 0) - return; - - /* - * Catch all other cpus and make them wait until we have - * successfully synced the clock. smp_call_function will - * return after all other cpus are in clock_sync_cpu_start. - */ - memset(&stp_sync, 0, sizeof(stp_sync)); - preempt_disable(); - smp_call_function(clock_sync_cpu_start, &stp_sync, 0, 0); - local_irq_disable(); - enable_sync_clock(); - - set_bit(CLOCK_SYNC_STP, &clock_sync_flags); - if (test_and_clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags)) - schedule_work(&etr_work); - - rc = 0; - if (stp_info.todoff[0] || stp_info.todoff[1] || - stp_info.todoff[2] || stp_info.todoff[3] || - stp_info.tmd != 2) { - old_clock = get_clock(); - rc = chsc_sstpc(stp_page, STP_OP_SYNC, 0); - if (rc == 0) { - delta = adjust_time(old_clock, get_clock(), 0); - fixup_clock_comparator(delta); - rc = chsc_sstpi(stp_page, &stp_info, - sizeof(struct stp_sstpi)); - if (rc == 0 && stp_info.tmd != 2) - rc = -EAGAIN; - } - } - if (rc) { - disable_sync_clock(NULL); - stp_sync.in_sync = -EAGAIN; - clear_bit(CLOCK_SYNC_STP, &clock_sync_flags); - if (etr_port0_online || etr_port1_online) - schedule_work(&etr_work); - } else - stp_sync.in_sync = 1; - - local_irq_enable(); - smp_call_function(clock_sync_cpu_end, NULL, 0, 0); - preempt_enable(); -} - -/* - * STP class sysfs interface functions - */ -static struct sysdev_class stp_sysclass = { - .name = "stp", -}; - -static ssize_t stp_ctn_id_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%016llx\n", - *(unsigned long long *) stp_info.ctnid); -} - -static SYSDEV_CLASS_ATTR(ctn_id, 0400, stp_ctn_id_show, NULL); - -static ssize_t stp_ctn_type_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", stp_info.ctn); -} - -static SYSDEV_CLASS_ATTR(ctn_type, 0400, stp_ctn_type_show, NULL); - -static ssize_t stp_dst_offset_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x2000)) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.dsto); -} - -static SYSDEV_CLASS_ATTR(dst_offset, 0400, stp_dst_offset_show, NULL); - -static ssize_t stp_leap_seconds_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x8000)) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.leaps); -} - -static SYSDEV_CLASS_ATTR(leap_seconds, 0400, stp_leap_seconds_show, NULL); - -static ssize_t stp_stratum_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.stratum); -} - -static SYSDEV_CLASS_ATTR(stratum, 0400, stp_stratum_show, NULL); - -static ssize_t stp_time_offset_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x0800)) - return -ENODATA; - return sprintf(buf, "%i\n", (int) stp_info.tto); -} - -static SYSDEV_CLASS_ATTR(time_offset, 0400, stp_time_offset_show, NULL); - -static ssize_t stp_time_zone_offset_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online || !(stp_info.vbits & 0x4000)) - return -ENODATA; - return sprintf(buf, "%i\n", (int)(s16) stp_info.tzo); -} - -static SYSDEV_CLASS_ATTR(time_zone_offset, 0400, - stp_time_zone_offset_show, NULL); - -static ssize_t stp_timing_mode_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", stp_info.tmd); -} - -static SYSDEV_CLASS_ATTR(timing_mode, 0400, stp_timing_mode_show, NULL); - -static ssize_t stp_timing_state_show(struct sysdev_class *class, char *buf) -{ - if (!stp_online) - return -ENODATA; - return sprintf(buf, "%i\n", stp_info.tst); -} - -static SYSDEV_CLASS_ATTR(timing_state, 0400, stp_timing_state_show, NULL); - -static ssize_t stp_online_show(struct sysdev_class *class, char *buf) -{ - return sprintf(buf, "%i\n", stp_online); -} - -static ssize_t stp_online_store(struct sysdev_class *class, - const char *buf, size_t count) -{ - unsigned int value; - - value = simple_strtoul(buf, NULL, 0); - if (value != 0 && value != 1) - return -EINVAL; - if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) - return -EOPNOTSUPP; - stp_online = value; - schedule_work(&stp_work); - return count; -} - -/* - * Can't use SYSDEV_CLASS_ATTR because the attribute should be named - * stp/online but attr_online already exists in this file .. - */ -static struct sysdev_class_attribute attr_stp_online = { - .attr = { .name = "online", .mode = 0600 }, - .show = stp_online_show, - .store = stp_online_store, -}; - -static struct sysdev_class_attribute *stp_attributes[] = { - &attr_ctn_id, - &attr_ctn_type, - &attr_dst_offset, - &attr_leap_seconds, - &attr_stp_online, - &attr_stratum, - &attr_time_offset, - &attr_time_zone_offset, - &attr_timing_mode, - &attr_timing_state, - NULL -}; - -static int __init stp_init_sysfs(void) -{ - struct sysdev_class_attribute **attr; - int rc; - - rc = sysdev_class_register(&stp_sysclass); - if (rc) - goto out; - for (attr = stp_attributes; *attr; attr++) { - rc = sysdev_class_create_file(&stp_sysclass, *attr); - if (rc) - goto out_unreg; - } - return 0; -out_unreg: - for (; attr >= stp_attributes; attr--) - sysdev_class_remove_file(&stp_sysclass, *attr); - sysdev_class_unregister(&stp_sysclass); -out: - return rc; -} - -device_initcall(stp_init_sysfs); diff --git a/trunk/arch/s390/kernel/topology.c b/trunk/arch/s390/kernel/topology.c index 212d618b0095..661a07217057 100644 --- a/trunk/arch/s390/kernel/topology.c +++ b/trunk/arch/s390/kernel/topology.c @@ -313,6 +313,8 @@ void __init s390_init_cpu_topology(void) machine_has_topology_irq = 1; tl_info = alloc_bootmem_pages(PAGE_SIZE); + if (!tl_info) + goto error; info = tl_info; stsi(info, 15, 1, 2); diff --git a/trunk/arch/s390/kernel/vtime.c b/trunk/arch/s390/kernel/vtime.c index 0fa5dc5d68e1..ca90ee3f930e 100644 --- a/trunk/arch/s390/kernel/vtime.c +++ b/trunk/arch/s390/kernel/vtime.c @@ -136,7 +136,7 @@ static inline void set_vtimer(__u64 expires) } #endif -void vtime_start_cpu_timer(void) +static void start_cpu_timer(void) { struct vtimer_queue *vt_list; @@ -150,7 +150,7 @@ void vtime_start_cpu_timer(void) set_vtimer(vt_list->idle); } -void vtime_stop_cpu_timer(void) +static void stop_cpu_timer(void) { struct vtimer_queue *vt_list; @@ -318,7 +318,8 @@ static void internal_add_vtimer(struct vtimer_list *timer) vt_list = &per_cpu(virt_cpu_timer, timer->cpu); spin_lock_irqsave(&vt_list->lock, flags); - BUG_ON(timer->cpu != smp_processor_id()); + if (timer->cpu != smp_processor_id()) + printk("internal_add_vtimer: BUG, running on wrong CPU"); /* if list is empty we only have to set the timer */ if (list_empty(&vt_list->list)) { @@ -352,12 +353,25 @@ static void internal_add_vtimer(struct vtimer_list *timer) put_cpu(); } -static inline void prepare_vtimer(struct vtimer_list *timer) +static inline int prepare_vtimer(struct vtimer_list *timer) { - BUG_ON(!timer->function); - BUG_ON(!timer->expires || timer->expires > VTIMER_MAX_SLICE); - BUG_ON(vtimer_pending(timer)); + if (!timer->function) { + printk("add_virt_timer: uninitialized timer\n"); + return -EINVAL; + } + + if (!timer->expires || timer->expires > VTIMER_MAX_SLICE) { + printk("add_virt_timer: invalid timer expire value!\n"); + return -EINVAL; + } + + if (vtimer_pending(timer)) { + printk("add_virt_timer: timer pending\n"); + return -EBUSY; + } + timer->cpu = get_cpu(); + return 0; } /* @@ -368,7 +382,10 @@ void add_virt_timer(void *new) struct vtimer_list *timer; timer = (struct vtimer_list *)new; - prepare_vtimer(timer); + + if (prepare_vtimer(timer) < 0) + return; + timer->interval = 0; internal_add_vtimer(timer); } @@ -382,7 +399,10 @@ void add_virt_timer_periodic(void *new) struct vtimer_list *timer; timer = (struct vtimer_list *)new; - prepare_vtimer(timer); + + if (prepare_vtimer(timer) < 0) + return; + timer->interval = timer->expires; internal_add_vtimer(timer); } @@ -403,8 +423,15 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) unsigned long flags; int cpu; - BUG_ON(!timer->function); - BUG_ON(!expires || expires > VTIMER_MAX_SLICE); + if (!timer->function) { + printk("mod_virt_timer: uninitialized timer\n"); + return -EINVAL; + } + + if (!expires || expires > VTIMER_MAX_SLICE) { + printk("mod_virt_timer: invalid expire range\n"); + return -EINVAL; + } /* * This is a common optimization triggered by the @@ -417,9 +444,6 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) cpu = get_cpu(); vt_list = &per_cpu(virt_cpu_timer, cpu); - /* check if we run on the right CPU */ - BUG_ON(timer->cpu != cpu); - /* disable interrupts before test if timer is pending */ spin_lock_irqsave(&vt_list->lock, flags); @@ -434,6 +458,14 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires) return 0; } + /* check if we run on the right CPU */ + if (timer->cpu != cpu) { + printk("mod_virt_timer: running on wrong CPU, check your code\n"); + spin_unlock_irqrestore(&vt_list->lock, flags); + put_cpu(); + return -EINVAL; + } + list_del_init(&timer->entry); timer->expires = expires; @@ -504,6 +536,24 @@ void init_cpu_vtimer(void) } +static int vtimer_idle_notify(struct notifier_block *self, + unsigned long action, void *hcpu) +{ + switch (action) { + case S390_CPU_IDLE: + stop_cpu_timer(); + break; + case S390_CPU_NOT_IDLE: + start_cpu_timer(); + break; + } + return NOTIFY_OK; +} + +static struct notifier_block vtimer_idle_nb = { + .notifier_call = vtimer_idle_notify, +}; + void __init vtime_init(void) { /* request the cpu timer external interrupt */ @@ -511,6 +561,9 @@ void __init vtime_init(void) &ext_int_info_timer) != 0) panic("Couldn't request external interrupt 0x1005"); + if (register_idle_notifier(&vtimer_idle_nb)) + panic("Couldn't register idle notifier"); + /* Enable cpu timer interrupts on the boot cpu. */ init_cpu_vtimer(); } diff --git a/trunk/arch/s390/mm/init.c b/trunk/arch/s390/mm/init.c index 388cc7420055..05598649b326 100644 --- a/trunk/arch/s390/mm/init.c +++ b/trunk/arch/s390/mm/init.c @@ -202,22 +202,3 @@ void free_initrd_mem(unsigned long start, unsigned long end) } } #endif - -#ifdef CONFIG_MEMORY_HOTPLUG -int arch_add_memory(int nid, u64 start, u64 size) -{ - struct pglist_data *pgdat; - struct zone *zone; - int rc; - - pgdat = NODE_DATA(nid); - zone = pgdat->node_zones + ZONE_NORMAL; - rc = vmem_add_mapping(start, size); - if (rc) - return rc; - rc = __add_pages(zone, PFN_DOWN(start), PFN_DOWN(size)); - if (rc) - vmem_remove_mapping(start, size); - return rc; -} -#endif /* CONFIG_MEMORY_HOTPLUG */ diff --git a/trunk/arch/x86/kernel/traps_64.c b/trunk/arch/x86/kernel/traps_64.c index f1a95d105953..adff76ea97c4 100644 --- a/trunk/arch/x86/kernel/traps_64.c +++ b/trunk/arch/x86/kernel/traps_64.c @@ -104,7 +104,30 @@ int kstack_depth_to_print = 12; void printk_address(unsigned long address, int reliable) { - printk(" [<%016lx>] %s%pS\n", address, reliable ? "": "? ", (void *) address); +#ifdef CONFIG_KALLSYMS + unsigned long offset = 0, symsize; + const char *symname; + char *modname; + char *delim = ":"; + char namebuf[KSYM_NAME_LEN]; + char reliab[4] = ""; + + symname = kallsyms_lookup(address, &symsize, &offset, + &modname, namebuf); + if (!symname) { + printk(" [<%016lx>]\n", address); + return; + } + if (!reliable) + strcpy(reliab, "? "); + + if (!modname) + modname = delim = ""; + printk(" [<%016lx>] %s%s%s%s%s+0x%lx/0x%lx\n", + address, reliab, delim, modname, delim, symname, offset, symsize); +#else + printk(" [<%016lx>]\n", address); +#endif } static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, diff --git a/trunk/block/Kconfig b/trunk/block/Kconfig index 1ab7c15c8d7a..3e97f2bc446f 100644 --- a/trunk/block/Kconfig +++ b/trunk/block/Kconfig @@ -81,18 +81,6 @@ config BLK_DEV_BSG If unsure, say N. -config BLK_DEV_INTEGRITY - bool "Block layer data integrity support" - ---help--- - Some storage devices allow extra information to be - stored/retrieved to help protect the data. The block layer - data integrity option provides hooks which can be used by - filesystems to ensure better data integrity. - - Say yes here if you have a storage device that provides the - T10/SCSI Data Integrity Field or the T13/ATA External Path - Protection. If in doubt, say N. - endif # BLOCK config BLOCK_COMPAT diff --git a/trunk/block/Makefile b/trunk/block/Makefile index 208000b0750d..5a43c7d79594 100644 --- a/trunk/block/Makefile +++ b/trunk/block/Makefile @@ -4,8 +4,7 @@ obj-$(CONFIG_BLOCK) := elevator.o blk-core.o blk-tag.o blk-sysfs.o \ blk-barrier.o blk-settings.o blk-ioc.o blk-map.o \ - blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o \ - cmd-filter.o + blk-exec.o blk-merge.o ioctl.o genhd.o scsi_ioctl.o obj-$(CONFIG_BLK_DEV_BSG) += bsg.o obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o @@ -15,4 +14,3 @@ obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o obj-$(CONFIG_BLK_DEV_IO_TRACE) += blktrace.o obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o -obj-$(CONFIG_BLK_DEV_INTEGRITY) += blk-integrity.o diff --git a/trunk/block/as-iosched.c b/trunk/block/as-iosched.c index 9735acb5b4f5..743f33a01a07 100644 --- a/trunk/block/as-iosched.c +++ b/trunk/block/as-iosched.c @@ -151,7 +151,6 @@ enum arq_state { static DEFINE_PER_CPU(unsigned long, ioc_count); static struct completion *ioc_gone; -static DEFINE_SPINLOCK(ioc_gone_lock); static void as_move_to_dispatch(struct as_data *ad, struct request *rq); static void as_antic_stop(struct as_data *ad); @@ -165,19 +164,8 @@ static void free_as_io_context(struct as_io_context *aic) { kfree(aic); elv_ioc_count_dec(ioc_count); - if (ioc_gone) { - /* - * AS scheduler is exiting, grab exit lock and check - * the pending io context count. If it hits zero, - * complete ioc_gone and set it back to NULL. - */ - spin_lock(&ioc_gone_lock); - if (ioc_gone && !elv_ioc_count_read(ioc_count)) { - complete(ioc_gone); - ioc_gone = NULL; - } - spin_unlock(&ioc_gone_lock); - } + if (ioc_gone && !elv_ioc_count_read(ioc_count)) + complete(ioc_gone); } static void as_trim(struct io_context *ioc) @@ -1505,7 +1493,7 @@ static void __exit as_exit(void) /* ioc_gone's update must be visible before reading ioc_count */ smp_wmb(); if (elv_ioc_count_read(ioc_count)) - wait_for_completion(&all_gone); + wait_for_completion(ioc_gone); synchronize_rcu(); } diff --git a/trunk/block/blk-core.c b/trunk/block/blk-core.c index dbc7f42b5d2b..1905aaba49fb 100644 --- a/trunk/block/blk-core.c +++ b/trunk/block/blk-core.c @@ -143,10 +143,6 @@ static void req_bio_endio(struct request *rq, struct bio *bio, bio->bi_size -= nbytes; bio->bi_sector += (nbytes >> 9); - - if (bio_integrity(bio)) - bio_integrity_advance(bio, nbytes); - if (bio->bi_size == 0) bio_endio(bio, error); } else { @@ -205,7 +201,8 @@ void blk_plug_device(struct request_queue *q) if (blk_queue_stopped(q)) return; - if (!queue_flag_test_and_set(QUEUE_FLAG_PLUGGED, q)) { + if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) { + __set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags); mod_timer(&q->unplug_timer, jiffies + q->unplug_delay); blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG); } @@ -220,9 +217,10 @@ int blk_remove_plug(struct request_queue *q) { WARN_ON(!irqs_disabled()); - if (!queue_flag_test_and_clear(QUEUE_FLAG_PLUGGED, q)) + if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) return 0; + queue_flag_clear(QUEUE_FLAG_PLUGGED, q); del_timer(&q->unplug_timer); return 1; } @@ -326,7 +324,8 @@ void blk_start_queue(struct request_queue *q) * one level of recursion is ok and is much faster than kicking * the unplug handling */ - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { + if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { + queue_flag_set(QUEUE_FLAG_REENTER, q); q->request_fn(q); queue_flag_clear(QUEUE_FLAG_REENTER, q); } else { @@ -391,7 +390,8 @@ void __blk_run_queue(struct request_queue *q) * handling reinvoke the handler shortly if we already got there. */ if (!elv_queue_empty(q)) { - if (!queue_flag_test_and_set(QUEUE_FLAG_REENTER, q)) { + if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) { + queue_flag_set(QUEUE_FLAG_REENTER, q); q->request_fn(q); queue_flag_clear(QUEUE_FLAG_REENTER, q); } else { @@ -1381,9 +1381,6 @@ static inline void __generic_make_request(struct bio *bio) */ blk_partition_remap(bio); - if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) - goto end_io; - if (old_sector != -1) blk_add_trace_remap(q, bio, old_dev, bio->bi_sector, old_sector); diff --git a/trunk/block/blk-integrity.c b/trunk/block/blk-integrity.c deleted file mode 100644 index 3f1a8478cc38..000000000000 --- a/trunk/block/blk-integrity.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * blk-integrity.c - Block layer data integrity extensions - * - * Copyright (C) 2007, 2008 Oracle Corporation - * Written by: Martin K. Petersen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - */ - -#include -#include -#include -#include - -#include "blk.h" - -static struct kmem_cache *integrity_cachep; - -/** - * blk_rq_count_integrity_sg - Count number of integrity scatterlist elements - * @rq: request with integrity metadata attached - * - * Description: Returns the number of elements required in a - * scatterlist corresponding to the integrity metadata in a request. - */ -int blk_rq_count_integrity_sg(struct request *rq) -{ - struct bio_vec *iv, *ivprv; - struct req_iterator iter; - unsigned int segments; - - ivprv = NULL; - segments = 0; - - rq_for_each_integrity_segment(iv, rq, iter) { - - if (!ivprv || !BIOVEC_PHYS_MERGEABLE(ivprv, iv)) - segments++; - - ivprv = iv; - } - - return segments; -} -EXPORT_SYMBOL(blk_rq_count_integrity_sg); - -/** - * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist - * @rq: request with integrity metadata attached - * @sglist: target scatterlist - * - * Description: Map the integrity vectors in request into a - * scatterlist. The scatterlist must be big enough to hold all - * elements. I.e. sized using blk_rq_count_integrity_sg(). - */ -int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist) -{ - struct bio_vec *iv, *ivprv; - struct req_iterator iter; - struct scatterlist *sg; - unsigned int segments; - - ivprv = NULL; - sg = NULL; - segments = 0; - - rq_for_each_integrity_segment(iv, rq, iter) { - - if (ivprv) { - if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv)) - goto new_segment; - - sg->length += iv->bv_len; - } else { -new_segment: - if (!sg) - sg = sglist; - else { - sg->page_link &= ~0x02; - sg = sg_next(sg); - } - - sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset); - segments++; - } - - ivprv = iv; - } - - if (sg) - sg_mark_end(sg); - - return segments; -} -EXPORT_SYMBOL(blk_rq_map_integrity_sg); - -/** - * blk_integrity_compare - Compare integrity profile of two block devices - * @b1: Device to compare - * @b2: Device to compare - * - * Description: Meta-devices like DM and MD need to verify that all - * sub-devices use the same integrity format before advertising to - * upper layers that they can send/receive integrity metadata. This - * function can be used to check whether two block devices have - * compatible integrity formats. - */ -int blk_integrity_compare(struct block_device *bd1, struct block_device *bd2) -{ - struct blk_integrity *b1 = bd1->bd_disk->integrity; - struct blk_integrity *b2 = bd2->bd_disk->integrity; - - BUG_ON(bd1->bd_disk == NULL); - BUG_ON(bd2->bd_disk == NULL); - - if (!b1 || !b2) - return 0; - - if (b1->sector_size != b2->sector_size) { - printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->sector_size, b2->sector_size); - return -1; - } - - if (b1->tuple_size != b2->tuple_size) { - printk(KERN_ERR "%s: %s/%s tuple sz %u != %u\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->tuple_size, b2->tuple_size); - return -1; - } - - if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) { - printk(KERN_ERR "%s: %s/%s tag sz %u != %u\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->tag_size, b2->tag_size); - return -1; - } - - if (strcmp(b1->name, b2->name)) { - printk(KERN_ERR "%s: %s/%s type %s != %s\n", __func__, - bd1->bd_disk->disk_name, bd2->bd_disk->disk_name, - b1->name, b2->name); - return -1; - } - - return 0; -} -EXPORT_SYMBOL(blk_integrity_compare); - -struct integrity_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_integrity *, char *); - ssize_t (*store)(struct blk_integrity *, const char *, size_t); -}; - -static ssize_t integrity_attr_show(struct kobject *kobj, struct attribute *attr, - char *page) -{ - struct blk_integrity *bi = - container_of(kobj, struct blk_integrity, kobj); - struct integrity_sysfs_entry *entry = - container_of(attr, struct integrity_sysfs_entry, attr); - - return entry->show(bi, page); -} - -static ssize_t integrity_attr_store(struct kobject *kobj, - struct attribute *attr, const char *page, - size_t count) -{ - struct blk_integrity *bi = - container_of(kobj, struct blk_integrity, kobj); - struct integrity_sysfs_entry *entry = - container_of(attr, struct integrity_sysfs_entry, attr); - ssize_t ret = 0; - - if (entry->store) - ret = entry->store(bi, page, count); - - return ret; -} - -static ssize_t integrity_format_show(struct blk_integrity *bi, char *page) -{ - if (bi != NULL && bi->name != NULL) - return sprintf(page, "%s\n", bi->name); - else - return sprintf(page, "none\n"); -} - -static ssize_t integrity_tag_size_show(struct blk_integrity *bi, char *page) -{ - if (bi != NULL) - return sprintf(page, "%u\n", bi->tag_size); - else - return sprintf(page, "0\n"); -} - -static ssize_t integrity_read_store(struct blk_integrity *bi, - const char *page, size_t count) -{ - char *p = (char *) page; - unsigned long val = simple_strtoul(p, &p, 10); - - if (val) - bi->flags |= INTEGRITY_FLAG_READ; - else - bi->flags &= ~INTEGRITY_FLAG_READ; - - return count; -} - -static ssize_t integrity_read_show(struct blk_integrity *bi, char *page) -{ - return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_READ) != 0); -} - -static ssize_t integrity_write_store(struct blk_integrity *bi, - const char *page, size_t count) -{ - char *p = (char *) page; - unsigned long val = simple_strtoul(p, &p, 10); - - if (val) - bi->flags |= INTEGRITY_FLAG_WRITE; - else - bi->flags &= ~INTEGRITY_FLAG_WRITE; - - return count; -} - -static ssize_t integrity_write_show(struct blk_integrity *bi, char *page) -{ - return sprintf(page, "%d\n", (bi->flags & INTEGRITY_FLAG_WRITE) != 0); -} - -static struct integrity_sysfs_entry integrity_format_entry = { - .attr = { .name = "format", .mode = S_IRUGO }, - .show = integrity_format_show, -}; - -static struct integrity_sysfs_entry integrity_tag_size_entry = { - .attr = { .name = "tag_size", .mode = S_IRUGO }, - .show = integrity_tag_size_show, -}; - -static struct integrity_sysfs_entry integrity_read_entry = { - .attr = { .name = "read_verify", .mode = S_IRUGO | S_IWUSR }, - .show = integrity_read_show, - .store = integrity_read_store, -}; - -static struct integrity_sysfs_entry integrity_write_entry = { - .attr = { .name = "write_generate", .mode = S_IRUGO | S_IWUSR }, - .show = integrity_write_show, - .store = integrity_write_store, -}; - -static struct attribute *integrity_attrs[] = { - &integrity_format_entry.attr, - &integrity_tag_size_entry.attr, - &integrity_read_entry.attr, - &integrity_write_entry.attr, - NULL, -}; - -static struct sysfs_ops integrity_ops = { - .show = &integrity_attr_show, - .store = &integrity_attr_store, -}; - -static int __init blk_dev_integrity_init(void) -{ - integrity_cachep = kmem_cache_create("blkdev_integrity", - sizeof(struct blk_integrity), - 0, SLAB_PANIC, NULL); - return 0; -} -subsys_initcall(blk_dev_integrity_init); - -static void blk_integrity_release(struct kobject *kobj) -{ - struct blk_integrity *bi = - container_of(kobj, struct blk_integrity, kobj); - - kmem_cache_free(integrity_cachep, bi); -} - -static struct kobj_type integrity_ktype = { - .default_attrs = integrity_attrs, - .sysfs_ops = &integrity_ops, - .release = blk_integrity_release, -}; - -/** - * blk_integrity_register - Register a gendisk as being integrity-capable - * @disk: struct gendisk pointer to make integrity-aware - * @template: integrity profile - * - * Description: When a device needs to advertise itself as being able - * to send/receive integrity metadata it must use this function to - * register the capability with the block layer. The template is a - * blk_integrity struct with values appropriate for the underlying - * hardware. See Documentation/block/data-integrity.txt. - */ -int blk_integrity_register(struct gendisk *disk, struct blk_integrity *template) -{ - struct blk_integrity *bi; - - BUG_ON(disk == NULL); - BUG_ON(template == NULL); - - if (disk->integrity == NULL) { - bi = kmem_cache_alloc(integrity_cachep, - GFP_KERNEL | __GFP_ZERO); - if (!bi) - return -1; - - if (kobject_init_and_add(&bi->kobj, &integrity_ktype, - &disk->dev.kobj, "%s", "integrity")) { - kmem_cache_free(integrity_cachep, bi); - return -1; - } - - kobject_uevent(&bi->kobj, KOBJ_ADD); - - bi->flags |= INTEGRITY_FLAG_READ | INTEGRITY_FLAG_WRITE; - bi->sector_size = disk->queue->hardsect_size; - disk->integrity = bi; - } else - bi = disk->integrity; - - /* Use the provided profile as template */ - bi->name = template->name; - bi->generate_fn = template->generate_fn; - bi->verify_fn = template->verify_fn; - bi->tuple_size = template->tuple_size; - bi->set_tag_fn = template->set_tag_fn; - bi->get_tag_fn = template->get_tag_fn; - bi->tag_size = template->tag_size; - - return 0; -} -EXPORT_SYMBOL(blk_integrity_register); - -/** - * blk_integrity_unregister - Remove block integrity profile - * @disk: disk whose integrity profile to deallocate - * - * Description: This function frees all memory used by the block - * integrity profile. To be called at device teardown. - */ -void blk_integrity_unregister(struct gendisk *disk) -{ - struct blk_integrity *bi; - - if (!disk || !disk->integrity) - return; - - bi = disk->integrity; - - kobject_uevent(&bi->kobj, KOBJ_REMOVE); - kobject_del(&bi->kobj); - kobject_put(&disk->dev.kobj); - kmem_cache_free(integrity_cachep, bi); -} -EXPORT_SYMBOL(blk_integrity_unregister); diff --git a/trunk/block/blk-map.c b/trunk/block/blk-map.c index ddd96fb11a7d..0b1af5a3537c 100644 --- a/trunk/block/blk-map.c +++ b/trunk/block/blk-map.c @@ -210,7 +210,6 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, if (!bio_flagged(bio, BIO_USER_MAPPED)) rq->cmd_flags |= REQ_COPY_USER; - blk_queue_bounce(q, &bio); bio_get(bio); blk_rq_bio_prep(q, rq, bio); rq->buffer = rq->data = NULL; @@ -269,7 +268,6 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, int reading = rq_data_dir(rq) == READ; int do_copy = 0; struct bio *bio; - unsigned long stack_mask = ~(THREAD_SIZE - 1); if (len > (q->max_hw_sectors << 9)) return -EINVAL; @@ -280,10 +278,6 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, alignment = queue_dma_alignment(q) | q->dma_pad_mask; do_copy = ((kaddr & alignment) || (len & alignment)); - if (!((kaddr & stack_mask) ^ - ((unsigned long)current->stack & stack_mask))) - do_copy = 1; - if (do_copy) bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading); else diff --git a/trunk/block/blk-merge.c b/trunk/block/blk-merge.c index 5efc9e7a68b7..651136aae76e 100644 --- a/trunk/block/blk-merge.c +++ b/trunk/block/blk-merge.c @@ -441,9 +441,6 @@ static int attempt_merge(struct request_queue *q, struct request *req, || next->special) return 0; - if (blk_integrity_rq(req) != blk_integrity_rq(next)) - return 0; - /* * If we are allowed to merge, then append bio list * from next to rq and release next. merge_requests_fn diff --git a/trunk/block/blk-settings.c b/trunk/block/blk-settings.c index dfc77012843f..8dd86418f35d 100644 --- a/trunk/block/blk-settings.c +++ b/trunk/block/blk-settings.c @@ -302,10 +302,11 @@ EXPORT_SYMBOL(blk_queue_stack_limits); * @q: the request queue for the device * @mask: pad mask * - * Set dma pad mask. + * Set pad mask. Direct IO requests are padded to the mask specified. * - * Appending pad buffer to a request modifies the last entry of a - * scatter list such that it includes the pad buffer. + * Appending pad buffer to a request modifies ->data_len such that it + * includes the pad buffer. The original requested data length can be + * obtained using blk_rq_raw_data_len(). **/ void blk_queue_dma_pad(struct request_queue *q, unsigned int mask) { @@ -313,23 +314,6 @@ void blk_queue_dma_pad(struct request_queue *q, unsigned int mask) } EXPORT_SYMBOL(blk_queue_dma_pad); -/** - * blk_queue_update_dma_pad - update pad mask - * @q: the request queue for the device - * @mask: pad mask - * - * Update dma pad mask. - * - * Appending pad buffer to a request modifies the last entry of a - * scatter list such that it includes the pad buffer. - **/ -void blk_queue_update_dma_pad(struct request_queue *q, unsigned int mask) -{ - if (mask > q->dma_pad_mask) - q->dma_pad_mask = mask; -} -EXPORT_SYMBOL(blk_queue_update_dma_pad); - /** * blk_queue_dma_drain - Set up a drain buffer for excess dma. * @q: the request queue for the device diff --git a/trunk/block/blk.h b/trunk/block/blk.h index c79f30e1df52..59776ab4742a 100644 --- a/trunk/block/blk.h +++ b/trunk/block/blk.h @@ -51,12 +51,4 @@ static inline int queue_congestion_off_threshold(struct request_queue *q) return q->nr_congestion_off; } -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -#define rq_for_each_integrity_segment(bvl, _rq, _iter) \ - __rq_for_each_bio(_iter.bio, _rq) \ - bip_for_each_vec(bvl, _iter.bio->bi_integrity, _iter.i) - -#endif /* BLK_DEV_INTEGRITY */ - #endif diff --git a/trunk/block/blktrace.c b/trunk/block/blktrace.c index eb9651ccb241..8d3a27780260 100644 --- a/trunk/block/blktrace.c +++ b/trunk/block/blktrace.c @@ -244,7 +244,6 @@ static struct dentry *blk_create_tree(const char *blk_name) static void blk_trace_cleanup(struct blk_trace *bt) { relay_close(bt->rchan); - debugfs_remove(bt->msg_file); debugfs_remove(bt->dropped_file); blk_remove_tree(bt->dir); free_percpu(bt->sequence); @@ -292,44 +291,6 @@ static const struct file_operations blk_dropped_fops = { .read = blk_dropped_read, }; -static int blk_msg_open(struct inode *inode, struct file *filp) -{ - filp->private_data = inode->i_private; - - return 0; -} - -static ssize_t blk_msg_write(struct file *filp, const char __user *buffer, - size_t count, loff_t *ppos) -{ - char *msg; - struct blk_trace *bt; - - if (count > BLK_TN_MAX_MSG) - return -EINVAL; - - msg = kmalloc(count, GFP_KERNEL); - if (msg == NULL) - return -ENOMEM; - - if (copy_from_user(msg, buffer, count)) { - kfree(msg); - return -EFAULT; - } - - bt = filp->private_data; - __trace_note_message(bt, "%s", msg); - kfree(msg); - - return count; -} - -static const struct file_operations blk_msg_fops = { - .owner = THIS_MODULE, - .open = blk_msg_open, - .write = blk_msg_write, -}; - /* * Keep track of how many times we encountered a full subbuffer, to aid * the user space app in telling how many lost events there were. @@ -419,10 +380,6 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, if (!bt->dropped_file) goto err; - bt->msg_file = debugfs_create_file("msg", 0222, dir, bt, &blk_msg_fops); - if (!bt->msg_file) - goto err; - bt->rchan = relay_open("trace", dir, buts->buf_size, buts->buf_nr, &blk_relay_callbacks, bt); if (!bt->rchan) @@ -452,8 +409,6 @@ int do_blk_trace_setup(struct request_queue *q, char *name, dev_t dev, if (dir) blk_remove_tree(dir); if (bt) { - if (bt->msg_file) - debugfs_remove(bt->msg_file); if (bt->dropped_file) debugfs_remove(bt->dropped_file); free_percpu(bt->sequence); diff --git a/trunk/block/bsg.c b/trunk/block/bsg.c index 93e757d7174b..54d617f7df3e 100644 --- a/trunk/block/bsg.c +++ b/trunk/block/bsg.c @@ -44,12 +44,11 @@ struct bsg_device { char name[BUS_ID_SIZE]; int max_queue; unsigned long flags; - struct blk_scsi_cmd_filter *cmd_filter; - mode_t *f_mode; }; enum { BSG_F_BLOCK = 1, + BSG_F_WRITE_PERM = 2, }; #define BSG_DEFAULT_CMDS 64 @@ -173,7 +172,7 @@ static int bsg_io_schedule(struct bsg_device *bd) } static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, - struct sg_io_v4 *hdr, struct bsg_device *bd) + struct sg_io_v4 *hdr, int has_write_perm) { if (hdr->request_len > BLK_MAX_CDB) { rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL); @@ -186,8 +185,7 @@ static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, return -EFAULT; if (hdr->subprotocol == BSG_SUB_PROTOCOL_SCSI_CMD) { - if (blk_cmd_filter_verify_command(bd->cmd_filter, rq->cmd, - bd->f_mode)) + if (blk_verify_command(rq->cmd, has_write_perm)) return -EPERM; } else if (!capable(CAP_SYS_RAWIO)) return -EPERM; @@ -265,7 +263,8 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr) rq = blk_get_request(q, rw, GFP_KERNEL); if (!rq) return ERR_PTR(-ENOMEM); - ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, bd); + ret = blk_fill_sgv4_hdr_rq(q, rq, hdr, test_bit(BSG_F_WRITE_PERM, + &bd->flags)); if (ret) goto out; @@ -567,23 +566,12 @@ static inline void bsg_set_block(struct bsg_device *bd, struct file *file) set_bit(BSG_F_BLOCK, &bd->flags); } -static void bsg_set_cmd_filter(struct bsg_device *bd, - struct file *file) +static inline void bsg_set_write_perm(struct bsg_device *bd, struct file *file) { - struct inode *inode; - struct gendisk *disk; - - if (!file) - return; - - inode = file->f_dentry->d_inode; - if (!inode) - return; - - disk = inode->i_bdev->bd_disk; - - bd->cmd_filter = &disk->cmd_filter; - bd->f_mode = &file->f_mode; + if (file->f_mode & FMODE_WRITE) + set_bit(BSG_F_WRITE_PERM, &bd->flags); + else + clear_bit(BSG_F_WRITE_PERM, &bd->flags); } /* @@ -607,8 +595,6 @@ bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) dprintk("%s: read %Zd bytes\n", bd->name, count); bsg_set_block(bd, file); - bsg_set_cmd_filter(bd, file); - bytes_read = 0; ret = __bsg_read(buf, count, bd, NULL, &bytes_read); *ppos = bytes_read; @@ -682,7 +668,7 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) dprintk("%s: write %Zd bytes\n", bd->name, count); bsg_set_block(bd, file); - bsg_set_cmd_filter(bd, file); + bsg_set_write_perm(bd, file); bytes_written = 0; ret = __bsg_write(bd, buf, count, &bytes_written); @@ -786,9 +772,7 @@ static struct bsg_device *bsg_add_device(struct inode *inode, } bd->queue = rq; - bsg_set_block(bd, file); - bsg_set_cmd_filter(bd, file); atomic_set(&bd->ref_count, 1); mutex_lock(&bsg_mutex); diff --git a/trunk/block/cfq-iosched.c b/trunk/block/cfq-iosched.c index 1e2aff812ee2..d01b411c72f0 100644 --- a/trunk/block/cfq-iosched.c +++ b/trunk/block/cfq-iosched.c @@ -11,7 +11,6 @@ #include #include #include -#include /* * tunables @@ -42,14 +41,13 @@ static int cfq_slice_idle = HZ / 125; #define RQ_CIC(rq) \ ((struct cfq_io_context *) (rq)->elevator_private) -#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elevator_private2) +#define RQ_CFQQ(rq) ((rq)->elevator_private2) static struct kmem_cache *cfq_pool; static struct kmem_cache *cfq_ioc_pool; static DEFINE_PER_CPU(unsigned long, ioc_count); static struct completion *ioc_gone; -static DEFINE_SPINLOCK(ioc_gone_lock); #define CFQ_PRIO_LISTS IOPRIO_BE_NR #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) @@ -157,7 +155,6 @@ struct cfq_queue { unsigned short ioprio, org_ioprio; unsigned short ioprio_class, org_ioprio_class; - pid_t pid; }; enum cfqq_state_flags { @@ -201,11 +198,6 @@ CFQ_CFQQ_FNS(slice_new); CFQ_CFQQ_FNS(sync); #undef CFQ_CFQQ_FNS -#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ - blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args) -#define cfq_log(cfqd, fmt, args...) \ - blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args) - static void cfq_dispatch_insert(struct request_queue *, struct request *); static struct cfq_queue *cfq_get_queue(struct cfq_data *, int, struct io_context *, gfp_t); @@ -242,10 +234,8 @@ static inline int cfq_bio_sync(struct bio *bio) */ static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) { - if (cfqd->busy_queues) { - cfq_log(cfqd, "schedule dispatch"); + if (cfqd->busy_queues) kblockd_schedule_work(&cfqd->unplug_work); - } } static int cfq_queue_empty(struct request_queue *q) @@ -280,7 +270,6 @@ static inline void cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) { cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies; - cfq_log_cfqq(cfqd, cfqq, "set_slice=%lu", cfqq->slice_end - jiffies); } /* @@ -550,7 +539,6 @@ static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq) */ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_log_cfqq(cfqd, cfqq, "add_to_rr"); BUG_ON(cfq_cfqq_on_rr(cfqq)); cfq_mark_cfqq_on_rr(cfqq); cfqd->busy_queues++; @@ -564,7 +552,6 @@ static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) */ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_log_cfqq(cfqd, cfqq, "del_from_rr"); BUG_ON(!cfq_cfqq_on_rr(cfqq)); cfq_clear_cfqq_on_rr(cfqq); @@ -651,8 +638,6 @@ static void cfq_activate_request(struct request_queue *q, struct request *rq) struct cfq_data *cfqd = q->elevator->elevator_data; cfqd->rq_in_driver++; - cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d", - cfqd->rq_in_driver); /* * If the depth is larger 1, it really could be queueing. But lets @@ -672,8 +657,6 @@ static void cfq_deactivate_request(struct request_queue *q, struct request *rq) WARN_ON(!cfqd->rq_in_driver); cfqd->rq_in_driver--; - cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d", - cfqd->rq_in_driver); } static void cfq_remove_request(struct request *rq) @@ -763,7 +746,6 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) { if (cfqq) { - cfq_log_cfqq(cfqd, cfqq, "set_active"); cfqq->slice_end = 0; cfq_clear_cfqq_must_alloc_slice(cfqq); cfq_clear_cfqq_fifo_expire(cfqq); @@ -781,8 +763,6 @@ static void __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, int timed_out) { - cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out); - if (cfq_cfqq_wait_request(cfqq)) del_timer(&cfqd->idle_slice_timer); @@ -792,10 +772,8 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, /* * store what was left of this slice, if the queue idled/timed out */ - if (timed_out && !cfq_cfqq_slice_new(cfqq)) { + if (timed_out && !cfq_cfqq_slice_new(cfqq)) cfqq->slice_resid = cfqq->slice_end - jiffies; - cfq_log_cfqq(cfqd, cfqq, "resid=%ld", cfqq->slice_resid); - } cfq_resort_rr_list(cfqd, cfqq); @@ -887,12 +865,6 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) if (!cfqd->cfq_slice_idle || !cfq_cfqq_idle_window(cfqq)) return; - /* - * still requests with the driver, don't idle - */ - if (cfqd->rq_in_driver) - return; - /* * task has exited, don't wait */ @@ -920,7 +892,6 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd) sl = min(sl, msecs_to_jiffies(CFQ_MIN_TT)); mod_timer(&cfqd->idle_slice_timer, jiffies + sl); - cfq_log(cfqd, "arm_idle: %lu", sl); } /* @@ -931,8 +902,6 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = RQ_CFQQ(rq); - cfq_log_cfqq(cfqd, cfqq, "dispatch_insert"); - cfq_remove_request(rq); cfqq->dispatched++; elv_dispatch_sort(q, rq); @@ -962,9 +931,8 @@ static struct request *cfq_check_fifo(struct cfq_queue *cfqq) rq = rq_entry_fifo(cfqq->fifo.next); if (time_before(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) - rq = NULL; + return NULL; - cfq_log_cfqq(cfqd, cfqq, "fifo=%p", rq); return rq; } @@ -1104,7 +1072,6 @@ static int cfq_forced_dispatch(struct cfq_data *cfqd) BUG_ON(cfqd->busy_queues); - cfq_log(cfqd, "forced_dispatch=%d\n", dispatched); return dispatched; } @@ -1145,7 +1112,6 @@ static int cfq_dispatch_requests(struct request_queue *q, int force) dispatched += __cfq_dispatch_requests(cfqd, cfqq, max_dispatch); } - cfq_log(cfqd, "dispatched=%d", dispatched); return dispatched; } @@ -1164,7 +1130,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq) if (!atomic_dec_and_test(&cfqq->ref)) return; - cfq_log_cfqq(cfqd, cfqq, "put_queue"); BUG_ON(rb_first(&cfqq->sort_list)); BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]); BUG_ON(cfq_cfqq_on_rr(cfqq)); @@ -1212,19 +1177,8 @@ static void cfq_cic_free_rcu(struct rcu_head *head) kmem_cache_free(cfq_ioc_pool, cic); elv_ioc_count_dec(ioc_count); - if (ioc_gone) { - /* - * CFQ scheduler is exiting, grab exit lock and check - * the pending io context count. If it hits zero, - * complete ioc_gone and set it back to NULL - */ - spin_lock(&ioc_gone_lock); - if (ioc_gone && !elv_ioc_count_read(ioc_count)) { - complete(ioc_gone); - ioc_gone = NULL; - } - spin_unlock(&ioc_gone_lock); - } + if (ioc_gone && !elv_ioc_count_read(ioc_count)) + complete(ioc_gone); } static void cfq_cic_free(struct cfq_io_context *cic) @@ -1473,8 +1427,6 @@ cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync, cfq_mark_cfqq_idle_window(cfqq); cfq_mark_cfqq_sync(cfqq); } - cfqq->pid = current->pid; - cfq_log_cfqq(cfqd, cfqq, "alloced"); } if (new_cfqq) @@ -1723,7 +1675,7 @@ static void cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct cfq_io_context *cic) { - int old_idle, enable_idle; + int enable_idle; /* * Don't idle for async or idle io prio class @@ -1731,7 +1683,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq)) return; - enable_idle = old_idle = cfq_cfqq_idle_window(cfqq); + enable_idle = cfq_cfqq_idle_window(cfqq); if (!atomic_read(&cic->ioc->nr_tasks) || !cfqd->cfq_slice_idle || (cfqd->hw_tag && CIC_SEEKY(cic))) @@ -1743,13 +1695,10 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, enable_idle = 1; } - if (old_idle != enable_idle) { - cfq_log_cfqq(cfqd, cfqq, "idle=%d", enable_idle); - if (enable_idle) - cfq_mark_cfqq_idle_window(cfqq); - else - cfq_clear_cfqq_idle_window(cfqq); - } + if (enable_idle) + cfq_mark_cfqq_idle_window(cfqq); + else + cfq_clear_cfqq_idle_window(cfqq); } /* @@ -1808,7 +1757,6 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, */ static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) { - cfq_log_cfqq(cfqd, cfqq, "preempt"); cfq_slice_expired(cfqd, 1); /* @@ -1870,7 +1818,6 @@ static void cfq_insert_request(struct request_queue *q, struct request *rq) struct cfq_data *cfqd = q->elevator->elevator_data; struct cfq_queue *cfqq = RQ_CFQQ(rq); - cfq_log_cfqq(cfqd, cfqq, "insert_request"); cfq_init_prio_data(cfqq, RQ_CIC(rq)->ioc); cfq_add_rq_rb(rq); @@ -1888,7 +1835,6 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq) unsigned long now; now = jiffies; - cfq_log_cfqq(cfqd, cfqq, "complete"); WARN_ON(!cfqd->rq_in_driver); WARN_ON(!cfqq->dispatched); @@ -2058,7 +2004,6 @@ cfq_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask) cfq_schedule_dispatch(cfqd); spin_unlock_irqrestore(q->queue_lock, flags); - cfq_log(cfqd, "set_request fail"); return 1; } @@ -2084,8 +2029,6 @@ static void cfq_idle_slice_timer(unsigned long data) unsigned long flags; int timed_out = 1; - cfq_log(cfqd, "idle timer fired"); - spin_lock_irqsave(cfqd->queue->queue_lock, flags); cfqq = cfqd->active_queue; @@ -2374,7 +2317,7 @@ static void __exit cfq_exit(void) * pending RCU callbacks */ if (elv_ioc_count_read(ioc_count)) - wait_for_completion(&all_gone); + wait_for_completion(ioc_gone); cfq_slab_kill(); } diff --git a/trunk/block/cmd-filter.c b/trunk/block/cmd-filter.c deleted file mode 100644 index eec4404fd357..000000000000 --- a/trunk/block/cmd-filter.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2004 Peter M. Jones - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public Licens - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter, - unsigned char *cmd, mode_t *f_mode) -{ - /* root can do any command. */ - if (capable(CAP_SYS_RAWIO)) - return 0; - - /* if there's no filter set, assume we're filtering everything out */ - if (!filter) - return -EPERM; - - /* Anybody who can open the device can do a read-safe command */ - if (test_bit(cmd[0], filter->read_ok)) - return 0; - - /* Write-safe commands require a writable open */ - if (test_bit(cmd[0], filter->write_ok) && (*f_mode & FMODE_WRITE)) - return 0; - - return -EPERM; -} -EXPORT_SYMBOL(blk_cmd_filter_verify_command); - -int blk_verify_command(struct file *file, unsigned char *cmd) -{ - struct gendisk *disk; - struct inode *inode; - - if (!file) - return -EINVAL; - - inode = file->f_dentry->d_inode; - if (!inode) - return -EINVAL; - - disk = inode->i_bdev->bd_disk; - - return blk_cmd_filter_verify_command(&disk->cmd_filter, - cmd, &file->f_mode); -} -EXPORT_SYMBOL(blk_verify_command); - -/* and now, the sysfs stuff */ -static ssize_t rcf_cmds_show(struct blk_scsi_cmd_filter *filter, char *page, - int rw) -{ - char *npage = page; - unsigned long *okbits; - int i; - - if (rw == READ) - okbits = filter->read_ok; - else - okbits = filter->write_ok; - - for (i = 0; i < BLK_SCSI_MAX_CMDS; i++) { - if (test_bit(i, okbits)) { - sprintf(npage, "%02x", i); - npage += 2; - if (i < BLK_SCSI_MAX_CMDS - 1) - sprintf(npage++, " "); - } - } - - if (npage != page) - npage += sprintf(npage, "\n"); - - return npage - page; -} - -static ssize_t rcf_readcmds_show(struct blk_scsi_cmd_filter *filter, char *page) -{ - return rcf_cmds_show(filter, page, READ); -} - -static ssize_t rcf_writecmds_show(struct blk_scsi_cmd_filter *filter, - char *page) -{ - return rcf_cmds_show(filter, page, WRITE); -} - -static ssize_t rcf_cmds_store(struct blk_scsi_cmd_filter *filter, - const char *page, size_t count, int rw) -{ - ssize_t ret = 0; - unsigned long okbits[BLK_SCSI_CMD_PER_LONG], *target_okbits; - int cmd, status, len; - substring_t ss; - - memset(&okbits, 0, sizeof(okbits)); - - for (len = strlen(page); len > 0; len -= 3) { - if (len < 2) - break; - ss.from = (char *) page + ret; - ss.to = (char *) page + ret + 2; - ret += 3; - status = match_hex(&ss, &cmd); - /* either of these cases means invalid input, so do nothing. */ - if (status || cmd >= BLK_SCSI_MAX_CMDS) - return -EINVAL; - - __set_bit(cmd, okbits); - } - - if (rw == READ) - target_okbits = filter->read_ok; - else - target_okbits = filter->write_ok; - - memmove(target_okbits, okbits, sizeof(okbits)); - return count; -} - -static ssize_t rcf_readcmds_store(struct blk_scsi_cmd_filter *filter, - const char *page, size_t count) -{ - return rcf_cmds_store(filter, page, count, READ); -} - -static ssize_t rcf_writecmds_store(struct blk_scsi_cmd_filter *filter, - const char *page, size_t count) -{ - return rcf_cmds_store(filter, page, count, WRITE); -} - -struct rcf_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_scsi_cmd_filter *, char *); - ssize_t (*store)(struct blk_scsi_cmd_filter *, const char *, size_t); -}; - -static struct rcf_sysfs_entry rcf_readcmds_entry = { - .attr = { .name = "read_table", .mode = S_IRUGO | S_IWUSR }, - .show = rcf_readcmds_show, - .store = rcf_readcmds_store, -}; - -static struct rcf_sysfs_entry rcf_writecmds_entry = { - .attr = {.name = "write_table", .mode = S_IRUGO | S_IWUSR }, - .show = rcf_writecmds_show, - .store = rcf_writecmds_store, -}; - -static struct attribute *default_attrs[] = { - &rcf_readcmds_entry.attr, - &rcf_writecmds_entry.attr, - NULL, -}; - -#define to_rcf(atr) container_of((atr), struct rcf_sysfs_entry, attr) - -static ssize_t -rcf_attr_show(struct kobject *kobj, struct attribute *attr, char *page) -{ - struct rcf_sysfs_entry *entry = to_rcf(attr); - struct blk_scsi_cmd_filter *filter; - - filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj); - if (entry->show) - return entry->show(filter, page); - - return 0; -} - -static ssize_t -rcf_attr_store(struct kobject *kobj, struct attribute *attr, - const char *page, size_t length) -{ - struct rcf_sysfs_entry *entry = to_rcf(attr); - struct blk_scsi_cmd_filter *filter; - - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (!entry->store) - return -EINVAL; - - filter = container_of(kobj, struct blk_scsi_cmd_filter, kobj); - return entry->store(filter, page, length); -} - -static struct sysfs_ops rcf_sysfs_ops = { - .show = rcf_attr_show, - .store = rcf_attr_store, -}; - -static struct kobj_type rcf_ktype = { - .sysfs_ops = &rcf_sysfs_ops, - .default_attrs = default_attrs, -}; - -#ifndef MAINTENANCE_IN_CMD -#define MAINTENANCE_IN_CMD 0xa3 -#endif - -static void rcf_set_defaults(struct blk_scsi_cmd_filter *filter) -{ - /* Basic read-only commands */ - __set_bit(TEST_UNIT_READY, filter->read_ok); - __set_bit(REQUEST_SENSE, filter->read_ok); - __set_bit(READ_6, filter->read_ok); - __set_bit(READ_10, filter->read_ok); - __set_bit(READ_12, filter->read_ok); - __set_bit(READ_16, filter->read_ok); - __set_bit(READ_BUFFER, filter->read_ok); - __set_bit(READ_DEFECT_DATA, filter->read_ok); - __set_bit(READ_CAPACITY, filter->read_ok); - __set_bit(READ_LONG, filter->read_ok); - __set_bit(INQUIRY, filter->read_ok); - __set_bit(MODE_SENSE, filter->read_ok); - __set_bit(MODE_SENSE_10, filter->read_ok); - __set_bit(LOG_SENSE, filter->read_ok); - __set_bit(START_STOP, filter->read_ok); - __set_bit(GPCMD_VERIFY_10, filter->read_ok); - __set_bit(VERIFY_16, filter->read_ok); - __set_bit(REPORT_LUNS, filter->read_ok); - __set_bit(SERVICE_ACTION_IN, filter->read_ok); - __set_bit(RECEIVE_DIAGNOSTIC, filter->read_ok); - __set_bit(MAINTENANCE_IN_CMD, filter->read_ok); - __set_bit(GPCMD_READ_BUFFER_CAPACITY, filter->read_ok); - - /* Audio CD commands */ - __set_bit(GPCMD_PLAY_CD, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_10, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_MSF, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_TI, filter->read_ok); - __set_bit(GPCMD_PAUSE_RESUME, filter->read_ok); - - /* CD/DVD data reading */ - __set_bit(GPCMD_READ_CD, filter->read_ok); - __set_bit(GPCMD_READ_CD_MSF, filter->read_ok); - __set_bit(GPCMD_READ_DISC_INFO, filter->read_ok); - __set_bit(GPCMD_READ_CDVD_CAPACITY, filter->read_ok); - __set_bit(GPCMD_READ_DVD_STRUCTURE, filter->read_ok); - __set_bit(GPCMD_READ_HEADER, filter->read_ok); - __set_bit(GPCMD_READ_TRACK_RZONE_INFO, filter->read_ok); - __set_bit(GPCMD_READ_SUBCHANNEL, filter->read_ok); - __set_bit(GPCMD_READ_TOC_PMA_ATIP, filter->read_ok); - __set_bit(GPCMD_REPORT_KEY, filter->read_ok); - __set_bit(GPCMD_SCAN, filter->read_ok); - __set_bit(GPCMD_GET_CONFIGURATION, filter->read_ok); - __set_bit(GPCMD_READ_FORMAT_CAPACITIES, filter->read_ok); - __set_bit(GPCMD_GET_EVENT_STATUS_NOTIFICATION, filter->read_ok); - __set_bit(GPCMD_GET_PERFORMANCE, filter->read_ok); - __set_bit(GPCMD_SEEK, filter->read_ok); - __set_bit(GPCMD_STOP_PLAY_SCAN, filter->read_ok); - - /* Basic writing commands */ - __set_bit(WRITE_6, filter->write_ok); - __set_bit(WRITE_10, filter->write_ok); - __set_bit(WRITE_VERIFY, filter->write_ok); - __set_bit(WRITE_12, filter->write_ok); - __set_bit(WRITE_VERIFY_12, filter->write_ok); - __set_bit(WRITE_16, filter->write_ok); - __set_bit(WRITE_LONG, filter->write_ok); - __set_bit(WRITE_LONG_2, filter->write_ok); - __set_bit(ERASE, filter->write_ok); - __set_bit(GPCMD_MODE_SELECT_10, filter->write_ok); - __set_bit(MODE_SELECT, filter->write_ok); - __set_bit(LOG_SELECT, filter->write_ok); - __set_bit(GPCMD_BLANK, filter->write_ok); - __set_bit(GPCMD_CLOSE_TRACK, filter->write_ok); - __set_bit(GPCMD_FLUSH_CACHE, filter->write_ok); - __set_bit(GPCMD_FORMAT_UNIT, filter->write_ok); - __set_bit(GPCMD_REPAIR_RZONE_TRACK, filter->write_ok); - __set_bit(GPCMD_RESERVE_RZONE_TRACK, filter->write_ok); - __set_bit(GPCMD_SEND_DVD_STRUCTURE, filter->write_ok); - __set_bit(GPCMD_SEND_EVENT, filter->write_ok); - __set_bit(GPCMD_SEND_KEY, filter->write_ok); - __set_bit(GPCMD_SEND_OPC, filter->write_ok); - __set_bit(GPCMD_SEND_CUE_SHEET, filter->write_ok); - __set_bit(GPCMD_SET_SPEED, filter->write_ok); - __set_bit(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, filter->write_ok); - __set_bit(GPCMD_LOAD_UNLOAD, filter->write_ok); - __set_bit(GPCMD_SET_STREAMING, filter->write_ok); -} - -int blk_register_filter(struct gendisk *disk) -{ - int ret; - struct blk_scsi_cmd_filter *filter = &disk->cmd_filter; - struct kobject *parent = kobject_get(disk->holder_dir->parent); - - if (!parent) - return -ENODEV; - - ret = kobject_init_and_add(&filter->kobj, &rcf_ktype, parent, - "%s", "cmd_filter"); - - if (ret < 0) - return ret; - - rcf_set_defaults(filter); - return 0; -} - -void blk_unregister_filter(struct gendisk *disk) -{ - struct blk_scsi_cmd_filter *filter = &disk->cmd_filter; - - kobject_put(&filter->kobj); - kobject_put(disk->holder_dir->parent); -} - diff --git a/trunk/block/elevator.c b/trunk/block/elevator.c index ed6f8f32d27e..902dd1344d56 100644 --- a/trunk/block/elevator.c +++ b/trunk/block/elevator.c @@ -86,12 +86,6 @@ int elv_rq_merge_ok(struct request *rq, struct bio *bio) if (rq->rq_disk != bio->bi_bdev->bd_disk || rq->special) return 0; - /* - * only merge integrity protected bio into ditto rq - */ - if (bio_integrity(bio) != blk_integrity_rq(rq)) - return 0; - if (!elv_iosched_allow_merge(rq, bio)) return 0; @@ -150,7 +144,7 @@ static struct elevator_type *elevator_get(const char *name) else sprintf(elv, "%s-iosched", name); - request_module("%s", elv); + request_module(elv); spin_lock(&elv_list_lock); e = elevator_find(name); } diff --git a/trunk/block/genhd.c b/trunk/block/genhd.c index 9074f384b097..b922d4801c87 100644 --- a/trunk/block/genhd.c +++ b/trunk/block/genhd.c @@ -189,7 +189,6 @@ void add_disk(struct gendisk *disk) disk->minors, NULL, exact_match, exact_lock, disk); register_disk(disk); blk_register_queue(disk); - blk_register_filter(disk); bdi = &disk->queue->backing_dev_info; bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor)); @@ -201,7 +200,6 @@ EXPORT_SYMBOL(del_gendisk); /* in partitions/check.c */ void unlink_gendisk(struct gendisk *disk) { - blk_unregister_filter(disk); sysfs_remove_link(&disk->dev.kobj, "bdi"); bdi_unregister(&disk->queue->backing_dev_info); blk_unregister_queue(disk); @@ -402,14 +400,6 @@ static ssize_t disk_removable_show(struct device *dev, (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); } -static ssize_t disk_ro_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", disk->policy ? 1 : 0); -} - static ssize_t disk_size_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -482,7 +472,6 @@ static ssize_t disk_fail_store(struct device *dev, static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); -static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); static DEVICE_ATTR(size, S_IRUGO, disk_size_show, NULL); static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); static DEVICE_ATTR(stat, S_IRUGO, disk_stat_show, NULL); @@ -494,7 +483,6 @@ static struct device_attribute dev_attr_fail = static struct attribute *disk_attrs[] = { &dev_attr_range.attr, &dev_attr_removable.attr, - &dev_attr_ro.attr, &dev_attr_size.attr, &dev_attr_capability.attr, &dev_attr_stat.attr, diff --git a/trunk/block/scsi_ioctl.c b/trunk/block/scsi_ioctl.c index c5b9bcfc0a6d..78199c08ec92 100644 --- a/trunk/block/scsi_ioctl.c +++ b/trunk/block/scsi_ioctl.c @@ -105,12 +105,120 @@ static int sg_emulated_host(struct request_queue *q, int __user *p) return put_user(1, p); } +#define CMD_READ_SAFE 0x01 +#define CMD_WRITE_SAFE 0x02 +#define CMD_WARNED 0x04 +#define safe_for_read(cmd) [cmd] = CMD_READ_SAFE +#define safe_for_write(cmd) [cmd] = CMD_WRITE_SAFE + +int blk_verify_command(unsigned char *cmd, int has_write_perm) +{ + static unsigned char cmd_type[256] = { + + /* Basic read-only commands */ + safe_for_read(TEST_UNIT_READY), + safe_for_read(REQUEST_SENSE), + safe_for_read(READ_6), + safe_for_read(READ_10), + safe_for_read(READ_12), + safe_for_read(READ_16), + safe_for_read(READ_BUFFER), + safe_for_read(READ_DEFECT_DATA), + safe_for_read(READ_LONG), + safe_for_read(INQUIRY), + safe_for_read(MODE_SENSE), + safe_for_read(MODE_SENSE_10), + safe_for_read(LOG_SENSE), + safe_for_read(START_STOP), + safe_for_read(GPCMD_VERIFY_10), + safe_for_read(VERIFY_16), + + /* Audio CD commands */ + safe_for_read(GPCMD_PLAY_CD), + safe_for_read(GPCMD_PLAY_AUDIO_10), + safe_for_read(GPCMD_PLAY_AUDIO_MSF), + safe_for_read(GPCMD_PLAY_AUDIO_TI), + safe_for_read(GPCMD_PAUSE_RESUME), + + /* CD/DVD data reading */ + safe_for_read(GPCMD_READ_BUFFER_CAPACITY), + safe_for_read(GPCMD_READ_CD), + safe_for_read(GPCMD_READ_CD_MSF), + safe_for_read(GPCMD_READ_DISC_INFO), + safe_for_read(GPCMD_READ_CDVD_CAPACITY), + safe_for_read(GPCMD_READ_DVD_STRUCTURE), + safe_for_read(GPCMD_READ_HEADER), + safe_for_read(GPCMD_READ_TRACK_RZONE_INFO), + safe_for_read(GPCMD_READ_SUBCHANNEL), + safe_for_read(GPCMD_READ_TOC_PMA_ATIP), + safe_for_read(GPCMD_REPORT_KEY), + safe_for_read(GPCMD_SCAN), + safe_for_read(GPCMD_GET_CONFIGURATION), + safe_for_read(GPCMD_READ_FORMAT_CAPACITIES), + safe_for_read(GPCMD_GET_EVENT_STATUS_NOTIFICATION), + safe_for_read(GPCMD_GET_PERFORMANCE), + safe_for_read(GPCMD_SEEK), + safe_for_read(GPCMD_STOP_PLAY_SCAN), + + /* Basic writing commands */ + safe_for_write(WRITE_6), + safe_for_write(WRITE_10), + safe_for_write(WRITE_VERIFY), + safe_for_write(WRITE_12), + safe_for_write(WRITE_VERIFY_12), + safe_for_write(WRITE_16), + safe_for_write(WRITE_LONG), + safe_for_write(WRITE_LONG_2), + safe_for_write(ERASE), + safe_for_write(GPCMD_MODE_SELECT_10), + safe_for_write(MODE_SELECT), + safe_for_write(LOG_SELECT), + safe_for_write(GPCMD_BLANK), + safe_for_write(GPCMD_CLOSE_TRACK), + safe_for_write(GPCMD_FLUSH_CACHE), + safe_for_write(GPCMD_FORMAT_UNIT), + safe_for_write(GPCMD_REPAIR_RZONE_TRACK), + safe_for_write(GPCMD_RESERVE_RZONE_TRACK), + safe_for_write(GPCMD_SEND_DVD_STRUCTURE), + safe_for_write(GPCMD_SEND_EVENT), + safe_for_write(GPCMD_SEND_KEY), + safe_for_write(GPCMD_SEND_OPC), + safe_for_write(GPCMD_SEND_CUE_SHEET), + safe_for_write(GPCMD_SET_SPEED), + safe_for_write(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL), + safe_for_write(GPCMD_LOAD_UNLOAD), + safe_for_write(GPCMD_SET_STREAMING), + }; + unsigned char type = cmd_type[cmd[0]]; + + /* Anybody who can open the device can do a read-safe command */ + if (type & CMD_READ_SAFE) + return 0; + + /* Write-safe commands just require a writable open.. */ + if ((type & CMD_WRITE_SAFE) && has_write_perm) + return 0; + + /* And root can do any command.. */ + if (capable(CAP_SYS_RAWIO)) + return 0; + + if (!type) { + cmd_type[cmd[0]] = CMD_WARNED; + printk(KERN_WARNING "scsi: unknown opcode 0x%02x\n", cmd[0]); + } + + /* Otherwise fail it with an "Operation not permitted" */ + return -EPERM; +} +EXPORT_SYMBOL_GPL(blk_verify_command); + static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, - struct sg_io_hdr *hdr, struct file *file) + struct sg_io_hdr *hdr, int has_write_perm) { if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) return -EFAULT; - if (blk_verify_command(file, rq->cmd)) + if (blk_verify_command(rq->cmd, has_write_perm)) return -EPERM; /* @@ -179,7 +287,7 @@ static int sg_io(struct file *file, struct request_queue *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; - int writing = 0, ret = 0; + int writing = 0, ret = 0, has_write_perm = 0; struct request *rq; char sense[SCSI_SENSE_BUFFERSIZE]; struct bio *bio; @@ -208,7 +316,10 @@ static int sg_io(struct file *file, struct request_queue *q, if (!rq) return -ENOMEM; - if (blk_fill_sghdr_rq(q, rq, hdr, file)) { + if (file) + has_write_perm = file->f_mode & FMODE_WRITE; + + if (blk_fill_sghdr_rq(q, rq, hdr, has_write_perm)) { blk_put_request(rq); return -EFAULT; } @@ -340,7 +451,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q, if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) goto error; - err = blk_verify_command(file, rq->cmd); + err = blk_verify_command(rq->cmd, file->f_mode & FMODE_WRITE); if (err) goto error; diff --git a/trunk/drivers/ata/libata-scsi.c b/trunk/drivers/ata/libata-scsi.c index 499ccc628d81..57a43649a461 100644 --- a/trunk/drivers/ata/libata-scsi.c +++ b/trunk/drivers/ata/libata-scsi.c @@ -885,8 +885,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev, /* set the min alignment and padding */ blk_queue_update_dma_alignment(sdev->request_queue, ATA_DMA_PAD_SZ - 1); - blk_queue_update_dma_pad(sdev->request_queue, - ATA_DMA_PAD_SZ - 1); + blk_queue_dma_pad(sdev->request_queue, ATA_DMA_PAD_SZ - 1); /* configure draining */ buf = kmalloc(ATAPI_MAX_DRAIN, q->bounce_gfp | GFP_KERNEL); diff --git a/trunk/drivers/block/DAC960.c b/trunk/drivers/block/DAC960.c index a002a381df92..cd03473f3547 100644 --- a/trunk/drivers/block/DAC960.c +++ b/trunk/drivers/block/DAC960.c @@ -6628,18 +6628,15 @@ static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller) * DAC960_gam_ioctl is the ioctl function for performing RAID operations. */ -static long DAC960_gam_ioctl(struct file *file, unsigned int Request, - unsigned long Argument) +static int DAC960_gam_ioctl(struct inode *inode, struct file *file, + unsigned int Request, unsigned long Argument) { - long ErrorCode = 0; + int ErrorCode = 0; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - - lock_kernel(); switch (Request) { case DAC960_IOCTL_GET_CONTROLLER_COUNT: - ErrorCode = DAC960_ControllerCount; - break; + return DAC960_ControllerCount; case DAC960_IOCTL_GET_CONTROLLER_INFO: { DAC960_ControllerInfo_T __user *UserSpaceControllerInfo = @@ -6647,20 +6644,15 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, DAC960_ControllerInfo_T ControllerInfo; DAC960_Controller_T *Controller; int ControllerNumber; - if (UserSpaceControllerInfo == NULL) - ErrorCode = -EINVAL; - else ErrorCode = get_user(ControllerNumber, + if (UserSpaceControllerInfo == NULL) return -EINVAL; + ErrorCode = get_user(ControllerNumber, &UserSpaceControllerInfo->ControllerNumber); - if (ErrorCode != 0) - break;; - ErrorCode = -ENXIO; + if (ErrorCode != 0) return ErrorCode; if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) { - break; - } + ControllerNumber > DAC960_ControllerCount - 1) + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break;; + if (Controller == NULL) return -ENXIO; memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); ControllerInfo.ControllerNumber = ControllerNumber; ControllerInfo.FirmwareType = Controller->FirmwareType; @@ -6673,9 +6665,8 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, ControllerInfo.PCI_Address = Controller->PCI_Address; strcpy(ControllerInfo.ModelName, Controller->ModelName); strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion); - ErrorCode = (copy_to_user(UserSpaceControllerInfo, &ControllerInfo, + return (copy_to_user(UserSpaceControllerInfo, &ControllerInfo, sizeof(DAC960_ControllerInfo_T)) ? -EFAULT : 0); - break; } case DAC960_IOCTL_V1_EXECUTE_COMMAND: { @@ -6693,39 +6684,30 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, int ControllerNumber, DataTransferLength; unsigned char *DataTransferBuffer = NULL; dma_addr_t DataTransferBufferDMA; - if (UserSpaceUserCommand == NULL) { - ErrorCode = -EINVAL; - break; - } + if (UserSpaceUserCommand == NULL) return -EINVAL; if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V1_UserCommand_T))) { ErrorCode = -EFAULT; - break; + goto Failure1a; } ControllerNumber = UserCommand.ControllerNumber; - ErrorCode = -ENXIO; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break; - ErrorCode = -EINVAL; - if (Controller->FirmwareType != DAC960_V1_Controller) - break; + if (Controller == NULL) return -ENXIO; + if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL; CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode; DataTransferLength = UserCommand.DataTransferLength; - if (CommandOpcode & 0x80) - break; + if (CommandOpcode & 0x80) return -EINVAL; if (CommandOpcode == DAC960_V1_DCDB) { if (copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T))) { ErrorCode = -EFAULT; - break; + goto Failure1a; } - if (DCDB.Channel >= DAC960_V1_MaxChannels) - break; + if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && DCDB.Direction == DAC960_V1_DCDB_NoDataTransfer) || @@ -6735,37 +6717,38 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, (DataTransferLength < 0 && DCDB.Direction == DAC960_V1_DCDB_DataTransferSystemToDevice))) - break; + return -EINVAL; if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) != abs(DataTransferLength)) - break; + return -EINVAL; DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA); - if (DCDB_IOBUF == NULL) { - ErrorCode = -ENOMEM; - break; - } + if (DCDB_IOBUF == NULL) + return -ENOMEM; } - ErrorCode = -ENOMEM; if (DataTransferLength > 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) { + ErrorCode = -ENOMEM; + goto Failure1; + } memset(DataTransferBuffer, 0, DataTransferLength); } else if (DataTransferLength < 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, -DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) { + ErrorCode = -ENOMEM; + goto Failure1; + } if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, -DataTransferLength)) { ErrorCode = -EFAULT; - break; + goto Failure1; } } if (CommandOpcode == DAC960_V1_DCDB) @@ -6842,7 +6825,8 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, if (DCDB_IOBUF != NULL) pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), DCDB_IOBUF, DCDB_IOBUFDMA); - break; + Failure1a: + return ErrorCode; } case DAC960_IOCTL_V2_EXECUTE_COMMAND: { @@ -6860,43 +6844,32 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, dma_addr_t DataTransferBufferDMA; unsigned char *RequestSenseBuffer = NULL; dma_addr_t RequestSenseBufferDMA; - - ErrorCode = -EINVAL; - if (UserSpaceUserCommand == NULL) - break; + if (UserSpaceUserCommand == NULL) return -EINVAL; if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V2_UserCommand_T))) { ErrorCode = -EFAULT; - break; + goto Failure2a; } - ErrorCode = -ENXIO; ControllerNumber = UserCommand.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break; - if (Controller->FirmwareType != DAC960_V2_Controller){ - ErrorCode = -EINVAL; - break; - } + if (Controller == NULL) return -ENXIO; + if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL; DataTransferLength = UserCommand.DataTransferLength; - ErrorCode = -ENOMEM; if (DataTransferLength > 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) return -ENOMEM; memset(DataTransferBuffer, 0, DataTransferLength); } else if (DataTransferLength < 0) { DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, -DataTransferLength, &DataTransferBufferDMA); - if (DataTransferBuffer == NULL) - break; + if (DataTransferBuffer == NULL) return -ENOMEM; if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, -DataTransferLength)) { @@ -7006,7 +6979,8 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, if (RequestSenseBuffer != NULL) pci_free_consistent(Controller->PCIDevice, RequestSenseLength, RequestSenseBuffer, RequestSenseBufferDMA); - break; + Failure2a: + return ErrorCode; } case DAC960_IOCTL_V2_GET_HEALTH_STATUS: { @@ -7016,33 +6990,21 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer; DAC960_Controller_T *Controller; int ControllerNumber; - if (UserSpaceGetHealthStatus == NULL) { - ErrorCode = -EINVAL; - break; - } + if (UserSpaceGetHealthStatus == NULL) return -EINVAL; if (copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus, - sizeof(DAC960_V2_GetHealthStatus_T))) { - ErrorCode = -EFAULT; - break; - } - ErrorCode = -ENXIO; + sizeof(DAC960_V2_GetHealthStatus_T))) + return -EFAULT; ControllerNumber = GetHealthStatus.ControllerNumber; if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1) - break; + return -ENXIO; Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) - break; - if (Controller->FirmwareType != DAC960_V2_Controller) { - ErrorCode = -EINVAL; - break; - } + if (Controller == NULL) return -ENXIO; + if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL; if (copy_from_user(&HealthStatusBuffer, GetHealthStatus.HealthStatusBuffer, - sizeof(DAC960_V2_HealthStatusBuffer_T))) { - ErrorCode = -EFAULT; - break; - } + sizeof(DAC960_V2_HealthStatusBuffer_T))) + return -EFAULT; while (Controller->V2.HealthStatusBuffer->StatusChangeCounter == HealthStatusBuffer.StatusChangeCounter && Controller->V2.HealthStatusBuffer->NextEventSequenceNumber @@ -7050,28 +7012,21 @@ static long DAC960_gam_ioctl(struct file *file, unsigned int Request, { interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue, DAC960_MonitoringTimerInterval); - if (signal_pending(current)) { - ErrorCode = -EINTR; - break; - } + if (signal_pending(current)) return -EINTR; } if (copy_to_user(GetHealthStatus.HealthStatusBuffer, Controller->V2.HealthStatusBuffer, sizeof(DAC960_V2_HealthStatusBuffer_T))) - ErrorCode = -EFAULT; - else - ErrorCode = 0; + return -EFAULT; + return 0; } - default: - ErrorCode = -ENOTTY; } - unlock_kernel(); - return ErrorCode; + return -EINVAL; } static const struct file_operations DAC960_gam_fops = { .owner = THIS_MODULE, - .unlocked_ioctl = DAC960_gam_ioctl + .ioctl = DAC960_gam_ioctl }; static struct miscdevice DAC960_gam_dev = { diff --git a/trunk/drivers/block/aoe/aoecmd.c b/trunk/drivers/block/aoe/aoecmd.c index 2f1746295d06..41f818be2f7e 100644 --- a/trunk/drivers/block/aoe/aoecmd.c +++ b/trunk/drivers/block/aoe/aoecmd.c @@ -1003,7 +1003,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb) * Enough people have their dip switches set backwards to * warrant a loud message for this special case. */ - aoemajor = get_unaligned_be16(&h->major); + aoemajor = be16_to_cpu(get_unaligned(&h->major)); if (aoemajor == 0xfff) { printk(KERN_ERR "aoe: Warning: shelf address is all ones. " "Check shelf dip switches.\n"); diff --git a/trunk/drivers/block/paride/pt.c b/trunk/drivers/block/paride/pt.c index 27455ee1e9da..8b9549ab4a4e 100644 --- a/trunk/drivers/block/paride/pt.c +++ b/trunk/drivers/block/paride/pt.c @@ -146,7 +146,6 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include #include #include /* current, TASK_*, schedule_timeout() */ -#include #include @@ -190,7 +189,8 @@ module_param_array(drive3, int, NULL, 0); #define ATAPI_LOG_SENSE 0x4d static int pt_open(struct inode *inode, struct file *file); -static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +static int pt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); static int pt_release(struct inode *inode, struct file *file); static ssize_t pt_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos); @@ -236,7 +236,7 @@ static const struct file_operations pt_fops = { .owner = THIS_MODULE, .read = pt_read, .write = pt_write, - .unlocked_ioctl = pt_ioctl, + .ioctl = pt_ioctl, .open = pt_open, .release = pt_release, }; @@ -685,7 +685,8 @@ static int pt_open(struct inode *inode, struct file *file) return err; } -static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static int pt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { struct pt_unit *tape = file->private_data; struct mtop __user *p = (void __user *)arg; @@ -699,26 +700,23 @@ static long pt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) switch (mtop.mt_op) { case MTREW: - lock_kernel(); pt_rewind(tape); - unlock_kernel(); return 0; case MTWEOF: - lock_kernel(); pt_write_fm(tape); - unlock_kernel(); return 0; default: - /* FIXME: rate limit ?? */ - printk(KERN_DEBUG "%s: Unimplemented mt_op %d\n", tape->name, + printk("%s: Unimplemented mt_op %d\n", tape->name, mtop.mt_op); return -EINVAL; } default: - return -ENOTTY; + printk("%s: Unimplemented ioctl 0x%x\n", tape->name, cmd); + return -EINVAL; + } } diff --git a/trunk/drivers/block/pktcdvd.c b/trunk/drivers/block/pktcdvd.c index 45bee918c46a..3ba1df93e9e3 100644 --- a/trunk/drivers/block/pktcdvd.c +++ b/trunk/drivers/block/pktcdvd.c @@ -49,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -2080,6 +2079,7 @@ static noinline_for_stack int pkt_write_caching(struct pktcdvd_device *pd, unsigned char buf[64]; int ret; + memset(buf, 0, sizeof(buf)); init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); cgc.sense = &sense; cgc.buflen = pd->mode_offset + 12; @@ -2126,6 +2126,7 @@ static noinline_for_stack int pkt_get_max_speed(struct pktcdvd_device *pd, unsigned char *cap_buf; int ret, offset; + memset(buf, 0, sizeof(buf)); cap_buf = &buf[sizeof(struct mode_page_header) + pd->mode_offset]; init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_UNKNOWN); cgc.sense = &sense; @@ -2632,12 +2633,11 @@ static int pkt_make_request(struct request_queue *q, struct bio *bio) -static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, - struct bio_vec *bvec) +static int pkt_merge_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *bvec) { struct pktcdvd_device *pd = q->queuedata; - sector_t zone = ZONE(bmd->bi_sector, pd); - int used = ((bmd->bi_sector - zone) << 9) + bmd->bi_size; + sector_t zone = ZONE(bio->bi_sector, pd); + int used = ((bio->bi_sector - zone) << 9) + bio->bi_size; int remaining = (pd->settings.size << 9) - used; int remaining2; @@ -2645,7 +2645,7 @@ static int pkt_merge_bvec(struct request_queue *q, struct bvec_merge_data *bmd, * A bio <= PAGE_SIZE must be allowed. If it crosses a packet * boundary, pkt_make_request() will split the bio. */ - remaining2 = PAGE_SIZE - bmd->bi_size; + remaining2 = PAGE_SIZE - bio->bi_size; remaining = max(remaining, remaining2); BUG_ON(remaining < 0); @@ -2796,14 +2796,9 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev) return ret; } -static long pkt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - struct pktcdvd_device *pd; - long ret; - - lock_kernel(); - pd = inode->i_bdev->bd_disk->private_data; + struct pktcdvd_device *pd = inode->i_bdev->bd_disk->private_data; VPRINTK("pkt_ioctl: cmd %x, dev %d:%d\n", cmd, imajor(inode), iminor(inode)); @@ -2816,8 +2811,7 @@ static long pkt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case CDROM_LAST_WRITTEN: case CDROM_SEND_PACKET: case SCSI_IOCTL_SEND_COMMAND: - ret = blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); - break; + return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); case CDROMEJECT: /* @@ -2826,15 +2820,14 @@ static long pkt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) */ if (pd->refcnt == 1) pkt_lock_door(pd, 0); - ret = blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); - break; + return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg); default: VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd); - ret = -ENOTTY; + return -ENOTTY; } - unlock_kernel(); - return ret; + + return 0; } static int pkt_media_changed(struct gendisk *disk) @@ -2856,7 +2849,7 @@ static struct block_device_operations pktcdvd_ops = { .owner = THIS_MODULE, .open = pkt_open, .release = pkt_close, - .unlocked_ioctl = pkt_ioctl, + .ioctl = pkt_ioctl, .media_changed = pkt_media_changed, }; @@ -3021,8 +3014,7 @@ static void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) mutex_unlock(&ctl_mutex); } -static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) +static int pkt_ctl_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { void __user *argp = (void __user *)arg; struct pkt_ctrl_command ctrl_cmd; @@ -3039,22 +3031,16 @@ static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, case PKT_CTRL_CMD_SETUP: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); ret = pkt_setup_dev(new_decode_dev(ctrl_cmd.dev), &pkt_dev); ctrl_cmd.pkt_dev = new_encode_dev(pkt_dev); - unlock_kernel(); break; case PKT_CTRL_CMD_TEARDOWN: if (!capable(CAP_SYS_ADMIN)) return -EPERM; - lock_kernel(); ret = pkt_remove_dev(new_decode_dev(ctrl_cmd.pkt_dev)); - unlock_kernel(); break; case PKT_CTRL_CMD_STATUS: - lock_kernel(); pkt_get_status(&ctrl_cmd); - unlock_kernel(); break; default: return -ENOTTY; @@ -3067,7 +3053,7 @@ static long pkt_ctl_ioctl(struct file *file, unsigned int cmd, static const struct file_operations pkt_ctl_fops = { - .unlocked_ioctl = pkt_ctl_ioctl, + .ioctl = pkt_ctl_ioctl, .owner = THIS_MODULE, }; diff --git a/trunk/drivers/block/xen-blkfront.c b/trunk/drivers/block/xen-blkfront.c index 9ae05c584234..f2fff5799ddf 100644 --- a/trunk/drivers/block/xen-blkfront.c +++ b/trunk/drivers/block/xen-blkfront.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -154,40 +153,6 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg) return 0; } -int blkif_ioctl(struct inode *inode, struct file *filep, - unsigned command, unsigned long argument) -{ - struct blkfront_info *info = - inode->i_bdev->bd_disk->private_data; - int i; - - dev_dbg(&info->xbdev->dev, "command: 0x%x, argument: 0x%lx\n", - command, (long)argument); - - switch (command) { - case CDROMMULTISESSION: - dev_dbg(&info->xbdev->dev, "FIXME: support multisession CDs later\n"); - for (i = 0; i < sizeof(struct cdrom_multisession); i++) - if (put_user(0, (char __user *)(argument + i))) - return -EFAULT; - return 0; - - case CDROM_GET_CAPABILITY: { - struct gendisk *gd = info->gd; - if (gd->flags & GENHD_FL_CD) - return 0; - return -EINVAL; - } - - default: - /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n", - command);*/ - return -EINVAL; /* same return as native Linux */ - } - - return 0; -} - /* * blkif_queue_request * @@ -359,9 +324,6 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size) /* Make sure buffer addresses are sector-aligned. */ blk_queue_dma_alignment(rq, 511); - /* Make sure we don't use bounce buffers. */ - blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY); - gd->queue = rq; return 0; @@ -584,7 +546,7 @@ static int setup_blkring(struct xenbus_device *dev, info->ring_ref = GRANT_INVALID_REF; - sring = (struct blkif_sring *)__get_free_page(GFP_NOIO | __GFP_HIGH); + sring = (struct blkif_sring *)__get_free_page(GFP_KERNEL); if (!sring) { xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); return -ENOMEM; @@ -741,8 +703,7 @@ static int blkif_recover(struct blkfront_info *info) int j; /* Stage 1: Make a safe copy of the shadow state. */ - copy = kmalloc(sizeof(info->shadow), - GFP_NOIO | __GFP_REPEAT | __GFP_HIGH); + copy = kmalloc(sizeof(info->shadow), GFP_KERNEL); if (!copy) return -ENOMEM; memcpy(copy, info->shadow, sizeof(info->shadow)); @@ -998,7 +959,7 @@ static int blkif_release(struct inode *inode, struct file *filep) struct xenbus_device *dev = info->xbdev; enum xenbus_state state = xenbus_read_driver_state(dev->otherend); - if (state == XenbusStateClosing && info->is_ready) + if (state == XenbusStateClosing) blkfront_closing(dev); } return 0; @@ -1010,7 +971,6 @@ static struct block_device_operations xlvbd_block_fops = .open = blkif_open, .release = blkif_release, .getgeo = blkif_getgeo, - .ioctl = blkif_ioctl, }; @@ -1046,7 +1006,7 @@ static int __init xlblk_init(void) module_init(xlblk_init); -static void __exit xlblk_exit(void) +static void xlblk_exit(void) { return xenbus_unregister_driver(&blkfront); } diff --git a/trunk/drivers/cdrom/cdrom.c b/trunk/drivers/cdrom/cdrom.c index a5da35632651..69f26eb6415b 100644 --- a/trunk/drivers/cdrom/cdrom.c +++ b/trunk/drivers/cdrom/cdrom.c @@ -461,27 +461,37 @@ int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med) { struct packet_command cgc; - unsigned char buffer[8]; - struct event_header *eh = (struct event_header *) buffer; + unsigned char *buffer; + struct event_header *eh; + int ret = 1; + + buffer = kmalloc(8, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + eh = (struct event_header *)buffer; + + init_cdrom_command(&cgc, buffer, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; cgc.cmd[1] = 1; /* IMMED */ cgc.cmd[4] = 1 << 4; /* media event */ - cgc.cmd[8] = sizeof(buffer); + cgc.cmd[8] = 8; cgc.quiet = 1; if (cdi->ops->generic_packet(cdi, &cgc)) - return 1; + goto err; if (be16_to_cpu(eh->data_len) < sizeof(*med)) - return 1; + goto err; if (eh->nea || eh->notification_class != 0x4) - return 1; + goto err; - memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); - return 0; + memcpy(med, buffer + sizeof(*eh), sizeof(*med)); + ret = 0; +err: + kfree(buffer); + return ret; } /* @@ -491,68 +501,82 @@ int cdrom_get_media_event(struct cdrom_device_info *cdi, static int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[16]; + char *buffer; + int ret = 1; + + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.timeout = HZ; cgc.quiet = 1; if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) { cdi->mrw_mode_page = MRW_MODE_PC; - return 0; + ret = 0; } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) { cdi->mrw_mode_page = MRW_MODE_PC_PRE1; - return 0; + ret = 0; } - - return 1; + kfree(buffer); + return ret; } static int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write) { struct packet_command cgc; struct mrw_feature_desc *mfd; - unsigned char buffer[16]; + unsigned char *buffer; int ret; *write = 0; + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[3] = CDF_MRW; - cgc.cmd[8] = sizeof(buffer); + cgc.cmd[8] = 16; cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) - return ret; + goto err; mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; - if (be16_to_cpu(mfd->feature_code) != CDF_MRW) - return 1; + if (be16_to_cpu(mfd->feature_code) != CDF_MRW) { + ret = 1; + goto err; + } *write = mfd->write; if ((ret = cdrom_mrw_probe_pc(cdi))) { *write = 0; - return ret; } - - return 0; +err: + kfree(buffer); + return ret; } static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) { struct packet_command cgc; - unsigned char buffer[12]; + unsigned char *buffer; int ret; printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : ""); + buffer = kmalloc(12, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + /* * FmtData bit set (bit 4), format type is 1 */ - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE); + init_cdrom_command(&cgc, buffer, 12, CGC_DATA_WRITE); cgc.cmd[0] = GPCMD_FORMAT_UNIT; cgc.cmd[1] = (1 << 4) | 1; @@ -579,6 +603,7 @@ static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) if (ret) printk(KERN_INFO "cdrom: bgformat failed\n"); + kfree(buffer); return ret; } @@ -638,16 +663,17 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) { struct packet_command cgc; struct mode_page_header *mph; - char buffer[16]; + char *buffer; int ret, offset, size; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; - cgc.buffer = buffer; - cgc.buflen = sizeof(buffer); + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) - return ret; + goto err; mph = (struct mode_page_header *) buffer; offset = be16_to_cpu(mph->desc_length); @@ -657,55 +683,70 @@ static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) cgc.buflen = size; if ((ret = cdrom_mode_select(cdi, &cgc))) - return ret; + goto err; printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]); - return 0; + ret = 0; +err: + kfree(buffer); + return ret; } static int cdrom_get_random_writable(struct cdrom_device_info *cdi, struct rwrt_feature_desc *rfd) { struct packet_command cgc; - char buffer[24]; + char *buffer; int ret; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(24, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + init_cdrom_command(&cgc, buffer, 24, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; /* often 0x46 */ cgc.cmd[3] = CDF_RWRT; /* often 0x0020 */ - cgc.cmd[8] = sizeof(buffer); /* often 0x18 */ + cgc.cmd[8] = 24; /* often 0x18 */ cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) - return ret; + goto err; memcpy(rfd, &buffer[sizeof(struct feature_header)], sizeof (*rfd)); - return 0; + ret = 0; +err: + kfree(buffer); + return ret; } static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[16]; + char *buffer; __be16 *feature_code; int ret; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(16, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[3] = CDF_HWDM; - cgc.cmd[8] = sizeof(buffer); + cgc.cmd[8] = 16; cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) - return ret; + goto err; feature_code = (__be16 *) &buffer[sizeof(struct feature_header)]; if (be16_to_cpu(*feature_code) == CDF_HWDM) - return 0; - - return 1; + ret = 0; +err: + kfree(buffer); + return ret; } @@ -796,10 +837,14 @@ static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) static int mo_open_write(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[255]; + char *buffer; int ret; - init_cdrom_command(&cgc, &buffer, 4, CGC_DATA_READ); + buffer = kmalloc(255, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + init_cdrom_command(&cgc, buffer, 4, CGC_DATA_READ); cgc.quiet = 1; /* @@ -816,10 +861,15 @@ static int mo_open_write(struct cdrom_device_info *cdi) } /* drive gave us no info, let the user go ahead */ - if (ret) - return 0; + if (ret) { + ret = 0; + goto err; + } - return buffer[3] & 0x80; + ret = buffer[3] & 0x80; +err: + kfree(buffer); + return ret; } static int cdrom_ram_open_write(struct cdrom_device_info *cdi) @@ -842,15 +892,19 @@ static int cdrom_ram_open_write(struct cdrom_device_info *cdi) static void cdrom_mmc3_profile(struct cdrom_device_info *cdi) { struct packet_command cgc; - char buffer[32]; + char *buffer; int ret, mmc3_profile; - init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + buffer = kmalloc(32, GFP_KERNEL); + if (!buffer) + return; + + init_cdrom_command(&cgc, buffer, 32, CGC_DATA_READ); cgc.cmd[0] = GPCMD_GET_CONFIGURATION; cgc.cmd[1] = 0; cgc.cmd[2] = cgc.cmd[3] = 0; /* Starting Feature Number */ - cgc.cmd[8] = sizeof(buffer); /* Allocation Length */ + cgc.cmd[8] = 32; /* Allocation Length */ cgc.quiet = 1; if ((ret = cdi->ops->generic_packet(cdi, &cgc))) @@ -859,6 +913,7 @@ static void cdrom_mmc3_profile(struct cdrom_device_info *cdi) mmc3_profile = (buffer[6] << 8) | buffer[7]; cdi->mmc3_profile = mmc3_profile; + kfree(buffer); } static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi) @@ -1573,12 +1628,15 @@ static void setup_send_key(struct packet_command *cgc, unsigned agid, unsigned t static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) { int ret; - u_char buf[20]; + u_char *buf; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - rpc_state_t rpc_state; + rpc_state_t *rpc_state; + + buf = kzalloc(20, GFP_KERNEL); + if (!buf) + return -ENOMEM; - memset(buf, 0, sizeof(buf)); init_cdrom_command(&cgc, buf, 0, CGC_DATA_READ); switch (ai->type) { @@ -1589,7 +1647,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsa.agid, 0); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->lsa.agid = buf[7] >> 6; /* Returning data, let host change state */ @@ -1600,7 +1658,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsk.agid, 2); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; copy_key(ai->lsk.key, &buf[4]); /* Returning data, let host change state */ @@ -1611,7 +1669,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsc.agid, 1); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; copy_chal(ai->lsc.chal, &buf[4]); /* Returning data, let host change state */ @@ -1628,7 +1686,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) cgc.cmd[2] = ai->lstk.lba >> 24; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->lstk.cpm = (buf[4] >> 7) & 1; ai->lstk.cp_sec = (buf[4] >> 6) & 1; @@ -1642,7 +1700,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) setup_report_key(&cgc, ai->lsasf.agid, 5); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->lsasf.asf = buf[7] & 1; break; @@ -1655,7 +1713,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) copy_chal(&buf[4], ai->hsc.chal); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; ai->type = DVD_LU_SEND_KEY1; break; @@ -1668,7 +1726,7 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) if ((ret = cdo->generic_packet(cdi, &cgc))) { ai->type = DVD_AUTH_FAILURE; - return ret; + goto err; } ai->type = DVD_AUTH_ESTABLISHED; break; @@ -1679,24 +1737,23 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) cdinfo(CD_DVD, "entering DVD_INVALIDATE_AGID\n"); setup_report_key(&cgc, ai->lsa.agid, 0x3f); if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; break; /* Get region settings */ case DVD_LU_SEND_RPC_STATE: cdinfo(CD_DVD, "entering DVD_LU_SEND_RPC_STATE\n"); setup_report_key(&cgc, 0, 8); - memset(&rpc_state, 0, sizeof(rpc_state_t)); - cgc.buffer = (char *) &rpc_state; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; - ai->lrpcs.type = rpc_state.type_code; - ai->lrpcs.vra = rpc_state.vra; - ai->lrpcs.ucca = rpc_state.ucca; - ai->lrpcs.region_mask = rpc_state.region_mask; - ai->lrpcs.rpc_scheme = rpc_state.rpc_scheme; + rpc_state = (rpc_state_t *)buf; + ai->lrpcs.type = rpc_state->type_code; + ai->lrpcs.vra = rpc_state->vra; + ai->lrpcs.ucca = rpc_state->ucca; + ai->lrpcs.region_mask = rpc_state->region_mask; + ai->lrpcs.rpc_scheme = rpc_state->rpc_scheme; break; /* Set region settings */ @@ -1707,20 +1764,23 @@ static int dvd_do_auth(struct cdrom_device_info *cdi, dvd_authinfo *ai) buf[4] = ai->hrpcs.pdrc; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; break; default: cdinfo(CD_WARNING, "Invalid DVD key ioctl (%d)\n", ai->type); - return -ENOTTY; + ret = -ENOTTY; + goto err; } - - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) { - unsigned char buf[21], *base; + unsigned char *buf, *base; struct dvd_layer *layer; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; @@ -1729,7 +1789,11 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) if (layer_num >= DVD_LAYERS) return -EINVAL; - init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + buf = kmalloc(21, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, 21, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = layer_num; cgc.cmd[7] = s->type; @@ -1741,7 +1805,7 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) cgc.quiet = 1; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; base = &buf[4]; layer = &s->physical.layer[layer_num]; @@ -1765,17 +1829,24 @@ static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s) layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; layer->bca = base[16] >> 7; - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) { int ret; - u_char buf[8]; + u_char *buf; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + buf = kmalloc(8, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, 8, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[6] = s->copyright.layer_num; cgc.cmd[7] = s->type; @@ -1783,12 +1854,15 @@ static int dvd_read_copyright(struct cdrom_device_info *cdi, dvd_struct *s) cgc.cmd[9] = cgc.buflen & 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; s->copyright.cpst = buf[4]; s->copyright.rmi = buf[5]; - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) @@ -1820,26 +1894,33 @@ static int dvd_read_disckey(struct cdrom_device_info *cdi, dvd_struct *s) static int dvd_read_bca(struct cdrom_device_info *cdi, dvd_struct *s) { int ret; - u_char buf[4 + 188]; + u_char *buf; struct packet_command cgc; struct cdrom_device_ops *cdo = cdi->ops; - init_cdrom_command(&cgc, buf, sizeof(buf), CGC_DATA_READ); + buf = kmalloc(4 + 188, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + init_cdrom_command(&cgc, buf, 4 + 188, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE; cgc.cmd[7] = s->type; cgc.cmd[9] = cgc.buflen & 0xff; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; s->bca.len = buf[0] << 8 | buf[1]; if (s->bca.len < 12 || s->bca.len > 188) { cdinfo(CD_WARNING, "Received invalid BCA length (%d)\n", s->bca.len); - return -EIO; + ret = -EIO; + goto err; } memcpy(s->bca.value, &buf[4], s->bca.len); - - return 0; + ret = 0; +err: + kfree(buf); + return ret; } static int dvd_read_manufact(struct cdrom_device_info *cdi, dvd_struct *s) @@ -1939,9 +2020,13 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi, { struct cdrom_device_ops *cdo = cdi->ops; struct packet_command cgc; - char buffer[32]; + char *buffer; int ret; + buffer = kmalloc(32, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + init_cdrom_command(&cgc, buffer, 16, CGC_DATA_READ); cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; cgc.cmd[1] = 2; /* MSF addressing */ @@ -1950,7 +2035,7 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi, cgc.cmd[8] = 16; if ((ret = cdo->generic_packet(cdi, &cgc))) - return ret; + goto err; subchnl->cdsc_audiostatus = cgc.buffer[1]; subchnl->cdsc_format = CDROM_MSF; @@ -1965,7 +2050,10 @@ static int cdrom_read_subchannel(struct cdrom_device_info *cdi, subchnl->cdsc_absaddr.msf.second = cgc.buffer[10]; subchnl->cdsc_absaddr.msf.frame = cgc.buffer[11]; - return 0; + ret = 0; +err: + kfree(buffer); + return ret; } /* diff --git a/trunk/drivers/char/pcmcia/cm4000_cs.c b/trunk/drivers/char/pcmcia/cm4000_cs.c index 59ca35156d81..4a933d413423 100644 --- a/trunk/drivers/char/pcmcia/cm4000_cs.c +++ b/trunk/drivers/char/pcmcia/cm4000_cs.c @@ -32,9 +32,8 @@ #include #include #include -#include -#include -#include +#include +#include #include #include @@ -1406,11 +1405,11 @@ static void stop_monitor(struct cm4000_dev *dev) DEBUGP(3, dev, "<- stop_monitor\n"); } -static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long arg) { struct cm4000_dev *dev = filp->private_data; unsigned int iobase = dev->p_dev->io.BasePort1; - struct inode *inode = filp->f_path.dentry->d_inode; struct pcmcia_device *link; int size; int rc; @@ -1427,42 +1426,38 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) DEBUGP(3, dev, "cmm_ioctl(device=%d.%d) %s\n", imajor(inode), iminor(inode), ioctl_names[_IOC_NR(cmd)]); - lock_kernel(); - rc = -ENODEV; link = dev_table[iminor(inode)]; if (!pcmcia_dev_present(link)) { DEBUGP(4, dev, "DEV_OK false\n"); - goto out; + return -ENODEV; } if (test_bit(IS_CMM_ABSENT, &dev->flags)) { DEBUGP(4, dev, "CMM_ABSENT flag set\n"); - goto out; + return -ENODEV; } - rc = EINVAL; if (_IOC_TYPE(cmd) != CM_IOC_MAGIC) { DEBUGP(4, dev, "ioctype mismatch\n"); - goto out; + return -EINVAL; } if (_IOC_NR(cmd) > CM_IOC_MAXNR) { DEBUGP(4, dev, "iocnr mismatch\n"); - goto out; + return -EINVAL; } size = _IOC_SIZE(cmd); - rc = -EFAULT; + rc = 0; DEBUGP(4, dev, "iocdir=%.4x iocr=%.4x iocw=%.4x iocsize=%d cmd=%.4x\n", _IOC_DIR(cmd), _IOC_READ, _IOC_WRITE, size, cmd); if (_IOC_DIR(cmd) & _IOC_READ) { if (!access_ok(VERIFY_WRITE, argp, size)) - goto out; + return -EFAULT; } if (_IOC_DIR(cmd) & _IOC_WRITE) { if (!access_ok(VERIFY_READ, argp, size)) - goto out; + return -EFAULT; } - rc = 0; switch (cmd) { case CM_IOCGSTATUS: @@ -1482,9 +1477,9 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (test_bit(IS_BAD_CARD, &dev->flags)) status |= CM_BAD_CARD; if (copy_to_user(argp, &status, sizeof(int))) - rc = -EFAULT; + return -EFAULT; } - break; + return 0; case CM_IOCGATR: DEBUGP(4, dev, "... in CM_IOCGATR\n"); { @@ -1497,29 +1492,25 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } - rc = -EFAULT; if (test_bit(IS_ATR_VALID, &dev->flags) == 0) { tmp = -1; if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) - break; + return -EFAULT; } else { if (copy_to_user(atreq->atr, dev->atr, dev->atr_len)) - break; + return -EFAULT; tmp = dev->atr_len; if (copy_to_user(&(atreq->atr_len), &tmp, sizeof(int))) - break; + return -EFAULT; } - rc = 0; - break; + return 0; } case CM_IOCARDOFF: @@ -1547,10 +1538,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } /* Set Flags0 = 0x42 */ DEBUGP(4, dev, "Set Flags0=0x42 \n"); @@ -1565,10 +1554,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_bit(IS_ATR_VALID, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } } /* release lock */ @@ -1581,10 +1568,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) struct ptsreq krnptsreq; if (copy_from_user(&krnptsreq, argp, - sizeof(struct ptsreq))) { - rc = -EFAULT; - break; - } + sizeof(struct ptsreq))) + return -EFAULT; rc = 0; DEBUGP(4, dev, "... in CM_IOCSPTS\n"); @@ -1595,10 +1580,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_bit(IS_ATR_PRESENT, (void *)&dev->flags) != 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } /* get IO lock */ if (wait_event_interruptible @@ -1607,10 +1590,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) || (test_and_set_bit(LOCK_IO, (void *)&dev->flags) == 0)))) { if (filp->f_flags & O_NONBLOCK) - rc = -EAGAIN; - else - rc = -ERESTARTSYS; - break; + return -EAGAIN; + return -ERESTARTSYS; } if ((rc = set_protocol(dev, &krnptsreq)) != 0) { @@ -1623,7 +1604,7 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) wake_up_interruptible(&dev->ioq); } - break; + return rc; #ifdef PCMCIA_DEBUG case CM_IOSDBGLVL: /* set debug log level */ { @@ -1631,20 +1612,18 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) old_pc_debug = pc_debug; if (copy_from_user(&pc_debug, argp, sizeof(int))) - rc = -EFAULT; - else if (old_pc_debug != pc_debug) + return -EFAULT; + + if (old_pc_debug != pc_debug) DEBUGP(0, dev, "Changed debug log level " "to %i\n", pc_debug); } - break; + return rc; #endif default: DEBUGP(4, dev, "... in default (unknown IOCTL code)\n"); - rc = -ENOTTY; + return -EINVAL; } -out: - unlock_kernel(); - return rc; } static int cmm_open(struct inode *inode, struct file *filp) @@ -1652,22 +1631,16 @@ static int cmm_open(struct inode *inode, struct file *filp) struct cm4000_dev *dev; struct pcmcia_device *link; int minor = iminor(inode); - int ret; if (minor >= CM4000_MAX_DEV) return -ENODEV; - lock_kernel(); link = dev_table[minor]; - if (link == NULL || !pcmcia_dev_present(link)) { - ret = -ENODEV; - goto out; - } + if (link == NULL || !pcmcia_dev_present(link)) + return -ENODEV; - if (link->open) { - ret = -EBUSY; - goto out; - } + if (link->open) + return -EBUSY; dev = link->priv; filp->private_data = dev; @@ -1687,10 +1660,8 @@ static int cmm_open(struct inode *inode, struct file *filp) * vaild = block until valid (or card * inserted) */ - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - goto out; - } + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; dev->mdelay = T_50MSEC; @@ -1700,10 +1671,7 @@ static int cmm_open(struct inode *inode, struct file *filp) link->open = 1; /* only one open per device */ DEBUGP(2, dev, "<- cmm_open\n"); - ret = nonseekable_open(inode, filp); -out: - unlock_kernel(); - return ret; + return nonseekable_open(inode, filp); } static int cmm_close(struct inode *inode, struct file *filp) @@ -1929,7 +1897,7 @@ static const struct file_operations cm4000_fops = { .owner = THIS_MODULE, .read = cmm_read, .write = cmm_write, - .unlocked_ioctl = cmm_ioctl, + .ioctl = cmm_ioctl, .open = cmm_open, .release= cmm_close, }; diff --git a/trunk/drivers/char/pcmcia/cm4040_cs.c b/trunk/drivers/char/pcmcia/cm4040_cs.c index 6181f8a9b0bd..035084c07329 100644 --- a/trunk/drivers/char/pcmcia/cm4040_cs.c +++ b/trunk/drivers/char/pcmcia/cm4040_cs.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -449,30 +448,23 @@ static int cm4040_open(struct inode *inode, struct file *filp) struct reader_dev *dev; struct pcmcia_device *link; int minor = iminor(inode); - int ret; if (minor >= CM_MAX_DEV) return -ENODEV; - lock_kernel(); link = dev_table[minor]; - if (link == NULL || !pcmcia_dev_present(link)) { - ret = -ENODEV; - goto out; - } + if (link == NULL || !pcmcia_dev_present(link)) + return -ENODEV; - if (link->open) { - ret = -EBUSY; - goto out; - } + if (link->open) + return -EBUSY; dev = link->priv; filp->private_data = dev; if (filp->f_flags & O_NONBLOCK) { DEBUGP(4, dev, "filep->f_flags O_NONBLOCK set\n"); - ret = -EAGAIN; - goto out; + return -EAGAIN; } link->open = 1; @@ -481,10 +473,7 @@ static int cm4040_open(struct inode *inode, struct file *filp) mod_timer(&dev->poll_timer, jiffies + POLL_PERIOD); DEBUGP(2, dev, "<- cm4040_open (successfully)\n"); - ret = nonseekable_open(inode, filp); -out: - unlock_kernel(); - return ret; + return nonseekable_open(inode, filp); } static int cm4040_close(struct inode *inode, struct file *filp) diff --git a/trunk/drivers/char/pcmcia/ipwireless/main.c b/trunk/drivers/char/pcmcia/ipwireless/main.c index cc7dcea2d283..00c7f8407e3e 100644 --- a/trunk/drivers/char/pcmcia/ipwireless/main.c +++ b/trunk/drivers/char/pcmcia/ipwireless/main.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/ide/legacy/ide-cs.c b/trunk/drivers/ide/legacy/ide-cs.c index 8dbf4d9b6447..3381424d70a1 100644 --- a/trunk/drivers/ide/legacy/ide-cs.c +++ b/trunk/drivers/ide/legacy/ide-cs.c @@ -63,11 +63,11 @@ MODULE_LICENSE("Dual MPL/GPL"); #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0) -#ifdef CONFIG_PCMCIA_DEBUG -INT_MODULE_PARM(pc_debug, 0); +#ifdef PCMCIA_DEBUG +INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -/*static char *version = -"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";*/ +static char *version = +"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -375,7 +375,7 @@ static int ide_config(struct pcmcia_device *link) ======================================================================*/ -static void ide_release(struct pcmcia_device *link) +void ide_release(struct pcmcia_device *link) { ide_info_t *info = link->priv; ide_hwif_t *hwif = info->hwif; diff --git a/trunk/drivers/md/linear.c b/trunk/drivers/md/linear.c index 6a866d7c8ae5..10748240cb2f 100644 --- a/trunk/drivers/md/linear.c +++ b/trunk/drivers/md/linear.c @@ -50,19 +50,17 @@ static inline dev_info_t *which_dev(mddev_t *mddev, sector_t sector) /** * linear_mergeable_bvec -- tell bio layer if two requests can be merged * @q: request queue - * @bvm: properties of new bio + * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * * Return amount of bytes we can take at this offset */ -static int linear_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int linear_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) { mddev_t *mddev = q->queuedata; dev_info_t *dev0; - unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + unsigned long maxsectors, bio_sectors = bio->bi_size >> 9; + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); dev0 = which_dev(mddev, sector); maxsectors = (dev0->size << 1) - (sector - (dev0->offset<<1)); diff --git a/trunk/drivers/md/raid0.c b/trunk/drivers/md/raid0.c index bcbb82594a19..914c04ddec7c 100644 --- a/trunk/drivers/md/raid0.c +++ b/trunk/drivers/md/raid0.c @@ -241,20 +241,18 @@ static int create_strip_zones (mddev_t *mddev) /** * raid0_mergeable_bvec -- tell bio layer if a two requests can be merged * @q: request queue - * @bvm: properties of new bio + * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * * Return amount of bytes we can accept at this offset */ -static int raid0_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int raid0_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) { mddev_t *mddev = q->queuedata; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); int max; unsigned int chunk_sectors = mddev->chunk_size >> 9; - unsigned int bio_sectors = bvm->bi_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; if (max < 0) max = 0; /* bio_add cannot handle a negative return */ diff --git a/trunk/drivers/md/raid10.c b/trunk/drivers/md/raid10.c index 22bb2b1b886d..a71277b640ab 100644 --- a/trunk/drivers/md/raid10.c +++ b/trunk/drivers/md/raid10.c @@ -439,27 +439,26 @@ static sector_t raid10_find_virt(conf_t *conf, sector_t sector, int dev) /** * raid10_mergeable_bvec -- tell bio layer if a two requests can be merged * @q: request queue - * @bvm: properties of new bio + * @bio: the buffer head that's been built up so far * @biovec: the request that could be merged to it. * * Return amount of bytes we can accept at this offset * If near_copies == raid_disk, there are no striping issues, * but in that case, the function isn't called at all. */ -static int raid10_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int raid10_mergeable_bvec(struct request_queue *q, struct bio *bio, + struct bio_vec *bio_vec) { mddev_t *mddev = q->queuedata; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); int max; unsigned int chunk_sectors = mddev->chunk_size >> 9; - unsigned int bio_sectors = bvm->bi_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; if (max < 0) max = 0; /* bio_add cannot handle a negative return */ - if (max <= biovec->bv_len && bio_sectors == 0) - return biovec->bv_len; + if (max <= bio_vec->bv_len && bio_sectors == 0) + return bio_vec->bv_len; else return max; } diff --git a/trunk/drivers/md/raid5.c b/trunk/drivers/md/raid5.c index 9ce7154845c6..3b27df52456b 100644 --- a/trunk/drivers/md/raid5.c +++ b/trunk/drivers/md/raid5.c @@ -3314,17 +3314,15 @@ static int raid5_congested(void *data, int bits) /* We want read requests to align with chunks where possible, * but write requests don't need to. */ -static int raid5_mergeable_bvec(struct request_queue *q, - struct bvec_merge_data *bvm, - struct bio_vec *biovec) +static int raid5_mergeable_bvec(struct request_queue *q, struct bio *bio, struct bio_vec *biovec) { mddev_t *mddev = q->queuedata; - sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); + sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev); int max; unsigned int chunk_sectors = mddev->chunk_size >> 9; - unsigned int bio_sectors = bvm->bi_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; - if ((bvm->bi_rw & 1) == WRITE) + if (bio_data_dir(bio) == WRITE) return biovec->bv_len; /* always allow writes to be mergeable */ max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; diff --git a/trunk/drivers/mtd/ftl.c b/trunk/drivers/mtd/ftl.c index 5c29872184e6..4a79b187b568 100644 --- a/trunk/drivers/mtd/ftl.c +++ b/trunk/drivers/mtd/ftl.c @@ -130,6 +130,10 @@ typedef struct partition_t { u_int16_t DataUnits; u_int32_t BlocksPerUnit; erase_unit_header_t header; +#if 0 + region_info_t region; + memory_handle_t handle; +#endif } partition_t; /* Partition state flags */ diff --git a/trunk/drivers/mtd/maps/pcmciamtd.c b/trunk/drivers/mtd/maps/pcmciamtd.c index 0cc31675aeb9..1912d968718b 100644 --- a/trunk/drivers/mtd/maps/pcmciamtd.c +++ b/trunk/drivers/mtd/maps/pcmciamtd.c @@ -498,14 +498,17 @@ static int pcmciamtd_config(struct pcmcia_device *link) int i; config_info_t t; static char *probes[] = { "jedec_probe", "cfi_probe" }; + cisinfo_t cisinfo; int new_name = 0; DEBUG(3, "link=0x%p", link); DEBUG(2, "Validating CIS"); - ret = pcmcia_validate_cis(link, NULL); + ret = pcmcia_validate_cis(link, &cisinfo); if(ret != CS_SUCCESS) { cs_error(link, GetTupleData, ret); + } else { + DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains); } card_settings(dev, link, &new_name); @@ -560,7 +563,9 @@ static int pcmciamtd_config(struct pcmcia_device *link) DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); /* Get write protect status */ - DEBUG(2, "window handle = 0x%8.8lx", (unsigned long)link->win); + CS_CHECK(GetStatus, pcmcia_get_status(link, &status)); + DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx", + status.CardState, (unsigned long)link->win); dev->win_base = ioremap(req.Base, req.Size); if(!dev->win_base) { err("ioremap(%lu, %u) failed", req.Base, req.Size); diff --git a/trunk/drivers/net/xen-netfront.c b/trunk/drivers/net/xen-netfront.c index ef671d1a3bf0..d26f69b0184f 100644 --- a/trunk/drivers/net/xen-netfront.c +++ b/trunk/drivers/net/xen-netfront.c @@ -1324,7 +1324,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) goto fail; } - txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); + txs = (struct xen_netif_tx_sring *)get_zeroed_page(GFP_KERNEL); if (!txs) { err = -ENOMEM; xenbus_dev_fatal(dev, err, "allocating tx ring page"); @@ -1340,7 +1340,7 @@ static int setup_netfront(struct xenbus_device *dev, struct netfront_info *info) } info->tx_ring_ref = err; - rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); + rxs = (struct xen_netif_rx_sring *)get_zeroed_page(GFP_KERNEL); if (!rxs) { err = -ENOMEM; xenbus_dev_fatal(dev, err, "allocating rx ring page"); diff --git a/trunk/drivers/pcmcia/Kconfig b/trunk/drivers/pcmcia/Kconfig index e45402adac3f..1b0eb5aaf650 100644 --- a/trunk/drivers/pcmcia/Kconfig +++ b/trunk/drivers/pcmcia/Kconfig @@ -263,13 +263,6 @@ config OMAP_CF Say Y here to support the CompactFlash controller on OMAP. Note that this doesn't support "True IDE" mode. -config BFIN_CFPCMCIA - tristate "Blackfin CompactFlash PCMCIA Driver" - depends on PCMCIA && BLACKFIN - help - Say Y here to support the CompactFlash PCMCIA driver for Blackfin. - - config AT91_CF tristate "AT91 CompactFlash Controller" depends on PCMCIA && ARCH_AT91RM9200 diff --git a/trunk/drivers/pcmcia/Makefile b/trunk/drivers/pcmcia/Makefile index 85c6cc931f97..6f6478ba7174 100644 --- a/trunk/drivers/pcmcia/Makefile +++ b/trunk/drivers/pcmcia/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o obj-$(CONFIG_OMAP_CF) += omap_cf.o -obj-$(CONFIG_BFIN_CFPCMCIA) += bfin_cf_pcmcia.o obj-$(CONFIG_AT91_CF) += at91_cf.o obj-$(CONFIG_ELECTRA_CF) += electra_cf.o diff --git a/trunk/drivers/pcmcia/au1000_generic.h b/trunk/drivers/pcmcia/au1000_generic.h index a53ef5902518..1e467bb54077 100644 --- a/trunk/drivers/pcmcia/au1000_generic.h +++ b/trunk/drivers/pcmcia/au1000_generic.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "cs_internal.h" @@ -33,9 +34,9 @@ #define AU1000_PCMCIA_IO_SPEED (255) #define AU1000_PCMCIA_MEM_SPEED (300) -#define AU1X_SOCK0_IO 0xF00000000ULL -#define AU1X_SOCK0_PHYS_ATTR 0xF40000000ULL -#define AU1X_SOCK0_PHYS_MEM 0xF80000000ULL +#define AU1X_SOCK0_IO 0xF00000000 +#define AU1X_SOCK0_PHYS_ATTR 0xF40000000 +#define AU1X_SOCK0_PHYS_MEM 0xF80000000 /* pseudo 32 bit phys addresses, which get fixed up to the * real 36 bit address in fixup_bigphys_addr() */ #define AU1X_SOCK0_PSEUDO_PHYS_ATTR 0xF4000000 @@ -44,20 +45,16 @@ /* pcmcia socket 1 needs external glue logic so the memory map * differs from board to board. */ -#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || \ - defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || \ - defined(CONFIG_MIPS_PB1200) -#define AU1X_SOCK1_IO 0xF08000000ULL -#define AU1X_SOCK1_PHYS_ATTR 0xF48000000ULL -#define AU1X_SOCK1_PHYS_MEM 0xF88000000ULL +#if defined(CONFIG_MIPS_PB1000) || defined(CONFIG_MIPS_PB1100) || defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1550) || defined(CONFIG_MIPS_PB1200) +#define AU1X_SOCK1_IO 0xF08000000 +#define AU1X_SOCK1_PHYS_ATTR 0xF48000000 +#define AU1X_SOCK1_PHYS_MEM 0xF88000000 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4800000 #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8800000 -#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || \ - defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || \ - defined(CONFIG_MIPS_DB1200) -#define AU1X_SOCK1_IO 0xF04000000ULL -#define AU1X_SOCK1_PHYS_ATTR 0xF44000000ULL -#define AU1X_SOCK1_PHYS_MEM 0xF84000000ULL +#elif defined(CONFIG_MIPS_DB1000) || defined(CONFIG_MIPS_DB1100) || defined(CONFIG_MIPS_DB1500) || defined(CONFIG_MIPS_DB1550) || defined(CONFIG_MIPS_DB1200) +#define AU1X_SOCK1_IO 0xF04000000 +#define AU1X_SOCK1_PHYS_ATTR 0xF44000000 +#define AU1X_SOCK1_PHYS_MEM 0xF84000000 #define AU1X_SOCK1_PSEUDO_PHYS_ATTR 0xF4400000 #define AU1X_SOCK1_PSEUDO_PHYS_MEM 0xF8400000 #endif diff --git a/trunk/drivers/pcmcia/au1000_pb1x00.c b/trunk/drivers/pcmcia/au1000_pb1x00.c index aa1cd4d3aa29..157e41423a0a 100644 --- a/trunk/drivers/pcmcia/au1000_pb1x00.c +++ b/trunk/drivers/pcmcia/au1000_pb1x00.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/au1000_xxs1500.c b/trunk/drivers/pcmcia/au1000_xxs1500.c index 8a9b18cee847..c78ed5347510 100644 --- a/trunk/drivers/pcmcia/au1000_xxs1500.c +++ b/trunk/drivers/pcmcia/au1000_xxs1500.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/bfin_cf_pcmcia.c b/trunk/drivers/pcmcia/bfin_cf_pcmcia.c deleted file mode 100644 index bb7338863fb9..000000000000 --- a/trunk/drivers/pcmcia/bfin_cf_pcmcia.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * file: drivers/pcmcia/bfin_cf.c - * - * based on: drivers/pcmcia/omap_cf.c - * omap_cf.c -- OMAP 16xx CompactFlash controller driver - * - * Copyright (c) 2005 David Brownell - * Copyright (c) 2006-2008 Michael Hennerich Analog Devices Inc. - * - * bugs: enter bugs at http://blackfin.uclinux.org/ - * - * this program is free software; you can redistribute it and/or modify - * it under the terms of the gnu general public license as published by - * the free software foundation; either version 2, or (at your option) - * any later version. - * - * this program is distributed in the hope that it will be useful, - * but without any warranty; without even the implied warranty of - * merchantability or fitness for a particular purpose. see the - * gnu general public license for more details. - * - * you should have received a copy of the gnu general public license - * along with this program; see the file copying. - * if not, write to the free software foundation, - * 59 temple place - suite 330, boston, ma 02111-1307, usa. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SZ_1K 0x00000400 -#define SZ_8K 0x00002000 -#define SZ_2K (2 * SZ_1K) - -#define POLL_INTERVAL (2 * HZ) - -#define CF_ATASEL_ENA 0x20311802 /* Inverts RESET */ -#define CF_ATASEL_DIS 0x20311800 - -#define bfin_cf_present(pfx) (gpio_get_value(pfx)) - -/*--------------------------------------------------------------------------*/ - -static const char driver_name[] = "bfin_cf_pcmcia"; - -struct bfin_cf_socket { - struct pcmcia_socket socket; - - struct timer_list timer; - unsigned present:1; - unsigned active:1; - - struct platform_device *pdev; - unsigned long phys_cf_io; - unsigned long phys_cf_attr; - u_int irq; - u_short cd_pfx; -}; - -/*--------------------------------------------------------------------------*/ -static int bfin_cf_reset(void) -{ - outw(0, CF_ATASEL_ENA); - mdelay(200); - outw(0, CF_ATASEL_DIS); - - return 0; -} - -static int bfin_cf_ss_init(struct pcmcia_socket *s) -{ - return 0; -} - -/* the timer is primarily to kick this socket's pccardd */ -static void bfin_cf_timer(unsigned long _cf) -{ - struct bfin_cf_socket *cf = (void *)_cf; - unsigned short present = bfin_cf_present(cf->cd_pfx); - - if (present != cf->present) { - cf->present = present; - dev_dbg(&cf->pdev->dev, ": card %s\n", - present ? "present" : "gone"); - pcmcia_parse_events(&cf->socket, SS_DETECT); - } - - if (cf->active) - mod_timer(&cf->timer, jiffies + POLL_INTERVAL); -} - -static int bfin_cf_get_status(struct pcmcia_socket *s, u_int *sp) -{ - struct bfin_cf_socket *cf; - - if (!sp) - return -EINVAL; - - cf = container_of(s, struct bfin_cf_socket, socket); - - if (bfin_cf_present(cf->cd_pfx)) { - *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD; - s->irq.AssignedIRQ = 0; - s->pci_irq = cf->irq; - - } else - *sp = 0; - return 0; -} - -static int -bfin_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) -{ - - struct bfin_cf_socket *cf; - cf = container_of(sock, struct bfin_cf_socket, socket); - - switch (s->Vcc) { - case 0: - case 33: - break; - case 50: - break; - default: - return -EINVAL; - } - - if (s->flags & SS_RESET) { - disable_irq(cf->irq); - bfin_cf_reset(); - enable_irq(cf->irq); - } - - dev_dbg(&cf->pdev->dev, ": Vcc %d, io_irq %d, flags %04x csc %04x\n", - s->Vcc, s->io_irq, s->flags, s->csc_mask); - - return 0; -} - -static int bfin_cf_ss_suspend(struct pcmcia_socket *s) -{ - return bfin_cf_set_socket(s, &dead_socket); -} - -/* regions are 2K each: mem, attrib, io (and reserved-for-ide) */ - -static int bfin_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) -{ - struct bfin_cf_socket *cf; - - cf = container_of(s, struct bfin_cf_socket, socket); - io->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT; - io->start = cf->phys_cf_io; - io->stop = io->start + SZ_2K - 1; - return 0; -} - -static int -bfin_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) -{ - struct bfin_cf_socket *cf; - - if (map->card_start) - return -EINVAL; - cf = container_of(s, struct bfin_cf_socket, socket); - map->static_start = cf->phys_cf_io; - map->flags &= MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT; - if (map->flags & MAP_ATTRIB) - map->static_start = cf->phys_cf_attr; - - return 0; -} - -static struct pccard_operations bfin_cf_ops = { - .init = bfin_cf_ss_init, - .suspend = bfin_cf_ss_suspend, - .get_status = bfin_cf_get_status, - .set_socket = bfin_cf_set_socket, - .set_io_map = bfin_cf_set_io_map, - .set_mem_map = bfin_cf_set_mem_map, -}; - -/*--------------------------------------------------------------------------*/ - -static int __devinit bfin_cf_probe(struct platform_device *pdev) -{ - struct bfin_cf_socket *cf; - struct resource *io_mem, *attr_mem; - int irq; - unsigned short cd_pfx; - int status = 0; - - dev_info(&pdev->dev, "Blackfin CompactFlash/PCMCIA Socket Driver\n"); - - irq = platform_get_irq(pdev, 0); - if (!irq) - return -EINVAL; - - cd_pfx = platform_get_irq(pdev, 1); /*Card Detect GPIO PIN */ - - if (gpio_request(cd_pfx, "pcmcia: CD")) { - dev_err(&pdev->dev, - "Failed ro request Card Detect GPIO_%d\n", - cd_pfx); - return -EBUSY; - } - gpio_direction_input(cd_pfx); - - cf = kzalloc(sizeof *cf, GFP_KERNEL); - if (!cf) { - gpio_free(cd_pfx); - return -ENOMEM; - } - - cf->cd_pfx = cd_pfx; - - setup_timer(&cf->timer, bfin_cf_timer, (unsigned long)cf); - - cf->pdev = pdev; - platform_set_drvdata(pdev, cf); - - cf->irq = irq; - cf->socket.pci_irq = irq; - - set_irq_type(irq, IRQF_TRIGGER_LOW); - - io_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - attr_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - if (!io_mem || !attr_mem) - goto fail0; - - cf->phys_cf_io = io_mem->start; - cf->phys_cf_attr = attr_mem->start; - - /* pcmcia layer only remaps "real" memory */ - cf->socket.io_offset = (unsigned long) - ioremap(cf->phys_cf_io, SZ_2K); - - if (!cf->socket.io_offset) - goto fail0; - - dev_err(&pdev->dev, ": on irq %d\n", irq); - - dev_dbg(&pdev->dev, ": %s\n", - bfin_cf_present(cf->cd_pfx) ? "present" : "(not present)"); - - cf->socket.owner = THIS_MODULE; - cf->socket.dev.parent = &pdev->dev; - cf->socket.ops = &bfin_cf_ops; - cf->socket.resource_ops = &pccard_static_ops; - cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP - | SS_CAP_MEM_ALIGN; - cf->socket.map_size = SZ_2K; - - status = pcmcia_register_socket(&cf->socket); - if (status < 0) - goto fail2; - - cf->active = 1; - mod_timer(&cf->timer, jiffies + POLL_INTERVAL); - return 0; - -fail2: - iounmap((void __iomem *)cf->socket.io_offset); - release_mem_region(cf->phys_cf_io, SZ_8K); - -fail0: - gpio_free(cf->cd_pfx); - kfree(cf); - platform_set_drvdata(pdev, NULL); - - return status; -} - -static int __devexit bfin_cf_remove(struct platform_device *pdev) -{ - struct bfin_cf_socket *cf = platform_get_drvdata(pdev); - - gpio_free(cf->cd_pfx); - cf->active = 0; - pcmcia_unregister_socket(&cf->socket); - del_timer_sync(&cf->timer); - iounmap((void __iomem *)cf->socket.io_offset); - release_mem_region(cf->phys_cf_io, SZ_8K); - platform_set_drvdata(pdev, NULL); - kfree(cf); - return 0; -} - -static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg) -{ - return pcmcia_socket_dev_suspend(&pdev->dev, mesg); -} - -static int bfin_cf_resume(struct platform_device *pdev) -{ - return pcmcia_socket_dev_resume(&pdev->dev); -} - -static struct platform_driver bfin_cf_driver = { - .driver = { - .name = (char *)driver_name, - .owner = THIS_MODULE, - }, - .probe = bfin_cf_probe, - .remove = __devexit_p(bfin_cf_remove), - .suspend = bfin_cf_suspend, - .resume = bfin_cf_resume, -}; - -static int __init bfin_cf_init(void) -{ - return platform_driver_register(&bfin_cf_driver); -} - -static void __exit bfin_cf_exit(void) -{ - platform_driver_unregister(&bfin_cf_driver); -} - -module_init(bfin_cf_init); -module_exit(bfin_cf_exit); - -MODULE_AUTHOR("Michael Hennerich ") -MODULE_DESCRIPTION("BFIN CF/PCMCIA Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/pcmcia/cardbus.c b/trunk/drivers/pcmcia/cardbus.c index 911ca0e8dfc2..fb2f38dc92c5 100644 --- a/trunk/drivers/pcmcia/cardbus.c +++ b/trunk/drivers/pcmcia/cardbus.c @@ -30,9 +30,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/cistpl.c b/trunk/drivers/pcmcia/cistpl.c index 9fcff0c33619..36379535f9da 100644 --- a/trunk/drivers/pcmcia/cistpl.c +++ b/trunk/drivers/pcmcia/cistpl.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include "cs_internal.h" @@ -1438,11 +1439,10 @@ EXPORT_SYMBOL(pccard_read_tuple); ======================================================================*/ -int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *info) +int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info) { tuple_t *tuple; cisparse_t *p; - unsigned int count = 0; int ret, reserved, dev_ok = 0, ident_ok = 0; if (!s) @@ -1457,7 +1457,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned return CS_OUT_OF_RESOURCE; } - count = reserved = 0; + info->Chains = reserved = 0; tuple->DesiredTuple = RETURN_FIRST_TUPLE; tuple->Attributes = TUPLE_RETURN_COMMON; ret = pccard_get_first_tuple(s, function, tuple); @@ -1482,7 +1482,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned if (!dev_ok && !ident_ok) goto done; - for (count = 1; count < MAX_TUPLES; count++) { + for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) { ret = pccard_get_next_tuple(s, function, tuple); if (ret != CS_SUCCESS) break; if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || @@ -1490,13 +1490,11 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) reserved++; } - if ((count) || (reserved > 5) || - ((!dev_ok || !ident_ok) && (count > 10))) - count = 0; + if ((info->Chains == MAX_TUPLES) || (reserved > 5) || + ((!dev_ok || !ident_ok) && (info->Chains > 10))) + info->Chains = 0; done: - if (info) - *info = count; kfree(tuple); kfree(p); return CS_SUCCESS; diff --git a/trunk/drivers/pcmcia/cs.c b/trunk/drivers/pcmcia/cs.c index d1207393fc3e..29276bd28295 100644 --- a/trunk/drivers/pcmcia/cs.c +++ b/trunk/drivers/pcmcia/cs.c @@ -32,9 +32,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include #include @@ -236,6 +238,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) init_completion(&socket->socket_released); init_completion(&socket->thread_done); + init_waitqueue_head(&socket->thread_wait); mutex_init(&socket->skt_mutex); spin_lock_init(&socket->thread_lock); @@ -275,9 +278,10 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops); - if (socket->thread) + if (socket->thread) { + wake_up(&socket->thread_wait); kthread_stop(socket->thread); - + } release_cis_mem(socket); /* remove from our own list */ @@ -631,6 +635,7 @@ static void socket_detect_change(struct pcmcia_socket *skt) static int pccardd(void *__skt) { struct pcmcia_socket *skt = __skt; + DECLARE_WAITQUEUE(wait, current); int ret; skt->thread = current; @@ -651,6 +656,7 @@ static int pccardd(void *__skt) if (ret) dev_warn(&skt->dev, "err %d adding socket attributes\n", ret); + add_wait_queue(&skt->thread_wait, &wait); complete(&skt->thread_done); set_freezable(); @@ -688,6 +694,8 @@ static int pccardd(void *__skt) /* make sure we are running before we exit */ set_current_state(TASK_RUNNING); + remove_wait_queue(&skt->thread_wait, &wait); + /* remove from the device core */ pccard_sysfs_remove_socket(&skt->dev); device_unregister(&skt->dev); @@ -708,7 +716,7 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) s->thread_events |= events; spin_unlock_irqrestore(&s->thread_lock, flags); - wake_up_process(s->thread); + wake_up(&s->thread_wait); } } /* pcmcia_parse_events */ EXPORT_SYMBOL(pcmcia_parse_events); diff --git a/trunk/drivers/pcmcia/cs_internal.h b/trunk/drivers/pcmcia/cs_internal.h index 63dc1a28bda2..e7d5d141f24d 100644 --- a/trunk/drivers/pcmcia/cs_internal.h +++ b/trunk/drivers/pcmcia/cs_internal.h @@ -26,6 +26,18 @@ #define CLIENT_WIN_REQ(i) (0x1<<(i)) #define CLIENT_CARDBUS 0x8000 +#define REGION_MAGIC 0xE3C9 +typedef struct region_t { + u_short region_magic; + u_short state; + dev_info_t dev_info; + struct pcmcia_device *mtd; + u_int MediaID; + region_info_t info; +} region_t; + +#define REGION_STALE 0x01 + /* Each card function gets one of these guys */ typedef struct config_t { struct kref ref; @@ -118,6 +130,7 @@ extern struct list_head pcmcia_socket_list; int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req); int pccard_get_configuration_info(struct pcmcia_socket *s, struct pcmcia_device *p_dev, config_info_t *config); int pccard_reset_card(struct pcmcia_socket *skt); +int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, cs_status_t *status); struct pcmcia_callback{ diff --git a/trunk/drivers/pcmcia/ds.c b/trunk/drivers/pcmcia/ds.c index 4174d9656e35..e40775443d04 100644 --- a/trunk/drivers/pcmcia/ds.c +++ b/trunk/drivers/pcmcia/ds.c @@ -25,6 +25,7 @@ #include #include +#define IN_CARD_SERVICES #include #include #include @@ -740,8 +741,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f static int pcmcia_card_add(struct pcmcia_socket *s) { + cisinfo_t cisinfo; cistpl_longlink_mfc_t mfc; - unsigned int no_funcs, i, no_chains; + unsigned int no_funcs, i; int ret = 0; if (!(s->resource_setup_done)) { @@ -755,8 +757,8 @@ static int pcmcia_card_add(struct pcmcia_socket *s) return -EAGAIN; /* try again, but later... */ } - ret = pccard_validate_cis(s, BIND_FN_ALL, &no_chains); - if (ret || !no_chains) { + ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); + if (ret || !cisinfo.Chains) { ds_dbg(0, "invalid CIS or invalid resources\n"); return -ENODEV; } @@ -850,7 +852,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) { struct pcmcia_socket *s = dev->socket; const struct firmware *fw; - char path[FIRMWARE_NAME_MAX]; + char path[20]; int ret = -ENOMEM; int no_funcs; int old_funcs; @@ -862,7 +864,7 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) ds_dbg(1, "trying to load CIS file %s\n", filename); - if (strlen(filename) > (FIRMWARE_NAME_MAX - 1)) { + if (strlen(filename) > 14) { printk(KERN_WARNING "pcmcia: CIS filename is too long [%s]\n", filename); return -EINVAL; diff --git a/trunk/drivers/pcmcia/hd64465_ss.c b/trunk/drivers/pcmcia/hd64465_ss.c index fb2bc1fb015d..f2e810f53c81 100644 --- a/trunk/drivers/pcmcia/hd64465_ss.c +++ b/trunk/drivers/pcmcia/hd64465_ss.c @@ -1,4 +1,6 @@ /* + * $Id: hd64465_ss.c,v 1.7 2003/07/06 14:42:50 lethal Exp $ + * * Device driver for the PCMCIA controller module of the * Hitachi HD64465 handheld companion chip. * @@ -46,6 +48,7 @@ #include #include #include +#include #include "cs_internal.h" #define MODNAME "hd64465_ss" diff --git a/trunk/drivers/pcmcia/i82092.c b/trunk/drivers/pcmcia/i82092.c index 46561face128..e13618656ff7 100644 --- a/trunk/drivers/pcmcia/i82092.c +++ b/trunk/drivers/pcmcia/i82092.c @@ -5,6 +5,8 @@ * * Author: Arjan Van De Ven * Loosly based on i82365.c from the pcmcia-cs package + * + * $Id: i82092aa.c,v 1.2 2001/10/23 14:43:34 arjanv Exp $ */ #include diff --git a/trunk/drivers/pcmcia/i82092aa.h b/trunk/drivers/pcmcia/i82092aa.h index 8836d393ad02..b0d453303c5d 100644 --- a/trunk/drivers/pcmcia/i82092aa.h +++ b/trunk/drivers/pcmcia/i82092aa.h @@ -3,6 +3,8 @@ #include +/* $Id: i82092aa.h,v 1.1.1.1 2001/09/19 14:53:15 dwmw2 Exp $ */ + /* Debuging defines */ #ifdef NOTRACE #define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) diff --git a/trunk/drivers/pcmcia/i82365.c b/trunk/drivers/pcmcia/i82365.c index 68f6b2702bc4..32a2ab119798 100644 --- a/trunk/drivers/pcmcia/i82365.c +++ b/trunk/drivers/pcmcia/i82365.c @@ -1263,7 +1263,7 @@ static int __init init_i82365(void) ret = driver_register(&i82365_driver); if (ret) - goto err_out; + return ret; i82365_device = platform_device_alloc("i82365", 0); if (i82365_device) { @@ -1273,8 +1273,10 @@ static int __init init_i82365(void) } else ret = -ENOMEM; - if (ret) - goto err_driver_unregister; + if (ret) { + driver_unregister(&i82365_driver); + return ret; + } printk(KERN_INFO "Intel ISA PCIC probe: "); sockets = 0; @@ -1283,17 +1285,16 @@ static int __init init_i82365(void) if (sockets == 0) { printk("not found.\n"); - ret = -ENODEV; - goto err_dev_unregister; + platform_device_unregister(i82365_device); + release_region(i365_base, 2); + driver_unregister(&i82365_driver); + return -ENODEV; } /* Set up interrupt handler(s) */ if (grab_irq != 0) - ret = request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); - - if (ret) - goto err_socket_release; - + request_irq(cs_irq, pcic_interrupt, 0, "i82365", pcic_interrupt); + /* register sockets with the pcmcia core */ for (i = 0; i < sockets; i++) { socket[i].socket.dev.parent = &i82365_device->dev; @@ -1323,23 +1324,7 @@ static int __init init_i82365(void) } return 0; -err_socket_release: - for (i = 0; i < sockets; i++) { - /* Turn off all interrupt sources! */ - i365_set(i, I365_CSCINT, 0); - release_region(socket[i].ioaddr, 2); - } -err_dev_unregister: - platform_device_unregister(i82365_device); - release_region(i365_base, 2); -#ifdef CONFIG_PNP - if (i82365_pnpdev) - pnp_disable_dev(i82365_pnpdev); -#endif -err_driver_unregister: - driver_unregister(&i82365_driver); -err_out: - return ret; + } /* init_i82365 */ static void __exit exit_i82365(void) diff --git a/trunk/drivers/pcmcia/m8xx_pcmcia.c b/trunk/drivers/pcmcia/m8xx_pcmcia.c index 13a5fbd50a07..ac70d2cb7dd4 100644 --- a/trunk/drivers/pcmcia/m8xx_pcmcia.c +++ b/trunk/drivers/pcmcia/m8xx_pcmcia.c @@ -1,7 +1,7 @@ /* * m8xx_pcmcia.c - Linux PCMCIA socket driver for the mpc8xx series. * - * (C) 1999-2000 Magnus Damm + * (C) 1999-2000 Magnus Damm * (C) 2001-2002 Montavista Software, Inc. * * @@ -60,6 +60,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/pcmcia/pcmcia_ioctl.c b/trunk/drivers/pcmcia/pcmcia_ioctl.c index afd00e7bbbef..5f186abca108 100644 --- a/trunk/drivers/pcmcia/pcmcia_ioctl.c +++ b/trunk/drivers/pcmcia/pcmcia_ioctl.c @@ -29,10 +29,10 @@ #include #include +#define IN_CARD_SERVICES #include #include #include -#include #include #include @@ -138,154 +138,6 @@ static int proc_read_drivers(char *buf, char **start, off_t pos, } #endif - -#ifdef CONFIG_PCMCIA_PROBE - -static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) -{ - int irq; - u32 mask; - - irq = adj->resource.irq.IRQ; - if ((irq < 0) || (irq > 15)) - return CS_BAD_IRQ; - - if (adj->Action != REMOVE_MANAGED_RESOURCE) - return 0; - - mask = 1 << irq; - - if (!(s->irq_mask & mask)) - return 0; - - s->irq_mask &= ~mask; - - return 0; -} - -#else - -static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { - return CS_SUCCESS; -} - -#endif - -static int pcmcia_adjust_resource_info(adjust_t *adj) -{ - struct pcmcia_socket *s; - int ret = CS_UNSUPPORTED_FUNCTION; - unsigned long flags; - - down_read(&pcmcia_socket_list_rwsem); - list_for_each_entry(s, &pcmcia_socket_list, socket_list) { - - if (adj->Resource == RES_IRQ) - ret = adjust_irq(s, adj); - - else if (s->resource_ops->add_io) { - unsigned long begin, end; - - /* you can't use the old interface if the new - * one was used before */ - spin_lock_irqsave(&s->lock, flags); - if ((s->resource_setup_new) && - !(s->resource_setup_old)) { - spin_unlock_irqrestore(&s->lock, flags); - continue; - } else if (!(s->resource_setup_old)) - s->resource_setup_old = 1; - spin_unlock_irqrestore(&s->lock, flags); - - switch (adj->Resource) { - case RES_MEMORY_RANGE: - begin = adj->resource.memory.Base; - end = adj->resource.memory.Base + adj->resource.memory.Size - 1; - if (s->resource_ops->add_mem) - ret =s->resource_ops->add_mem(s, adj->Action, begin, end); - case RES_IO_RANGE: - begin = adj->resource.io.BasePort; - end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1; - if (s->resource_ops->add_io) - ret = s->resource_ops->add_io(s, adj->Action, begin, end); - } - if (!ret) { - /* as there's no way we know this is the - * last call to adjust_resource_info, we - * always need to assume this is the latest - * one... */ - spin_lock_irqsave(&s->lock, flags); - s->resource_setup_done = 1; - spin_unlock_irqrestore(&s->lock, flags); - } - } - } - up_read(&pcmcia_socket_list_rwsem); - - return (ret); -} - -/** pccard_get_status - * - * Get the current socket state bits. We don't support the latched - * SocketState yet: I haven't seen any point for it. - */ - -static int pccard_get_status(struct pcmcia_socket *s, - struct pcmcia_device *p_dev, - cs_status_t *status) -{ - config_t *c; - int val; - - s->ops->get_status(s, &val); - status->CardState = status->SocketState = 0; - status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; - status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; - status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; - status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; - if (s->state & SOCKET_SUSPEND) - status->CardState |= CS_EVENT_PM_SUSPEND; - if (!(s->state & SOCKET_PRESENT)) - return CS_NO_CARD; - - c = (p_dev) ? p_dev->function_config : NULL; - - if ((c != NULL) && (c->state & CONFIG_LOCKED) && - (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { - u_char reg; - if (c->CardValues & PRESENT_PIN_REPLACE) { - pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); - status->CardState |= - (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; - status->CardState |= - (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; - status->CardState |= - (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; - status->CardState |= - (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; - } else { - /* No PRR? Then assume we're always ready */ - status->CardState |= CS_EVENT_READY_CHANGE; - } - if (c->CardValues & PRESENT_EXT_STATUS) { - pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); - status->CardState |= - (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; - } - return CS_SUCCESS; - } - status->CardState |= - (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; - status->CardState |= - (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; - status->CardState |= - (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; - status->CardState |= - (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; - return CS_SUCCESS; -} /* pccard_get_status */ - /*====================================================================== These manage a ring buffer of events pending for one user process @@ -694,6 +546,8 @@ static u_int ds_poll(struct file *file, poll_table *wait) /*====================================================================*/ +extern int pcmcia_adjust_resource_info(adjust_t *adj); + static int ds_ioctl(struct inode * inode, struct file * file, u_int cmd, u_long arg) { @@ -795,7 +649,7 @@ static int ds_ioctl(struct inode * inode, struct file * file, mutex_lock(&s->skt_mutex); pcmcia_validate_mem(s); mutex_unlock(&s->skt_mutex); - ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo.Chains); + ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo); break; case DS_SUSPEND_CARD: ret = pcmcia_suspend_card(s); diff --git a/trunk/drivers/pcmcia/pcmcia_resource.c b/trunk/drivers/pcmcia/pcmcia_resource.c index 4884a18cf9e6..1d128fbd1a92 100644 --- a/trunk/drivers/pcmcia/pcmcia_resource.c +++ b/trunk/drivers/pcmcia/pcmcia_resource.c @@ -21,9 +21,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include #include @@ -309,6 +311,74 @@ int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, EXPORT_SYMBOL(pcmcia_get_window); +/** pccard_get_status + * + * Get the current socket state bits. We don't support the latched + * SocketState yet: I haven't seen any point for it. + */ + +int pccard_get_status(struct pcmcia_socket *s, struct pcmcia_device *p_dev, + cs_status_t *status) +{ + config_t *c; + int val; + + s->ops->get_status(s, &val); + status->CardState = status->SocketState = 0; + status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0; + status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0; + status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0; + status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0; + if (s->state & SOCKET_SUSPEND) + status->CardState |= CS_EVENT_PM_SUSPEND; + if (!(s->state & SOCKET_PRESENT)) + return CS_NO_CARD; + + c = (p_dev) ? p_dev->function_config : NULL; + + if ((c != NULL) && (c->state & CONFIG_LOCKED) && + (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) { + u_char reg; + if (c->CardValues & PRESENT_PIN_REPLACE) { + pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, ®); + status->CardState |= + (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0; + status->CardState |= + (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0; + status->CardState |= + (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0; + status->CardState |= + (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0; + } else { + /* No PRR? Then assume we're always ready */ + status->CardState |= CS_EVENT_READY_CHANGE; + } + if (c->CardValues & PRESENT_EXT_STATUS) { + pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, ®); + status->CardState |= + (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0; + } + return CS_SUCCESS; + } + status->CardState |= + (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0; + status->CardState |= + (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0; + status->CardState |= + (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0; + status->CardState |= + (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0; + return CS_SUCCESS; +} /* pccard_get_status */ + +int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status) +{ + return pccard_get_status(p_dev->socket, p_dev, status); +} +EXPORT_SYMBOL(pcmcia_get_status); + + + /** pcmcia_get_mem_page * * Change the card address of an already open memory window. @@ -742,15 +812,6 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) type = IRQF_SHARED; #ifdef CONFIG_PCMCIA_PROBE - -#ifdef IRQ_NOAUTOEN - /* if the underlying IRQ infrastructure allows for it, only allocate - * the IRQ, but do not enable it - */ - if (!(req->Attributes & IRQ_HANDLE_PRESENT)) - type |= IRQ_NOAUTOEN; -#endif /* IRQ_NOAUTOEN */ - if (s->irq.AssignedIRQ != 0) { /* If the interrupt is already assigned, it must be the same */ irq = s->irq.AssignedIRQ; @@ -905,7 +966,7 @@ void pcmcia_disable_device(struct pcmcia_device *p_dev) { pcmcia_release_configuration(p_dev); pcmcia_release_io(p_dev, &p_dev->io); pcmcia_release_irq(p_dev, &p_dev->irq); - if (p_dev->win) + if (&p_dev->win) pcmcia_release_window(p_dev->win); } EXPORT_SYMBOL(pcmcia_disable_device); diff --git a/trunk/drivers/pcmcia/pxa2xx_base.c b/trunk/drivers/pcmcia/pxa2xx_base.c index ccfdf1969a7f..9414163c78e7 100644 --- a/trunk/drivers/pcmcia/pxa2xx_base.c +++ b/trunk/drivers/pcmcia/pxa2xx_base.c @@ -33,6 +33,7 @@ #include #include +#include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/rsrc_mgr.c b/trunk/drivers/pcmcia/rsrc_mgr.c index c0e2afc79e3e..ce2226273aaa 100644 --- a/trunk/drivers/pcmcia/rsrc_mgr.c +++ b/trunk/drivers/pcmcia/rsrc_mgr.c @@ -21,6 +21,86 @@ #include "cs_internal.h" +#ifdef CONFIG_PCMCIA_IOCTL + +#ifdef CONFIG_PCMCIA_PROBE + +static int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) +{ + int irq; + u32 mask; + + irq = adj->resource.irq.IRQ; + if ((irq < 0) || (irq > 15)) + return CS_BAD_IRQ; + + if (adj->Action != REMOVE_MANAGED_RESOURCE) + return 0; + + mask = 1 << irq; + + if (!(s->irq_mask & mask)) + return 0; + + s->irq_mask &= ~mask; + + return 0; +} + +#else + +static inline int adjust_irq(struct pcmcia_socket *s, adjust_t *adj) { + return CS_SUCCESS; +} + +#endif + + +int pcmcia_adjust_resource_info(adjust_t *adj) +{ + struct pcmcia_socket *s; + int ret = CS_UNSUPPORTED_FUNCTION; + unsigned long flags; + + down_read(&pcmcia_socket_list_rwsem); + list_for_each_entry(s, &pcmcia_socket_list, socket_list) { + + if (adj->Resource == RES_IRQ) + ret = adjust_irq(s, adj); + + else if (s->resource_ops->adjust_resource) { + + /* you can't use the old interface if the new + * one was used before */ + spin_lock_irqsave(&s->lock, flags); + if ((s->resource_setup_new) && + !(s->resource_setup_old)) { + spin_unlock_irqrestore(&s->lock, flags); + continue; + } else if (!(s->resource_setup_old)) + s->resource_setup_old = 1; + spin_unlock_irqrestore(&s->lock, flags); + + ret = s->resource_ops->adjust_resource(s, adj); + if (!ret) { + /* as there's no way we know this is the + * last call to adjust_resource_info, we + * always need to assume this is the latest + * one... */ + spin_lock_irqsave(&s->lock, flags); + s->resource_setup_done = 1; + spin_unlock_irqrestore(&s->lock, flags); + } + } + } + up_read(&pcmcia_socket_list_rwsem); + + return (ret); +} +EXPORT_SYMBOL(pcmcia_adjust_resource_info); + +#endif + int pcmcia_validate_mem(struct pcmcia_socket *s) { if (s->resource_ops->validate_mem) @@ -84,8 +164,7 @@ struct pccard_resource_ops pccard_static_ops = { .adjust_io_region = NULL, .find_io = NULL, .find_mem = NULL, - .add_io = NULL, - .add_mem = NULL, + .adjust_resource = NULL, .init = static_init, .exit = NULL, }; @@ -185,8 +264,7 @@ struct pccard_resource_ops pccard_iodyn_ops = { .adjust_io_region = iodyn_adjust_io_region, .find_io = iodyn_find_io_region, .find_mem = NULL, - .add_io = NULL, - .add_mem = NULL, + .adjust_resource = NULL, .init = static_init, .exit = NULL, }; diff --git a/trunk/drivers/pcmcia/rsrc_nonstatic.c b/trunk/drivers/pcmcia/rsrc_nonstatic.c index d0c1d63d1891..0fcf763b9175 100644 --- a/trunk/drivers/pcmcia/rsrc_nonstatic.c +++ b/trunk/drivers/pcmcia/rsrc_nonstatic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "cs_internal.h" @@ -260,22 +261,21 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base, ======================================================================*/ /* Validation function for cards with a valid CIS */ -static int readable(struct pcmcia_socket *s, struct resource *res, - unsigned int *count) +static int readable(struct pcmcia_socket *s, struct resource *res, cisinfo_t *info) { int ret = -1; s->cis_mem.res = res; s->cis_virt = ioremap(res->start, s->map_size); if (s->cis_virt) { - ret = pccard_validate_cis(s, BIND_FN_ALL, count); + ret = pccard_validate_cis(s, BIND_FN_ALL, info); /* invalidate mapping and CIS cache */ iounmap(s->cis_virt); s->cis_virt = NULL; destroy_cis_cache(s); } s->cis_mem.res = NULL; - if ((ret != 0) || (count == 0)) + if ((ret != 0) || (info->Chains == 0)) return 0; return 1; } @@ -316,7 +316,7 @@ static int cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) { struct resource *res1, *res2; - unsigned int info1, info2; + cisinfo_t info1, info2; int ret = 0; res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe"); @@ -330,7 +330,7 @@ cis_readable(struct pcmcia_socket *s, unsigned long base, unsigned long size) free_region(res2); free_region(res1); - return (ret == 2) && (info1 == info2); + return (ret == 2) && (info1.Chains == info2.Chains); } static int @@ -766,6 +766,21 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long } +static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj) +{ + unsigned long end; + + switch (adj->Resource) { + case RES_MEMORY_RANGE: + end = adj->resource.memory.Base + adj->resource.memory.Size - 1; + return adjust_memory(s, adj->Action, adj->resource.memory.Base, end); + case RES_IO_RANGE: + end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1; + return adjust_io(s, adj->Action, adj->resource.io.BasePort, end); + } + return CS_UNSUPPORTED_FUNCTION; +} + #ifdef CONFIG_PCI static int nonstatic_autoadd_resources(struct pcmcia_socket *s) { @@ -874,8 +889,7 @@ struct pccard_resource_ops pccard_nonstatic_ops = { .adjust_io_region = nonstatic_adjust_io_region, .find_io = nonstatic_find_io_region, .find_mem = nonstatic_find_mem_region, - .add_io = adjust_io, - .add_mem = adjust_memory, + .adjust_resource = nonstatic_adjust_resource_info, .init = nonstatic_init, .exit = nonstatic_release_resource_db, }; @@ -994,34 +1008,41 @@ static ssize_t store_mem_db(struct device *dev, } static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db); -static struct attribute *pccard_rsrc_attributes[] = { - &dev_attr_available_resources_io.attr, - &dev_attr_available_resources_mem.attr, +static struct device_attribute *pccard_rsrc_attributes[] = { + &dev_attr_available_resources_io, + &dev_attr_available_resources_mem, NULL, }; -static const struct attribute_group rsrc_attributes = { - .attrs = pccard_rsrc_attributes, -}; - static int __devinit pccard_sysfs_add_rsrc(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *s = dev_get_drvdata(dev); - + struct device_attribute **attr; + int ret = 0; if (s->resource_ops != &pccard_nonstatic_ops) return 0; - return sysfs_create_group(&dev->kobj, &rsrc_attributes); + + for (attr = pccard_rsrc_attributes; *attr; attr++) { + ret = device_create_file(dev, *attr); + if (ret) + break; + } + + return ret; } static void __devexit pccard_sysfs_remove_rsrc(struct device *dev, struct class_interface *class_intf) { struct pcmcia_socket *s = dev_get_drvdata(dev); + struct device_attribute **attr; if (s->resource_ops != &pccard_nonstatic_ops) return; - sysfs_remove_group(&dev->kobj, &rsrc_attributes); + + for (attr = pccard_rsrc_attributes; *attr; attr++) + device_remove_file(dev, *attr); } static struct class_interface pccard_rsrc_interface __refdata = { diff --git a/trunk/drivers/pcmcia/soc_common.h b/trunk/drivers/pcmcia/soc_common.h index 91ef6a0da3ab..1edc1da9d353 100644 --- a/trunk/drivers/pcmcia/soc_common.h +++ b/trunk/drivers/pcmcia/soc_common.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include "cs_internal.h" diff --git a/trunk/drivers/pcmcia/socket_sysfs.c b/trunk/drivers/pcmcia/socket_sysfs.c index 006a29e91d83..562384d6f321 100644 --- a/trunk/drivers/pcmcia/socket_sysfs.c +++ b/trunk/drivers/pcmcia/socket_sysfs.c @@ -27,9 +27,11 @@ #include #include +#define IN_CARD_SERVICES #include #include #include +#include #include #include #include @@ -291,7 +293,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, count = 0; else { struct pcmcia_socket *s; - unsigned int chains; + cisinfo_t cisinfo; if (off + count > size) count = size - off; @@ -300,9 +302,9 @@ static ssize_t pccard_show_cis(struct kobject *kobj, if (!(s->state & SOCKET_PRESENT)) return -ENODEV; - if (pccard_validate_cis(s, BIND_FN_ALL, &chains)) + if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo)) return -EIO; - if (!chains) + if (!cisinfo.Chains) return -ENODATA; count = pccard_extract_cis(s, buf, off, count); diff --git a/trunk/drivers/pcmcia/ti113x.h b/trunk/drivers/pcmcia/ti113x.h index 129db7bd06c3..d29657bf1b40 100644 --- a/trunk/drivers/pcmcia/ti113x.h +++ b/trunk/drivers/pcmcia/ti113x.h @@ -155,7 +155,7 @@ #define ENE_TEST_C9_TLTENABLE 0x02 #define ENE_TEST_C9_PFENABLE_F0 0x04 #define ENE_TEST_C9_PFENABLE_F1 0x08 -#define ENE_TEST_C9_PFENABLE (ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F1) +#define ENE_TEST_C9_PFENABLE (ENE_TEST_C9_PFENABLE_F0 | ENE_TEST_C9_PFENABLE_F0) #define ENE_TEST_C9_WPDISALBLE_F0 0x40 #define ENE_TEST_C9_WPDISALBLE_F1 0x80 #define ENE_TEST_C9_WPDISALBLE (ENE_TEST_C9_WPDISALBLE_F0 | ENE_TEST_C9_WPDISALBLE_F1) @@ -692,7 +692,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) goto out; /* check state */ - yenta_get_status(&slot2->socket, &state); + yenta_get_status(&socket->socket, &state); if (state & SS_DETECT) { ret = 0; goto out; diff --git a/trunk/drivers/s390/block/dasd.c b/trunk/drivers/s390/block/dasd.c index 1b6c52ef7339..1a4025683362 100644 --- a/trunk/drivers/s390/block/dasd.c +++ b/trunk/drivers/s390/block/dasd.c @@ -995,14 +995,14 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, now = get_clock(); DBF_EVENT(DBF_ERR, "Interrupt: bus_id %s CS/DS %04x ip %08x", - cdev->dev.bus_id, ((irb->scsw.cmd.cstat << 8) | - irb->scsw.cmd.dstat), (unsigned int) intparm); + cdev->dev.bus_id, ((irb->scsw.cstat<<8)|irb->scsw.dstat), + (unsigned int) intparm); /* check for unsolicited interrupts */ cqr = (struct dasd_ccw_req *) intparm; - if (!cqr || ((irb->scsw.cmd.cc == 1) && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && - (irb->scsw.cmd.stctl & SCSW_STCTL_STATUS_PEND))) { + if (!cqr || ((irb->scsw.cc == 1) && + (irb->scsw.fctl & SCSW_FCTL_START_FUNC) && + (irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) ) { if (cqr && cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_QUEUED; device = dasd_device_from_cdev_locked(cdev); @@ -1025,7 +1025,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, /* Check for clear pending */ if (cqr->status == DASD_CQR_CLEAR_PENDING && - irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { + irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { cqr->status = DASD_CQR_CLEARED; dasd_device_clear_timer(device); wake_up(&dasd_flush_wq); @@ -1041,11 +1041,11 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, return; } DBF_DEV_EVENT(DBF_DEBUG, device, "Int: CS/DS 0x%04x for cqr %p", - ((irb->scsw.cmd.cstat << 8) | irb->scsw.cmd.dstat), cqr); + ((irb->scsw.cstat << 8) | irb->scsw.dstat), cqr); next = NULL; expires = 0; - if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && - irb->scsw.cmd.cstat == 0 && !irb->esw.esw0.erw.cons) { + if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END) && + irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) { /* request was completed successfully */ cqr->status = DASD_CQR_SUCCESS; cqr->stopclk = now; diff --git a/trunk/drivers/s390/block/dasd_3990_erp.c b/trunk/drivers/s390/block/dasd_3990_erp.c index 5c6e6f331cb0..e6700df52df4 100644 --- a/trunk/drivers/s390/block/dasd_3990_erp.c +++ b/trunk/drivers/s390/block/dasd_3990_erp.c @@ -1572,7 +1572,7 @@ dasd_3990_erp_action_1B_32(struct dasd_ccw_req * default_erp, char *sense) /* determine the address of the CCW to be restarted */ /* Imprecise ending is not set -> addr from IRB-SCSW */ - cpa = default_erp->refers->irb.scsw.cmd.cpa; + cpa = default_erp->refers->irb.scsw.cpa; if (cpa == 0) { @@ -1725,7 +1725,7 @@ dasd_3990_update_1B(struct dasd_ccw_req * previous_erp, char *sense) /* determine the address of the CCW to be restarted */ /* Imprecise ending is not set -> addr from IRB-SCSW */ - cpa = previous_erp->irb.scsw.cmd.cpa; + cpa = previous_erp->irb.scsw.cpa; if (cpa == 0) { @@ -2171,7 +2171,7 @@ dasd_3990_erp_control_check(struct dasd_ccw_req *erp) { struct dasd_device *device = erp->startdev; - if (erp->refers->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK + if (erp->refers->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK)) { DEV_MESSAGE(KERN_DEBUG, device, "%s", "channel or interface control check"); @@ -2352,9 +2352,9 @@ dasd_3990_erp_error_match(struct dasd_ccw_req *cqr1, struct dasd_ccw_req *cqr2) if ((cqr1->irb.esw.esw0.erw.cons == 0) && (cqr2->irb.esw.esw0.erw.cons == 0)) { - if ((cqr1->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | + if ((cqr1->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK)) == - (cqr2->irb.scsw.cmd.cstat & (SCHN_STAT_INTF_CTRL_CHK | + (cqr2->irb.scsw.cstat & (SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_CTRL_CHK))) return 1; /* match with ifcc*/ } @@ -2622,9 +2622,8 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } /* double-check if current erp/cqr was successfull */ - if ((cqr->irb.scsw.cmd.cstat == 0x00) && - (cqr->irb.scsw.cmd.dstat == - (DEV_STAT_CHN_END | DEV_STAT_DEV_END))) { + if ((cqr->irb.scsw.cstat == 0x00) && + (cqr->irb.scsw.dstat == (DEV_STAT_CHN_END|DEV_STAT_DEV_END))) { DEV_MESSAGE(KERN_DEBUG, device, "ERP called for successful request %p" diff --git a/trunk/drivers/s390/block/dasd_eckd.c b/trunk/drivers/s390/block/dasd_eckd.c index e0b77210d37a..a0edae091b5e 100644 --- a/trunk/drivers/s390/block/dasd_eckd.c +++ b/trunk/drivers/s390/block/dasd_eckd.c @@ -1404,14 +1404,13 @@ static void dasd_eckd_handle_unsolicited_interrupt(struct dasd_device *device, /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; - if ((irb->scsw.cmd.dstat & mask) == mask) { + if ((irb->scsw.dstat & mask) == mask) { dasd_generic_handle_state_change(device); return; } /* summary unit check */ - if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && - (irb->ecw[7] == 0x0D)) { + if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && irb->ecw[7] == 0x0D) { dasd_alias_handle_summary_unit_check(device, irb); return; } @@ -2069,11 +2068,11 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, device->cdev->dev.bus_id); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, - irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); + irb->scsw.cstat, irb->scsw.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", device->cdev->dev.bus_id, - (void *) (addr_t) irb->scsw.cmd.cpa); + (void *) (addr_t) irb->scsw.cpa); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER @@ -2123,8 +2122,7 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, /* scsw->cda is either valid or zero */ len = 0; from = ++to; - fail = (struct ccw1 *)(addr_t) - irb->scsw.cmd.cpa; /* failing CCW */ + fail = (struct ccw1 *)(addr_t) irb->scsw.cpa; /* failing CCW */ if (from < fail - 2) { from = fail - 2; /* there is a gap - print header */ len += sprintf(page, KERN_ERR PRINTK_HEADER "......\n"); diff --git a/trunk/drivers/s390/block/dasd_fba.c b/trunk/drivers/s390/block/dasd_fba.c index aee4656127f7..116611583df8 100644 --- a/trunk/drivers/s390/block/dasd_fba.c +++ b/trunk/drivers/s390/block/dasd_fba.c @@ -222,7 +222,7 @@ static void dasd_fba_handle_unsolicited_interrupt(struct dasd_device *device, /* first of all check for state change pending interrupt */ mask = DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP; - if ((irb->scsw.cmd.dstat & mask) == mask) { + if ((irb->scsw.dstat & mask) == mask) { dasd_generic_handle_state_change(device); return; } @@ -449,11 +449,11 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, device->cdev->dev.bus_id); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " in req: %p CS: 0x%02X DS: 0x%02X\n", req, - irb->scsw.cmd.cstat, irb->scsw.cmd.dstat); + irb->scsw.cstat, irb->scsw.dstat); len += sprintf(page + len, KERN_ERR PRINTK_HEADER " device %s: Failing CCW: %p\n", device->cdev->dev.bus_id, - (void *) (addr_t) irb->scsw.cmd.cpa); + (void *) (addr_t) irb->scsw.cpa); if (irb->esw.esw0.erw.cons) { for (sl = 0; sl < 4; sl++) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER @@ -498,11 +498,11 @@ dasd_fba_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, /* print failing CCW area */ len = 0; - if (act < ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2) { - act = ((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa) - 2; + if (act < ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2) { + act = ((struct ccw1 *)(addr_t) irb->scsw.cpa) - 2; len += sprintf(page + len, KERN_ERR PRINTK_HEADER "......\n"); } - end = min((struct ccw1 *)(addr_t) irb->scsw.cmd.cpa + 2, last); + end = min((struct ccw1 *)(addr_t) irb->scsw.cpa + 2, last); while (act <= end) { len += sprintf(page + len, KERN_ERR PRINTK_HEADER " CCW %p: %08X %08X DAT:", diff --git a/trunk/drivers/s390/block/dcssblk.c b/trunk/drivers/s390/block/dcssblk.c index 01fcdd91b846..bb52d2fbac18 100644 --- a/trunk/drivers/s390/block/dcssblk.c +++ b/trunk/drivers/s390/block/dcssblk.c @@ -167,8 +167,10 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch struct dcssblk_dev_info *dev_info; int rc; - if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) + if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) { + PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; + } down_write(&dcssblk_devices_sem); dev_info = container_of(dev, struct dcssblk_dev_info, dev); if (atomic_read(&dev_info->use_count)) { @@ -213,6 +215,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch set_disk_ro(dev_info->gd, 0); } } else { + PRINT_WARN("Invalid value, must be 0 or 1\n"); rc = -EINVAL; goto out; } @@ -255,8 +258,10 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char { struct dcssblk_dev_info *dev_info; - if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) + if ((count > 1) && (inbuf[1] != '\n') && (inbuf[1] != '\0')) { + PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; + } dev_info = container_of(dev, struct dcssblk_dev_info, dev); down_write(&dcssblk_devices_sem); @@ -284,6 +289,7 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char } } else { up_write(&dcssblk_devices_sem); + PRINT_WARN("Invalid value, must be 0 or 1\n"); return -EINVAL; } up_write(&dcssblk_devices_sem); @@ -435,6 +441,7 @@ dcssblk_add_store(struct device *dev, struct device_attribute *attr, const char goto out; unregister_dev: + PRINT_ERR("device_create_file() failed!\n"); list_del(&dev_info->lh); blk_cleanup_queue(dev_info->dcssblk_queue); dev_info->gd->queue = NULL; @@ -695,8 +702,10 @@ dcssblk_check_params(void) static void __exit dcssblk_exit(void) { + PRINT_DEBUG("DCSSBLOCK EXIT...\n"); s390_root_dev_unregister(dcssblk_root_dev); unregister_blkdev(dcssblk_major, DCSSBLK_NAME); + PRINT_DEBUG("...finished!\n"); } static int __init @@ -704,21 +713,27 @@ dcssblk_init(void) { int rc; + PRINT_DEBUG("DCSSBLOCK INIT...\n"); dcssblk_root_dev = s390_root_dev_register("dcssblk"); - if (IS_ERR(dcssblk_root_dev)) + if (IS_ERR(dcssblk_root_dev)) { + PRINT_ERR("device_register() failed!\n"); return PTR_ERR(dcssblk_root_dev); + } rc = device_create_file(dcssblk_root_dev, &dev_attr_add); if (rc) { + PRINT_ERR("device_create_file(add) failed!\n"); s390_root_dev_unregister(dcssblk_root_dev); return rc; } rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); if (rc) { + PRINT_ERR("device_create_file(remove) failed!\n"); s390_root_dev_unregister(dcssblk_root_dev); return rc; } rc = register_blkdev(0, DCSSBLK_NAME); if (rc < 0) { + PRINT_ERR("Can't get dynamic major!\n"); s390_root_dev_unregister(dcssblk_root_dev); return rc; } @@ -727,6 +742,7 @@ dcssblk_init(void) dcssblk_check_params(); + PRINT_DEBUG("...finished!\n"); return 0; } diff --git a/trunk/drivers/s390/block/xpram.c b/trunk/drivers/s390/block/xpram.c index dd9b986389a2..f231bc21b1ca 100644 --- a/trunk/drivers/s390/block/xpram.c +++ b/trunk/drivers/s390/block/xpram.c @@ -100,10 +100,15 @@ static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index) : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc"); if (cc == 3) return -ENXIO; - if (cc == 2) + if (cc == 2) { + PRINT_ERR("expanded storage lost!\n"); return -ENXIO; - if (cc == 1) + } + if (cc == 1) { + PRINT_ERR("page in failed for page index %u.\n", + xpage_index); return -EIO; + } return 0; } @@ -130,10 +135,15 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc"); if (cc == 3) return -ENXIO; - if (cc == 2) + if (cc == 2) { + PRINT_ERR("expanded storage lost!\n"); return -ENXIO; - if (cc == 1) + } + if (cc == 1) { + PRINT_ERR("page out failed for page index %u.\n", + xpage_index); return -EIO; + } return 0; } diff --git a/trunk/drivers/s390/char/con3215.c b/trunk/drivers/s390/char/con3215.c index d3ec9b55ab35..3e5653c92f4b 100644 --- a/trunk/drivers/s390/char/con3215.c +++ b/trunk/drivers/s390/char/con3215.c @@ -93,6 +93,9 @@ struct raw3215_info { struct raw3215_req *queued_write;/* pointer to queued write requests */ wait_queue_head_t empty_wait; /* wait queue for flushing */ struct timer_list timer; /* timer for delayed output */ + char *message; /* pending message from raw3215_irq */ + int msg_dstat; /* dstat for pending message */ + int msg_cstat; /* cstat for pending message */ int line_pos; /* position on the line (for tabs) */ char ubuffer[80]; /* copy_from_user buffer */ }; @@ -356,6 +359,11 @@ raw3215_tasklet(void *data) raw3215_mk_write_req(raw); raw3215_try_io(raw); spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); + /* Check for pending message from raw3215_irq */ + if (raw->message != NULL) { + printk(raw->message, raw->msg_dstat, raw->msg_cstat); + raw->message = NULL; + } tty = raw->tty; if (tty != NULL && RAW3215_BUFFER_SIZE - raw->count >= RAW3215_MIN_SPACE) { @@ -373,14 +381,20 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) struct raw3215_req *req; struct tty_struct *tty; int cstat, dstat; - int count; + int count, slen; raw = cdev->dev.driver_data; req = (struct raw3215_req *) intparm; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; - if (cstat != 0) + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; + if (cstat != 0) { + raw->message = KERN_WARNING + "Got nonzero channel status in raw3215_irq " + "(dev sts 0x%2x, sch sts 0x%2x)"; + raw->msg_dstat = dstat; + raw->msg_cstat = cstat; tasklet_schedule(&raw->tasklet); + } if (dstat & 0x01) { /* we got a unit exception */ dstat &= ~0x01; /* we can ignore it */ } @@ -390,6 +404,8 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) break; /* Attention interrupt, someone hit the enter key */ raw3215_mk_read_req(raw); + if (MACHINE_IS_P390) + memset(raw->inbuf, 0, RAW3215_INBUF_SIZE); tasklet_schedule(&raw->tasklet); break; case 0x08: @@ -399,7 +415,7 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) return; /* That shouldn't happen ... */ if (req->type == RAW3215_READ) { /* store residual count, then wait for device end */ - req->residual = irb->scsw.cmd.count; + req->residual = irb->scsw.count; } if (dstat == 0x08) break; @@ -412,6 +428,11 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) tty = raw->tty; count = 160 - req->residual; + if (MACHINE_IS_P390) { + slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE); + if (count > slen) + count = slen; + } else EBCASC(raw->inbuf, count); cchar = ctrlchar_handle(raw->inbuf, count, tty); switch (cchar & CTRLCHAR_MASK) { @@ -460,6 +481,11 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) raw->flags &= ~RAW3215_WORKING; raw3215_free_req(req); } + raw->message = KERN_WARNING + "Spurious interrupt in in raw3215_irq " + "(dev sts 0x%2x, sch sts 0x%2x)"; + raw->msg_dstat = dstat; + raw->msg_cstat = cstat; tasklet_schedule(&raw->tasklet); } return; @@ -857,6 +883,7 @@ con3215_init(void) free_bootmem((unsigned long) raw->buffer, RAW3215_BUFFER_SIZE); free_bootmem((unsigned long) raw, sizeof(struct raw3215_info)); raw3215[0] = NULL; + printk("Couldn't find a 3215 console device\n"); return -ENODEV; } register_console(&con3215); @@ -1130,6 +1157,7 @@ tty3215_init(void) tty_set_operations(driver, &tty3215_ops); ret = tty_register_driver(driver); if (ret) { + printk("Couldn't register tty3215 driver\n"); put_tty_driver(driver); return ret; } diff --git a/trunk/drivers/s390/char/con3270.c b/trunk/drivers/s390/char/con3270.c index 3c07974886ed..0b040557db02 100644 --- a/trunk/drivers/s390/char/con3270.c +++ b/trunk/drivers/s390/char/con3270.c @@ -411,15 +411,15 @@ static int con3270_irq(struct con3270 *cp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Schedule tasklet to read aid. */ - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) + if (irb->scsw.dstat & DEV_STAT_ATTENTION) con3270_issue_read(cp); if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } return RAW3270_IO_DONE; } diff --git a/trunk/drivers/s390/char/fs3270.c b/trunk/drivers/s390/char/fs3270.c index e136d10a0de6..ef36f2132aa4 100644 --- a/trunk/drivers/s390/char/fs3270.c +++ b/trunk/drivers/s390/char/fs3270.c @@ -216,17 +216,17 @@ static int fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Set indication and wake waiters for attention. */ - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { fp->attention = 1; wake_up(&fp->wait); } if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } return RAW3270_IO_DONE; } @@ -512,8 +512,11 @@ fs3270_init(void) int rc; rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops); - if (rc) + if (rc) { + printk(KERN_ERR "fs3270 can't get major number %d: errno %d\n", + IBM_FS3270_MAJOR, rc); return rc; + } return 0; } diff --git a/trunk/drivers/s390/char/monreader.c b/trunk/drivers/s390/char/monreader.c index f0e4c96afbf8..1e1f50655bbf 100644 --- a/trunk/drivers/s390/char/monreader.c +++ b/trunk/drivers/s390/char/monreader.c @@ -3,8 +3,9 @@ * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright IBM Corp. 2004, 2008 - * Author: Gerald Schaefer + * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. + * + * Author: Gerald Schaefer */ #include @@ -17,11 +18,12 @@ #include #include #include -#include -#include #include #include #include +#include +#include + //#define MON_DEBUG /* Debug messages on/off */ @@ -150,7 +152,10 @@ static int mon_check_mca(struct mon_msg *monmsg) (mon_mca_end(monmsg) > mon_dcss_end) || (mon_mca_start(monmsg) < mon_dcss_start) || ((mon_mca_type(monmsg, 1) == 0) && (mon_mca_type(monmsg, 2) == 0))) + { + P_DEBUG("READ, IGNORED INVALID MCA\n\n"); return -EINVAL; + } return 0; } @@ -159,6 +164,10 @@ static int mon_send_reply(struct mon_msg *monmsg, { int rc; + P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " + "0x%08X\n\n", + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); + rc = iucv_message_reply(monpriv->path, &monmsg->msg, IUCV_IPRMDATA, NULL, 0); atomic_dec(&monpriv->msglim_count); @@ -193,12 +202,15 @@ static struct mon_private *mon_alloc_mem(void) struct mon_private *monpriv; monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); - if (!monpriv) + if (!monpriv) { + P_ERROR("no memory for monpriv\n"); return NULL; + } for (i = 0; i < MON_MSGLIM; i++) { monpriv->msg_array[i] = kzalloc(sizeof(struct mon_msg), GFP_KERNEL); if (!monpriv->msg_array[i]) { + P_ERROR("open, no memory for msg_array\n"); mon_free_mem(monpriv); return NULL; } @@ -206,10 +218,41 @@ static struct mon_private *mon_alloc_mem(void) return monpriv; } +static inline void mon_read_debug(struct mon_msg *monmsg, + struct mon_private *monpriv) +{ +#ifdef MON_DEBUG + u8 msg_type[2], mca_type; + unsigned long records_len; + + records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; + + memcpy(msg_type, &monmsg->msg.class, 2); + EBCASC(msg_type, 2); + mca_type = mon_mca_type(monmsg, 0); + EBCASC(&mca_type, 1); + + P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", + monpriv->read_index, monpriv->write_index); + P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", + monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); + P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", + msg_type[0], msg_type[1], mca_type ? mca_type : 'X', + mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); + P_DEBUG("read, MCA: start = 0x%lX, end = 0x%lX\n", + mon_mca_start(monmsg), mon_mca_end(monmsg)); + P_DEBUG("read, REC: start = 0x%X, end = 0x%X, len = %lu\n\n", + mon_rec_start(monmsg), mon_rec_end(monmsg), records_len); + if (mon_mca_size(monmsg) > 12) + P_DEBUG("READ, MORE THAN ONE MCA\n\n"); +#endif +} + static inline void mon_next_mca(struct mon_msg *monmsg) { if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) return; + P_DEBUG("READ, NEXT MCA\n\n"); monmsg->mca_offset += 12; monmsg->pos = 0; } @@ -226,6 +269,7 @@ static struct mon_msg *mon_next_message(struct mon_private *monpriv) monmsg->msglim_reached = 0; monmsg->pos = 0; monmsg->mca_offset = 0; + P_WARNING("read, message limit reached\n"); monpriv->read_index = (monpriv->read_index + 1) % MON_MSGLIM; atomic_dec(&monpriv->read_ready); @@ -242,6 +286,10 @@ static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { struct mon_private *monpriv = path->private; + P_DEBUG("IUCV connection completed\n"); + P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " + "0x%02X, Sample = 0x%02X\n", + ipuser[0], ipuser[1], ipuser[2]); atomic_set(&monpriv->iucv_connected, 1); wake_up(&mon_conn_wait_queue); } @@ -262,6 +310,7 @@ static void mon_iucv_message_pending(struct iucv_path *path, { struct mon_private *monpriv = path->private; + P_DEBUG("IUCV message pending\n"); memcpy(&monpriv->msg_array[monpriv->write_index]->msg, msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { @@ -326,6 +375,7 @@ static int mon_open(struct inode *inode, struct file *filp) rc = -EIO; goto out_path; } + P_INFO("open, established connection to *MONITOR service\n\n"); filp->private_data = monpriv; return nonseekable_open(inode, filp); @@ -350,6 +400,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); + else + P_INFO("close, terminated connection to *MONITOR service\n"); atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); @@ -390,8 +442,10 @@ static ssize_t mon_read(struct file *filp, char __user *data, monmsg = monpriv->msg_array[monpriv->read_index]; } - if (!monmsg->pos) + if (!monmsg->pos) { monmsg->pos = mon_mca_start(monmsg) + monmsg->mca_offset; + mon_read_debug(monmsg, monpriv); + } if (mon_check_mca(monmsg)) goto reply; @@ -477,6 +531,7 @@ static int __init mon_init(void) P_ERROR("failed to register with iucv driver\n"); return rc; } + P_INFO("open, registered with IUCV\n"); rc = segment_type(mon_dcss_name); if (rc < 0) { @@ -500,8 +555,13 @@ static int __init mon_init(void) dcss_mkname(mon_dcss_name, &user_data_connect[8]); rc = misc_register(&mon_dev); - if (rc < 0 ) + if (rc < 0 ) { + P_ERROR("misc_register failed, rc = %i\n", rc); goto out; + } + P_INFO("Loaded segment %s from %p to %p, size = %lu Byte\n", + mon_dcss_name, (void *) mon_dcss_start, (void *) mon_dcss_end, + mon_dcss_end - mon_dcss_start + 1); return 0; out: diff --git a/trunk/drivers/s390/char/raw3270.c b/trunk/drivers/s390/char/raw3270.c index 81a96e019080..848ef7e8523f 100644 --- a/trunk/drivers/s390/char/raw3270.c +++ b/trunk/drivers/s390/char/raw3270.c @@ -153,10 +153,19 @@ struct raw3270_request __init *raw3270_request_alloc_bootmem(size_t size) struct raw3270_request *rq; rq = alloc_bootmem_low(sizeof(struct raw3270)); + if (!rq) + return ERR_PTR(-ENOMEM); + memset(rq, 0, sizeof(struct raw3270_request)); /* alloc output buffer. */ - if (size > 0) + if (size > 0) { rq->buffer = alloc_bootmem_low(size); + if (!rq->buffer) { + free_bootmem((unsigned long) rq, + sizeof(struct raw3270)); + return ERR_PTR(-ENOMEM); + } + } rq->size = size; INIT_LIST_HEAD(&rq->list); @@ -363,17 +372,17 @@ raw3270_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) if (IS_ERR(irb)) rc = RAW3270_IO_RETRY; - else if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) { + else if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { rq->rc = -EIO; rc = RAW3270_IO_DONE; - } else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END | - DEV_STAT_UNIT_EXCEP)) { + } else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END | + DEV_STAT_UNIT_EXCEP)) { /* Handle CE-DE-UE and subsequent UDE */ set_bit(RAW3270_FLAGS_BUSY, &rp->flags); rc = RAW3270_IO_BUSY; } else if (test_bit(RAW3270_FLAGS_BUSY, &rp->flags)) { /* Wait for UDE if busy flag is set. */ - if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { + if (irb->scsw.dstat & DEV_STAT_DEV_END) { clear_bit(RAW3270_FLAGS_BUSY, &rp->flags); /* Got it, now retry. */ rc = RAW3270_IO_RETRY; @@ -488,7 +497,7 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq, * Unit-Check Processing: * Expect Command Reject or Intervention Required. */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { /* Request finished abnormally. */ if (irb->ecw[0] & SNS0_INTERVENTION_REQ) { set_bit(RAW3270_FLAGS_BUSY, &view->dev->flags); @@ -496,16 +505,16 @@ raw3270_init_irq(struct raw3270_view *view, struct raw3270_request *rq, } } if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { if (irb->ecw[0] & SNS0_CMD_REJECT) rq->rc = -EOPNOTSUPP; else rq->rc = -EIO; } else /* Request finished normally. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { set_bit(RAW3270_FLAGS_ATTN, &view->dev->flags); wake_up(&raw3270_wait_queue); } @@ -610,6 +619,7 @@ __raw3270_size_device_vm(struct raw3270 *rp) rp->cols = 132; break; default: + printk(KERN_WARNING "vrdccrmd is 0x%.8x\n", model); rc = -EOPNOTSUPP; break; } diff --git a/trunk/drivers/s390/char/sclp.c b/trunk/drivers/s390/char/sclp.c index 3c8b25e6c345..2c7a1ee6b041 100644 --- a/trunk/drivers/s390/char/sclp.c +++ b/trunk/drivers/s390/char/sclp.c @@ -506,8 +506,6 @@ sclp_state_change_cb(struct evbuf_header *evbuf) if (scbuf->validity_sclp_send_mask) sclp_send_mask = scbuf->sclp_send_mask; spin_unlock_irqrestore(&sclp_lock, flags); - if (scbuf->validity_sclp_active_facility_mask) - sclp_facilities = scbuf->sclp_active_facility_mask; sclp_dispatch_state_change(); } @@ -784,9 +782,11 @@ sclp_check_handler(__u16 code) /* Is this the interrupt we are waiting for? */ if (finished_sccb == 0) return; - if (finished_sccb != (u32) (addr_t) sclp_init_sccb) - panic("sclp: unsolicited interrupt for buffer at 0x%x\n", - finished_sccb); + if (finished_sccb != (u32) (addr_t) sclp_init_sccb) { + printk(KERN_WARNING SCLP_HEADER "unsolicited interrupt " + "for buffer at 0x%x\n", finished_sccb); + return; + } spin_lock(&sclp_lock); if (sclp_running_state == sclp_running_state_running) { sclp_init_req.status = SCLP_REQ_DONE; @@ -883,6 +883,8 @@ sclp_init(void) unsigned long flags; int rc; + if (!MACHINE_HAS_SCLP) + return -ENODEV; spin_lock_irqsave(&sclp_lock, flags); /* Check for previous or running initialization */ if (sclp_init_state != sclp_init_state_uninitialized) { diff --git a/trunk/drivers/s390/char/sclp_cmd.c b/trunk/drivers/s390/char/sclp_cmd.c index 0c2b77493db4..b5c23396f8fe 100644 --- a/trunk/drivers/s390/char/sclp_cmd.c +++ b/trunk/drivers/s390/char/sclp_cmd.c @@ -11,9 +11,6 @@ #include #include #include -#include -#include -#include #include #include #include "sclp.h" @@ -46,8 +43,6 @@ static int __initdata early_read_info_sccb_valid; u64 sclp_facilities; static u8 sclp_fac84; -static unsigned long long rzm; -static unsigned long long rnmax; static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) { @@ -67,7 +62,7 @@ static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) return rc; } -static void __init sclp_read_info_early(void) +void __init sclp_read_info_early(void) { int rc; int i; @@ -97,33 +92,34 @@ static void __init sclp_read_info_early(void) void __init sclp_facilities_detect(void) { - struct read_info_sccb *sccb; - - sclp_read_info_early(); if (!early_read_info_sccb_valid) return; - - sccb = &early_read_info_sccb; - sclp_facilities = sccb->facilities; - sclp_fac84 = sccb->fac84; - rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; - rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; - rzm <<= 20; + sclp_facilities = early_read_info_sccb.facilities; + sclp_fac84 = early_read_info_sccb.fac84; } -unsigned long long sclp_get_rnmax(void) +unsigned long long __init sclp_memory_detect(void) { - return rnmax; -} + unsigned long long memsize; + struct read_info_sccb *sccb; -unsigned long long sclp_get_rzm(void) -{ - return rzm; + if (!early_read_info_sccb_valid) + return 0; + sccb = &early_read_info_sccb; + if (sccb->rnsize) + memsize = sccb->rnsize << 20; + else + memsize = sccb->rnsize2 << 20; + if (sccb->rnmax) + memsize *= sccb->rnmax; + else + memsize *= sccb->rnmax2; + return memsize; } /* - * This function will be called after sclp_facilities_detect(), which gets - * called from early.c code. Therefore the sccb should have valid contents. + * This function will be called after sclp_memory_detect(), which gets called + * early from early.c code. Therefore the sccb should have valid contents. */ void __init sclp_get_ipl_info(struct sclp_ipl_info *info) { @@ -282,305 +278,6 @@ int sclp_cpu_deconfigure(u8 cpu) return do_cpu_configure(SCLP_CMDW_DECONFIGURE_CPU | cpu << 8); } -#ifdef CONFIG_MEMORY_HOTPLUG - -static DEFINE_MUTEX(sclp_mem_mutex); -static LIST_HEAD(sclp_mem_list); -static u8 sclp_max_storage_id; -static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; - -struct memory_increment { - struct list_head list; - u16 rn; - int standby; - int usecount; -}; - -struct assign_storage_sccb { - struct sccb_header header; - u16 rn; -} __packed; - -static unsigned long long rn2addr(u16 rn) -{ - return (unsigned long long) (rn - 1) * rzm; -} - -static int do_assign_storage(sclp_cmdw_t cmd, u16 rn) -{ - struct assign_storage_sccb *sccb; - int rc; - - sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - return -ENOMEM; - sccb->header.length = PAGE_SIZE; - sccb->rn = rn; - rc = do_sync_request(cmd, sccb); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0020: - case 0x0120: - break; - default: - rc = -EIO; - break; - } -out: - free_page((unsigned long) sccb); - return rc; -} - -static int sclp_assign_storage(u16 rn) -{ - return do_assign_storage(0x000d0001, rn); -} - -static int sclp_unassign_storage(u16 rn) -{ - return do_assign_storage(0x000c0001, rn); -} - -struct attach_storage_sccb { - struct sccb_header header; - u16 :16; - u16 assigned; - u32 :32; - u32 entries[0]; -} __packed; - -static int sclp_attach_storage(u8 id) -{ - struct attach_storage_sccb *sccb; - int rc; - int i; - - sccb = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - return -ENOMEM; - sccb->header.length = PAGE_SIZE; - rc = do_sync_request(0x00080001 | id << 8, sccb); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0020: - set_bit(id, sclp_storage_ids); - for (i = 0; i < sccb->assigned; i++) - sclp_unassign_storage(sccb->entries[i] >> 16); - break; - default: - rc = -EIO; - break; - } -out: - free_page((unsigned long) sccb); - return rc; -} - -static int sclp_mem_change_state(unsigned long start, unsigned long size, - int online) -{ - struct memory_increment *incr; - unsigned long long istart; - int rc = 0; - - list_for_each_entry(incr, &sclp_mem_list, list) { - istart = rn2addr(incr->rn); - if (start + size - 1 < istart) - break; - if (start > istart + rzm - 1) - continue; - if (online) { - if (incr->usecount++) - continue; - /* - * Don't break the loop if one assign fails. Loop may - * be walked again on CANCEL and we can't save - * information if state changed before or not. - * So continue and increase usecount for all increments. - */ - rc |= sclp_assign_storage(incr->rn); - } else { - if (--incr->usecount) - continue; - sclp_unassign_storage(incr->rn); - } - } - return rc ? -EIO : 0; -} - -static int sclp_mem_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - unsigned long start, size; - struct memory_notify *arg; - unsigned char id; - int rc = 0; - - arg = data; - start = arg->start_pfn << PAGE_SHIFT; - size = arg->nr_pages << PAGE_SHIFT; - mutex_lock(&sclp_mem_mutex); - for (id = 0; id <= sclp_max_storage_id; id++) - if (!test_bit(id, sclp_storage_ids)) - sclp_attach_storage(id); - switch (action) { - case MEM_ONLINE: - break; - case MEM_GOING_ONLINE: - rc = sclp_mem_change_state(start, size, 1); - break; - case MEM_CANCEL_ONLINE: - sclp_mem_change_state(start, size, 0); - break; - default: - rc = -EINVAL; - break; - } - mutex_unlock(&sclp_mem_mutex); - return rc ? NOTIFY_BAD : NOTIFY_OK; -} - -static struct notifier_block sclp_mem_nb = { - .notifier_call = sclp_mem_notifier, -}; - -static void __init add_memory_merged(u16 rn) -{ - static u16 first_rn, num; - unsigned long long start, size; - - if (rn && first_rn && (first_rn + num == rn)) { - num++; - return; - } - if (!first_rn) - goto skip_add; - start = rn2addr(first_rn); - size = (unsigned long long ) num * rzm; - if (start >= VMEM_MAX_PHYS) - goto skip_add; - if (start + size > VMEM_MAX_PHYS) - size = VMEM_MAX_PHYS - start; - add_memory(0, start, size); -skip_add: - first_rn = rn; - num = 1; -} - -static void __init sclp_add_standby_memory(void) -{ - struct memory_increment *incr; - - list_for_each_entry(incr, &sclp_mem_list, list) - if (incr->standby) - add_memory_merged(incr->rn); - add_memory_merged(0); -} - -static void __init insert_increment(u16 rn, int standby, int assigned) -{ - struct memory_increment *incr, *new_incr; - struct list_head *prev; - u16 last_rn; - - new_incr = kzalloc(sizeof(*new_incr), GFP_KERNEL); - if (!new_incr) - return; - new_incr->rn = rn; - new_incr->standby = standby; - last_rn = 0; - prev = &sclp_mem_list; - list_for_each_entry(incr, &sclp_mem_list, list) { - if (assigned && incr->rn > rn) - break; - if (!assigned && incr->rn - last_rn > 1) - break; - last_rn = incr->rn; - prev = &incr->list; - } - if (!assigned) - new_incr->rn = last_rn + 1; - if (new_incr->rn > rnmax) { - kfree(new_incr); - return; - } - list_add(&new_incr->list, prev); -} - -struct read_storage_sccb { - struct sccb_header header; - u16 max_id; - u16 assigned; - u16 standby; - u16 :16; - u32 entries[0]; -} __packed; - -static int __init sclp_detect_standby_memory(void) -{ - struct read_storage_sccb *sccb; - int i, id, assigned, rc; - - if (!early_read_info_sccb_valid) - return 0; - if ((sclp_facilities & 0xe00000000000ULL) != 0xe00000000000ULL) - return 0; - rc = -ENOMEM; - sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA); - if (!sccb) - goto out; - assigned = 0; - for (id = 0; id <= sclp_max_storage_id; id++) { - memset(sccb, 0, PAGE_SIZE); - sccb->header.length = PAGE_SIZE; - rc = do_sync_request(0x00040001 | id << 8, sccb); - if (rc) - goto out; - switch (sccb->header.response_code) { - case 0x0010: - set_bit(id, sclp_storage_ids); - for (i = 0; i < sccb->assigned; i++) { - if (!sccb->entries[i]) - continue; - assigned++; - insert_increment(sccb->entries[i] >> 16, 0, 1); - } - break; - case 0x0310: - break; - case 0x0410: - for (i = 0; i < sccb->assigned; i++) { - if (!sccb->entries[i]) - continue; - assigned++; - insert_increment(sccb->entries[i] >> 16, 1, 1); - } - break; - default: - rc = -EIO; - break; - } - if (!rc) - sclp_max_storage_id = sccb->max_id; - } - if (rc || list_empty(&sclp_mem_list)) - goto out; - for (i = 1; i <= rnmax - assigned; i++) - insert_increment(0, 1, 0); - rc = register_memory_notifier(&sclp_mem_nb); - if (rc) - goto out; - sclp_add_standby_memory(); -out: - free_page((unsigned long) sccb); - return rc; -} -__initcall(sclp_detect_standby_memory); - -#endif /* CONFIG_MEMORY_HOTPLUG */ - /* * Channel path configuration related functions. */ diff --git a/trunk/drivers/s390/char/sclp_con.c b/trunk/drivers/s390/char/sclp_con.c index 7e619c534bf4..ead1043d788e 100644 --- a/trunk/drivers/s390/char/sclp_con.c +++ b/trunk/drivers/s390/char/sclp_con.c @@ -14,13 +14,14 @@ #include #include #include -#include #include #include "sclp.h" #include "sclp_rw.h" #include "sclp_tty.h" +#define SCLP_CON_PRINT_HEADER "sclp console driver: " + #define sclp_console_major 4 /* TTYAUX_MAJOR */ #define sclp_console_minor 64 #define sclp_console_name "ttyS" @@ -221,6 +222,8 @@ sclp_console_init(void) INIT_LIST_HEAD(&sclp_con_pages); for (i = 0; i < MAX_CONSOLE_PAGES; i++) { page = alloc_bootmem_low_pages(PAGE_SIZE); + if (page == NULL) + return -ENOMEM; list_add_tail((struct list_head *) page, &sclp_con_pages); } INIT_LIST_HEAD(&sclp_con_outqueue); diff --git a/trunk/drivers/s390/char/sclp_config.c b/trunk/drivers/s390/char/sclp_config.c index fff4ff485d9b..ad05a87bc480 100644 --- a/trunk/drivers/s390/char/sclp_config.c +++ b/trunk/drivers/s390/char/sclp_config.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -41,19 +40,9 @@ static void sclp_cpu_capability_notify(struct work_struct *work) put_online_cpus(); } -static int sclp_cpu_kthread(void *data) -{ - smp_rescan_cpus(); - return 0; -} - static void __ref sclp_cpu_change_notify(struct work_struct *work) { - /* Can't call smp_rescan_cpus() from workqueue context since it may - * deadlock in case of cpu hotplug. So we have to create a kernel - * thread in order to call it. - */ - kthread_run(sclp_cpu_kthread, NULL, "cpu_rescan"); + smp_rescan_cpus(); } static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) @@ -85,8 +74,10 @@ static int __init sclp_conf_init(void) INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); rc = sclp_register(&sclp_conf_register); - if (rc) + if (rc) { + printk(KERN_ERR TAG "failed to register (%d).\n", rc); return rc; + } if (!(sclp_conf_register.sclp_send_mask & EVTYP_CONFMGMDATA_MASK)) { printk(KERN_WARNING TAG "no configuration management.\n"); diff --git a/trunk/drivers/s390/char/sclp_cpi_sys.c b/trunk/drivers/s390/char/sclp_cpi_sys.c index d887bd261d28..9f37456222e9 100644 --- a/trunk/drivers/s390/char/sclp_cpi_sys.c +++ b/trunk/drivers/s390/char/sclp_cpi_sys.c @@ -27,8 +27,6 @@ #define CPI_LENGTH_NAME 8 #define CPI_LENGTH_LEVEL 16 -static DEFINE_MUTEX(sclp_cpi_mutex); - struct cpi_evbuf { struct evbuf_header header; u8 id_format; @@ -126,15 +124,21 @@ static int cpi_req(void) int response; rc = sclp_register(&sclp_cpi_event); - if (rc) + if (rc) { + printk(KERN_WARNING "cpi: could not register " + "to hardware console.\n"); goto out; + } if (!(sclp_cpi_event.sclp_receive_mask & EVTYP_CTLPROGIDENT_MASK)) { + printk(KERN_WARNING "cpi: no control program " + "identification support\n"); rc = -EOPNOTSUPP; goto out_unregister; } req = cpi_prepare_req(); if (IS_ERR(req)) { + printk(KERN_WARNING "cpi: could not allocate request\n"); rc = PTR_ERR(req); goto out_unregister; } @@ -144,8 +148,10 @@ static int cpi_req(void) /* Add request to sclp queue */ rc = sclp_add_request(req); - if (rc) + if (rc) { + printk(KERN_WARNING "cpi: could not start request\n"); goto out_free_req; + } wait_for_completion(&completion); @@ -217,12 +223,7 @@ static void set_string(char *attr, const char *value) static ssize_t system_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - int rc; - - mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", system_name); - mutex_unlock(&sclp_cpi_mutex); - return rc; + return snprintf(page, PAGE_SIZE, "%s\n", system_name); } static ssize_t system_name_store(struct kobject *kobj, @@ -236,9 +237,7 @@ static ssize_t system_name_store(struct kobject *kobj, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(system_name, buf); - mutex_unlock(&sclp_cpi_mutex); return len; } @@ -249,12 +248,7 @@ static struct kobj_attribute system_name_attr = static ssize_t sysplex_name_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - int rc; - - mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", sysplex_name); - mutex_unlock(&sclp_cpi_mutex); - return rc; + return snprintf(page, PAGE_SIZE, "%s\n", sysplex_name); } static ssize_t sysplex_name_store(struct kobject *kobj, @@ -268,9 +262,7 @@ static ssize_t sysplex_name_store(struct kobject *kobj, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(sysplex_name, buf); - mutex_unlock(&sclp_cpi_mutex); return len; } @@ -281,12 +273,7 @@ static struct kobj_attribute sysplex_name_attr = static ssize_t system_type_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - int rc; - - mutex_lock(&sclp_cpi_mutex); - rc = snprintf(page, PAGE_SIZE, "%s\n", system_type); - mutex_unlock(&sclp_cpi_mutex); - return rc; + return snprintf(page, PAGE_SIZE, "%s\n", system_type); } static ssize_t system_type_store(struct kobject *kobj, @@ -300,9 +287,7 @@ static ssize_t system_type_store(struct kobject *kobj, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(system_type, buf); - mutex_unlock(&sclp_cpi_mutex); return len; } @@ -313,11 +298,8 @@ static struct kobj_attribute system_type_attr = static ssize_t system_level_show(struct kobject *kobj, struct kobj_attribute *attr, char *page) { - unsigned long long level; + unsigned long long level = system_level; - mutex_lock(&sclp_cpi_mutex); - level = system_level; - mutex_unlock(&sclp_cpi_mutex); return snprintf(page, PAGE_SIZE, "%#018llx\n", level); } @@ -338,9 +320,8 @@ static ssize_t system_level_store(struct kobject *kobj, if (*endp) return -EINVAL; - mutex_lock(&sclp_cpi_mutex); system_level = level; - mutex_unlock(&sclp_cpi_mutex); + return len; } @@ -353,9 +334,7 @@ static ssize_t set_store(struct kobject *kobj, { int rc; - mutex_lock(&sclp_cpi_mutex); rc = cpi_req(); - mutex_unlock(&sclp_cpi_mutex); if (rc) return rc; @@ -394,16 +373,12 @@ int sclp_cpi_set_data(const char *system, const char *sysplex, const char *type, if (rc) return rc; - mutex_lock(&sclp_cpi_mutex); set_string(system_name, system); set_string(sysplex_name, sysplex); set_string(system_type, type); system_level = level; - rc = cpi_req(); - mutex_unlock(&sclp_cpi_mutex); - - return rc; + return cpi_req(); } EXPORT_SYMBOL(sclp_cpi_set_data); diff --git a/trunk/drivers/s390/char/sclp_quiesce.c b/trunk/drivers/s390/char/sclp_quiesce.c index 84c191c1cd62..45ff25e787cb 100644 --- a/trunk/drivers/s390/char/sclp_quiesce.c +++ b/trunk/drivers/s390/char/sclp_quiesce.c @@ -51,7 +51,13 @@ static struct sclp_register sclp_quiesce_event = { static int __init sclp_quiesce_init(void) { - return sclp_register(&sclp_quiesce_event); + int rc; + + rc = sclp_register(&sclp_quiesce_event); + if (rc) + printk(KERN_WARNING "sclp: could not register quiesce handler " + "(rc=%d)\n", rc); + return rc; } module_init(sclp_quiesce_init); diff --git a/trunk/drivers/s390/char/sclp_rw.c b/trunk/drivers/s390/char/sclp_rw.c index 710af42603f8..da09781b32f7 100644 --- a/trunk/drivers/s390/char/sclp_rw.c +++ b/trunk/drivers/s390/char/sclp_rw.c @@ -19,6 +19,8 @@ #include "sclp.h" #include "sclp_rw.h" +#define SCLP_RW_PRINT_HEADER "sclp low level driver: " + /* * The room for the SCCB (only for writing) is not equal to a pages size * (as it is specified as the maximum size in the SCLP documentation) diff --git a/trunk/drivers/s390/char/sclp_sdias.c b/trunk/drivers/s390/char/sclp_sdias.c index 8b854857ba07..1c064976b32b 100644 --- a/trunk/drivers/s390/char/sclp_sdias.c +++ b/trunk/drivers/s390/char/sclp_sdias.c @@ -239,8 +239,10 @@ int __init sclp_sdias_init(void) debug_register_view(sdias_dbf, &debug_sprintf_view); debug_set_level(sdias_dbf, 6); rc = sclp_register(&sclp_sdias_register); - if (rc) + if (rc) { + ERROR_MSG("sclp register failed\n"); return rc; + } init_waitqueue_head(&sdias_wq); TRACE("init done\n"); return 0; diff --git a/trunk/drivers/s390/char/sclp_tty.c b/trunk/drivers/s390/char/sclp_tty.c index 434ba04b1309..40b11521cd20 100644 --- a/trunk/drivers/s390/char/sclp_tty.c +++ b/trunk/drivers/s390/char/sclp_tty.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,8 @@ #include "sclp_rw.h" #include "sclp_tty.h" +#define SCLP_TTY_PRINT_HEADER "sclp tty driver: " + /* * size of a buffer that collects single characters coming in * via sclp_tty_put_char() @@ -47,6 +50,8 @@ static int sclp_tty_buffer_count; static struct sclp_buffer *sclp_ttybuf; /* Timer for delayed output of console messages. */ static struct timer_list sclp_tty_timer; +/* Waitqueue to wait for buffers to get empty. */ +static wait_queue_head_t sclp_tty_waitq; static struct tty_struct *sclp_tty; static unsigned char sclp_tty_chars[SCLP_TTY_BUF_SIZE]; @@ -54,11 +59,19 @@ static unsigned short int sclp_tty_chars_count; struct tty_driver *sclp_tty_driver; -static int sclp_tty_tolower; -static int sclp_tty_columns = 80; - -#define SPACES_PER_TAB 8 -#define CASE_DELIMITER 0x6c /* to separate upper and lower case (% in EBCDIC) */ +static struct sclp_ioctls sclp_ioctls; +static struct sclp_ioctls sclp_ioctls_init = +{ + 8, /* 1 hor. tab. = 8 spaces */ + 0, /* no echo of input by this driver */ + 80, /* 80 characters/line */ + 1, /* write after 1/10 s without final new line */ + MAX_KMEM_PAGES, /* quick fix: avoid __alloc_pages */ + MAX_KMEM_PAGES, /* take 32/64 pages from kernel memory, */ + 0, /* do not convert to lower case */ + 0x6c /* to seprate upper and lower case */ + /* ('%' in EBCDIC) */ +}; /* This routine is called whenever we try to open a SCLP terminal. */ static int @@ -79,6 +92,136 @@ sclp_tty_close(struct tty_struct *tty, struct file *filp) sclp_tty = NULL; } +/* execute commands to control the i/o behaviour of the SCLP tty at runtime */ +static int +sclp_tty_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + unsigned long flags; + unsigned int obuf; + int check; + int rc; + + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + rc = 0; + check = 0; + switch (cmd) { + case TIOCSCLPSHTAB: + /* set width of horizontal tab */ + if (get_user(sclp_ioctls.htab, (unsigned short __user *) arg)) + rc = -EFAULT; + else + check = 1; + break; + case TIOCSCLPGHTAB: + /* get width of horizontal tab */ + if (put_user(sclp_ioctls.htab, (unsigned short __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSECHO: + /* enable/disable echo of input */ + if (get_user(sclp_ioctls.echo, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGECHO: + /* Is echo of input enabled ? */ + if (put_user(sclp_ioctls.echo, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSCOLS: + /* set number of columns for output */ + if (get_user(sclp_ioctls.columns, (unsigned short __user *) arg)) + rc = -EFAULT; + else + check = 1; + break; + case TIOCSCLPGCOLS: + /* get number of columns for output */ + if (put_user(sclp_ioctls.columns, (unsigned short __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSNL: + /* enable/disable writing without final new line character */ + if (get_user(sclp_ioctls.final_nl, (signed char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGNL: + /* Is writing without final new line character enabled ? */ + if (put_user(sclp_ioctls.final_nl, (signed char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSOBUF: + /* + * set the maximum buffers size for output, will be rounded + * up to next 4kB boundary and stored as number of SCCBs + * (4kB Buffers) limitation: 256 x 4kB + */ + if (get_user(obuf, (unsigned int __user *) arg) == 0) { + if (obuf & 0xFFF) + sclp_ioctls.max_sccb = (obuf >> 12) + 1; + else + sclp_ioctls.max_sccb = (obuf >> 12); + } else + rc = -EFAULT; + break; + case TIOCSCLPGOBUF: + /* get the maximum buffers size for output */ + obuf = sclp_ioctls.max_sccb << 12; + if (put_user(obuf, (unsigned int __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGKBUF: + /* get the number of buffers got from kernel at startup */ + if (put_user(sclp_ioctls.kmem_sccb, (unsigned short __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSCASE: + /* enable/disable conversion from upper to lower case */ + if (get_user(sclp_ioctls.tolower, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGCASE: + /* Is conversion from upper to lower case of input enabled? */ + if (put_user(sclp_ioctls.tolower, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSDELIM: + /* + * set special character used for separating upper and + * lower case, 0x00 disables this feature + */ + if (get_user(sclp_ioctls.delim, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPGDELIM: + /* + * get special character used for separating upper and + * lower case, 0x00 disables this feature + */ + if (put_user(sclp_ioctls.delim, (unsigned char __user *) arg)) + rc = -EFAULT; + break; + case TIOCSCLPSINIT: + /* set initial (default) sclp ioctls */ + sclp_ioctls = sclp_ioctls_init; + check = 1; + break; + default: + rc = -ENOIOCTLCMD; + break; + } + if (check) { + spin_lock_irqsave(&sclp_tty_lock, flags); + if (sclp_ttybuf != NULL) { + sclp_set_htab(sclp_ttybuf, sclp_ioctls.htab); + sclp_set_columns(sclp_ttybuf, sclp_ioctls.columns); + } + spin_unlock_irqrestore(&sclp_tty_lock, flags); + } + return rc; +} + /* * This routine returns the numbers of characters the tty driver * will accept for queuing to be written. This number is subject @@ -125,6 +268,7 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc) struct sclp_buffer, list); spin_unlock_irqrestore(&sclp_tty_lock, flags); } while (buffer && sclp_emit_buffer(buffer, sclp_ttybuf_callback)); + wake_up(&sclp_tty_waitq); /* check if the tty needs a wake up call */ if (sclp_tty != NULL) { tty_wakeup(sclp_tty); @@ -172,37 +316,37 @@ sclp_tty_timeout(unsigned long data) /* * Write a string to the sclp tty. */ -static int sclp_tty_write_string(const unsigned char *str, int count, int may_fail) +static void +sclp_tty_write_string(const unsigned char *str, int count) { unsigned long flags; void *page; int written; - int overall_written; struct sclp_buffer *buf; if (count <= 0) - return 0; - overall_written = 0; + return; spin_lock_irqsave(&sclp_tty_lock, flags); do { /* Create a sclp output buffer if none exists yet */ if (sclp_ttybuf == NULL) { while (list_empty(&sclp_tty_pages)) { spin_unlock_irqrestore(&sclp_tty_lock, flags); - if (may_fail) - goto out; - else + if (in_interrupt()) sclp_sync_wait(); + else + wait_event(sclp_tty_waitq, + !list_empty(&sclp_tty_pages)); spin_lock_irqsave(&sclp_tty_lock, flags); } page = sclp_tty_pages.next; list_del((struct list_head *) page); - sclp_ttybuf = sclp_make_buffer(page, sclp_tty_columns, - SPACES_PER_TAB); + sclp_ttybuf = sclp_make_buffer(page, + sclp_ioctls.columns, + sclp_ioctls.htab); } /* try to write the string to the current output buffer */ written = sclp_write(sclp_ttybuf, str, count); - overall_written += written; if (written == count) break; /* @@ -219,17 +363,27 @@ static int sclp_tty_write_string(const unsigned char *str, int count, int may_fa count -= written; } while (count > 0); /* Setup timer to output current console buffer after 1/10 second */ - if (sclp_ttybuf && sclp_chars_in_buffer(sclp_ttybuf) && - !timer_pending(&sclp_tty_timer)) { - init_timer(&sclp_tty_timer); - sclp_tty_timer.function = sclp_tty_timeout; - sclp_tty_timer.data = 0UL; - sclp_tty_timer.expires = jiffies + HZ/10; - add_timer(&sclp_tty_timer); + if (sclp_ioctls.final_nl) { + if (sclp_ttybuf != NULL && + sclp_chars_in_buffer(sclp_ttybuf) != 0 && + !timer_pending(&sclp_tty_timer)) { + init_timer(&sclp_tty_timer); + sclp_tty_timer.function = sclp_tty_timeout; + sclp_tty_timer.data = 0UL; + sclp_tty_timer.expires = jiffies + HZ/10; + add_timer(&sclp_tty_timer); + } + } else { + if (sclp_ttybuf != NULL && + sclp_chars_in_buffer(sclp_ttybuf) != 0) { + buf = sclp_ttybuf; + sclp_ttybuf = NULL; + spin_unlock_irqrestore(&sclp_tty_lock, flags); + __sclp_ttybuf_emit(buf); + spin_lock_irqsave(&sclp_tty_lock, flags); + } } spin_unlock_irqrestore(&sclp_tty_lock, flags); -out: - return overall_written; } /* @@ -241,10 +395,11 @@ static int sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) { if (sclp_tty_chars_count > 0) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; } - return sclp_tty_write_string(buf, count, 1); + sclp_tty_write_string(buf, count); + return count; } /* @@ -262,10 +417,9 @@ sclp_tty_put_char(struct tty_struct *tty, unsigned char ch) { sclp_tty_chars[sclp_tty_chars_count++] = ch; if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; - } - return 1; + } return 1; } /* @@ -276,7 +430,7 @@ static void sclp_tty_flush_chars(struct tty_struct *tty) { if (sclp_tty_chars_count > 0) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; } } @@ -315,7 +469,7 @@ static void sclp_tty_flush_buffer(struct tty_struct *tty) { if (sclp_tty_chars_count > 0) { - sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count, 0); + sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); sclp_tty_chars_count = 0; } } @@ -363,7 +517,9 @@ sclp_tty_input(unsigned char* buf, unsigned int count) * modifiy original string, * returns length of resulting string */ -static int sclp_switch_cases(unsigned char *buf, int count) +static int +sclp_switch_cases(unsigned char *buf, int count, + unsigned char delim, int tolower) { unsigned char *ip, *op; int toggle; @@ -373,9 +529,9 @@ static int sclp_switch_cases(unsigned char *buf, int count) ip = op = buf; while (count-- > 0) { /* compare with special character */ - if (*ip == CASE_DELIMITER) { + if (*ip == delim) { /* followed by another special character? */ - if (count && ip[1] == CASE_DELIMITER) { + if (count && ip[1] == delim) { /* * ... then put a single copy of the special * character to the output string @@ -394,7 +550,7 @@ static int sclp_switch_cases(unsigned char *buf, int count) /* not the special character */ if (toggle) /* but case switching is on */ - if (sclp_tty_tolower) + if (tolower) /* switch to uppercase */ *op++ = _ebc_toupper[(int) *ip++]; else @@ -414,12 +570,30 @@ sclp_get_input(unsigned char *start, unsigned char *end) int count; count = end - start; - if (sclp_tty_tolower) + /* + * if set in ioctl convert EBCDIC to lower case + * (modify original input in SCCB) + */ + if (sclp_ioctls.tolower) EBC_TOLOWER(start, count); - count = sclp_switch_cases(start, count); + + /* + * if set in ioctl find out characters in lower or upper case + * (depends on current case) separated by a special character, + * works on EBCDIC + */ + if (sclp_ioctls.delim) + count = sclp_switch_cases(start, count, + sclp_ioctls.delim, + sclp_ioctls.tolower); + /* convert EBCDIC to ASCII (modify original input in SCCB) */ sclp_ebcasc_str(start, count); + /* if set in ioctl write operators input to console */ + if (sclp_ioctls.echo) + sclp_tty_write(sclp_tty, start, count); + /* transfer input to high level driver */ sclp_tty_input(start, count); } @@ -543,6 +717,7 @@ static const struct tty_operations sclp_ops = { .write_room = sclp_tty_write_room, .chars_in_buffer = sclp_tty_chars_in_buffer, .flush_buffer = sclp_tty_flush_buffer, + .ioctl = sclp_tty_ioctl, }; static int __init @@ -561,6 +736,9 @@ sclp_tty_init(void) rc = sclp_rw_init(); if (rc) { + printk(KERN_ERR SCLP_TTY_PRINT_HEADER + "could not register tty - " + "sclp_rw_init returned %d\n", rc); put_tty_driver(driver); return rc; } @@ -576,6 +754,7 @@ sclp_tty_init(void) } INIT_LIST_HEAD(&sclp_tty_outqueue); spin_lock_init(&sclp_tty_lock); + init_waitqueue_head(&sclp_tty_waitq); init_timer(&sclp_tty_timer); sclp_ttybuf = NULL; sclp_tty_buffer_count = 0; @@ -584,10 +763,11 @@ sclp_tty_init(void) * save 4 characters for the CPU number * written at start of each line by VM/CP */ - sclp_tty_columns = 76; + sclp_ioctls_init.columns = 76; /* case input lines to lowercase */ - sclp_tty_tolower = 1; + sclp_ioctls_init.tolower = 1; } + sclp_ioctls = sclp_ioctls_init; sclp_tty_chars_count = 0; sclp_tty = NULL; @@ -612,6 +792,9 @@ sclp_tty_init(void) tty_set_operations(driver, &sclp_ops); rc = tty_register_driver(driver); if (rc) { + printk(KERN_ERR SCLP_TTY_PRINT_HEADER + "could not register tty - " + "tty_register_driver returned %d\n", rc); put_tty_driver(driver); return rc; } diff --git a/trunk/drivers/s390/char/sclp_tty.h b/trunk/drivers/s390/char/sclp_tty.h index 4b965b22fecd..0ce2c1fc5340 100644 --- a/trunk/drivers/s390/char/sclp_tty.h +++ b/trunk/drivers/s390/char/sclp_tty.h @@ -11,8 +11,61 @@ #ifndef __SCLP_TTY_H__ #define __SCLP_TTY_H__ +#include +#include #include +/* This is the type of data structures storing sclp ioctl setting. */ +struct sclp_ioctls { + unsigned short htab; + unsigned char echo; + unsigned short columns; + unsigned char final_nl; + unsigned short max_sccb; + unsigned short kmem_sccb; /* can't be modified at run time */ + unsigned char tolower; + unsigned char delim; +}; + +/* must be unique, FIXME: must be added in Documentation/ioctl_number.txt */ +#define SCLP_IOCTL_LETTER 'B' + +/* set width of horizontal tabulator */ +#define TIOCSCLPSHTAB _IOW(SCLP_IOCTL_LETTER, 0, unsigned short) +/* enable/disable echo of input (independent from line discipline) */ +#define TIOCSCLPSECHO _IOW(SCLP_IOCTL_LETTER, 1, unsigned char) +/* set number of colums for output */ +#define TIOCSCLPSCOLS _IOW(SCLP_IOCTL_LETTER, 2, unsigned short) +/* enable/disable writing without final new line character */ +#define TIOCSCLPSNL _IOW(SCLP_IOCTL_LETTER, 4, signed char) +/* set the maximum buffers size for output, rounded up to next 4kB boundary */ +#define TIOCSCLPSOBUF _IOW(SCLP_IOCTL_LETTER, 5, unsigned short) +/* set initial (default) sclp ioctls */ +#define TIOCSCLPSINIT _IO(SCLP_IOCTL_LETTER, 6) +/* enable/disable conversion from upper to lower case of input */ +#define TIOCSCLPSCASE _IOW(SCLP_IOCTL_LETTER, 7, unsigned char) +/* set special character used for separating upper and lower case, */ +/* 0x00 disables this feature */ +#define TIOCSCLPSDELIM _IOW(SCLP_IOCTL_LETTER, 9, unsigned char) + +/* get width of horizontal tabulator */ +#define TIOCSCLPGHTAB _IOR(SCLP_IOCTL_LETTER, 10, unsigned short) +/* Is echo of input enabled ? (independent from line discipline) */ +#define TIOCSCLPGECHO _IOR(SCLP_IOCTL_LETTER, 11, unsigned char) +/* get number of colums for output */ +#define TIOCSCLPGCOLS _IOR(SCLP_IOCTL_LETTER, 12, unsigned short) +/* Is writing without final new line character enabled ? */ +#define TIOCSCLPGNL _IOR(SCLP_IOCTL_LETTER, 14, signed char) +/* get the maximum buffers size for output */ +#define TIOCSCLPGOBUF _IOR(SCLP_IOCTL_LETTER, 15, unsigned short) +/* Is conversion from upper to lower case of input enabled ? */ +#define TIOCSCLPGCASE _IOR(SCLP_IOCTL_LETTER, 17, unsigned char) +/* get special character used for separating upper and lower case, */ +/* 0x00 disables this feature */ +#define TIOCSCLPGDELIM _IOR(SCLP_IOCTL_LETTER, 19, unsigned char) +/* get the number of buffers/pages got from kernel at startup */ +#define TIOCSCLPGKBUF _IOR(SCLP_IOCTL_LETTER, 20, unsigned short) + extern struct tty_driver *sclp_tty_driver; #endif /* __SCLP_TTY_H__ */ diff --git a/trunk/drivers/s390/char/sclp_vt220.c b/trunk/drivers/s390/char/sclp_vt220.c index ad51738c4261..3e577f655b18 100644 --- a/trunk/drivers/s390/char/sclp_vt220.c +++ b/trunk/drivers/s390/char/sclp_vt220.c @@ -27,6 +27,7 @@ #include #include "sclp.h" +#define SCLP_VT220_PRINT_HEADER "sclp vt220 tty driver: " #define SCLP_VT220_MAJOR TTY_MAJOR #define SCLP_VT220_MINOR 65 #define SCLP_VT220_DRIVER_NAME "sclp_vt220" @@ -81,8 +82,8 @@ static struct sclp_vt220_request *sclp_vt220_current_request; /* Number of characters in current request buffer */ static int sclp_vt220_buffered_chars; -/* Counter controlling core driver initialization. */ -static int __initdata sclp_vt220_init_count; +/* Flag indicating whether this driver has already been initialized */ +static int sclp_vt220_initialized = 0; /* Flag indicating that sclp_vt220_current_request should really * have been already queued but wasn't because the SCLP was processing @@ -608,8 +609,10 @@ sclp_vt220_flush_buffer(struct tty_struct *tty) sclp_vt220_emit_current(); } -/* Release allocated pages. */ -static void __init __sclp_vt220_free_pages(void) +/* + * Initialize all relevant components and register driver with system. + */ +static void __init __sclp_vt220_cleanup(void) { struct list_head *page, *p; @@ -620,30 +623,21 @@ static void __init __sclp_vt220_free_pages(void) else free_bootmem((unsigned long) page, PAGE_SIZE); } + if (!list_empty(&sclp_vt220_register.list)) + sclp_unregister(&sclp_vt220_register); + sclp_vt220_initialized = 0; } -/* Release memory and unregister from sclp core. Controlled by init counting - - * only the last invoker will actually perform these actions. */ -static void __init __sclp_vt220_cleanup(void) -{ - sclp_vt220_init_count--; - if (sclp_vt220_init_count != 0) - return; - sclp_unregister(&sclp_vt220_register); - __sclp_vt220_free_pages(); -} - -/* Allocate buffer pages and register with sclp core. Controlled by init - * counting - only the first invoker will actually perform these actions. */ -static int __init __sclp_vt220_init(int num_pages) +static int __init __sclp_vt220_init(void) { void *page; int i; + int num_pages; int rc; - sclp_vt220_init_count++; - if (sclp_vt220_init_count != 1) + if (sclp_vt220_initialized) return 0; + sclp_vt220_initialized = 1; spin_lock_init(&sclp_vt220_lock); INIT_LIST_HEAD(&sclp_vt220_empty); INIT_LIST_HEAD(&sclp_vt220_outqueue); @@ -655,22 +649,24 @@ static int __init __sclp_vt220_init(int num_pages) sclp_vt220_flush_later = 0; /* Allocate pages for output buffering */ + num_pages = slab_is_available() ? MAX_KMEM_PAGES : MAX_CONSOLE_PAGES; for (i = 0; i < num_pages; i++) { if (slab_is_available()) page = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA); else page = alloc_bootmem_low_pages(PAGE_SIZE); if (!page) { - rc = -ENOMEM; - goto out; + __sclp_vt220_cleanup(); + return -ENOMEM; } list_add_tail((struct list_head *) page, &sclp_vt220_empty); } rc = sclp_register(&sclp_vt220_register); -out: if (rc) { - __sclp_vt220_free_pages(); - sclp_vt220_init_count--; + printk(KERN_ERR SCLP_VT220_PRINT_HEADER + "could not register vt220 - " + "sclp_register returned %d\n", rc); + __sclp_vt220_cleanup(); } return rc; } @@ -693,13 +689,15 @@ static int __init sclp_vt220_tty_init(void) { struct tty_driver *driver; int rc; + int cleanup; /* Note: we're not testing for CONSOLE_IS_SCLP here to preserve * symmetry between VM and LPAR systems regarding ttyS1. */ driver = alloc_tty_driver(1); if (!driver) return -ENOMEM; - rc = __sclp_vt220_init(MAX_KMEM_PAGES); + cleanup = !sclp_vt220_initialized; + rc = __sclp_vt220_init(); if (rc) goto out_driver; @@ -715,13 +713,18 @@ static int __init sclp_vt220_tty_init(void) tty_set_operations(driver, &sclp_vt220_ops); rc = tty_register_driver(driver); - if (rc) + if (rc) { + printk(KERN_ERR SCLP_VT220_PRINT_HEADER + "could not register tty - " + "tty_register_driver returned %d\n", rc); goto out_init; + } sclp_vt220_driver = driver; return 0; out_init: - __sclp_vt220_cleanup(); + if (cleanup) + __sclp_vt220_cleanup(); out_driver: put_tty_driver(driver); return rc; @@ -770,9 +773,10 @@ sclp_vt220_con_init(void) { int rc; + INIT_LIST_HEAD(&sclp_vt220_register.list); if (!CONSOLE_IS_SCLP) return 0; - rc = __sclp_vt220_init(MAX_CONSOLE_PAGES); + rc = __sclp_vt220_init(); if (rc) return rc; /* Attach linux console */ diff --git a/trunk/drivers/s390/char/tape_34xx.c b/trunk/drivers/s390/char/tape_34xx.c index 22ca34361ed7..874adf365e46 100644 --- a/trunk/drivers/s390/char/tape_34xx.c +++ b/trunk/drivers/s390/char/tape_34xx.c @@ -196,7 +196,7 @@ tape_34xx_erp_retry(struct tape_request *request) static int tape_34xx_unsolicited_irq(struct tape_device *device, struct irb *irb) { - if (irb->scsw.cmd.dstat == 0x85) { /* READY */ + if (irb->scsw.dstat == 0x85 /* READY */) { /* A medium was inserted in the drive. */ DBF_EVENT(6, "xuud med\n"); tape_34xx_delete_sbid_from(device, 0); @@ -844,22 +844,22 @@ tape_34xx_irq(struct tape_device *device, struct tape_request *request, if (request == NULL) return tape_34xx_unsolicited_irq(device, irb); - if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) && - (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) && + if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) && + (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) { /* Write at end of volume */ PRINT_INFO("End of volume\n"); /* XXX */ return tape_34xx_erp_failed(request, -ENOSPC); } - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) return tape_34xx_unit_check(device, request, irb); - if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { + if (irb->scsw.dstat & DEV_STAT_DEV_END) { /* * A unit exception occurs on skipping over a tapemark block. */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) { + if (irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) { if (request->op == TO_BSB || request->op == TO_FSB) request->rescnt++; else diff --git a/trunk/drivers/s390/char/tape_3590.c b/trunk/drivers/s390/char/tape_3590.c index 839987618ffd..42ce7915fc5d 100644 --- a/trunk/drivers/s390/char/tape_3590.c +++ b/trunk/drivers/s390/char/tape_3590.c @@ -837,13 +837,13 @@ tape_3590_erp_retry(struct tape_device *device, struct tape_request *request, static int tape_3590_unsolicited_irq(struct tape_device *device, struct irb *irb) { - if (irb->scsw.cmd.dstat == DEV_STAT_CHN_END) + if (irb->scsw.dstat == DEV_STAT_CHN_END) /* Probably result of halt ssch */ return TAPE_IO_PENDING; - else if (irb->scsw.cmd.dstat == 0x85) + else if (irb->scsw.dstat == 0x85) /* Device Ready */ DBF_EVENT(3, "unsol.irq! tape ready: %08x\n", device->cdev_id); - else if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + else if (irb->scsw.dstat & DEV_STAT_ATTENTION) { tape_3590_schedule_work(device, TO_READ_ATTMSG); } else { DBF_EVENT(3, "unsol.irq! dev end: %08x\n", device->cdev_id); @@ -1515,19 +1515,18 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request, if (request == NULL) return tape_3590_unsolicited_irq(device, irb); - if ((irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) && - (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) && - (request->op == TO_WRI)) { + if ((irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) && + (irb->scsw.dstat & DEV_STAT_DEV_END) && (request->op == TO_WRI)) { /* Write at end of volume */ DBF_EVENT(2, "End of volume\n"); return tape_3590_erp_failed(device, request, irb, -ENOSPC); } - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) return tape_3590_unit_check(device, request, irb); - if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) { - if (irb->scsw.cmd.dstat == DEV_STAT_UNIT_EXCEP) { + if (irb->scsw.dstat & DEV_STAT_DEV_END) { + if (irb->scsw.dstat == DEV_STAT_UNIT_EXCEP) { if (request->op == TO_FSB || request->op == TO_BSB) request->rescnt++; else @@ -1537,12 +1536,12 @@ tape_3590_irq(struct tape_device *device, struct tape_request *request, return tape_3590_done(device, request); } - if (irb->scsw.cmd.dstat & DEV_STAT_CHN_END) { + if (irb->scsw.dstat & DEV_STAT_CHN_END) { DBF_EVENT(2, "cannel end\n"); return TAPE_IO_PENDING; } - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { DBF_EVENT(2, "Unit Attention when busy..\n"); return TAPE_IO_PENDING; } diff --git a/trunk/drivers/s390/char/tape_core.c b/trunk/drivers/s390/char/tape_core.c index 181a5441af16..c20e3c548343 100644 --- a/trunk/drivers/s390/char/tape_core.c +++ b/trunk/drivers/s390/char/tape_core.c @@ -839,7 +839,7 @@ tape_dump_sense(struct tape_device* device, struct tape_request *request, PRINT_INFO("-------------------------------------------------\n"); PRINT_INFO("DSTAT : %02x CSTAT: %02x CPA: %04x\n", - irb->scsw.cmd.dstat, irb->scsw.cmd.cstat, irb->scsw.cmd.cpa); + irb->scsw.dstat, irb->scsw.cstat, irb->scsw.cpa); PRINT_INFO("DEVICE: %s\n", device->cdev->dev.bus_id); if (request != NULL) PRINT_INFO("OP : %s\n", tape_op_verbose[request->op]); @@ -867,7 +867,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request, else op = "---"; DBF_EVENT(3, "DSTAT : %02x CSTAT: %02x\n", - irb->scsw.cmd.dstat, irb->scsw.cmd.cstat); + irb->scsw.dstat,irb->scsw.cstat); DBF_EVENT(3, "DEVICE: %08x OP\t: %s\n", device->cdev_id, op); sptr = (unsigned int *) irb->ecw; DBF_EVENT(3, "%08x %08x\n", sptr[0], sptr[1]); @@ -1083,11 +1083,10 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) * error might still apply. So we just schedule the request to be * started later. */ - if (irb->scsw.cmd.cc != 0 && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) && + if (irb->scsw.cc != 0 && (irb->scsw.fctl & SCSW_FCTL_START_FUNC) && (request->status == TAPE_REQUEST_IN_IO)) { DBF_EVENT(3,"(%08x): deferred cc=%i, fctl=%i. restarting\n", - device->cdev_id, irb->scsw.cmd.cc, irb->scsw.cmd.fctl); + device->cdev_id, irb->scsw.cc, irb->scsw.fctl); request->status = TAPE_REQUEST_QUEUED; schedule_delayed_work(&device->tape_dnr, HZ); return; @@ -1095,8 +1094,8 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) /* May be an unsolicited irq */ if(request != NULL) - request->rescnt = irb->scsw.cmd.count; - else if ((irb->scsw.cmd.dstat == 0x85 || irb->scsw.cmd.dstat == 0x80) && + request->rescnt = irb->scsw.count; + else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) && !list_empty(&device->req_queue)) { /* Not Ready to Ready after long busy ? */ struct tape_request *req; @@ -1112,7 +1111,7 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) return; } } - if (irb->scsw.cmd.dstat != 0x0c) { + if (irb->scsw.dstat != 0x0c) { /* Set the 'ONLINE' flag depending on sense byte 1 */ if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE) device->tape_generic_status |= GMT_ONLINE(~0); diff --git a/trunk/drivers/s390/char/tty3270.c b/trunk/drivers/s390/char/tty3270.c index a7fe6302c982..5043150019ac 100644 --- a/trunk/drivers/s390/char/tty3270.c +++ b/trunk/drivers/s390/char/tty3270.c @@ -663,7 +663,7 @@ static int tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) { /* Handle ATTN. Schedule tasklet to read aid. */ - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { if (!tp->throttle) tty3270_issue_read(tp, 0); else @@ -671,11 +671,11 @@ tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb) } if (rq) { - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) rq->rc = -EIO; else /* Normal end. Copy residual count. */ - rq->rescnt = irb->scsw.cmd.count; + rq->rescnt = irb->scsw.count; } return RAW3270_IO_DONE; } @@ -1792,12 +1792,15 @@ static int __init tty3270_init(void) tty_set_operations(driver, &tty3270_ops); ret = tty_register_driver(driver); if (ret) { + printk(KERN_ERR "tty3270 registration failed with %d\n", ret); put_tty_driver(driver); return ret; } tty3270_driver = driver; ret = raw3270_register_notifier(tty3270_notifier); if (ret) { + printk(KERN_ERR "tty3270 notifier registration failed " + "with %d\n", ret); put_tty_driver(driver); return ret; diff --git a/trunk/drivers/s390/char/vmcp.c b/trunk/drivers/s390/char/vmcp.c index 401ea84b3059..2f419b0ea628 100644 --- a/trunk/drivers/s390/char/vmcp.c +++ b/trunk/drivers/s390/char/vmcp.c @@ -61,24 +61,30 @@ static int vmcp_release(struct inode *inode, struct file *file) static ssize_t vmcp_read(struct file *file, char __user *buff, size_t count, loff_t *ppos) { - ssize_t ret; - size_t size; + size_t tocopy; struct vmcp_session *session; - session = file->private_data; + session = (struct vmcp_session *)file->private_data; if (mutex_lock_interruptible(&session->mutex)) return -ERESTARTSYS; if (!session->response) { mutex_unlock(&session->mutex); return 0; } - size = min_t(size_t, session->resp_size, session->bufsize); - ret = simple_read_from_buffer(buff, count, ppos, - session->response, size); + if (*ppos > session->resp_size) { + mutex_unlock(&session->mutex); + return 0; + } + tocopy = min(session->resp_size - (size_t) (*ppos), count); + tocopy = min(tocopy, session->bufsize - (size_t) (*ppos)); + if (copy_to_user(buff, session->response + (*ppos), tocopy)) { + mutex_unlock(&session->mutex); + return -EFAULT; + } mutex_unlock(&session->mutex); - - return ret; + *ppos += tocopy; + return tocopy; } static ssize_t @@ -192,23 +198,27 @@ static int __init vmcp_init(void) PRINT_WARN("z/VM CP interface is only available under z/VM\n"); return -ENODEV; } - vmcp_debug = debug_register("vmcp", 1, 1, 240); - if (!vmcp_debug) + if (!vmcp_debug) { + PRINT_ERR("z/VM CP interface not loaded. Could not register " + "debug feature\n"); return -ENOMEM; - + } ret = debug_register_view(vmcp_debug, &debug_hex_ascii_view); if (ret) { + PRINT_ERR("z/VM CP interface not loaded. Could not register " + "debug feature view. Error code: %d\n", ret); debug_unregister(vmcp_debug); return ret; } - ret = misc_register(&vmcp_dev); if (ret) { + PRINT_ERR("z/VM CP interface not loaded. Could not register " + "misc device. Error code: %d\n", ret); debug_unregister(vmcp_debug); return ret; } - + PRINT_INFO("z/VM CP interface loaded\n"); return 0; } @@ -216,6 +226,7 @@ static void __exit vmcp_exit(void) { misc_deregister(&vmcp_dev); debug_unregister(vmcp_debug); + PRINT_INFO("z/VM CP interface unloaded.\n"); } module_init(vmcp_init); diff --git a/trunk/drivers/s390/char/vmlogrdr.c b/trunk/drivers/s390/char/vmlogrdr.c index a246bc73ae64..2c2428cc05d8 100644 --- a/trunk/drivers/s390/char/vmlogrdr.c +++ b/trunk/drivers/s390/char/vmlogrdr.c @@ -216,7 +216,9 @@ static int vmlogrdr_get_recording_class_AB(void) char *tail; int len,i; + printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response); len = strnlen(cp_response,sizeof(cp_response)); // now the parsing tail=strnchr(cp_response,len,'='); @@ -266,7 +268,11 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, logptr->recording_name, qid_string); + printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", + cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: recording response: %s", + cp_response); } memset(cp_command, 0x00, sizeof(cp_command)); @@ -276,7 +282,10 @@ static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, onoff, qid_string); + printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: recording response: %s", + cp_response); /* The recording command will usually answer with 'Command complete' * on success, but when the specific service was never connected * before then there might be an additional informational message @@ -558,7 +567,10 @@ static ssize_t vmlogrdr_purge_store(struct device * dev, "RECORDING %s PURGE ", priv->recording_name); + printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command); cpcmd(cp_command, cp_response, sizeof(cp_response), NULL); + printk (KERN_DEBUG "vmlogrdr: recording response: %s", + cp_response); return count; } @@ -670,20 +682,28 @@ static int vmlogrdr_register_driver(void) /* Register with iucv driver */ ret = iucv_register(&vmlogrdr_iucv_handler, 1); - if (ret) + if (ret) { + printk (KERN_ERR "vmlogrdr: failed to register with " + "iucv driver\n"); goto out; + } ret = driver_register(&vmlogrdr_driver); - if (ret) + if (ret) { + printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); goto out_iucv; + } ret = driver_create_file(&vmlogrdr_driver, &driver_attr_recording_status); - if (ret) + if (ret) { + printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); goto out_driver; + } vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); if (IS_ERR(vmlogrdr_class)) { + printk(KERN_ERR "vmlogrdr: failed to create class.\n"); ret = PTR_ERR(vmlogrdr_class); vmlogrdr_class = NULL; goto out_attr; @@ -851,10 +871,12 @@ static int __init vmlogrdr_init(void) rc = vmlogrdr_register_cdev(dev); if (rc) goto cleanup; + printk (KERN_INFO "vmlogrdr: driver loaded\n"); return 0; cleanup: vmlogrdr_cleanup(); + printk (KERN_ERR "vmlogrdr: driver not loaded.\n"); return rc; } @@ -862,6 +884,7 @@ static int __init vmlogrdr_init(void) static void __exit vmlogrdr_exit(void) { vmlogrdr_cleanup(); + printk (KERN_INFO "vmlogrdr: driver unloaded\n"); return; } diff --git a/trunk/drivers/s390/char/vmur.c b/trunk/drivers/s390/char/vmur.c index 49cba9effe89..83ae9a852f00 100644 --- a/trunk/drivers/s390/char/vmur.c +++ b/trunk/drivers/s390/char/vmur.c @@ -277,8 +277,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, struct urdev *urd; TRACE("ur_int_handler: intparm=0x%lx cstat=%02x dstat=%02x res=%u\n", - intparm, irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, - irb->scsw.cmd.count); + intparm, irb->scsw.cstat, irb->scsw.dstat, irb->scsw.count); if (!intparm) { TRACE("ur_int_handler: unsolicited interrupt\n"); @@ -289,7 +288,7 @@ static void ur_int_handler(struct ccw_device *cdev, unsigned long intparm, /* On special conditions irb is an error pointer */ if (IS_ERR(irb)) urd->io_request_rc = PTR_ERR(irb); - else if (irb->scsw.cmd.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) + else if (irb->scsw.dstat == (DEV_STAT_CHN_END | DEV_STAT_DEV_END)) urd->io_request_rc = 0; else urd->io_request_rc = -EIO; diff --git a/trunk/drivers/s390/char/vmwatchdog.c b/trunk/drivers/s390/char/vmwatchdog.c index 56b3eab019cb..19f8389291b6 100644 --- a/trunk/drivers/s390/char/vmwatchdog.c +++ b/trunk/drivers/s390/char/vmwatchdog.c @@ -92,15 +92,23 @@ static int vmwdt_keepalive(void) func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; ret = __diag288(func, vmwdt_interval, ebc_cmd, len); - WARN_ON(ret != 0); kfree(ebc_cmd); + + if (ret) { + printk(KERN_WARNING "%s: problem setting interval %d, " + "cmd %s\n", __func__, vmwdt_interval, + vmwdt_cmd); + } return ret; } static int vmwdt_disable(void) { int ret = __diag288(wdt_cancel, 0, "", 0); - WARN_ON(ret != 0); + if (ret) { + printk(KERN_WARNING "%s: problem disabling watchdog\n", + __func__); + } return ret; } @@ -113,8 +121,10 @@ static int __init vmwdt_probe(void) static char __initdata ebc_begin[] = { 194, 197, 199, 201, 213 }; - if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) + if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) { + printk(KERN_INFO "z/VM watchdog not available\n"); return -EINVAL; + } return vmwdt_disable(); } diff --git a/trunk/drivers/s390/char/zcore.c b/trunk/drivers/s390/char/zcore.c index 047dd92ae804..bbbd14e9d48f 100644 --- a/trunk/drivers/s390/char/zcore.c +++ b/trunk/drivers/s390/char/zcore.c @@ -223,10 +223,12 @@ static int __init init_cpu_info(enum arch_id arch) /* get info for boot cpu from lowcore, stored in the HSA */ sa = kmalloc(sizeof(*sa), GFP_KERNEL); - if (!sa) + if (!sa) { + ERROR_MSG("kmalloc failed: %s: %i\n",__func__, __LINE__); return -ENOMEM; + } if (memcpy_hsa_kernel(sa, sys_info.sa_base, sys_info.sa_size) < 0) { - TRACE("could not copy from HSA\n"); + ERROR_MSG("could not copy from HSA\n"); kfree(sa); return -EIO; } @@ -509,8 +511,6 @@ static void __init set_s390x_lc_mask(union save_area *map) */ static int __init sys_info_init(enum arch_id arch) { - int rc; - switch (arch) { case ARCH_S390X: MSG("DETECTED 'S390X (64 bit) OS'\n"); @@ -529,9 +529,10 @@ static int __init sys_info_init(enum arch_id arch) return -EINVAL; } sys_info.arch = arch; - rc = init_cpu_info(arch); - if (rc) - return rc; + if (init_cpu_info(arch)) { + ERROR_MSG("get cpu info failed\n"); + return -ENOMEM; + } sys_info.mem_size = real_memory_size; return 0; @@ -543,12 +544,12 @@ static int __init check_sdias(void) rc = sclp_sdias_blk_count(); if (rc < 0) { - TRACE("Could not determine HSA size\n"); + ERROR_MSG("Could not determine HSA size\n"); return rc; } act_hsa_size = (rc - 1) * PAGE_SIZE; if (act_hsa_size < ZFCPDUMP_HSA_SIZE) { - TRACE("HSA size too small: %i\n", act_hsa_size); + ERROR_MSG("HSA size too small: %i\n", act_hsa_size); return -EINVAL; } return 0; @@ -589,12 +590,16 @@ static int __init zcore_init(void) goto fail; rc = check_sdias(); - if (rc) + if (rc) { + ERROR_MSG("Dump initialization failed\n"); goto fail; + } rc = memcpy_hsa_kernel(&arch, __LC_AR_MODE_ID, 1); - if (rc) + if (rc) { + ERROR_MSG("sdial memcpy for arch id failed\n"); goto fail; + } #ifndef __s390x__ if (arch == ARCH_S390X) { @@ -605,8 +610,10 @@ static int __init zcore_init(void) #endif rc = sys_info_init(arch); - if (rc) + if (rc) { + ERROR_MSG("arch init failed\n"); goto fail; + } zcore_header_init(arch, &zcore_header); diff --git a/trunk/drivers/s390/cio/Makefile b/trunk/drivers/s390/cio/Makefile index 91e9e3f3073a..cfaf77b320f5 100644 --- a/trunk/drivers/s390/cio/Makefile +++ b/trunk/drivers/s390/cio/Makefile @@ -2,11 +2,9 @@ # Makefile for the S/390 common i/o drivers # -obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \ - fcx.o itcw.o +obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o ccw_device-objs += device.o device_fsm.o device_ops.o ccw_device-objs += device_id.o device_pgid.o device_status.o obj-y += ccw_device.o cmf.o -obj-$(CONFIG_CHSC_SCH) += chsc_sch.o obj-$(CONFIG_CCWGROUP) += ccwgroup.o obj-$(CONFIG_QDIO) += qdio.o diff --git a/trunk/drivers/s390/cio/airq.c b/trunk/drivers/s390/cio/airq.c index fe6cea15bbaf..b7a07a866291 100644 --- a/trunk/drivers/s390/cio/airq.c +++ b/trunk/drivers/s390/cio/airq.c @@ -15,7 +15,6 @@ #include #include -#include #include "cio.h" #include "cio_debug.h" @@ -34,15 +33,15 @@ struct airq_t { void *drv_data; }; -static union indicator_t indicators[MAX_ISC]; -static struct airq_t *airqs[MAX_ISC][NR_AIRQS]; +static union indicator_t indicators; +static struct airq_t *airqs[NR_AIRQS]; -static int register_airq(struct airq_t *airq, u8 isc) +static int register_airq(struct airq_t *airq) { int i; for (i = 0; i < NR_AIRQS; i++) - if (!cmpxchg(&airqs[isc][i], NULL, airq)) + if (!cmpxchg(&airqs[i], NULL, airq)) return i; return -ENOMEM; } @@ -51,21 +50,18 @@ static int register_airq(struct airq_t *airq, u8 isc) * s390_register_adapter_interrupt() - register adapter interrupt handler * @handler: adapter handler to be registered * @drv_data: driver data passed with each call to the handler - * @isc: isc for which the handler should be called * * Returns: * Pointer to the indicator to be used on success * ERR_PTR() if registration failed */ void *s390_register_adapter_interrupt(adapter_int_handler_t handler, - void *drv_data, u8 isc) + void *drv_data) { struct airq_t *airq; char dbf_txt[16]; int ret; - if (isc > MAX_ISC) - return ERR_PTR(-EINVAL); airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); if (!airq) { ret = -ENOMEM; @@ -73,35 +69,34 @@ void *s390_register_adapter_interrupt(adapter_int_handler_t handler, } airq->handler = handler; airq->drv_data = drv_data; - - ret = register_airq(airq, isc); + ret = register_airq(airq); + if (ret < 0) + kfree(airq); out: snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); CIO_TRACE_EVENT(4, dbf_txt); - if (ret < 0) { - kfree(airq); + if (ret < 0) return ERR_PTR(ret); - } else - return &indicators[isc].byte[ret]; + else + return &indicators.byte[ret]; } EXPORT_SYMBOL(s390_register_adapter_interrupt); /** * s390_unregister_adapter_interrupt - unregister adapter interrupt handler * @ind: indicator for which the handler is to be unregistered - * @isc: interruption subclass */ -void s390_unregister_adapter_interrupt(void *ind, u8 isc) +void s390_unregister_adapter_interrupt(void *ind) { struct airq_t *airq; char dbf_txt[16]; int i; - i = (int) ((addr_t) ind) - ((addr_t) &indicators[isc].byte[0]); + i = (int) ((addr_t) ind) - ((addr_t) &indicators.byte[0]); snprintf(dbf_txt, sizeof(dbf_txt), "urairq:%d", i); CIO_TRACE_EVENT(4, dbf_txt); - indicators[isc].byte[i] = 0; - airq = xchg(&airqs[isc][i], NULL); + indicators.byte[i] = 0; + airq = xchg(&airqs[i], NULL); /* * Allow interrupts to complete. This will ensure that the airq handle * is no longer referenced by any interrupt handler. @@ -113,7 +108,7 @@ EXPORT_SYMBOL(s390_unregister_adapter_interrupt); #define INDICATOR_MASK (0xffUL << ((NR_AIRQS_PER_WORD - 1) * 8)) -void do_adapter_IO(u8 isc) +void do_adapter_IO(void) { int w; int i; @@ -125,22 +120,22 @@ void do_adapter_IO(u8 isc) * fetch operations. */ for (w = 0; w < NR_AIRQ_WORDS; w++) { - word = indicators[isc].word[w]; + word = indicators.word[w]; i = w * NR_AIRQS_PER_WORD; /* * Check bytes within word for active indicators. */ while (word) { if (word & INDICATOR_MASK) { - airq = airqs[isc][i]; + airq = airqs[i]; if (likely(airq)) - airq->handler(&indicators[isc].byte[i], + airq->handler(&indicators.byte[i], airq->drv_data); else /* * Reset ill-behaved indicator. */ - indicators[isc].byte[i] = 0; + indicators.byte[i] = 0; } word <<= 8; i++; diff --git a/trunk/drivers/s390/cio/chp.c b/trunk/drivers/s390/cio/chp.c index db00b0591733..297cdceb0ca4 100644 --- a/trunk/drivers/s390/cio/chp.c +++ b/trunk/drivers/s390/cio/chp.c @@ -18,7 +18,6 @@ #include #include -#include "../s390mach.h" #include "cio.h" #include "css.h" #include "ioasm.h" @@ -95,7 +94,6 @@ u8 chp_get_sch_opm(struct subchannel *sch) } return opm; } -EXPORT_SYMBOL_GPL(chp_get_sch_opm); /** * chp_is_registered - check if a channel-path is registered @@ -123,8 +121,11 @@ static int s390_vary_chpid(struct chp_id chpid, int on) CIO_TRACE_EVENT(2, dbf_text); status = chp_get_status(chpid); - if (!on && !status) - return 0; + if (!on && !status) { + printk(KERN_ERR "cio: chpid %x.%02x is already offline\n", + chpid.cssid, chpid.id); + return -EINVAL; + } set_chp_logically_online(chpid, on); chsc_chp_vary(chpid, on); @@ -140,14 +141,21 @@ static ssize_t chp_measurement_chars_read(struct kobject *kobj, { struct channel_path *chp; struct device *device; + unsigned int size; device = container_of(kobj, struct device, kobj); chp = to_channelpath(device); if (!chp->cmg_chars) return 0; - return memory_read_from_buffer(buf, count, &off, - chp->cmg_chars, sizeof(struct cmg_chars)); + size = sizeof(struct cmg_chars); + + if (off > size) + return 0; + if (off + count > size) + count = size - off; + memcpy(buf, chp->cmg_chars + off, count); + return count; } static struct bin_attribute chp_measurement_chars_attr = { @@ -397,7 +405,7 @@ int chp_new(struct chp_id chpid) chpid.id); /* Obtain channel path description and fill it in. */ - ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc); + ret = chsc_determine_channel_path_description(chpid, &chp->desc); if (ret) goto out_free; if ((chp->desc.flags & 0x80) == 0) { @@ -405,7 +413,8 @@ int chp_new(struct chp_id chpid) goto out_free; } /* Get channel-measurement characteristics. */ - if (css_chsc_characteristics.scmc && css_chsc_characteristics.secm) { + if (css_characteristics_avail && css_chsc_characteristics.scmc + && css_chsc_characteristics.secm) { ret = chsc_get_channel_measurement_chars(chp); if (ret) goto out_free; @@ -467,74 +476,26 @@ void *chp_get_chp_desc(struct chp_id chpid) /** * chp_process_crw - process channel-path status change - * @crw0: channel report-word to handler - * @crw1: second channel-report word (always NULL) - * @overflow: crw overflow indication + * @id: channel-path ID number + * @status: non-zero if channel-path has become available, zero otherwise * * Handle channel-report-words indicating that the status of a channel-path * has changed. */ -static void chp_process_crw(struct crw *crw0, struct crw *crw1, - int overflow) +void chp_process_crw(int id, int status) { struct chp_id chpid; - if (overflow) { - css_schedule_eval_all(); - return; - } - CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, - crw0->erc, crw0->rsid); - /* - * Check for solicited machine checks. These are - * created by reset channel path and need not be - * handled here. - */ - if (crw0->slct) { - CIO_CRW_EVENT(2, "solicited machine check for " - "channel path %02X\n", crw0->rsid); - return; - } chp_id_init(&chpid); - chpid.id = crw0->rsid; - switch (crw0->erc) { - case CRW_ERC_IPARM: /* Path has come. */ + chpid.id = id; + if (status) { if (!chp_is_registered(chpid)) chp_new(chpid); chsc_chp_online(chpid); - break; - case CRW_ERC_PERRI: /* Path has gone. */ - case CRW_ERC_PERRN: + } else chsc_chp_offline(chpid); - break; - default: - CIO_CRW_EVENT(2, "Don't know how to handle erc=%x\n", - crw0->erc); - } } -int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct chp_link *link) -{ - int i; - int mask; - - for (i = 0; i < 8; i++) { - mask = 0x80 >> i; - if (!(ssd->path_mask & mask)) - continue; - if (!chp_id_is_equal(&ssd->chpid[i], &link->chpid)) - continue; - if ((ssd->fla_valid_mask & mask) && - ((ssd->fla[i] & link->fla_mask) != link->fla)) - continue; - return mask; - } - return 0; -} -EXPORT_SYMBOL_GPL(chp_ssd_get_mask); - static inline int info_bit_num(struct chp_id id) { return id.id + id.cssid * (__MAX_CHPID + 1); @@ -614,7 +575,6 @@ static void cfg_func(struct work_struct *work) { struct chp_id chpid; enum cfg_task_t t; - int rc; mutex_lock(&cfg_lock); t = cfg_none; @@ -629,24 +589,14 @@ static void cfg_func(struct work_struct *work) switch (t) { case cfg_configure: - rc = sclp_chp_configure(chpid); - if (rc) - CIO_MSG_EVENT(2, "chp: sclp_chp_configure(%x.%02x)=" - "%d\n", chpid.cssid, chpid.id, rc); - else { - info_expire(); - chsc_chp_online(chpid); - } + sclp_chp_configure(chpid); + info_expire(); + chsc_chp_online(chpid); break; case cfg_deconfigure: - rc = sclp_chp_deconfigure(chpid); - if (rc) - CIO_MSG_EVENT(2, "chp: sclp_chp_deconfigure(%x.%02x)=" - "%d\n", chpid.cssid, chpid.id, rc); - else { - info_expire(); - chsc_chp_offline(chpid); - } + sclp_chp_deconfigure(chpid); + info_expire(); + chsc_chp_offline(chpid); break; case cfg_none: /* Get updated information after last change. */ @@ -704,16 +654,10 @@ static int cfg_wait_idle(void) static int __init chp_init(void) { struct chp_id chpid; - int ret; - ret = s390_register_crw_handler(CRW_RSC_CPATH, chp_process_crw); - if (ret) - return ret; chp_wq = create_singlethread_workqueue("cio_chp"); - if (!chp_wq) { - s390_unregister_crw_handler(CRW_RSC_CPATH); + if (!chp_wq) return -ENOMEM; - } INIT_WORK(&cfg_work, cfg_func); init_waitqueue_head(&cfg_wait_queue); if (info_update()) diff --git a/trunk/drivers/s390/cio/chp.h b/trunk/drivers/s390/cio/chp.h index 26c3d2246176..65286563c592 100644 --- a/trunk/drivers/s390/cio/chp.h +++ b/trunk/drivers/s390/cio/chp.h @@ -12,24 +12,12 @@ #include #include #include "chsc.h" -#include "css.h" #define CHP_STATUS_STANDBY 0 #define CHP_STATUS_CONFIGURED 1 #define CHP_STATUS_RESERVED 2 #define CHP_STATUS_NOT_RECOGNIZED 3 -#define CHP_ONLINE 0 -#define CHP_OFFLINE 1 -#define CHP_VARY_ON 2 -#define CHP_VARY_OFF 3 - -struct chp_link { - struct chp_id chpid; - u32 fla_mask; - u16 fla; -}; - static inline int chp_test_bit(u8 *bitmap, int num) { int byte = num >> 3; @@ -54,11 +42,12 @@ int chp_get_status(struct chp_id chpid); u8 chp_get_sch_opm(struct subchannel *sch); int chp_is_registered(struct chp_id chpid); void *chp_get_chp_desc(struct chp_id chpid); +void chp_process_crw(int id, int available); void chp_remove_cmg_attr(struct channel_path *chp); int chp_add_cmg_attr(struct channel_path *chp); int chp_new(struct chp_id chpid); void chp_cfg_schedule(struct chp_id chpid, int configure); void chp_cfg_cancel_deconfigure(struct chp_id chpid); int chp_info_get_status(struct chp_id chpid); -int chp_ssd_get_mask(struct chsc_ssd_info *, struct chp_link *); + #endif /* S390_CHP_H */ diff --git a/trunk/drivers/s390/cio/chsc.c b/trunk/drivers/s390/cio/chsc.c index 65264a38057d..5de86908b0d0 100644 --- a/trunk/drivers/s390/cio/chsc.c +++ b/trunk/drivers/s390/cio/chsc.c @@ -2,7 +2,8 @@ * drivers/s390/cio/chsc.c * S/390 common I/O routines -- channel subsystem call * - * Copyright IBM Corp. 1999,2008 + * Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -15,9 +16,7 @@ #include #include -#include -#include "../s390mach.h" #include "css.h" #include "cio.h" #include "cio_debug.h" @@ -128,12 +127,77 @@ int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd) return ret; } +static int check_for_io_on_path(struct subchannel *sch, int mask) +{ + int cc; + + cc = stsch(sch->schid, &sch->schib); + if (cc) + return 0; + if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == mask) + return 1; + return 0; +} + +static void terminate_internal_io(struct subchannel *sch) +{ + if (cio_clear(sch)) { + /* Recheck device in case clear failed. */ + sch->lpm = 0; + if (device_trigger_verify(sch) != 0) + css_schedule_eval(sch->schid); + return; + } + /* Request retry of internal operation. */ + device_set_intretry(sch); + /* Call handler. */ + if (sch->driver && sch->driver->termination) + sch->driver->termination(sch); +} + static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) { + int j; + int mask; + struct chp_id *chpid = data; + struct schib schib; + + for (j = 0; j < 8; j++) { + mask = 0x80 >> j; + if ((sch->schib.pmcw.pim & mask) && + (sch->schib.pmcw.chpid[j] == chpid->id)) + break; + } + if (j >= 8) + return 0; + spin_lock_irq(sch->lock); - if (sch->driver && sch->driver->chp_event) - if (sch->driver->chp_event(sch, data, CHP_OFFLINE) != 0) + + stsch(sch->schid, &schib); + if (!css_sch_is_valid(&schib)) + goto out_unreg; + memcpy(&sch->schib, &schib, sizeof(struct schib)); + /* Check for single path devices. */ + if (sch->schib.pmcw.pim == 0x80) + goto out_unreg; + + if (check_for_io_on_path(sch, mask)) { + if (device_is_online(sch)) + device_kill_io(sch); + else { + terminate_internal_io(sch); + /* Re-start path verification. */ + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + } + } else { + /* trigger path verification. */ + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + else if (sch->lpm == mask) goto out_unreg; + } + spin_unlock_irq(sch->lock); return 0; @@ -147,18 +211,15 @@ static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) void chsc_chp_offline(struct chp_id chpid) { char dbf_txt[15]; - struct chp_link link; sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_txt); if (chp_get_status(chpid) <= 0) return; - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); - for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link); + for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid); } static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) @@ -181,25 +242,67 @@ static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) return 0; } +struct res_acc_data { + struct chp_id chpid; + u32 fla_mask; + u16 fla; +}; + +static int get_res_chpid_mask(struct chsc_ssd_info *ssd, + struct res_acc_data *data) +{ + int i; + int mask; + + for (i = 0; i < 8; i++) { + mask = 0x80 >> i; + if (!(ssd->path_mask & mask)) + continue; + if (!chp_id_is_equal(&ssd->chpid[i], &data->chpid)) + continue; + if ((ssd->fla_valid_mask & mask) && + ((ssd->fla[i] & data->fla_mask) != data->fla)) + continue; + return mask; + } + return 0; +} + static int __s390_process_res_acc(struct subchannel *sch, void *data) { + int chp_mask, old_lpm; + struct res_acc_data *res_data = data; + spin_lock_irq(sch->lock); - if (sch->driver && sch->driver->chp_event) - sch->driver->chp_event(sch, data, CHP_ONLINE); + chp_mask = get_res_chpid_mask(&sch->ssd_info, res_data); + if (chp_mask == 0) + goto out; + if (stsch(sch->schid, &sch->schib)) + goto out; + old_lpm = sch->lpm; + sch->lpm = ((sch->schib.pmcw.pim & + sch->schib.pmcw.pam & + sch->schib.pmcw.pom) + | chp_mask) & sch->opm; + if (!old_lpm && sch->lpm) + device_trigger_reprobe(sch); + else if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); +out: spin_unlock_irq(sch->lock); return 0; } -static void s390_process_res_acc(struct chp_link *link) +static void s390_process_res_acc (struct res_acc_data *res_data) { char dbf_txt[15]; - sprintf(dbf_txt, "accpr%x.%02x", link->chpid.cssid, - link->chpid.id); + sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid, + res_data->chpid.id); CIO_TRACE_EVENT( 2, dbf_txt); - if (link->fla != 0) { - sprintf(dbf_txt, "fla%x", link->fla); + if (res_data->fla != 0) { + sprintf(dbf_txt, "fla%x", res_data->fla); CIO_TRACE_EVENT( 2, dbf_txt); } /* Wait until previous actions have settled. */ @@ -212,7 +315,7 @@ static void s390_process_res_acc(struct chp_link *link) * will we have to do. */ for_each_subchannel_staged(__s390_process_res_acc, - s390_process_res_acc_new_sch, link); + s390_process_res_acc_new_sch, res_data); } static int @@ -285,7 +388,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) { - struct chp_link link; + struct res_acc_data res_data; struct chp_id chpid; int status; @@ -301,18 +404,18 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) chp_new(chpid); else if (!status) return; - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; + memset(&res_data, 0, sizeof(struct res_acc_data)); + res_data.chpid = chpid; if ((sei_area->vf & 0xc0) != 0) { - link.fla = sei_area->fla; + res_data.fla = sei_area->fla; if ((sei_area->vf & 0xc0) == 0xc0) /* full link address */ - link.fla_mask = 0xffff; + res_data.fla_mask = 0xffff; else /* link address */ - link.fla_mask = 0xff00; + res_data.fla_mask = 0xff00; } - s390_process_res_acc(&link); + s390_process_res_acc(&res_data); } struct chp_config_data { @@ -377,25 +480,17 @@ static void chsc_process_sei(struct chsc_sei_area *sei_area) } } -static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) +void chsc_process_crw(void) { struct chsc_sei_area *sei_area; - if (overflow) { - css_schedule_eval_all(); - return; - } - CIO_CRW_EVENT(2, "CRW reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, - crw0->erc, crw0->rsid); if (!sei_page) return; /* Access to sei_page is serialized through machine check handler * thread, so no need for locking. */ sei_area = sei_page; - CIO_TRACE_EVENT(2, "prcss"); + CIO_TRACE_EVENT( 2, "prcss"); do { memset(sei_area, 0, sizeof(*sei_area)); sei_area->request.length = 0x0010; @@ -414,36 +509,114 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) } while (sei_area->flags & 0x80); } +static int __chp_add_new_sch(struct subchannel_id schid, void *data) +{ + struct schib schib; + + if (stsch_err(schid, &schib)) + /* We're through */ + return -ENXIO; + + /* Put it on the slow path. */ + css_schedule_eval(schid); + return 0; +} + + +static int __chp_add(struct subchannel *sch, void *data) +{ + int i, mask; + struct chp_id *chpid = data; + + spin_lock_irq(sch->lock); + for (i=0; i<8; i++) { + mask = 0x80 >> i; + if ((sch->schib.pmcw.pim & mask) && + (sch->schib.pmcw.chpid[i] == chpid->id)) + break; + } + if (i==8) { + spin_unlock_irq(sch->lock); + return 0; + } + if (stsch(sch->schid, &sch->schib)) { + spin_unlock_irq(sch->lock); + css_schedule_eval(sch->schid); + return 0; + } + sch->lpm = ((sch->schib.pmcw.pim & + sch->schib.pmcw.pam & + sch->schib.pmcw.pom) + | mask) & sch->opm; + + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + + spin_unlock_irq(sch->lock); + + return 0; +} + void chsc_chp_online(struct chp_id chpid) { char dbf_txt[15]; - struct chp_link link; sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_txt); if (chp_get_status(chpid) != 0) { - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); - for_each_subchannel_staged(__s390_process_res_acc, NULL, - &link); + for_each_subchannel_staged(__chp_add, __chp_add_new_sch, + &chpid); } } static void __s390_subchannel_vary_chpid(struct subchannel *sch, struct chp_id chpid, int on) { + int chp, old_lpm; + int mask; unsigned long flags; - struct chp_link link; - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; spin_lock_irqsave(sch->lock, flags); - if (sch->driver && sch->driver->chp_event) - sch->driver->chp_event(sch, &link, - on ? CHP_VARY_ON : CHP_VARY_OFF); + old_lpm = sch->lpm; + for (chp = 0; chp < 8; chp++) { + mask = 0x80 >> chp; + if (!(sch->ssd_info.path_mask & mask)) + continue; + if (!chp_id_is_equal(&sch->ssd_info.chpid[chp], &chpid)) + continue; + + if (on) { + sch->opm |= mask; + sch->lpm |= mask; + if (!old_lpm) + device_trigger_reprobe(sch); + else if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + break; + } + sch->opm &= ~mask; + sch->lpm &= ~mask; + if (check_for_io_on_path(sch, mask)) { + if (device_is_online(sch)) + /* Path verification is done after killing. */ + device_kill_io(sch); + else { + /* Kill and retry internal I/O. */ + terminate_internal_io(sch); + /* Re-start path verification. */ + if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + } + } else if (!sch->lpm) { + if (device_trigger_verify(sch) != 0) + css_schedule_eval(sch->schid); + } else if (sch->driver && sch->driver->verify) + sch->driver->verify(sch); + break; + } spin_unlock_irqrestore(sch->lock, flags); } @@ -483,10 +656,6 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) */ int chsc_chp_vary(struct chp_id chpid, int on) { - struct chp_link link; - - memset(&link, 0, sizeof(struct chp_link)); - link.chpid = chpid; /* Wait until previous actions have settled. */ css_wait_for_slow_path(); /* @@ -495,10 +664,10 @@ int chsc_chp_vary(struct chp_id chpid, int on) if (on) for_each_subchannel_staged(s390_subchannel_vary_chpid_on, - __s390_vary_chpid_on, &link); + __s390_vary_chpid_on, &chpid); else for_each_subchannel_staged(s390_subchannel_vary_chpid_off, - NULL, &link); + NULL, &chpid); return 0; } @@ -628,33 +797,23 @@ chsc_secm(struct channel_subsystem *css, int enable) return ret; } -int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, - int c, int m, - struct chsc_response_struct *resp) +int chsc_determine_channel_path_description(struct chp_id chpid, + struct channel_path_desc *desc) { int ccode, ret; struct { struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 c : 1; - u32 fmt : 4; - u32 cssid : 8; - u32 : 4; - u32 rfmt : 4; + u32 : 24; u32 first_chpid : 8; u32 : 24; u32 last_chpid : 8; u32 zeroes1; struct chsc_header response; - u8 data[PAGE_SIZE - 20]; + u32 zeroes2; + struct channel_path_desc desc; } __attribute__ ((packed)) *scpd_area; - if ((rfmt == 1) && !css_general_characteristics.fcs) - return -EINVAL; - if ((rfmt == 2) && !css_general_characteristics.cib) - return -EINVAL; scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scpd_area) return -ENOMEM; @@ -662,13 +821,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, scpd_area->request.length = 0x0010; scpd_area->request.code = 0x0002; - scpd_area->cssid = chpid.cssid; scpd_area->first_chpid = chpid.id; scpd_area->last_chpid = chpid.id; - scpd_area->m = m; - scpd_area->c = c; - scpd_area->fmt = fmt; - scpd_area->rfmt = rfmt; ccode = chsc(scpd_area); if (ccode > 0) { @@ -679,7 +833,8 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, ret = chsc_error_from_response(scpd_area->response.code); if (ret == 0) /* Success. */ - memcpy(resp, &scpd_area->response, scpd_area->response.length); + memcpy(desc, &scpd_area->desc, + sizeof(struct channel_path_desc)); else CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n", scpd_area->response.code); @@ -687,25 +842,6 @@ int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, free_page((unsigned long)scpd_area); return ret; } -EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc); - -int chsc_determine_base_channel_path_desc(struct chp_id chpid, - struct channel_path_desc *desc) -{ - struct chsc_response_struct *chsc_resp; - int ret; - - chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL); - if (!chsc_resp) - return -ENOMEM; - ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp); - if (ret) - goto out_free; - memcpy(desc, &chsc_resp->data, chsc_resp->length); -out_free: - kfree(chsc_resp); - return ret; -} static void chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv, @@ -801,23 +937,15 @@ int chsc_get_channel_measurement_chars(struct channel_path *chp) int __init chsc_alloc_sei_area(void) { - int ret; - sei_page = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sei_page) { + if (!sei_page) CIO_MSG_EVENT(0, "Can't allocate page for processing of " "chsc machine checks!\n"); - return -ENOMEM; - } - ret = s390_register_crw_handler(CRW_RSC_CSS, chsc_process_crw); - if (ret) - kfree(sei_page); - return ret; + return (sei_page ? 0 : -ENOMEM); } void __init chsc_free_sei_area(void) { - s390_unregister_crw_handler(CRW_RSC_CSS); kfree(sei_page); } @@ -915,52 +1043,3 @@ chsc_determine_css_characteristics(void) EXPORT_SYMBOL_GPL(css_general_characteristics); EXPORT_SYMBOL_GPL(css_chsc_characteristics); - -int chsc_sstpc(void *page, unsigned int op, u16 ctrl) -{ - struct { - struct chsc_header request; - unsigned int rsvd0; - unsigned int op : 8; - unsigned int rsvd1 : 8; - unsigned int ctrl : 16; - unsigned int rsvd2[5]; - struct chsc_header response; - unsigned int rsvd3[7]; - } __attribute__ ((packed)) *rr; - int rc; - - memset(page, 0, PAGE_SIZE); - rr = page; - rr->request.length = 0x0020; - rr->request.code = 0x0033; - rr->op = op; - rr->ctrl = ctrl; - rc = chsc(rr); - if (rc) - return -EIO; - rc = (rr->response.code == 0x0001) ? 0 : -EIO; - return rc; -} - -int chsc_sstpi(void *page, void *result, size_t size) -{ - struct { - struct chsc_header request; - unsigned int rsvd0[3]; - struct chsc_header response; - char data[size]; - } __attribute__ ((packed)) *rr; - int rc; - - memset(page, 0, PAGE_SIZE); - rr = page; - rr->request.length = 0x0010; - rr->request.code = 0x0038; - rc = chsc(rr); - if (rc) - return -EIO; - memcpy(result, &rr->data, size); - return (rr->response.code == 0x0001) ? 0 : -EIO; -} - diff --git a/trunk/drivers/s390/cio/chsc.h b/trunk/drivers/s390/cio/chsc.h index fb6c4d6c45b4..d1f5db1e69b9 100644 --- a/trunk/drivers/s390/cio/chsc.h +++ b/trunk/drivers/s390/cio/chsc.h @@ -4,8 +4,7 @@ #include #include #include -#include -#include +#include "schid.h" #define CHSC_SDA_OC_MSS 0x2 @@ -37,15 +36,14 @@ struct channel_path_desc { struct channel_path; +extern void chsc_process_crw(void); + struct css_general_char { - u64 : 12; - u32 dynio : 1; /* bit 12 */ - u32 : 28; + u64 : 41; u32 aif : 1; /* bit 41 */ u32 : 3; u32 mcss : 1; /* bit 45 */ - u32 fcs : 1; /* bit 46 */ - u32 : 1; + u32 : 2; u32 ext_mb : 1; /* bit 48 */ u32 : 7; u32 aif_tdd : 1; /* bit 56 */ @@ -53,11 +51,7 @@ struct css_general_char { u32 qebsm : 1; /* bit 58 */ u32 : 8; u32 aif_osa : 1; /* bit 67 */ - u32 : 14; - u32 cib : 1; /* bit 82 */ - u32 : 5; - u32 fcx : 1; /* bit 88 */ - u32 : 7; + u32 : 28; }__attribute__((packed)); struct css_chsc_char { @@ -84,6 +78,7 @@ struct chsc_ssd_info { extern int chsc_get_ssd_info(struct subchannel_id schid, struct chsc_ssd_info *ssd); extern int chsc_determine_css_characteristics(void); +extern int css_characteristics_avail; extern int chsc_alloc_sei_area(void); extern void chsc_free_sei_area(void); @@ -92,11 +87,8 @@ struct channel_subsystem; extern int chsc_secm(struct channel_subsystem *, int); int chsc_chp_vary(struct chp_id chpid, int on); -int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, - int c, int m, - struct chsc_response_struct *resp); -int chsc_determine_base_channel_path_desc(struct chp_id chpid, - struct channel_path_desc *desc); +int chsc_determine_channel_path_description(struct chp_id chpid, + struct channel_path_desc *desc); void chsc_chp_online(struct chp_id chpid); void chsc_chp_offline(struct chp_id chpid); int chsc_get_channel_measurement_chars(struct channel_path *chp); diff --git a/trunk/drivers/s390/cio/chsc_sch.c b/trunk/drivers/s390/cio/chsc_sch.c deleted file mode 100644 index 91ca87aa9f97..000000000000 --- a/trunk/drivers/s390/cio/chsc_sch.c +++ /dev/null @@ -1,820 +0,0 @@ -/* - * Driver for s390 chsc subchannels - * - * Copyright IBM Corp. 2008 - * Author(s): Cornelia Huck - * - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include "cio.h" -#include "cio_debug.h" -#include "css.h" -#include "chsc_sch.h" -#include "ioasm.h" - -static debug_info_t *chsc_debug_msg_id; -static debug_info_t *chsc_debug_log_id; - -#define CHSC_MSG(imp, args...) do { \ - debug_sprintf_event(chsc_debug_msg_id, imp , ##args); \ - } while (0) - -#define CHSC_LOG(imp, txt) do { \ - debug_text_event(chsc_debug_log_id, imp , txt); \ - } while (0) - -static void CHSC_LOG_HEX(int level, void *data, int length) -{ - while (length > 0) { - debug_event(chsc_debug_log_id, level, data, length); - length -= chsc_debug_log_id->buf_size; - data += chsc_debug_log_id->buf_size; - } -} - -MODULE_AUTHOR("IBM Corporation"); -MODULE_DESCRIPTION("driver for s390 chsc subchannels"); -MODULE_LICENSE("GPL"); - -static void chsc_subchannel_irq(struct subchannel *sch) -{ - struct chsc_private *private = sch->private; - struct chsc_request *request = private->request; - struct irb *irb = (struct irb *)__LC_IRB; - - CHSC_LOG(4, "irb"); - CHSC_LOG_HEX(4, irb, sizeof(*irb)); - /* Copy irb to provided request and set done. */ - if (!request) { - CHSC_MSG(0, "Interrupt on sch 0.%x.%04x with no request\n", - sch->schid.ssid, sch->schid.sch_no); - return; - } - private->request = NULL; - memcpy(&request->irb, irb, sizeof(*irb)); - stsch(sch->schid, &sch->schib); - complete(&request->completion); - put_device(&sch->dev); -} - -static int chsc_subchannel_probe(struct subchannel *sch) -{ - struct chsc_private *private; - int ret; - - CHSC_MSG(6, "Detected chsc subchannel 0.%x.%04x\n", - sch->schid.ssid, sch->schid.sch_no); - sch->isc = CHSC_SCH_ISC; - private = kzalloc(sizeof(*private), GFP_KERNEL); - if (!private) - return -ENOMEM; - ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch); - if (ret) { - CHSC_MSG(0, "Failed to enable 0.%x.%04x: %d\n", - sch->schid.ssid, sch->schid.sch_no, ret); - kfree(private); - } else { - sch->private = private; - if (sch->dev.uevent_suppress) { - sch->dev.uevent_suppress = 0; - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } - } - return ret; -} - -static int chsc_subchannel_remove(struct subchannel *sch) -{ - struct chsc_private *private; - - cio_disable_subchannel(sch); - private = sch->private; - sch->private = NULL; - if (private->request) { - complete(&private->request->completion); - put_device(&sch->dev); - } - kfree(private); - return 0; -} - -static void chsc_subchannel_shutdown(struct subchannel *sch) -{ - cio_disable_subchannel(sch); -} - -static struct css_device_id chsc_subchannel_ids[] = { - { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(css, chsc_subchannel_ids); - -static struct css_driver chsc_subchannel_driver = { - .owner = THIS_MODULE, - .subchannel_type = chsc_subchannel_ids, - .irq = chsc_subchannel_irq, - .probe = chsc_subchannel_probe, - .remove = chsc_subchannel_remove, - .shutdown = chsc_subchannel_shutdown, - .name = "chsc_subchannel", -}; - -static int __init chsc_init_dbfs(void) -{ - chsc_debug_msg_id = debug_register("chsc_msg", 16, 1, - 16 * sizeof(long)); - if (!chsc_debug_msg_id) - goto out; - debug_register_view(chsc_debug_msg_id, &debug_sprintf_view); - debug_set_level(chsc_debug_msg_id, 2); - chsc_debug_log_id = debug_register("chsc_log", 16, 1, 16); - if (!chsc_debug_log_id) - goto out; - debug_register_view(chsc_debug_log_id, &debug_hex_ascii_view); - debug_set_level(chsc_debug_log_id, 2); - return 0; -out: - if (chsc_debug_msg_id) - debug_unregister(chsc_debug_msg_id); - return -ENOMEM; -} - -static void chsc_remove_dbfs(void) -{ - debug_unregister(chsc_debug_log_id); - debug_unregister(chsc_debug_msg_id); -} - -static int __init chsc_init_sch_driver(void) -{ - return css_driver_register(&chsc_subchannel_driver); -} - -static void chsc_cleanup_sch_driver(void) -{ - css_driver_unregister(&chsc_subchannel_driver); -} - -static DEFINE_SPINLOCK(chsc_lock); - -static int chsc_subchannel_match_next_free(struct device *dev, void *data) -{ - struct subchannel *sch = to_subchannel(dev); - - return sch->schib.pmcw.ena && !scsw_fctl(&sch->schib.scsw); -} - -static struct subchannel *chsc_get_next_subchannel(struct subchannel *sch) -{ - struct device *dev; - - dev = driver_find_device(&chsc_subchannel_driver.drv, - sch ? &sch->dev : NULL, NULL, - chsc_subchannel_match_next_free); - return dev ? to_subchannel(dev) : NULL; -} - -/** - * chsc_async() - try to start a chsc request asynchronously - * @chsc_area: request to be started - * @request: request structure to associate - * - * Tries to start a chsc request on one of the existing chsc subchannels. - * Returns: - * %0 if the request was performed synchronously - * %-EINPROGRESS if the request was successfully started - * %-EBUSY if all chsc subchannels are busy - * %-ENODEV if no chsc subchannels are available - * Context: - * interrupts disabled, chsc_lock held - */ -static int chsc_async(struct chsc_async_area *chsc_area, - struct chsc_request *request) -{ - int cc; - struct chsc_private *private; - struct subchannel *sch = NULL; - int ret = -ENODEV; - char dbf[10]; - - chsc_area->header.key = PAGE_DEFAULT_KEY; - while ((sch = chsc_get_next_subchannel(sch))) { - spin_lock(sch->lock); - private = sch->private; - if (private->request) { - spin_unlock(sch->lock); - ret = -EBUSY; - continue; - } - chsc_area->header.sid = sch->schid; - CHSC_LOG(2, "schid"); - CHSC_LOG_HEX(2, &sch->schid, sizeof(sch->schid)); - cc = chsc(chsc_area); - sprintf(dbf, "cc:%d", cc); - CHSC_LOG(2, dbf); - switch (cc) { - case 0: - ret = 0; - break; - case 1: - sch->schib.scsw.cmd.fctl |= SCSW_FCTL_START_FUNC; - ret = -EINPROGRESS; - private->request = request; - break; - case 2: - ret = -EBUSY; - break; - default: - ret = -ENODEV; - } - spin_unlock(sch->lock); - CHSC_MSG(2, "chsc on 0.%x.%04x returned cc=%d\n", - sch->schid.ssid, sch->schid.sch_no, cc); - if (ret == -EINPROGRESS) - return -EINPROGRESS; - put_device(&sch->dev); - if (ret == 0) - return 0; - } - return ret; -} - -static void chsc_log_command(struct chsc_async_area *chsc_area) -{ - char dbf[10]; - - sprintf(dbf, "CHSC:%x", chsc_area->header.code); - CHSC_LOG(0, dbf); - CHSC_LOG_HEX(0, chsc_area, 32); -} - -static int chsc_examine_irb(struct chsc_request *request) -{ - int backed_up; - - if (!scsw_stctl(&request->irb.scsw) & SCSW_STCTL_STATUS_PEND) - return -EIO; - backed_up = scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHAIN_CHECK; - request->irb.scsw.cmd.cstat &= ~SCHN_STAT_CHAIN_CHECK; - if (scsw_cstat(&request->irb.scsw) == 0) - return 0; - if (!backed_up) - return 0; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROG_CHECK) - return -EIO; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_PROT_CHECK) - return -EPERM; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_DATA_CHK) - return -EAGAIN; - if (scsw_cstat(&request->irb.scsw) & SCHN_STAT_CHN_CTRL_CHK) - return -EAGAIN; - return -EIO; -} - -static int chsc_ioctl_start(void __user *user_area) -{ - struct chsc_request *request; - struct chsc_async_area *chsc_area; - int ret; - char dbf[10]; - - if (!css_general_characteristics.dynio) - /* It makes no sense to try. */ - return -EOPNOTSUPP; - chsc_area = (void *)get_zeroed_page(GFP_DMA | GFP_KERNEL); - if (!chsc_area) - return -ENOMEM; - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (!request) { - ret = -ENOMEM; - goto out_free; - } - init_completion(&request->completion); - if (copy_from_user(chsc_area, user_area, PAGE_SIZE)) { - ret = -EFAULT; - goto out_free; - } - chsc_log_command(chsc_area); - spin_lock_irq(&chsc_lock); - ret = chsc_async(chsc_area, request); - spin_unlock_irq(&chsc_lock); - if (ret == -EINPROGRESS) { - wait_for_completion(&request->completion); - ret = chsc_examine_irb(request); - } - /* copy area back to user */ - if (!ret) - if (copy_to_user(user_area, chsc_area, PAGE_SIZE)) - ret = -EFAULT; -out_free: - sprintf(dbf, "ret:%d", ret); - CHSC_LOG(0, dbf); - kfree(request); - free_page((unsigned long)chsc_area); - return ret; -} - -static int chsc_ioctl_info_channel_path(void __user *user_cd) -{ - struct chsc_chp_cd *cd; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 1; - u32 fmt1 : 4; - u32 cssid : 8; - u32 : 8; - u32 first_chpid : 8; - u32 : 24; - u32 last_chpid : 8; - u32 : 32; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *scpcd_area; - - scpcd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!scpcd_area) - return -ENOMEM; - cd = kzalloc(sizeof(*cd), GFP_KERNEL); - if (!cd) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(cd, user_cd, sizeof(*cd))) { - ret = -EFAULT; - goto out_free; - } - scpcd_area->request.length = 0x0010; - scpcd_area->request.code = 0x0028; - scpcd_area->m = cd->m; - scpcd_area->fmt1 = cd->fmt; - scpcd_area->cssid = cd->chpid.cssid; - scpcd_area->first_chpid = cd->chpid.id; - scpcd_area->last_chpid = cd->chpid.id; - - ccode = chsc(scpcd_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (scpcd_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "scpcd: response code=%x\n", - scpcd_area->response.code); - goto out_free; - } - memcpy(&cd->cpcb, &scpcd_area->response, scpcd_area->response.length); - if (copy_to_user(user_cd, cd, sizeof(*cd))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(cd); - free_page((unsigned long)scpcd_area); - return ret; -} - -static int chsc_ioctl_info_cu(void __user *user_cd) -{ - struct chsc_cu_cd *cd; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 1; - u32 fmt1 : 4; - u32 cssid : 8; - u32 : 8; - u32 first_cun : 8; - u32 : 24; - u32 last_cun : 8; - u32 : 32; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *scucd_area; - - scucd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!scucd_area) - return -ENOMEM; - cd = kzalloc(sizeof(*cd), GFP_KERNEL); - if (!cd) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(cd, user_cd, sizeof(*cd))) { - ret = -EFAULT; - goto out_free; - } - scucd_area->request.length = 0x0010; - scucd_area->request.code = 0x0028; - scucd_area->m = cd->m; - scucd_area->fmt1 = cd->fmt; - scucd_area->cssid = cd->cssid; - scucd_area->first_cun = cd->cun; - scucd_area->last_cun = cd->cun; - - ccode = chsc(scucd_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (scucd_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "scucd: response code=%x\n", - scucd_area->response.code); - goto out_free; - } - memcpy(&cd->cucb, &scucd_area->response, scucd_area->response.length); - if (copy_to_user(user_cd, cd, sizeof(*cd))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(cd); - free_page((unsigned long)scucd_area); - return ret; -} - -static int chsc_ioctl_info_sch_cu(void __user *user_cud) -{ - struct chsc_sch_cud *cud; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 5; - u32 fmt1 : 4; - u32 : 2; - u32 ssid : 2; - u32 first_sch : 16; - u32 : 8; - u32 cssid : 8; - u32 last_sch : 16; - u32 : 32; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *sscud_area; - - sscud_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sscud_area) - return -ENOMEM; - cud = kzalloc(sizeof(*cud), GFP_KERNEL); - if (!cud) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(cud, user_cud, sizeof(*cud))) { - ret = -EFAULT; - goto out_free; - } - sscud_area->request.length = 0x0010; - sscud_area->request.code = 0x0006; - sscud_area->m = cud->schid.m; - sscud_area->fmt1 = cud->fmt; - sscud_area->ssid = cud->schid.ssid; - sscud_area->first_sch = cud->schid.sch_no; - sscud_area->cssid = cud->schid.cssid; - sscud_area->last_sch = cud->schid.sch_no; - - ccode = chsc(sscud_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sscud_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sscud: response code=%x\n", - sscud_area->response.code); - goto out_free; - } - memcpy(&cud->scub, &sscud_area->response, sscud_area->response.length); - if (copy_to_user(user_cud, cud, sizeof(*cud))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(cud); - free_page((unsigned long)sscud_area); - return ret; -} - -static int chsc_ioctl_conf_info(void __user *user_ci) -{ - struct chsc_conf_info *ci; - int ret, ccode; - struct { - struct chsc_header request; - u32 : 2; - u32 m : 1; - u32 : 1; - u32 fmt1 : 4; - u32 cssid : 8; - u32 : 6; - u32 ssid : 2; - u32 : 8; - u64 : 64; - struct chsc_header response; - u8 data[PAGE_SIZE - 20]; - } __attribute__ ((packed)) *sci_area; - - sci_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sci_area) - return -ENOMEM; - ci = kzalloc(sizeof(*ci), GFP_KERNEL); - if (!ci) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(ci, user_ci, sizeof(*ci))) { - ret = -EFAULT; - goto out_free; - } - sci_area->request.length = 0x0010; - sci_area->request.code = 0x0012; - sci_area->m = ci->id.m; - sci_area->fmt1 = ci->fmt; - sci_area->cssid = ci->id.cssid; - sci_area->ssid = ci->id.ssid; - - ccode = chsc(sci_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sci_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sci: response code=%x\n", - sci_area->response.code); - goto out_free; - } - memcpy(&ci->scid, &sci_area->response, sci_area->response.length); - if (copy_to_user(user_ci, ci, sizeof(*ci))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(ci); - free_page((unsigned long)sci_area); - return ret; -} - -static int chsc_ioctl_conf_comp_list(void __user *user_ccl) -{ - struct chsc_comp_list *ccl; - int ret, ccode; - struct { - struct chsc_header request; - u32 ctype : 8; - u32 : 4; - u32 fmt : 4; - u32 : 16; - u64 : 64; - u32 list_parm[2]; - u64 : 64; - struct chsc_header response; - u8 data[PAGE_SIZE - 36]; - } __attribute__ ((packed)) *sccl_area; - struct { - u32 m : 1; - u32 : 31; - u32 cssid : 8; - u32 : 16; - u32 chpid : 8; - } __attribute__ ((packed)) *chpid_parm; - struct { - u32 f_cssid : 8; - u32 l_cssid : 8; - u32 : 16; - u32 res; - } __attribute__ ((packed)) *cssids_parm; - - sccl_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sccl_area) - return -ENOMEM; - ccl = kzalloc(sizeof(*ccl), GFP_KERNEL); - if (!ccl) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(ccl, user_ccl, sizeof(*ccl))) { - ret = -EFAULT; - goto out_free; - } - sccl_area->request.length = 0x0020; - sccl_area->request.code = 0x0030; - sccl_area->fmt = ccl->req.fmt; - sccl_area->ctype = ccl->req.ctype; - switch (sccl_area->ctype) { - case CCL_CU_ON_CHP: - case CCL_IOP_CHP: - chpid_parm = (void *)&sccl_area->list_parm; - chpid_parm->m = ccl->req.chpid.m; - chpid_parm->cssid = ccl->req.chpid.chp.cssid; - chpid_parm->chpid = ccl->req.chpid.chp.id; - break; - case CCL_CSS_IMG: - case CCL_CSS_IMG_CONF_CHAR: - cssids_parm = (void *)&sccl_area->list_parm; - cssids_parm->f_cssid = ccl->req.cssids.f_cssid; - cssids_parm->l_cssid = ccl->req.cssids.l_cssid; - break; - } - ccode = chsc(sccl_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sccl_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sccl: response code=%x\n", - sccl_area->response.code); - goto out_free; - } - memcpy(&ccl->sccl, &sccl_area->response, sccl_area->response.length); - if (copy_to_user(user_ccl, ccl, sizeof(*ccl))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(ccl); - free_page((unsigned long)sccl_area); - return ret; -} - -static int chsc_ioctl_chpd(void __user *user_chpd) -{ - struct chsc_cpd_info *chpd; - int ret; - - chpd = kzalloc(sizeof(*chpd), GFP_KERNEL); - if (!chpd) - return -ENOMEM; - if (copy_from_user(chpd, user_chpd, sizeof(*chpd))) { - ret = -EFAULT; - goto out_free; - } - ret = chsc_determine_channel_path_desc(chpd->chpid, chpd->fmt, - chpd->rfmt, chpd->c, chpd->m, - &chpd->chpdb); - if (ret) - goto out_free; - if (copy_to_user(user_chpd, chpd, sizeof(*chpd))) - ret = -EFAULT; -out_free: - kfree(chpd); - return ret; -} - -static int chsc_ioctl_dcal(void __user *user_dcal) -{ - struct chsc_dcal *dcal; - int ret, ccode; - struct { - struct chsc_header request; - u32 atype : 8; - u32 : 4; - u32 fmt : 4; - u32 : 16; - u32 res0[2]; - u32 list_parm[2]; - u32 res1[2]; - struct chsc_header response; - u8 data[PAGE_SIZE - 36]; - } __attribute__ ((packed)) *sdcal_area; - - sdcal_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); - if (!sdcal_area) - return -ENOMEM; - dcal = kzalloc(sizeof(*dcal), GFP_KERNEL); - if (!dcal) { - ret = -ENOMEM; - goto out_free; - } - if (copy_from_user(dcal, user_dcal, sizeof(*dcal))) { - ret = -EFAULT; - goto out_free; - } - sdcal_area->request.length = 0x0020; - sdcal_area->request.code = 0x0034; - sdcal_area->atype = dcal->req.atype; - sdcal_area->fmt = dcal->req.fmt; - memcpy(&sdcal_area->list_parm, &dcal->req.list_parm, - sizeof(sdcal_area->list_parm)); - - ccode = chsc(sdcal_area); - if (ccode != 0) { - ret = -EIO; - goto out_free; - } - if (sdcal_area->response.code != 0x0001) { - ret = -EIO; - CHSC_MSG(0, "sdcal: response code=%x\n", - sdcal_area->response.code); - goto out_free; - } - memcpy(&dcal->sdcal, &sdcal_area->response, - sdcal_area->response.length); - if (copy_to_user(user_dcal, dcal, sizeof(*dcal))) - ret = -EFAULT; - else - ret = 0; -out_free: - kfree(dcal); - free_page((unsigned long)sdcal_area); - return ret; -} - -static long chsc_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - CHSC_MSG(2, "chsc_ioctl called, cmd=%x\n", cmd); - switch (cmd) { - case CHSC_START: - return chsc_ioctl_start((void __user *)arg); - case CHSC_INFO_CHANNEL_PATH: - return chsc_ioctl_info_channel_path((void __user *)arg); - case CHSC_INFO_CU: - return chsc_ioctl_info_cu((void __user *)arg); - case CHSC_INFO_SCH_CU: - return chsc_ioctl_info_sch_cu((void __user *)arg); - case CHSC_INFO_CI: - return chsc_ioctl_conf_info((void __user *)arg); - case CHSC_INFO_CCL: - return chsc_ioctl_conf_comp_list((void __user *)arg); - case CHSC_INFO_CPD: - return chsc_ioctl_chpd((void __user *)arg); - case CHSC_INFO_DCAL: - return chsc_ioctl_dcal((void __user *)arg); - default: /* unknown ioctl number */ - return -ENOIOCTLCMD; - } -} - -static const struct file_operations chsc_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = chsc_ioctl, - .compat_ioctl = chsc_ioctl, -}; - -static struct miscdevice chsc_misc_device = { - .minor = MISC_DYNAMIC_MINOR, - .name = "chsc", - .fops = &chsc_fops, -}; - -static int __init chsc_misc_init(void) -{ - return misc_register(&chsc_misc_device); -} - -static void chsc_misc_cleanup(void) -{ - misc_deregister(&chsc_misc_device); -} - -static int __init chsc_sch_init(void) -{ - int ret; - - ret = chsc_init_dbfs(); - if (ret) - return ret; - isc_register(CHSC_SCH_ISC); - ret = chsc_init_sch_driver(); - if (ret) - goto out_dbf; - ret = chsc_misc_init(); - if (ret) - goto out_driver; - return ret; -out_driver: - chsc_cleanup_sch_driver(); -out_dbf: - isc_unregister(CHSC_SCH_ISC); - chsc_remove_dbfs(); - return ret; -} - -static void __exit chsc_sch_exit(void) -{ - chsc_misc_cleanup(); - chsc_cleanup_sch_driver(); - isc_unregister(CHSC_SCH_ISC); - chsc_remove_dbfs(); -} - -module_init(chsc_sch_init); -module_exit(chsc_sch_exit); diff --git a/trunk/drivers/s390/cio/chsc_sch.h b/trunk/drivers/s390/cio/chsc_sch.h deleted file mode 100644 index 589ebfad6aad..000000000000 --- a/trunk/drivers/s390/cio/chsc_sch.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _CHSC_SCH_H -#define _CHSC_SCH_H - -struct chsc_request { - struct completion completion; - struct irb irb; -}; - -struct chsc_private { - struct chsc_request *request; -}; - -#endif diff --git a/trunk/drivers/s390/cio/cio.c b/trunk/drivers/s390/cio/cio.c index 33bff8fec7d1..b32d7eb3d81a 100644 --- a/trunk/drivers/s390/cio/cio.c +++ b/trunk/drivers/s390/cio/cio.c @@ -2,7 +2,7 @@ * drivers/s390/cio/cio.c * S/390 common I/O routines -- low level i/o calls * - * Copyright IBM Corp. 1999,2008 + * Copyright (C) IBM Corp. 1999,2006 * Author(s): Ingo Adlung (adlung@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Arnd Bergmann (arndb@de.ibm.com) @@ -24,9 +24,7 @@ #include #include #include -#include #include -#include #include "cio.h" #include "css.h" #include "chsc.h" @@ -74,6 +72,7 @@ static int __init cio_debug_init(void) debug_unregister(cio_debug_trace_id); if (cio_debug_crw_id) debug_unregister(cio_debug_crw_id); + printk(KERN_WARNING"cio: could not initialize debugging\n"); return -1; } @@ -129,7 +128,7 @@ cio_tpi(void) local_bh_disable(); irq_enter (); spin_lock(sch->lock); - memcpy(&sch->schib.scsw, &irb->scsw, sizeof(union scsw)); + memcpy (&sch->schib.scsw, &irb->scsw, sizeof (struct scsw)); if (sch->driver && sch->driver->irq) sch->driver->irq(sch); spin_unlock(sch->lock); @@ -168,30 +167,30 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ { char dbf_txt[15]; int ccode; - union orb *orb; + struct orb *orb; CIO_TRACE_EVENT(4, "stIO"); CIO_TRACE_EVENT(4, sch->dev.bus_id); orb = &to_io_private(sch)->orb; /* sch is always under 2G. */ - orb->cmd.intparm = (u32)(addr_t)sch; - orb->cmd.fmt = 1; + orb->intparm = (u32)(addr_t)sch; + orb->fmt = 1; - orb->cmd.pfch = sch->options.prefetch == 0; - orb->cmd.spnd = sch->options.suspend; - orb->cmd.ssic = sch->options.suspend && sch->options.inter; - orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm; + orb->pfch = sch->options.prefetch == 0; + orb->spnd = sch->options.suspend; + orb->ssic = sch->options.suspend && sch->options.inter; + orb->lpm = (lpm != 0) ? lpm : sch->lpm; #ifdef CONFIG_64BIT /* * for 64 bit we always support 64 bit IDAWs with 4k page size only */ - orb->cmd.c64 = 1; - orb->cmd.i2k = 0; + orb->c64 = 1; + orb->i2k = 0; #endif - orb->cmd.key = key >> 4; + orb->key = key >> 4; /* issue "Start Subchannel" */ - orb->cmd.cpa = (__u32) __pa(cpa); + orb->cpa = (__u32) __pa(cpa); ccode = ssch(sch->schid, orb); /* process condition code */ @@ -203,7 +202,7 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ /* * initialize device status information */ - sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_START_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ @@ -238,7 +237,7 @@ cio_resume (struct subchannel *sch) switch (ccode) { case 0: - sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_RESUME_PEND; return 0; case 1: return -EBUSY; @@ -278,7 +277,7 @@ cio_halt(struct subchannel *sch) switch (ccode) { case 0: - sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ @@ -313,7 +312,7 @@ cio_clear(struct subchannel *sch) switch (ccode) { case 0: - sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND; + sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND; return 0; default: /* device not operational */ return -ENODEV; @@ -388,10 +387,8 @@ cio_modify (struct subchannel *sch) return ret; } -/** - * cio_enable_subchannel - enable a subchannel. - * @sch: subchannel to be enabled - * @intparm: interruption parameter to set +/* + * Enable subchannel. */ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { @@ -437,13 +434,12 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) CIO_TRACE_EVENT (2, dbf_txt); return ret; } -EXPORT_SYMBOL_GPL(cio_enable_subchannel); -/** - * cio_disable_subchannel - disable a subchannel. - * @sch: subchannel to disable +/* + * Disable subchannel. */ -int cio_disable_subchannel(struct subchannel *sch) +int +cio_disable_subchannel (struct subchannel *sch) { char dbf_txt[15]; int ccode; @@ -459,7 +455,7 @@ int cio_disable_subchannel(struct subchannel *sch) if (ccode == 3) /* Not operational. */ return -ENODEV; - if (scsw_actl(&sch->schib.scsw) != 0) + if (sch->schib.scsw.actl != 0) /* * the disable function must not be called while there are * requests pending for completion ! @@ -488,7 +484,6 @@ int cio_disable_subchannel(struct subchannel *sch) CIO_TRACE_EVENT (2, dbf_txt); return ret; } -EXPORT_SYMBOL_GPL(cio_disable_subchannel); int cio_create_sch_lock(struct subchannel *sch) { @@ -499,61 +494,27 @@ int cio_create_sch_lock(struct subchannel *sch) return 0; } -static int cio_check_devno_blacklisted(struct subchannel *sch) -{ - if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) { - /* - * This device must not be known to Linux. So we simply - * say that there is no device and return ENODEV. - */ - CIO_MSG_EVENT(6, "Blacklisted device detected " - "at devno %04X, subchannel set %x\n", - sch->schib.pmcw.dev, sch->schid.ssid); - return -ENODEV; - } - return 0; -} - -static int cio_validate_io_subchannel(struct subchannel *sch) -{ - /* Initialization for io subchannels. */ - if (!css_sch_is_valid(&sch->schib)) - return -ENODEV; - - /* Devno is valid. */ - return cio_check_devno_blacklisted(sch); -} - -static int cio_validate_msg_subchannel(struct subchannel *sch) -{ - /* Initialization for message subchannels. */ - if (!css_sch_is_valid(&sch->schib)) - return -ENODEV; - - /* Devno is valid. */ - return cio_check_devno_blacklisted(sch); -} - -/** - * cio_validate_subchannel - basic validation of subchannel - * @sch: subchannel structure to be filled out - * @schid: subchannel id +/* + * cio_validate_subchannel() * * Find out subchannel type and initialize struct subchannel. * Return codes: - * 0 on success + * SUBCHANNEL_TYPE_IO for a normal io subchannel + * SUBCHANNEL_TYPE_CHSC for a chsc subchannel + * SUBCHANNEL_TYPE_MESSAGE for a messaging subchannel + * SUBCHANNEL_TYPE_ADM for a adm(?) subchannel * -ENXIO for non-defined subchannels - * -ENODEV for invalid subchannels or blacklisted devices - * -EIO for subchannels in an invalid subchannel set + * -ENODEV for subchannels with invalid device number or blacklisted devices */ -int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) +int +cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) { char dbf_txt[15]; int ccode; int err; - sprintf(dbf_txt, "valsch%x", schid.sch_no); - CIO_TRACE_EVENT(4, dbf_txt); + sprintf (dbf_txt, "valsch%x", schid.sch_no); + CIO_TRACE_EVENT (4, dbf_txt); /* Nuke all fields. */ memset(sch, 0, sizeof(struct subchannel)); @@ -585,21 +546,67 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) /* Copy subchannel type from path management control word. */ sch->st = sch->schib.pmcw.st; - switch (sch->st) { - case SUBCHANNEL_TYPE_IO: - err = cio_validate_io_subchannel(sch); - break; - case SUBCHANNEL_TYPE_MSG: - err = cio_validate_msg_subchannel(sch); - break; - default: - err = 0; + /* + * ... just being curious we check for non I/O subchannels + */ + if (sch->st != 0) { + CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports " + "non-I/O subchannel type %04X\n", + sch->schid.ssid, sch->schid.sch_no, sch->st); + /* We stop here for non-io subchannels. */ + err = sch->st; + goto out; + } + + /* Initialization for io subchannels. */ + if (!css_sch_is_valid(&sch->schib)) { + err = -ENODEV; + goto out; } - if (err) + + /* Devno is valid. */ + if (is_blacklisted (sch->schid.ssid, sch->schib.pmcw.dev)) { + /* + * This device must not be known to Linux. So we simply + * say that there is no device and return ENODEV. + */ + CIO_MSG_EVENT(6, "Blacklisted device detected " + "at devno %04X, subchannel set %x\n", + sch->schib.pmcw.dev, sch->schid.ssid); + err = -ENODEV; goto out; + } + if (cio_is_console(sch->schid)) { + sch->opm = 0xff; + sch->isc = 1; + } else { + sch->opm = chp_get_sch_opm(sch); + sch->isc = 3; + } + sch->lpm = sch->schib.pmcw.pam & sch->opm; + + CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X " + "- PIM = %02X, PAM = %02X, POM = %02X\n", + sch->schib.pmcw.dev, sch->schid.ssid, + sch->schid.sch_no, sch->schib.pmcw.pim, + sch->schib.pmcw.pam, sch->schib.pmcw.pom); - CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n", - sch->schid.ssid, sch->schid.sch_no, sch->st); + /* + * We now have to initially ... + * ... enable "concurrent sense" + * ... enable "multipath mode" if more than one + * CHPID is available. This is done regardless + * whether multiple paths are available for us. + */ + sch->schib.pmcw.csense = 1; /* concurrent sense */ + sch->schib.pmcw.ena = 0; + 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; return 0; out: if (!cio_is_console(schid)) @@ -640,7 +647,7 @@ do_IRQ (struct pt_regs *regs) */ if (tpi_info->adapter_IO == 1 && tpi_info->int_type == IO_INTERRUPT_TYPE) { - do_adapter_IO(tpi_info->isc); + do_adapter_IO(); continue; } sch = (struct subchannel *)(unsigned long)tpi_info->intparm; @@ -699,9 +706,9 @@ void wait_cons_dev(void) if (!console_subchannel_in_use) return; - /* disable all but the console isc */ + /* disable all but isc 1 (console device) */ __ctl_store (save_cr6, 6, 6); - cr6 = 1UL << (31 - CONSOLE_ISC); + cr6 = 0x40000000; __ctl_load (cr6, 6, 6); do { @@ -709,7 +716,7 @@ void wait_cons_dev(void) if (!cio_tpi()) cpu_relax(); spin_lock(console_subchannel.lock); - } while (console_subchannel.schib.scsw.cmd.actl != 0); + } while (console_subchannel.schib.scsw.actl != 0); /* * restore previous isc value */ @@ -754,6 +761,7 @@ cio_get_console_sch_no(void) /* unlike in 2.4, we cannot autoprobe here, since * the channel subsystem is not fully initialized. * With some luck, the HWC console can take over */ + printk(KERN_WARNING "cio: No ccw console found!\n"); return -1; } return console_irq; @@ -770,7 +778,6 @@ 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"); return ERR_PTR(-ENODEV); } memset(&console_subchannel, 0, sizeof(struct subchannel)); @@ -783,15 +790,15 @@ cio_probe_console(void) } /* - * enable console I/O-interrupt subclass + * enable console I/O-interrupt subclass 1 */ - isc_register(CONSOLE_ISC); - console_subchannel.schib.pmcw.isc = CONSOLE_ISC; + ctl_set_bit(6, 30); + console_subchannel.isc = 1; + console_subchannel.schib.pmcw.isc = 1; console_subchannel.schib.pmcw.intparm = (u32)(addr_t)&console_subchannel; ret = cio_modify(&console_subchannel); if (ret) { - isc_unregister(CONSOLE_ISC); console_subchannel_in_use = 0; return ERR_PTR(ret); } @@ -803,7 +810,7 @@ cio_release_console(void) { console_subchannel.schib.pmcw.intparm = 0; cio_modify(&console_subchannel); - isc_unregister(CONSOLE_ISC); + ctl_clear_bit(6, 24); console_subchannel_in_use = 0; } @@ -857,7 +864,7 @@ static void udelay_reset(unsigned long usecs) } static int -__clear_io_subchannel_easy(struct subchannel_id schid) +__clear_subchannel_easy(struct subchannel_id schid) { int retry; @@ -876,12 +883,6 @@ __clear_io_subchannel_easy(struct subchannel_id schid) return -EBUSY; } -static void __clear_chsc_subchannel_easy(void) -{ - /* It seems we can only wait for a bit here :/ */ - udelay_reset(100); -} - static int pgm_check_occured; static void cio_reset_pgm_check_handler(void) @@ -920,22 +921,11 @@ static int __shutdown_subchannel_easy(struct subchannel_id schid, void *data) case -ENODEV: break; default: /* -EBUSY */ - switch (schib.pmcw.st) { - case SUBCHANNEL_TYPE_IO: - if (__clear_io_subchannel_easy(schid)) - goto out; /* give up... */ - break; - case SUBCHANNEL_TYPE_CHSC: - __clear_chsc_subchannel_easy(); - break; - default: - /* No default clear strategy */ - break; - } + if (__clear_subchannel_easy(schid)) + break; /* give up... */ stsch(schid, &schib); __disable_subchannel_easy(schid, &schib); } -out: return 0; } @@ -1078,61 +1068,3 @@ int __init cio_get_iplinfo(struct cio_iplinfo *iplinfo) iplinfo->is_qdio = schib.pmcw.qf; return 0; } - -/** - * cio_tm_start_key - perform start function - * @sch: subchannel on which to perform the start function - * @tcw: transport-command word to be started - * @lpm: mask of paths to use - * @key: storage key to use for storage access - * - * Start the tcw on the given subchannel. Return zero on success, non-zero - * otherwise. - */ -int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key) -{ - int cc; - union orb *orb = &to_io_private(sch)->orb; - - memset(orb, 0, sizeof(union orb)); - orb->tm.intparm = (u32) (addr_t) sch; - orb->tm.key = key >> 4; - orb->tm.b = 1; - orb->tm.lpm = lpm ? lpm : sch->lpm; - orb->tm.tcw = (u32) (addr_t) tcw; - cc = ssch(sch->schid, orb); - switch (cc) { - case 0: - return 0; - case 1: - case 2: - return -EBUSY; - default: - return cio_start_handle_notoper(sch, lpm); - } -} - -/** - * cio_tm_intrg - perform interrogate function - * @sch - subchannel on which to perform the interrogate function - * - * If the specified subchannel is running in transport-mode, perform the - * interrogate function. Return zero on success, non-zero otherwie. - */ -int cio_tm_intrg(struct subchannel *sch) -{ - int cc; - - if (!to_io_private(sch)->orb.tm.b) - return -EINVAL; - cc = xsch(sch->schid); - switch (cc) { - case 0: - case 2: - return 0; - case 1: - return -EBUSY; - default: - return -ENODEV; - } -} diff --git a/trunk/drivers/s390/cio/cio.h b/trunk/drivers/s390/cio/cio.h index 3b236d20e835..6e933aebe013 100644 --- a/trunk/drivers/s390/cio/cio.h +++ b/trunk/drivers/s390/cio/cio.h @@ -3,12 +3,9 @@ #include #include -#include #include -#include -#include -#include #include "chsc.h" +#include "schid.h" /* * path management control word @@ -16,7 +13,7 @@ struct pmcw { u32 intparm; /* interruption parameter */ u32 qf : 1; /* qdio facility */ - u32 w : 1; + u32 res0 : 1; /* reserved zeros */ u32 isc : 3; /* interruption sublass */ u32 res5 : 3; /* reserved zeros */ u32 ena : 1; /* enabled */ @@ -50,7 +47,7 @@ struct pmcw { */ struct schib { struct pmcw pmcw; /* path management control word */ - union scsw scsw; /* subchannel status word */ + struct scsw scsw; /* subchannel status word */ __u64 mba; /* measurement block address */ __u8 mda[4]; /* model dependent area */ } __attribute__ ((packed,aligned(4))); @@ -102,11 +99,8 @@ extern int cio_set_options (struct subchannel *, int); extern int cio_get_options (struct subchannel *); extern int cio_modify (struct subchannel *); -int cio_tm_start_key(struct subchannel *sch, struct tcw *tcw, u8 lpm, u8 key); -int cio_tm_intrg(struct subchannel *sch); - int cio_create_sch_lock(struct subchannel *); -void do_adapter_IO(u8 isc); +void do_adapter_IO(void); void do_IRQ(struct pt_regs *); /* Use with care. */ diff --git a/trunk/drivers/s390/cio/cmf.c b/trunk/drivers/s390/cio/cmf.c index a90b28c0be57..2808b6833b9e 100644 --- a/trunk/drivers/s390/cio/cmf.c +++ b/trunk/drivers/s390/cio/cmf.c @@ -341,12 +341,12 @@ static int cmf_copy_block(struct ccw_device *cdev) if (stsch(sch->schid, &sch->schib)) return -ENODEV; - if (scsw_fctl(&sch->schib.scsw) & SCSW_FCTL_START_FUNC) { + if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) { /* Don't copy if a start function is in progress. */ - if ((!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_SUSPENDED)) && - (scsw_actl(&sch->schib.scsw) & + if ((!(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED)) && + (sch->schib.scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) && - (!(scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_SEC_STATUS))) + (!(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))) return -EBUSY; } cmb_data = cdev->private->cmb; @@ -612,6 +612,9 @@ static int alloc_cmb(struct ccw_device *cdev) free_pages((unsigned long)mem, get_order(size)); } else if (!mem) { /* no luck */ + printk(KERN_WARNING "cio: failed to allocate area " + "for measuring %d subchannels\n", + cmb_area.num_channels); ret = -ENOMEM; goto out; } else { @@ -1227,9 +1230,13 @@ static ssize_t cmb_enable_store(struct device *dev, switch (val) { case 0: ret = disable_cmf(cdev); + if (ret) + dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret); break; case 1: ret = enable_cmf(cdev); + if (ret && ret != -EBUSY) + dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret); break; } @@ -1337,7 +1344,8 @@ static int __init init_cmf(void) * to basic mode. */ if (format == CMF_AUTODETECT) { - if (!css_general_characteristics.ext_mb) { + if (!css_characteristics_avail || + !css_general_characteristics.ext_mb) { format = CMF_BASIC; } else { format = CMF_EXTENDED; @@ -1357,6 +1365,8 @@ static int __init init_cmf(void) cmbops = &cmbops_extended; break; default: + printk(KERN_ERR "cio: Invalid format %d for channel " + "measurement facility\n", format); return 1; } diff --git a/trunk/drivers/s390/cio/css.c b/trunk/drivers/s390/cio/css.c index 46c021d880dc..a76956512b2d 100644 --- a/trunk/drivers/s390/cio/css.c +++ b/trunk/drivers/s390/cio/css.c @@ -2,7 +2,8 @@ * drivers/s390/cio/css.c * driver for channel subsystem * - * Copyright IBM Corp. 2002,2008 + * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) */ @@ -13,9 +14,7 @@ #include #include #include -#include -#include "../s390mach.h" #include "css.h" #include "cio.h" #include "cio_debug.h" @@ -31,6 +30,8 @@ static int max_ssid = 0; struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1]; +int css_characteristics_avail = 0; + int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) { @@ -120,6 +121,25 @@ css_alloc_subchannel(struct subchannel_id schid) kfree(sch); return ERR_PTR(ret); } + + if (sch->st != SUBCHANNEL_TYPE_IO) { + /* For now we ignore all non-io subchannels. */ + kfree(sch); + return ERR_PTR(-EINVAL); + } + + /* + * Set intparm to subchannel address. + * This is fine even on 64bit since the subchannel is always located + * under 2G. + */ + sch->schib.pmcw.intparm = (u32)(addr_t)sch; + ret = cio_modify(sch); + if (ret) { + kfree(sch->lock); + kfree(sch); + return ERR_PTR(ret); + } return sch; } @@ -157,18 +177,12 @@ static int css_sch_device_register(struct subchannel *sch) return ret; } -/** - * css_sch_device_unregister - unregister a subchannel - * @sch: subchannel to be unregistered - */ void css_sch_device_unregister(struct subchannel *sch) { mutex_lock(&sch->reg_mutex); - if (device_is_registered(&sch->dev)) - device_unregister(&sch->dev); + device_unregister(&sch->dev); mutex_unlock(&sch->reg_mutex); } -EXPORT_SYMBOL_GPL(css_sch_device_unregister); static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw) { @@ -215,41 +229,6 @@ void css_update_ssd_info(struct subchannel *sch) } } -static ssize_t type_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct subchannel *sch = to_subchannel(dev); - - return sprintf(buf, "%01x\n", sch->st); -} - -static DEVICE_ATTR(type, 0444, type_show, NULL); - -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct subchannel *sch = to_subchannel(dev); - - return sprintf(buf, "css:t%01X\n", sch->st); -} - -static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); - -static struct attribute *subch_attrs[] = { - &dev_attr_type.attr, - &dev_attr_modalias.attr, - NULL, -}; - -static struct attribute_group subch_attr_group = { - .attrs = subch_attrs, -}; - -static struct attribute_group *default_subch_attr_groups[] = { - &subch_attr_group, - NULL, -}; - static int css_register_subchannel(struct subchannel *sch) { int ret; @@ -258,17 +237,16 @@ static int css_register_subchannel(struct subchannel *sch) sch->dev.parent = &channel_subsystems[0]->device; sch->dev.bus = &css_bus_type; sch->dev.release = &css_subchannel_release; - sch->dev.groups = default_subch_attr_groups; + sch->dev.groups = subch_attr_groups; /* * We don't want to generate uevents for I/O subchannels that don't * have a working ccw device behind them since they will be * unregistered before they can be used anyway, so we delay the add * uevent until after device recognition was successful. - * Note that we suppress the uevent for all subchannel types; - * the subchannel driver can decide itself when it wants to inform - * userspace of its existence. */ - sch->dev.uevent_suppress = 1; + if (!cio_is_console(sch->schid)) + /* Console is special, no need to suppress. */ + sch->dev.uevent_suppress = 1; css_update_ssd_info(sch); /* make it known to the system */ ret = css_sch_device_register(sch); @@ -277,19 +255,10 @@ static int css_register_subchannel(struct subchannel *sch) sch->schid.ssid, sch->schid.sch_no, ret); return ret; } - if (!sch->driver) { - /* - * No driver matched. Generate the uevent now so that - * a fitting driver module may be loaded based on the - * modalias. - */ - sch->dev.uevent_suppress = 0; - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); - } return ret; } -int css_probe_device(struct subchannel_id schid) +static int css_probe_device(struct subchannel_id schid) { int ret; struct subchannel *sch; @@ -332,12 +301,116 @@ int css_sch_is_valid(struct schib *schib) { if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv) return 0; - if ((schib->pmcw.st == SUBCHANNEL_TYPE_MSG) && !schib->pmcw.w) - return 0; return 1; } EXPORT_SYMBOL_GPL(css_sch_is_valid); +static int css_get_subchannel_status(struct subchannel *sch) +{ + struct schib schib; + + if (stsch(sch->schid, &schib)) + return CIO_GONE; + if (!css_sch_is_valid(&schib)) + return CIO_GONE; + if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev)) + return CIO_REVALIDATE; + if (!sch->lpm) + return CIO_NO_PATH; + return CIO_OPER; +} + +static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) +{ + int event, ret, disc; + unsigned long flags; + enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action; + + spin_lock_irqsave(sch->lock, flags); + disc = device_is_disconnected(sch); + if (disc && slow) { + /* Disconnected devices are evaluated directly only.*/ + spin_unlock_irqrestore(sch->lock, flags); + return 0; + } + /* No interrupt after machine check - kill pending timers. */ + device_kill_pending_timer(sch); + if (!disc && !slow) { + /* Non-disconnected devices are evaluated on the slow path. */ + spin_unlock_irqrestore(sch->lock, flags); + return -EAGAIN; + } + event = css_get_subchannel_status(sch); + CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n", + sch->schid.ssid, sch->schid.sch_no, event, + disc ? "disconnected" : "normal", + slow ? "slow" : "fast"); + /* Analyze subchannel status. */ + action = NONE; + switch (event) { + case CIO_NO_PATH: + if (disc) { + /* Check if paths have become available. */ + action = REPROBE; + break; + } + /* fall through */ + case CIO_GONE: + /* Prevent unwanted effects when opening lock. */ + cio_disable_subchannel(sch); + device_set_disconnected(sch); + /* Ask driver what to do with device. */ + action = UNREGISTER; + if (sch->driver && sch->driver->notify) { + spin_unlock_irqrestore(sch->lock, flags); + ret = sch->driver->notify(sch, event); + spin_lock_irqsave(sch->lock, flags); + if (ret) + action = NONE; + } + break; + case CIO_REVALIDATE: + /* Device will be removed, so no notify necessary. */ + if (disc) + /* Reprobe because immediate unregister might block. */ + action = REPROBE; + else + action = UNREGISTER_PROBE; + break; + case CIO_OPER: + if (disc) + /* Get device operational again. */ + action = REPROBE; + break; + } + /* Perform action. */ + ret = 0; + switch (action) { + case UNREGISTER: + case UNREGISTER_PROBE: + /* Unregister device (will use subchannel lock). */ + spin_unlock_irqrestore(sch->lock, flags); + css_sch_device_unregister(sch); + spin_lock_irqsave(sch->lock, flags); + + /* Reset intparm to zeroes. */ + sch->schib.pmcw.intparm = 0; + cio_modify(sch); + break; + case REPROBE: + device_trigger_reprobe(sch); + break; + default: + break; + } + spin_unlock_irqrestore(sch->lock, flags); + /* Probe if necessary. */ + if (action == UNREGISTER_PROBE) + ret = css_probe_device(sch->schid); + + return ret; +} + static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) { struct schib schib; @@ -356,21 +429,6 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) return css_probe_device(schid); } -static int css_evaluate_known_subchannel(struct subchannel *sch, int slow) -{ - int ret = 0; - - if (sch->driver) { - if (sch->driver->sch_event) - ret = sch->driver->sch_event(sch, slow); - else - dev_dbg(&sch->dev, - "Got subchannel machine check but " - "no sch_event handler provided.\n"); - } - return ret; -} - static void css_evaluate_subchannel(struct subchannel_id schid, int slow) { struct subchannel *sch; @@ -538,29 +596,18 @@ EXPORT_SYMBOL_GPL(css_schedule_reprobe); /* * Called from the machine check handler for subchannel report words. */ -static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow) +void css_process_crw(int rsid1, int rsid2) { struct subchannel_id mchk_schid; - if (overflow) { - css_schedule_eval_all(); - return; - } - CIO_CRW_EVENT(2, "CRW0 reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc, - crw0->erc, crw0->rsid); - if (crw1) - CIO_CRW_EVENT(2, "CRW1 reports slct=%d, oflw=%d, " - "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X\n", - crw1->slct, crw1->oflw, crw1->chn, crw1->rsc, - crw1->anc, crw1->erc, crw1->rsid); + CIO_CRW_EVENT(2, "source is subchannel %04X, subsystem id %x\n", + rsid1, rsid2); init_subchannel_id(&mchk_schid); - mchk_schid.sch_no = crw0->rsid; - if (crw1) - mchk_schid.ssid = (crw1->rsid >> 8) & 3; + mchk_schid.sch_no = rsid1; + if (rsid2 != 0) + mchk_schid.ssid = (rsid2 >> 8) & 3; - /* + /* * Since we are always presented with IPI in the CRW, we have to * use stsch() to find out if the subchannel in question has come * or gone. @@ -611,7 +658,7 @@ __init_channel_subsystem(struct subchannel_id schid, void *data) static void __init css_generate_pgid(struct channel_subsystem *css, u32 tod_high) { - if (css_general_characteristics.mcss) { + if (css_characteristics_avail && css_general_characteristics.mcss) { css->global_pgid.pgid_high.ext_cssid.version = 0x80; css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid; } else { @@ -748,6 +795,8 @@ init_channel_subsystem (void) ret = chsc_determine_css_characteristics(); if (ret == -ENOMEM) goto out; /* No need to continue. */ + if (ret == 0) + css_characteristics_avail = 1; ret = chsc_alloc_sei_area(); if (ret) @@ -757,10 +806,6 @@ init_channel_subsystem (void) if (ret) goto out; - ret = s390_register_crw_handler(CRW_RSC_SCH, css_process_crw); - if (ret) - goto out; - if ((ret = bus_register(&css_bus_type))) goto out; @@ -791,7 +836,8 @@ init_channel_subsystem (void) ret = device_register(&css->device); if (ret) goto out_free_all; - if (css_chsc_characteristics.secm) { + if (css_characteristics_avail && + css_chsc_characteristics.secm) { ret = device_create_file(&css->device, &dev_attr_cm_enable); if (ret) @@ -806,8 +852,7 @@ init_channel_subsystem (void) goto out_pseudo; css_init_done = 1; - /* Enable default isc for I/O subchannels. */ - isc_register(IO_SCH_ISC); + ctl_set_bit(6, 28); for_each_subchannel(__init_channel_subsystem, NULL); return 0; @@ -830,7 +875,7 @@ init_channel_subsystem (void) i--; css = channel_subsystems[i]; device_unregister(&css->pseudo_subchannel->dev); - if (css_chsc_characteristics.secm) + if (css_characteristics_avail && css_chsc_characteristics.secm) device_remove_file(&css->device, &dev_attr_cm_enable); device_unregister(&css->device); @@ -838,7 +883,6 @@ init_channel_subsystem (void) out_bus: bus_unregister(&css_bus_type); 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", @@ -851,16 +895,19 @@ int sch_is_pseudo_sch(struct subchannel *sch) return sch == to_css(sch->dev.parent)->pseudo_subchannel; } -static int css_bus_match(struct device *dev, struct device_driver *drv) +/* + * find a driver for a subchannel. They identify by the subchannel + * type with the exception that the console subchannel driver has its own + * subchannel type although the device is an i/o subchannel + */ +static int +css_bus_match (struct device *dev, struct device_driver *drv) { struct subchannel *sch = to_subchannel(dev); struct css_driver *driver = to_cssdriver(drv); - struct css_device_id *id; - for (id = driver->subchannel_type; id->match_flags; id++) { - if (sch->st == id->type) - return 1; - } + if (sch->st == driver->subchannel_type) + return 1; return 0; } @@ -898,25 +945,12 @@ static void css_shutdown(struct device *dev) sch->driver->shutdown(sch); } -static int css_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct subchannel *sch = to_subchannel(dev); - int ret; - - ret = add_uevent_var(env, "ST=%01X", sch->st); - if (ret) - return ret; - ret = add_uevent_var(env, "MODALIAS=css:t%01X", sch->st); - return ret; -} - struct bus_type css_bus_type = { .name = "css", .match = css_bus_match, .probe = css_probe, .remove = css_remove, .shutdown = css_shutdown, - .uevent = css_uevent, }; /** @@ -951,3 +985,4 @@ subsys_initcall(init_channel_subsystem); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(css_bus_type); +EXPORT_SYMBOL_GPL(css_characteristics_avail); diff --git a/trunk/drivers/s390/cio/css.h b/trunk/drivers/s390/cio/css.h index 57ebf120f825..e1913518f354 100644 --- a/trunk/drivers/s390/cio/css.h +++ b/trunk/drivers/s390/cio/css.h @@ -9,7 +9,8 @@ #include #include -#include + +#include "schid.h" /* * path grouping stuff @@ -57,28 +58,20 @@ struct pgid { __u32 tod_high; /* high word TOD clock */ } __attribute__ ((packed)); -struct subchannel; -struct chp_link; -/** - * struct css_driver - device driver for subchannels - * @owner: owning module - * @subchannel_type: subchannel type supported by this driver - * @drv: embedded device driver structure - * @irq: called on interrupts - * @chp_event: called for events affecting a channel path - * @sch_event: called for events affecting the subchannel - * @probe: function called on probe - * @remove: function called on remove - * @shutdown: called at device shutdown - * @name: name of the device driver +/* + * A css driver handles all subchannels of one type. + * Currently, we only care about I/O subchannels (type 0), these + * have a ccw_device connected to them. */ +struct subchannel; struct css_driver { struct module *owner; - struct css_device_id *subchannel_type; + unsigned int subchannel_type; struct device_driver drv; void (*irq)(struct subchannel *); - int (*chp_event)(struct subchannel *, struct chp_link *, int); - int (*sch_event)(struct subchannel *, int); + int (*notify)(struct subchannel *, int); + void (*verify)(struct subchannel *); + void (*termination)(struct subchannel *); int (*probe)(struct subchannel *); int (*remove)(struct subchannel *); void (*shutdown)(struct subchannel *); @@ -96,13 +89,13 @@ extern int css_driver_register(struct css_driver *); extern void css_driver_unregister(struct css_driver *); extern void css_sch_device_unregister(struct subchannel *); -extern int css_probe_device(struct subchannel_id); -extern struct subchannel *get_subchannel_by_schid(struct subchannel_id); +extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *), int (*fn_unknown)(struct subchannel_id, void *), void *data); extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); +extern void css_process_crw(int, int); extern void css_reiterate_subchannels(void); void css_update_ssd_info(struct subchannel *sch); @@ -128,6 +121,20 @@ struct channel_subsystem { extern struct bus_type css_bus_type; extern struct channel_subsystem *channel_subsystems[]; +/* Some helper functions for disconnected state. */ +int device_is_disconnected(struct subchannel *); +void device_set_disconnected(struct subchannel *); +void device_trigger_reprobe(struct subchannel *); + +/* Helper functions for vary on/off. */ +int device_is_online(struct subchannel *); +void device_kill_io(struct subchannel *); +void device_set_intretry(struct subchannel *sch); +int device_trigger_verify(struct subchannel *sch); + +/* Machine check helper function. */ +void device_kill_pending_timer(struct subchannel *); + /* Helper functions to build lists for the slow path. */ void css_schedule_eval(struct subchannel_id schid); void css_schedule_eval_all(void); @@ -138,4 +145,6 @@ int css_sch_is_valid(struct schib *); extern struct workqueue_struct *slow_path_wq; void css_wait_for_slow_path(void); + +extern struct attribute_group *subch_attr_groups[]; #endif diff --git a/trunk/drivers/s390/cio/device.c b/trunk/drivers/s390/cio/device.c index e818d0c54c09..e22813db74a2 100644 --- a/trunk/drivers/s390/cio/device.c +++ b/trunk/drivers/s390/cio/device.c @@ -2,7 +2,8 @@ * drivers/s390/cio/device.c * bus driver for ccw devices * - * Copyright IBM Corp. 2002,2008 + * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Arnd Bergmann (arndb@de.ibm.com) * Cornelia Huck (cornelia.huck@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) @@ -22,9 +23,7 @@ #include #include /* HZ */ #include -#include -#include "chp.h" #include "cio.h" #include "cio_debug.h" #include "css.h" @@ -126,24 +125,19 @@ struct bus_type ccw_bus_type; static void io_subchannel_irq(struct subchannel *); static int io_subchannel_probe(struct subchannel *); static int io_subchannel_remove(struct subchannel *); +static int io_subchannel_notify(struct subchannel *, int); +static void io_subchannel_verify(struct subchannel *); +static void io_subchannel_ioterm(struct subchannel *); static void io_subchannel_shutdown(struct subchannel *); -static int io_subchannel_sch_event(struct subchannel *, int); -static int io_subchannel_chp_event(struct subchannel *, struct chp_link *, - int); - -static struct css_device_id io_subchannel_ids[] = { - { .match_flags = 0x1, .type = SUBCHANNEL_TYPE_IO, }, - { /* end of list */ }, -}; -MODULE_DEVICE_TABLE(css, io_subchannel_ids); static struct css_driver io_subchannel_driver = { .owner = THIS_MODULE, - .subchannel_type = io_subchannel_ids, + .subchannel_type = SUBCHANNEL_TYPE_IO, .name = "io_subchannel", .irq = io_subchannel_irq, - .sch_event = io_subchannel_sch_event, - .chp_event = io_subchannel_chp_event, + .notify = io_subchannel_notify, + .verify = io_subchannel_verify, + .termination = io_subchannel_ioterm, .probe = io_subchannel_probe, .remove = io_subchannel_remove, .shutdown = io_subchannel_shutdown, @@ -493,22 +487,25 @@ static int online_store_recog_and_online(struct ccw_device *cdev) ccw_device_set_online(cdev); return 0; } -static int online_store_handle_online(struct ccw_device *cdev, int force) +static void online_store_handle_online(struct ccw_device *cdev, int force) { int ret; ret = online_store_recog_and_online(cdev); if (ret) - return ret; + return; if (force && cdev->private->state == DEV_STATE_BOXED) { ret = ccw_device_stlck(cdev); - if (ret) - return ret; + if (ret) { + dev_warn(&cdev->dev, + "ccw_device_stlck returned %d!\n", ret); + return; + } if (cdev->id.cu_type == 0) cdev->private->state = DEV_STATE_NOT_OPER; online_store_recog_and_online(cdev); } - return 0; + } static ssize_t online_store (struct device *dev, struct device_attribute *attr, @@ -541,9 +538,8 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, ret = count; break; case 1: - ret = online_store_handle_online(cdev, force); - if (!ret) - ret = count; + online_store_handle_online(cdev, force); + ret = count; break; default: ret = -EINVAL; @@ -588,14 +584,19 @@ static DEVICE_ATTR(modalias, 0444, modalias_show, NULL); static DEVICE_ATTR(online, 0644, online_show, online_store); static DEVICE_ATTR(availability, 0444, available_show, NULL); -static struct attribute *io_subchannel_attrs[] = { +static struct attribute * subch_attrs[] = { &dev_attr_chpids.attr, &dev_attr_pimpampom.attr, NULL, }; -static struct attribute_group io_subchannel_attr_group = { - .attrs = io_subchannel_attrs, +static struct attribute_group subch_attr_group = { + .attrs = subch_attrs, +}; + +struct attribute_group *subch_attr_groups[] = { + &subch_attr_group, + NULL, }; static struct attribute * ccwdev_attrs[] = { @@ -789,7 +790,7 @@ static void sch_attach_device(struct subchannel *sch, sch_set_cdev(sch, cdev); cdev->private->schid = sch->schid; cdev->ccwlock = sch->lock; - ccw_device_trigger_reprobe(cdev); + device_trigger_reprobe(sch); spin_unlock_irq(sch->lock); } @@ -1036,6 +1037,7 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch) struct ccw_device_private *priv; sch_set_cdev(sch, cdev); + sch->driver = &io_subchannel_driver; cdev->ccwlock = sch->lock; /* Init private data. */ @@ -1120,33 +1122,8 @@ static void io_subchannel_irq(struct subchannel *sch) dev_fsm_event(cdev, DEV_EVENT_INTERRUPT); } -static void io_subchannel_init_fields(struct subchannel *sch) -{ - if (cio_is_console(sch->schid)) - sch->opm = 0xff; - else - sch->opm = chp_get_sch_opm(sch); - sch->lpm = sch->schib.pmcw.pam & sch->opm; - sch->isc = cio_is_console(sch->schid) ? CONSOLE_ISC : IO_SCH_ISC; - - CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X" - " - PIM = %02X, PAM = %02X, POM = %02X\n", - 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; -} - -static int io_subchannel_probe(struct subchannel *sch) +static int +io_subchannel_probe (struct subchannel *sch) { struct ccw_device *cdev; int rc; @@ -1155,21 +1132,11 @@ static int io_subchannel_probe(struct subchannel *sch) cdev = sch_get_cdev(sch); if (cdev) { - rc = sysfs_create_group(&sch->dev.kobj, - &io_subchannel_attr_group); - if (rc) - CIO_MSG_EVENT(0, "Failed to create io subchannel " - "attributes for subchannel " - "0.%x.%04x (rc=%d)\n", - sch->schid.ssid, sch->schid.sch_no, rc); /* * This subchannel already has an associated ccw_device. - * Throw the delayed uevent for the subchannel, register - * the ccw_device and exit. This happens for all early - * devices, e.g. the console. + * Register it and exit. This happens for all early + * device, e.g. the console. */ - sch->dev.uevent_suppress = 0; - kobject_uevent(&sch->dev.kobj, KOBJ_ADD); cdev->dev.groups = ccwdev_attr_groups; device_initialize(&cdev->dev); ccw_device_register(cdev); @@ -1185,24 +1152,17 @@ static int io_subchannel_probe(struct subchannel *sch) get_device(&cdev->dev); 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 = sysfs_create_group(&sch->dev.kobj, - &io_subchannel_attr_group); - if (rc) - return rc; /* Allocate I/O subchannel private data. */ sch->private = kzalloc(sizeof(struct io_subchannel_private), GFP_KERNEL | GFP_DMA); - if (!sch->private) { - rc = -ENOMEM; - goto out_err; - } + if (!sch->private) + return -ENOMEM; cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); if (!cdev) cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), @@ -1221,8 +1181,8 @@ static int io_subchannel_probe(struct subchannel *sch) } cdev = io_subchannel_create_ccwdev(sch); if (IS_ERR(cdev)) { - rc = PTR_ERR(cdev); - goto out_err; + kfree(sch->private); + return PTR_ERR(cdev); } rc = io_subchannel_recog(cdev, sch); if (rc) { @@ -1231,12 +1191,9 @@ static int io_subchannel_probe(struct subchannel *sch) spin_unlock_irqrestore(sch->lock, flags); if (cdev->dev.release) cdev->dev.release(&cdev->dev); - goto out_err; + kfree(sch->private); } - return 0; -out_err: - kfree(sch->private); - sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); + return rc; } @@ -1257,7 +1214,6 @@ io_subchannel_remove (struct subchannel *sch) ccw_device_unregister(cdev); put_device(&cdev->dev); kfree(sch->private); - sysfs_remove_group(&sch->dev.kobj, &io_subchannel_attr_group); return 0; } @@ -1268,7 +1224,11 @@ static int io_subchannel_notify(struct subchannel *sch, int event) cdev = sch_get_cdev(sch); if (!cdev) return 0; - return ccw_device_notify(cdev, event); + if (!cdev->drv) + return 0; + if (!cdev->online) + return 0; + return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0; } static void io_subchannel_verify(struct subchannel *sch) @@ -1280,96 +1240,22 @@ static void io_subchannel_verify(struct subchannel *sch) dev_fsm_event(cdev, DEV_EVENT_VERIFY); } -static int check_for_io_on_path(struct subchannel *sch, int mask) +static void io_subchannel_ioterm(struct subchannel *sch) { - int cc; - - cc = stsch(sch->schid, &sch->schib); - if (cc) - return 0; - if (scsw_actl(&sch->schib.scsw) && sch->schib.pmcw.lpum == mask) - return 1; - return 0; -} + struct ccw_device *cdev; -static void terminate_internal_io(struct subchannel *sch, - struct ccw_device *cdev) -{ - if (cio_clear(sch)) { - /* Recheck device in case clear failed. */ - sch->lpm = 0; - if (cdev->online) - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - else - css_schedule_eval(sch->schid); + cdev = sch_get_cdev(sch); + if (!cdev) + return; + /* Internal I/O will be retried by the interrupt handler. */ + if (cdev->private->flags.intretry) return; - } cdev->private->state = DEV_STATE_CLEAR_VERIFY; - /* Request retry of internal operation. */ - cdev->private->flags.intretry = 1; - /* Call handler. */ if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, ERR_PTR(-EIO)); } -static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask) -{ - struct ccw_device *cdev; - - cdev = sch_get_cdev(sch); - if (!cdev) - return; - if (check_for_io_on_path(sch, mask)) { - if (cdev->private->state == DEV_STATE_ONLINE) - ccw_device_kill_io(cdev); - else { - terminate_internal_io(sch, cdev); - /* Re-start path verification. */ - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - } - } else - /* trigger path verification. */ - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - -} - -static int io_subchannel_chp_event(struct subchannel *sch, - struct chp_link *link, int event) -{ - int mask; - - mask = chp_ssd_get_mask(&sch->ssd_info, link); - if (!mask) - return 0; - switch (event) { - case CHP_VARY_OFF: - sch->opm &= ~mask; - sch->lpm &= ~mask; - io_subchannel_terminate_path(sch, mask); - break; - case CHP_VARY_ON: - sch->opm |= mask; - sch->lpm |= mask; - io_subchannel_verify(sch); - break; - case CHP_OFFLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; - if (!css_sch_is_valid(&sch->schib)) - return -ENODEV; - io_subchannel_terminate_path(sch, mask); - break; - case CHP_ONLINE: - if (stsch(sch->schid, &sch->schib)) - return -ENXIO; - sch->lpm |= mask & sch->opm; - io_subchannel_verify(sch); - break; - } - return 0; -} - static void io_subchannel_shutdown(struct subchannel *sch) { @@ -1399,195 +1285,6 @@ io_subchannel_shutdown(struct subchannel *sch) cio_disable_subchannel(sch); } -static int io_subchannel_get_status(struct subchannel *sch) -{ - struct schib schib; - - if (stsch(sch->schid, &schib) || !schib.pmcw.dnv) - return CIO_GONE; - if (sch->schib.pmcw.dnv && (schib.pmcw.dev != sch->schib.pmcw.dev)) - return CIO_REVALIDATE; - if (!sch->lpm) - return CIO_NO_PATH; - return CIO_OPER; -} - -static int device_is_disconnected(struct ccw_device *cdev) -{ - if (!cdev) - return 0; - return (cdev->private->state == DEV_STATE_DISCONNECTED || - cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID); -} - -static int recovery_check(struct device *dev, void *data) -{ - struct ccw_device *cdev = to_ccwdev(dev); - int *redo = data; - - spin_lock_irq(cdev->ccwlock); - switch (cdev->private->state) { - case DEV_STATE_DISCONNECTED: - CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n", - cdev->private->dev_id.ssid, - cdev->private->dev_id.devno); - dev_fsm_event(cdev, DEV_EVENT_VERIFY); - *redo = 1; - break; - case DEV_STATE_DISCONNECTED_SENSE_ID: - *redo = 1; - break; - } - spin_unlock_irq(cdev->ccwlock); - - return 0; -} - -static void recovery_work_func(struct work_struct *unused) -{ - int redo = 0; - - bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check); - if (redo) { - spin_lock_irq(&recovery_lock); - if (!timer_pending(&recovery_timer)) { - if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1) - recovery_phase++; - mod_timer(&recovery_timer, jiffies + - recovery_delay[recovery_phase] * HZ); - } - spin_unlock_irq(&recovery_lock); - } else - CIO_MSG_EVENT(4, "recovery: end\n"); -} - -static DECLARE_WORK(recovery_work, recovery_work_func); - -static void recovery_func(unsigned long data) -{ - /* - * We can't do our recovery in softirq context and it's not - * performance critical, so we schedule it. - */ - schedule_work(&recovery_work); -} - -static void ccw_device_schedule_recovery(void) -{ - unsigned long flags; - - CIO_MSG_EVENT(4, "recovery: schedule\n"); - spin_lock_irqsave(&recovery_lock, flags); - if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { - recovery_phase = 0; - mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ); - } - spin_unlock_irqrestore(&recovery_lock, flags); -} - -static void device_set_disconnected(struct ccw_device *cdev) -{ - if (!cdev) - return; - ccw_device_set_timeout(cdev, 0); - cdev->private->flags.fake_irb = 0; - cdev->private->state = DEV_STATE_DISCONNECTED; - if (cdev->online) - ccw_device_schedule_recovery(); -} - -static int io_subchannel_sch_event(struct subchannel *sch, int slow) -{ - int event, ret, disc; - unsigned long flags; - enum { NONE, UNREGISTER, UNREGISTER_PROBE, REPROBE } action; - struct ccw_device *cdev; - - spin_lock_irqsave(sch->lock, flags); - cdev = sch_get_cdev(sch); - disc = device_is_disconnected(cdev); - if (disc && slow) { - /* Disconnected devices are evaluated directly only.*/ - spin_unlock_irqrestore(sch->lock, flags); - return 0; - } - /* No interrupt after machine check - kill pending timers. */ - if (cdev) - ccw_device_set_timeout(cdev, 0); - if (!disc && !slow) { - /* Non-disconnected devices are evaluated on the slow path. */ - spin_unlock_irqrestore(sch->lock, flags); - return -EAGAIN; - } - event = io_subchannel_get_status(sch); - CIO_MSG_EVENT(4, "Evaluating schid 0.%x.%04x, event %d, %s, %s path.\n", - sch->schid.ssid, sch->schid.sch_no, event, - disc ? "disconnected" : "normal", - slow ? "slow" : "fast"); - /* Analyze subchannel status. */ - action = NONE; - switch (event) { - case CIO_NO_PATH: - if (disc) { - /* Check if paths have become available. */ - action = REPROBE; - break; - } - /* fall through */ - case CIO_GONE: - /* Prevent unwanted effects when opening lock. */ - cio_disable_subchannel(sch); - device_set_disconnected(cdev); - /* Ask driver what to do with device. */ - action = UNREGISTER; - spin_unlock_irqrestore(sch->lock, flags); - ret = io_subchannel_notify(sch, event); - spin_lock_irqsave(sch->lock, flags); - if (ret) - action = NONE; - break; - case CIO_REVALIDATE: - /* Device will be removed, so no notify necessary. */ - if (disc) - /* Reprobe because immediate unregister might block. */ - action = REPROBE; - else - action = UNREGISTER_PROBE; - break; - case CIO_OPER: - if (disc) - /* Get device operational again. */ - action = REPROBE; - break; - } - /* Perform action. */ - ret = 0; - switch (action) { - case UNREGISTER: - case UNREGISTER_PROBE: - /* Unregister device (will use subchannel lock). */ - spin_unlock_irqrestore(sch->lock, flags); - css_sch_device_unregister(sch); - spin_lock_irqsave(sch->lock, flags); - - /* Reset intparm to zeroes. */ - sch->schib.pmcw.intparm = 0; - cio_modify(sch); - break; - case REPROBE: - ccw_device_trigger_reprobe(cdev); - break; - default: - break; - } - spin_unlock_irqrestore(sch->lock, flags); - /* Probe if necessary. */ - if (action == UNREGISTER_PROBE) - ret = css_probe_device(sch->schid); - - return ret; -} - #ifdef CONFIG_CCW_CONSOLE static struct ccw_device console_cdev; static struct ccw_device_private console_private; @@ -1600,16 +1297,14 @@ spinlock_t * cio_get_console_lock(void) return &ccw_console_lock; } -static int ccw_device_console_enable(struct ccw_device *cdev, - struct subchannel *sch) +static int +ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) { int rc; /* Attach subchannel private data. */ sch->private = cio_get_console_priv(); memset(sch->private, 0, sizeof(struct io_subchannel_private)); - io_subchannel_init_fields(sch); - sch->driver = &io_subchannel_driver; /* Initialize the ccw_device structure. */ cdev->dev.parent= &sch->dev; rc = io_subchannel_recog(cdev, sch); @@ -1820,6 +1515,71 @@ ccw_device_get_subchannel_id(struct ccw_device *cdev) return sch->schid; } +static int recovery_check(struct device *dev, void *data) +{ + struct ccw_device *cdev = to_ccwdev(dev); + int *redo = data; + + spin_lock_irq(cdev->ccwlock); + switch (cdev->private->state) { + case DEV_STATE_DISCONNECTED: + CIO_MSG_EVENT(4, "recovery: trigger 0.%x.%04x\n", + cdev->private->dev_id.ssid, + cdev->private->dev_id.devno); + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + *redo = 1; + break; + case DEV_STATE_DISCONNECTED_SENSE_ID: + *redo = 1; + break; + } + spin_unlock_irq(cdev->ccwlock); + + return 0; +} + +static void recovery_work_func(struct work_struct *unused) +{ + int redo = 0; + + bus_for_each_dev(&ccw_bus_type, NULL, &redo, recovery_check); + if (redo) { + spin_lock_irq(&recovery_lock); + if (!timer_pending(&recovery_timer)) { + if (recovery_phase < ARRAY_SIZE(recovery_delay) - 1) + recovery_phase++; + mod_timer(&recovery_timer, jiffies + + recovery_delay[recovery_phase] * HZ); + } + spin_unlock_irq(&recovery_lock); + } else + CIO_MSG_EVENT(4, "recovery: end\n"); +} + +static DECLARE_WORK(recovery_work, recovery_work_func); + +static void recovery_func(unsigned long data) +{ + /* + * We can't do our recovery in softirq context and it's not + * performance critical, so we schedule it. + */ + schedule_work(&recovery_work); +} + +void ccw_device_schedule_recovery(void) +{ + unsigned long flags; + + CIO_MSG_EVENT(4, "recovery: schedule\n"); + spin_lock_irqsave(&recovery_lock, flags); + if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) { + recovery_phase = 0; + mod_timer(&recovery_timer, jiffies + recovery_delay[0] * HZ); + } + spin_unlock_irqrestore(&recovery_lock, flags); +} + MODULE_LICENSE("GPL"); EXPORT_SYMBOL(ccw_device_set_online); EXPORT_SYMBOL(ccw_device_set_offline); diff --git a/trunk/drivers/s390/cio/device.h b/trunk/drivers/s390/cio/device.h index 9800a8335a3f..cb08092be39f 100644 --- a/trunk/drivers/s390/cio/device.h +++ b/trunk/drivers/s390/cio/device.h @@ -88,6 +88,8 @@ int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); +void ccw_device_schedule_recovery(void); + /* Function prototypes for device status and basic sense stuff. */ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *); void ccw_device_accumulate_basic_sense(struct ccw_device *, struct irb *); @@ -116,11 +118,6 @@ int ccw_device_call_handler(struct ccw_device *); int ccw_device_stlck(struct ccw_device *); -/* Helper function for machine check handling. */ -void ccw_device_trigger_reprobe(struct ccw_device *); -void ccw_device_kill_io(struct ccw_device *); -int ccw_device_notify(struct ccw_device *, int); - /* qdio needs this. */ void ccw_device_set_timeout(struct ccw_device *, int); extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); diff --git a/trunk/drivers/s390/cio/device_fsm.c b/trunk/drivers/s390/cio/device_fsm.c index 8b5fe57fb2f3..e268d5a77c12 100644 --- a/trunk/drivers/s390/cio/device_fsm.c +++ b/trunk/drivers/s390/cio/device_fsm.c @@ -2,7 +2,8 @@ * drivers/s390/cio/device_fsm.c * finite state machine for device handling * - * Copyright IBM Corp. 2002,2008 + * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, + * IBM Corporation * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) */ @@ -26,6 +27,65 @@ static int timeout_log_enabled; +int +device_is_online(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return 0; + return (cdev->private->state == DEV_STATE_ONLINE); +} + +int +device_is_disconnected(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return 0; + return (cdev->private->state == DEV_STATE_DISCONNECTED || + cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID); +} + +void +device_set_disconnected(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return; + ccw_device_set_timeout(cdev, 0); + cdev->private->flags.fake_irb = 0; + cdev->private->state = DEV_STATE_DISCONNECTED; + if (cdev->online) + ccw_device_schedule_recovery(); +} + +void device_set_intretry(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return; + cdev->private->flags.intretry = 1; +} + +int device_trigger_verify(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev || !cdev->online) + return -EINVAL; + dev_fsm_event(cdev, DEV_EVENT_VERIFY); + return 0; +} + static int __init ccw_timeout_log_setup(char *unused) { timeout_log_enabled = 1; @@ -39,43 +99,31 @@ static void ccw_timeout_log(struct ccw_device *cdev) struct schib schib; struct subchannel *sch; struct io_subchannel_private *private; - union orb *orb; int cc; sch = to_subchannel(cdev->dev.parent); private = to_io_private(sch); - orb = &private->orb; cc = stsch(sch->schid, &schib); printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " "device information:\n", get_clock()); printk(KERN_WARNING "cio: orb:\n"); print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - orb, sizeof(*orb), 0); + &private->orb, sizeof(private->orb), 0); printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id); printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id); printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); - if (orb->tm.b) { - printk(KERN_WARNING "cio: orb indicates transport mode\n"); - printk(KERN_WARNING "cio: last tcw:\n"); - print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - (void *)(addr_t)orb->tm.tcw, - sizeof(struct tcw), 0); - } else { - printk(KERN_WARNING "cio: orb indicates command mode\n"); - if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw || - (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws) - printk(KERN_WARNING "cio: last channel program " - "(intern):\n"); - else - printk(KERN_WARNING "cio: last channel program:\n"); - - print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, - (void *)(addr_t)orb->cmd.cpa, - sizeof(struct ccw1), 0); - } + if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw || + (void *)(addr_t)private->orb.cpa == cdev->private->iccws) + printk(KERN_WARNING "cio: last channel program (intern):\n"); + else + printk(KERN_WARNING "cio: last channel program:\n"); + + print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, + (void *)(addr_t)private->orb.cpa, + sizeof(struct ccw1), 0); printk(KERN_WARNING "cio: ccw device state: %d\n", cdev->private->state); printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc); @@ -123,6 +171,18 @@ ccw_device_set_timeout(struct ccw_device *cdev, int expires) add_timer(&cdev->private->timer); } +/* Kill any pending timers after machine check. */ +void +device_kill_pending_timer(struct subchannel *sch) +{ + struct ccw_device *cdev; + + cdev = sch_get_cdev(sch); + if (!cdev) + return; + ccw_device_set_timeout(cdev, 0); +} + /* * Cancel running i/o. This is called repeatedly since halt/clear are * asynchronous operations. We do one try with cio_cancel, two tries @@ -145,18 +205,15 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) /* Not operational -> done. */ return 0; /* Stage 1: cancel io. */ - if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_HALT_PEND) && - !(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) { - if (!scsw_is_tm(&sch->schib.scsw)) { - ret = cio_cancel(sch); - if (ret != -EINVAL) - return ret; - } - /* cancel io unsuccessful or not applicable (transport mode). - * Continue with asynchronous instructions. */ + if (!(sch->schib.scsw.actl & SCSW_ACTL_HALT_PEND) && + !(sch->schib.scsw.actl & SCSW_ACTL_CLEAR_PEND)) { + ret = cio_cancel(sch); + if (ret != -EINVAL) + return ret; + /* cancel io unsuccessful. From now on it is asynchronous. */ cdev->private->iretry = 3; /* 3 halt retries. */ } - if (!(scsw_actl(&sch->schib.scsw) & SCSW_ACTL_CLEAR_PEND)) { + if (!(sch->schib.scsw.actl & SCSW_ACTL_CLEAR_PEND)) { /* Stage 2: halt io. */ if (cdev->private->iretry) { cdev->private->iretry--; @@ -331,30 +388,34 @@ ccw_device_sense_id_done(struct ccw_device *cdev, int err) } } -int ccw_device_notify(struct ccw_device *cdev, int event) -{ - if (!cdev->drv) - return 0; - if (!cdev->online) - return 0; - return cdev->drv->notify ? cdev->drv->notify(cdev, event) : 0; -} - static void ccw_device_oper_notify(struct work_struct *work) { struct ccw_device_private *priv; struct ccw_device *cdev; + struct subchannel *sch; int ret; + unsigned long flags; priv = container_of(work, struct ccw_device_private, kick_work); cdev = priv->cdev; - ret = ccw_device_notify(cdev, CIO_OPER); + spin_lock_irqsave(cdev->ccwlock, flags); + sch = to_subchannel(cdev->dev.parent); + if (sch->driver && sch->driver->notify) { + spin_unlock_irqrestore(cdev->ccwlock, flags); + ret = sch->driver->notify(sch, CIO_OPER); + spin_lock_irqsave(cdev->ccwlock, flags); + } else + ret = 0; if (ret) { /* Reenable channel measurements, if needed. */ + spin_unlock_irqrestore(cdev->ccwlock, flags); cmf_reenable(cdev); + spin_lock_irqsave(cdev->ccwlock, flags); wake_up(&cdev->private->wait_q); - } else + } + spin_unlock_irqrestore(cdev->ccwlock, flags); + if (!ret) /* Driver doesn't want device back. */ ccw_device_do_unreg_rereg(work); } @@ -560,11 +621,10 @@ ccw_device_verify_done(struct ccw_device *cdev, int err) /* Deliver fake irb to device driver, if needed. */ if (cdev->private->flags.fake_irb) { memset(&cdev->private->irb, 0, sizeof(struct irb)); - cdev->private->irb.scsw.cmd.cc = 1; - cdev->private->irb.scsw.cmd.fctl = SCSW_FCTL_START_FUNC; - cdev->private->irb.scsw.cmd.actl = SCSW_ACTL_START_PEND; - cdev->private->irb.scsw.cmd.stctl = - SCSW_STCTL_STATUS_PEND; + cdev->private->irb.scsw.cc = 1; + cdev->private->irb.scsw.fctl = SCSW_FCTL_START_FUNC; + cdev->private->irb.scsw.actl = SCSW_ACTL_START_PEND; + cdev->private->irb.scsw.stctl = SCSW_STCTL_STATUS_PEND; cdev->private->flags.fake_irb = 0; if (cdev->handler) cdev->handler(cdev, cdev->private->intparm, @@ -658,10 +718,13 @@ ccw_device_offline(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv) return -ENODEV; - if (scsw_actl(&sch->schib.scsw) != 0) - return -EBUSY; - if (cdev->private->state != DEV_STATE_ONLINE) + if (cdev->private->state != DEV_STATE_ONLINE) { + if (sch->schib.scsw.actl != 0) + return -EBUSY; return -EINVAL; + } + if (sch->schib.scsw.actl != 0) + return -EBUSY; /* Are we doing path grouping? */ if (!cdev->private->options.pgroup) { /* No, set state offline immediately. */ @@ -736,9 +799,9 @@ ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) */ stsch(sch->schid, &sch->schib); - if (scsw_actl(&sch->schib.scsw) != 0 || - (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || - (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { + if (sch->schib.scsw.actl != 0 || + (sch->schib.scsw.stctl & SCSW_STCTL_STATUS_PEND) || + (cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) { /* * No final status yet or final status not yet delivered * to the device driver. Can't do path verfication now, @@ -760,13 +823,13 @@ static void ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) { struct irb *irb; - int is_cmd; irb = (struct irb *) __LC_IRB; - is_cmd = !scsw_is_tm(&irb->scsw); /* Check for unsolicited interrupt. */ - if (!scsw_is_solicited(&irb->scsw)) { - if (is_cmd && (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && + if ((irb->scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) + && (!irb->scsw.cc)) { + if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && !irb->esw.esw0.erw.cons) { /* Unit check but no sense data. Need basic sense. */ if (ccw_device_do_sense(cdev, irb) != 0) @@ -785,7 +848,7 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) } /* Accumulate status and find out if a basic sense is needed. */ ccw_device_accumulate_irb(cdev, irb); - if (is_cmd && cdev->private->flags.dosense) { + if (cdev->private->flags.dosense) { if (ccw_device_do_sense(cdev, irb) == 0) { cdev->private->state = DEV_STATE_W4SENSE; } @@ -829,9 +892,9 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; /* Check for unsolicited interrupt. */ - if (scsw_stctl(&irb->scsw) == - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { - if (scsw_cc(&irb->scsw) == 1) + if (irb->scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { + if (irb->scsw.cc == 1) /* Basic sense hasn't started. Try again. */ ccw_device_do_sense(cdev, irb); else { @@ -849,8 +912,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) * only deliver the halt/clear interrupt to the device driver as if it * had killed the original request. */ - if (scsw_fctl(&irb->scsw) & - (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { /* Retry Basic Sense if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -924,10 +986,12 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) ERR_PTR(-EIO)); } -void ccw_device_kill_io(struct ccw_device *cdev) +void device_kill_io(struct subchannel *sch) { int ret; + struct ccw_device *cdev; + cdev = sch_get_cdev(sch); ret = ccw_device_cancel_halt_clear(cdev); if (ret == -EBUSY) { ccw_device_set_timeout(cdev, 3*HZ); @@ -957,9 +1021,9 @@ ccw_device_stlck_done(struct ccw_device *cdev, enum dev_event dev_event) case DEV_EVENT_INTERRUPT: irb = (struct irb *) __LC_IRB; /* Check for unsolicited interrupt. */ - if ((scsw_stctl(&irb->scsw) == + if ((irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) && - (!scsw_cc(&irb->scsw))) + (!irb->scsw.cc)) /* FIXME: we should restart stlck here, but this * is extremely unlikely ... */ goto out_wakeup; @@ -991,14 +1055,17 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) ccw_device_sense_id_start(cdev); } -void ccw_device_trigger_reprobe(struct ccw_device *cdev) +void +device_trigger_reprobe(struct subchannel *sch) { - struct subchannel *sch; + struct ccw_device *cdev; + cdev = sch_get_cdev(sch); + if (!cdev) + return; if (cdev->private->state != DEV_STATE_DISCONNECTED) return; - sch = to_subchannel(cdev->dev.parent); /* Update some values. */ if (stsch(sch->schid, &sch->schib)) return; @@ -1014,6 +1081,7 @@ void ccw_device_trigger_reprobe(struct ccw_device *cdev) sch->schib.pmcw.ena = 0; if ((sch->lpm & (sch->lpm - 1)) != 0) sch->schib.pmcw.mp = 1; + sch->schib.pmcw.intparm = (u32)(addr_t)sch; /* 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/trunk/drivers/s390/cio/device_id.c b/trunk/drivers/s390/cio/device_id.c index 1bdaa614e34f..cba7020517ed 100644 --- a/trunk/drivers/s390/cio/device_id.c +++ b/trunk/drivers/s390/cio/device_id.c @@ -196,7 +196,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) irb = &cdev->private->irb; /* Check the error cases. */ - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Sense ID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -234,10 +234,10 @@ ccw_device_check_sense_id(struct ccw_device *cdev) irb->ecw[6], irb->ecw[7]); return -EAGAIN; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { u8 lpm; - lpm = to_io_private(sch)->orb.cmd.lpm; + lpm = to_io_private(sch)->orb.lpm; if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x " "on subchannel 0.%x.%04x is " @@ -248,9 +248,9 @@ ccw_device_check_sense_id(struct ccw_device *cdev) } /* Did we get a proper answer ? */ - if (irb->scsw.cmd.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF && + if (irb->scsw.cc == 0 && cdev->private->senseid.cu_type != 0xFFFF && cdev->private->senseid.reserved == 0xFF) { - if (irb->scsw.cmd.count < sizeof(struct senseid) - 8) + if (irb->scsw.count < sizeof(struct senseid) - 8) cdev->private->flags.esid = 1; return 0; /* Success */ } @@ -260,7 +260,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev) "subchannel 0.%x.%04x returns status %02X%02X\n", cdev->private->dev_id.devno, sch->schid.ssid, sch->schid.sch_no, - irb->scsw.cmd.dstat, irb->scsw.cmd.cstat); + irb->scsw.dstat, irb->scsw.cstat); return -EAGAIN; } @@ -277,9 +277,9 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event) sch = to_subchannel(cdev->dev.parent); irb = (struct irb *) __LC_IRB; /* Retry sense id, if needed. */ - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { - if ((irb->scsw.cmd.cc == 1) || !irb->scsw.cmd.actl) { + if ((irb->scsw.cc == 1) || !irb->scsw.actl) { ret = __ccw_device_sense_id_start(cdev); if (ret && ret != -EBUSY) ccw_device_sense_id_done(cdev, ret); diff --git a/trunk/drivers/s390/cio/device_ops.c b/trunk/drivers/s390/cio/device_ops.c index ee1a28310fbb..f308ad55a6d5 100644 --- a/trunk/drivers/s390/cio/device_ops.c +++ b/trunk/drivers/s390/cio/device_ops.c @@ -17,7 +17,6 @@ #include #include #include -#include #include "cio.h" #include "cio_debug.h" @@ -180,8 +179,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, return -EBUSY; } if (cdev->private->state != DEV_STATE_ONLINE || - ((sch->schib.scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) && - !(sch->schib.scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS)) || + ((sch->schib.scsw.stctl & SCSW_STCTL_PRIM_STATUS) && + !(sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS)) || cdev->private->flags.doverify) return -EBUSY; ret = cio_set_options (sch, flags); @@ -380,7 +379,7 @@ int ccw_device_resume(struct ccw_device *cdev) if (cdev->private->state == DEV_STATE_NOT_OPER) return -ENODEV; if (cdev->private->state != DEV_STATE_ONLINE || - !(sch->schib.scsw.cmd.actl & SCSW_ACTL_SUSPENDED)) + !(sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED)) return -EINVAL; return cio_resume(sch); } @@ -405,7 +404,7 @@ ccw_device_call_handler(struct ccw_device *cdev) * - fast notification was requested (primary status) * - unsolicited interrupts */ - stctl = scsw_stctl(&cdev->private->irb.scsw); + stctl = cdev->private->irb.scsw.stctl; ending_status = (stctl & SCSW_STCTL_SEC_STATUS) || (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) || (stctl == SCSW_STCTL_STATUS_PEND); @@ -529,15 +528,14 @@ ccw_device_stlck(struct ccw_device *cdev) cio_disable_subchannel(sch); //FIXME: return code? goto out_unlock; } - cdev->private->irb.scsw.cmd.actl |= SCSW_ACTL_START_PEND; + cdev->private->irb.scsw.actl |= SCSW_ACTL_START_PEND; spin_unlock_irqrestore(sch->lock, flags); - wait_event(cdev->private->wait_q, - cdev->private->irb.scsw.cmd.actl == 0); + wait_event(cdev->private->wait_q, cdev->private->irb.scsw.actl == 0); spin_lock_irqsave(sch->lock, flags); cio_disable_subchannel(sch); //FIXME: return code? - if ((cdev->private->irb.scsw.cmd.dstat != + if ((cdev->private->irb.scsw.dstat != (DEV_STAT_CHN_END|DEV_STAT_DEV_END)) || - (cdev->private->irb.scsw.cmd.cstat != 0)) + (cdev->private->irb.scsw.cstat != 0)) ret = -EIO; /* Clear irb. */ memset(&cdev->private->irb, 0, sizeof(struct irb)); @@ -570,122 +568,6 @@ void ccw_device_get_id(struct ccw_device *cdev, struct ccw_dev_id *dev_id) } EXPORT_SYMBOL(ccw_device_get_id); -/** - * ccw_device_tm_start_key - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * @key: storage key to use for storage access - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key) -{ - struct subchannel *sch; - int rc; - - sch = to_subchannel(cdev->dev.parent); - if (cdev->private->state != DEV_STATE_ONLINE) - return -EIO; - /* Adjust requested path mask to excluded varied off paths. */ - if (lpm) { - lpm &= sch->opm; - if (lpm == 0) - return -EACCES; - } - rc = cio_tm_start_key(sch, tcw, lpm, key); - if (rc == 0) - cdev->private->intparm = intparm; - return rc; -} -EXPORT_SYMBOL(ccw_device_tm_start_key); - -/** - * ccw_device_tm_start_timeout_key - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * @key: storage key to use for storage access - * @expires: time span in jiffies after which to abort request - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key, - int expires) -{ - int ret; - - ccw_device_set_timeout(cdev, expires); - ret = ccw_device_tm_start_key(cdev, tcw, intparm, lpm, key); - if (ret != 0) - ccw_device_set_timeout(cdev, 0); - return ret; -} -EXPORT_SYMBOL(ccw_device_tm_start_timeout_key); - -/** - * ccw_device_tm_start - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm) -{ - return ccw_device_tm_start_key(cdev, tcw, intparm, lpm, - PAGE_DEFAULT_KEY); -} -EXPORT_SYMBOL(ccw_device_tm_start); - -/** - * ccw_device_tm_start_timeout - perform start function - * @cdev: ccw device on which to perform the start function - * @tcw: transport-command word to be started - * @intparm: user defined parameter to be passed to the interrupt handler - * @lpm: mask of paths to use - * @expires: time span in jiffies after which to abort request - * - * Start the tcw on the given ccw device. Return zero on success, non-zero - * otherwise. - */ -int ccw_device_tm_start_timeout(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, int expires) -{ - return ccw_device_tm_start_timeout_key(cdev, tcw, intparm, lpm, - PAGE_DEFAULT_KEY, expires); -} -EXPORT_SYMBOL(ccw_device_tm_start_timeout); - -/** - * ccw_device_tm_intrg - perform interrogate function - * @cdev: ccw device on which to perform the interrogate function - * - * Perform an interrogate function on the given ccw device. Return zero on - * success, non-zero otherwise. - */ -int ccw_device_tm_intrg(struct ccw_device *cdev) -{ - struct subchannel *sch = to_subchannel(cdev->dev.parent); - - if (cdev->private->state != DEV_STATE_ONLINE) - return -EIO; - if (!scsw_is_tm(&sch->schib.scsw) || - !(scsw_actl(&sch->schib.scsw) | SCSW_ACTL_START_PEND)) - return -EINVAL; - return cio_tm_intrg(sch); -} -EXPORT_SYMBOL(ccw_device_tm_intrg); - // FIXME: these have to go: int diff --git a/trunk/drivers/s390/cio/device_pgid.c b/trunk/drivers/s390/cio/device_pgid.c index 86bc94eb607f..5cf7be008e98 100644 --- a/trunk/drivers/s390/cio/device_pgid.c +++ b/trunk/drivers/s390/cio/device_pgid.c @@ -28,13 +28,13 @@ * Helper function called from interrupt context to decide whether an * operation should be tried again. */ -static int __ccw_device_should_retry(union scsw *scsw) +static int __ccw_device_should_retry(struct scsw *scsw) { /* CC is only valid if start function bit is set. */ - if ((scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && scsw->cmd.cc == 1) + if ((scsw->fctl & SCSW_FCTL_START_FUNC) && scsw->cc == 1) return 1; /* No more activity. For sense and set PGID we stubbornly try again. */ - if (!scsw->cmd.actl) + if (!scsw->actl) return 1; return 0; } @@ -125,7 +125,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Sense PGID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -155,10 +155,10 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) irb->ecw[6], irb->ecw[7]); return -EAGAIN; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { u8 lpm; - lpm = to_io_private(sch)->orb.cmd.lpm; + lpm = to_io_private(sch)->orb.lpm; CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, @@ -188,7 +188,7 @@ ccw_device_sense_pgid_irq(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (__ccw_device_should_retry(&irb->scsw)) { ret = __ccw_device_sense_pgid_start(cdev); @@ -331,7 +331,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry Set PGID if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -355,7 +355,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev) irb->ecw[6], irb->ecw[7]); return -EAGAIN; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, @@ -376,7 +376,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) sch = to_subchannel(cdev->dev.parent); irb = &cdev->private->irb; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { /* Retry NOP if requested. */ if (cdev->private->flags.intretry) { cdev->private->flags.intretry = 0; @@ -384,7 +384,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev) } return -ETIME; } - if (irb->scsw.cmd.cc == 3) { + if (irb->scsw.cc == 3) { CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x," " lpm %02X, became 'not operational'\n", cdev->private->dev_id.devno, sch->schid.ssid, @@ -438,7 +438,7 @@ ccw_device_verify_irq(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (__ccw_device_should_retry(&irb->scsw)) __ccw_device_verify_start(cdev); @@ -544,7 +544,7 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event) irb = (struct irb *) __LC_IRB; - if (irb->scsw.cmd.stctl == + if (irb->scsw.stctl == (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { if (__ccw_device_should_retry(&irb->scsw)) __ccw_device_disband_start(cdev); diff --git a/trunk/drivers/s390/cio/device_status.c b/trunk/drivers/s390/cio/device_status.c index 1b03c5423be2..4a38993000f2 100644 --- a/trunk/drivers/s390/cio/device_status.c +++ b/trunk/drivers/s390/cio/device_status.c @@ -29,11 +29,9 @@ static void ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) { - char dbf_text[15]; - - if (!scsw_is_valid_cstat(&irb->scsw) || - !(scsw_cstat(&irb->scsw) & (SCHN_STAT_CHN_DATA_CHK | - SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK))) + if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK | + SCHN_STAT_CHN_CTRL_CHK | + SCHN_STAT_INTF_CTRL_CHK))) return; CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check " "received" @@ -41,10 +39,15 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) ": %02X sch_stat : %02X\n", cdev->private->dev_id.devno, cdev->private->schid.ssid, cdev->private->schid.sch_no, - scsw_dstat(&irb->scsw), scsw_cstat(&irb->scsw)); - sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no); - CIO_TRACE_EVENT(0, dbf_text); - CIO_HEX_EVENT(0, irb, sizeof(struct irb)); + irb->scsw.dstat, irb->scsw.cstat); + + if (irb->scsw.cc != 3) { + char dbf_text[15]; + + sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no); + CIO_TRACE_EVENT(0, dbf_text); + CIO_HEX_EVENT(0, irb, sizeof (struct irb)); + } } /* @@ -78,12 +81,12 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) * are condition that have to be met for the extended control * bit to have meaning. Sick. */ - cdev->private->irb.scsw.cmd.ectl = 0; - if ((irb->scsw.cmd.stctl & SCSW_STCTL_ALERT_STATUS) && - !(irb->scsw.cmd.stctl & SCSW_STCTL_INTER_STATUS)) - cdev->private->irb.scsw.cmd.ectl = irb->scsw.cmd.ectl; + cdev->private->irb.scsw.ectl = 0; + if ((irb->scsw.stctl & SCSW_STCTL_ALERT_STATUS) && + !(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS)) + cdev->private->irb.scsw.ectl = irb->scsw.ectl; /* Check if extended control word is valid. */ - if (!cdev->private->irb.scsw.cmd.ectl) + if (!cdev->private->irb.scsw.ectl) return; /* Copy concurrent sense / model dependent information. */ memcpy (&cdev->private->irb.ecw, irb->ecw, sizeof (irb->ecw)); @@ -95,12 +98,11 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) static int ccw_device_accumulate_esw_valid(struct irb *irb) { - if (!irb->scsw.cmd.eswf && - (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND)) + if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) return 0; - if (irb->scsw.cmd.stctl == - (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) && - !(irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED)) + if (irb->scsw.stctl == + (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND) && + !(irb->scsw.actl & SCSW_ACTL_SUSPENDED)) return 0; return 1; } @@ -123,7 +125,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) cdev_irb->esw.esw1.lpum = irb->esw.esw1.lpum; /* Copy subchannel logout information if esw is of format 0. */ - if (irb->scsw.cmd.eswf) { + if (irb->scsw.eswf) { cdev_sublog = &cdev_irb->esw.esw0.sublog; sublog = &irb->esw.esw0.sublog; /* Copy extended status flags. */ @@ -132,7 +134,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) * Copy fields that have a meaning for channel data check * channel control check and interface control check. */ - if (irb->scsw.cmd.cstat & (SCHN_STAT_CHN_DATA_CHK | + if (irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK)) { /* Copy ancillary report bit. */ @@ -153,7 +155,7 @@ ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) /* Copy i/o-error alert. */ cdev_sublog->ioerr = sublog->ioerr; /* Copy channel path timeout bit. */ - if (irb->scsw.cmd.cstat & SCHN_STAT_INTF_CTRL_CHK) + if (irb->scsw.cstat & SCHN_STAT_INTF_CTRL_CHK) cdev_irb->esw.esw0.erw.cpt = irb->esw.esw0.erw.cpt; /* Copy failing storage address validity flag. */ cdev_irb->esw.esw0.erw.fsavf = irb->esw.esw0.erw.fsavf; @@ -198,24 +200,24 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * If not, the remaining bit have no meaning and we must ignore them. * The esw is not meaningful as well... */ - if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) + if (!(irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) return; /* Check for channel checks and interface control checks. */ ccw_device_msg_control_check(cdev, irb); /* Check for path not operational. */ - if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw)) + if (irb->scsw.pno && irb->scsw.fctl != 0 && + (!(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS) || + (irb->scsw.actl & SCSW_ACTL_SUSPENDED))) ccw_device_path_notoper(cdev); - /* No irb accumulation for transport mode irbs. */ - if (scsw_is_tm(&irb->scsw)) { - memcpy(&cdev->private->irb, irb, sizeof(struct irb)); - return; - } + /* * Don't accumulate unsolicited interrupts. */ - if (!scsw_is_solicited(&irb->scsw)) + if ((irb->scsw.stctl == + (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) && + (!irb->scsw.cc)) return; cdev_irb = &cdev->private->irb; @@ -225,63 +227,62 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * status at the subchannel has been cleared and we must not pass * intermediate accumulated status to the device driver. */ - if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) + if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) memset(&cdev->private->irb, 0, sizeof(struct irb)); /* Copy bits which are valid only for the start function. */ - if (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC) { + if (irb->scsw.fctl & SCSW_FCTL_START_FUNC) { /* Copy key. */ - cdev_irb->scsw.cmd.key = irb->scsw.cmd.key; + cdev_irb->scsw.key = irb->scsw.key; /* Copy suspend control bit. */ - cdev_irb->scsw.cmd.sctl = irb->scsw.cmd.sctl; + cdev_irb->scsw.sctl = irb->scsw.sctl; /* Accumulate deferred condition code. */ - cdev_irb->scsw.cmd.cc |= irb->scsw.cmd.cc; + cdev_irb->scsw.cc |= irb->scsw.cc; /* Copy ccw format bit. */ - cdev_irb->scsw.cmd.fmt = irb->scsw.cmd.fmt; + cdev_irb->scsw.fmt = irb->scsw.fmt; /* Copy prefetch bit. */ - cdev_irb->scsw.cmd.pfch = irb->scsw.cmd.pfch; + cdev_irb->scsw.pfch = irb->scsw.pfch; /* Copy initial-status-interruption-control. */ - cdev_irb->scsw.cmd.isic = irb->scsw.cmd.isic; + cdev_irb->scsw.isic = irb->scsw.isic; /* Copy address limit checking control. */ - cdev_irb->scsw.cmd.alcc = irb->scsw.cmd.alcc; + cdev_irb->scsw.alcc = irb->scsw.alcc; /* Copy suppress suspend bit. */ - cdev_irb->scsw.cmd.ssi = irb->scsw.cmd.ssi; + cdev_irb->scsw.ssi = irb->scsw.ssi; } /* Take care of the extended control bit and extended control word. */ ccw_device_accumulate_ecw(cdev, irb); /* Accumulate function control. */ - cdev_irb->scsw.cmd.fctl |= irb->scsw.cmd.fctl; + cdev_irb->scsw.fctl |= irb->scsw.fctl; /* Copy activity control. */ - cdev_irb->scsw.cmd.actl = irb->scsw.cmd.actl; + cdev_irb->scsw.actl= irb->scsw.actl; /* Accumulate status control. */ - cdev_irb->scsw.cmd.stctl |= irb->scsw.cmd.stctl; + cdev_irb->scsw.stctl |= irb->scsw.stctl; /* * Copy ccw address if it is valid. This is a bit simplified * but should be close enough for all practical purposes. */ - if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) || - ((irb->scsw.cmd.stctl == + if ((irb->scsw.stctl & SCSW_STCTL_PRIM_STATUS) || + ((irb->scsw.stctl == (SCSW_STCTL_INTER_STATUS|SCSW_STCTL_STATUS_PEND)) && - (irb->scsw.cmd.actl & SCSW_ACTL_DEVACT) && - (irb->scsw.cmd.actl & SCSW_ACTL_SCHACT)) || - (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED)) - cdev_irb->scsw.cmd.cpa = irb->scsw.cmd.cpa; + (irb->scsw.actl & SCSW_ACTL_DEVACT) && + (irb->scsw.actl & SCSW_ACTL_SCHACT)) || + (irb->scsw.actl & SCSW_ACTL_SUSPENDED)) + cdev_irb->scsw.cpa = irb->scsw.cpa; /* Accumulate device status, but not the device busy flag. */ - cdev_irb->scsw.cmd.dstat &= ~DEV_STAT_BUSY; + cdev_irb->scsw.dstat &= ~DEV_STAT_BUSY; /* dstat is not always valid. */ - if (irb->scsw.cmd.stctl & + if (irb->scsw.stctl & (SCSW_STCTL_PRIM_STATUS | SCSW_STCTL_SEC_STATUS | SCSW_STCTL_INTER_STATUS | SCSW_STCTL_ALERT_STATUS)) - cdev_irb->scsw.cmd.dstat |= irb->scsw.cmd.dstat; + cdev_irb->scsw.dstat |= irb->scsw.dstat; /* Accumulate subchannel status. */ - cdev_irb->scsw.cmd.cstat |= irb->scsw.cmd.cstat; + cdev_irb->scsw.cstat |= irb->scsw.cstat; /* Copy residual count if it is valid. */ - if ((irb->scsw.cmd.stctl & SCSW_STCTL_PRIM_STATUS) && - (irb->scsw.cmd.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN)) - == 0) - cdev_irb->scsw.cmd.count = irb->scsw.cmd.count; + if ((irb->scsw.stctl & SCSW_STCTL_PRIM_STATUS) && + (irb->scsw.cstat & ~(SCHN_STAT_PCI | SCHN_STAT_INCORR_LEN)) == 0) + cdev_irb->scsw.count = irb->scsw.count; /* Take care of bits in the extended status word. */ ccw_device_accumulate_esw(cdev, irb); @@ -298,7 +299,7 @@ ccw_device_accumulate_irb(struct ccw_device *cdev, struct irb *irb) * sense facility available/supported when enabling the * concurrent sense facility. */ - if ((cdev_irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && + if ((cdev_irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && !(cdev_irb->esw.esw0.erw.cons)) cdev->private->flags.dosense = 1; } @@ -316,7 +317,7 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) sch = to_subchannel(cdev->dev.parent); /* A sense is required, can we do it now ? */ - if (scsw_actl(&irb->scsw) & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) + if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) /* * we received an Unit Check but we have no final * status yet, therefore we must delay the SENSE @@ -354,18 +355,20 @@ ccw_device_accumulate_basic_sense(struct ccw_device *cdev, struct irb *irb) * If not, the remaining bit have no meaning and we must ignore them. * The esw is not meaningful as well... */ - if (!(scsw_stctl(&irb->scsw) & SCSW_STCTL_STATUS_PEND)) + if (!(irb->scsw.stctl & SCSW_STCTL_STATUS_PEND)) return; /* Check for channel checks and interface control checks. */ ccw_device_msg_control_check(cdev, irb); /* Check for path not operational. */ - if (scsw_is_valid_pno(&irb->scsw) && scsw_pno(&irb->scsw)) + if (irb->scsw.pno && irb->scsw.fctl != 0 && + (!(irb->scsw.stctl & SCSW_STCTL_INTER_STATUS) || + (irb->scsw.actl & SCSW_ACTL_SUSPENDED))) ccw_device_path_notoper(cdev); - if (!(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && - (irb->scsw.cmd.dstat & DEV_STAT_CHN_END)) { + if (!(irb->scsw.dstat & DEV_STAT_UNIT_CHECK) && + (irb->scsw.dstat & DEV_STAT_CHN_END)) { cdev->private->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; } @@ -383,11 +386,11 @@ int ccw_device_accumulate_and_sense(struct ccw_device *cdev, struct irb *irb) { ccw_device_accumulate_irb(cdev, irb); - if ((irb->scsw.cmd.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) + if ((irb->scsw.actl & (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) != 0) return -EBUSY; /* Check for basic sense. */ if (cdev->private->flags.dosense && - !(irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) { + !(irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) { cdev->private->irb.esw.esw0.erw.cons = 1; cdev->private->flags.dosense = 0; return 0; diff --git a/trunk/drivers/s390/cio/fcx.c b/trunk/drivers/s390/cio/fcx.c deleted file mode 100644 index 61677dfbdc9b..000000000000 --- a/trunk/drivers/s390/cio/fcx.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Functions for assembling fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include -#include -#include -#include -#include "cio.h" - -/** - * tcw_get_intrg - return pointer to associated interrogate tcw - * @tcw: pointer to the original tcw - * - * Return a pointer to the interrogate tcw associated with the specified tcw - * or %NULL if there is no associated interrogate tcw. - */ -struct tcw *tcw_get_intrg(struct tcw *tcw) -{ - return (struct tcw *) ((addr_t) tcw->intrg); -} -EXPORT_SYMBOL(tcw_get_intrg); - -/** - * tcw_get_data - return pointer to input/output data associated with tcw - * @tcw: pointer to the tcw - * - * Return the input or output data address specified in the tcw depending - * on whether the r-bit or the w-bit is set. If neither bit is set, return - * %NULL. - */ -void *tcw_get_data(struct tcw *tcw) -{ - if (tcw->r) - return (void *) ((addr_t) tcw->input); - if (tcw->w) - return (void *) ((addr_t) tcw->output); - return NULL; -} -EXPORT_SYMBOL(tcw_get_data); - -/** - * tcw_get_tccb - return pointer to tccb associated with tcw - * @tcw: pointer to the tcw - * - * Return pointer to the tccb associated with this tcw. - */ -struct tccb *tcw_get_tccb(struct tcw *tcw) -{ - return (struct tccb *) ((addr_t) tcw->tccb); -} -EXPORT_SYMBOL(tcw_get_tccb); - -/** - * tcw_get_tsb - return pointer to tsb associated with tcw - * @tcw: pointer to the tcw - * - * Return pointer to the tsb associated with this tcw. - */ -struct tsb *tcw_get_tsb(struct tcw *tcw) -{ - return (struct tsb *) ((addr_t) tcw->tsb); -} -EXPORT_SYMBOL(tcw_get_tsb); - -/** - * tcw_init - initialize tcw data structure - * @tcw: pointer to the tcw to be initialized - * @r: initial value of the r-bit - * @w: initial value of the w-bit - * - * Initialize all fields of the specified tcw data structure with zero and - * fill in the format, flags, r and w fields. - */ -void tcw_init(struct tcw *tcw, int r, int w) -{ - memset(tcw, 0, sizeof(struct tcw)); - tcw->format = TCW_FORMAT_DEFAULT; - tcw->flags = TCW_FLAGS_TIDAW_FORMAT(TCW_TIDAW_FORMAT_DEFAULT); - if (r) - tcw->r = 1; - if (w) - tcw->w = 1; -} -EXPORT_SYMBOL(tcw_init); - -static inline size_t tca_size(struct tccb *tccb) -{ - return tccb->tcah.tcal - 12; -} - -static u32 calc_dcw_count(struct tccb *tccb) -{ - int offset; - struct dcw *dcw; - u32 count = 0; - size_t size; - - size = tca_size(tccb); - for (offset = 0; offset < size;) { - dcw = (struct dcw *) &tccb->tca[offset]; - count += dcw->count; - if (!(dcw->flags & DCW_FLAGS_CC)) - break; - offset += sizeof(struct dcw) + ALIGN((int) dcw->cd_count, 4); - } - return count; -} - -static u32 calc_cbc_size(struct tidaw *tidaw, int num) -{ - int i; - u32 cbc_data; - u32 cbc_count = 0; - u64 data_count = 0; - - for (i = 0; i < num; i++) { - if (tidaw[i].flags & TIDAW_FLAGS_LAST) - break; - /* TODO: find out if padding applies to total of data - * transferred or data transferred by this tidaw. Assumption: - * applies to total. */ - data_count += tidaw[i].count; - if (tidaw[i].flags & TIDAW_FLAGS_INSERT_CBC) { - cbc_data = 4 + ALIGN(data_count, 4) - data_count; - cbc_count += cbc_data; - data_count += cbc_data; - } - } - return cbc_count; -} - -/** - * tcw_finalize - finalize tcw length fields and tidaw list - * @tcw: pointer to the tcw - * @num_tidaws: the number of tidaws used to address input/output data or zero - * if no tida is used - * - * Calculate the input-/output-count and tccbl field in the tcw, add a - * tcat the tccb and terminate the data tidaw list if used. - * - * Note: in case input- or output-tida is used, the tidaw-list must be stored - * in contiguous storage (no ttic). The tcal field in the tccb must be - * up-to-date. - */ -void tcw_finalize(struct tcw *tcw, int num_tidaws) -{ - struct tidaw *tidaw; - struct tccb *tccb; - struct tccb_tcat *tcat; - u32 count; - - /* Terminate tidaw list. */ - tidaw = tcw_get_data(tcw); - if (num_tidaws > 0) - tidaw[num_tidaws - 1].flags |= TIDAW_FLAGS_LAST; - /* Add tcat to tccb. */ - tccb = tcw_get_tccb(tcw); - tcat = (struct tccb_tcat *) &tccb->tca[tca_size(tccb)]; - memset(tcat, 0, sizeof(tcat)); - /* Calculate tcw input/output count and tcat transport count. */ - count = calc_dcw_count(tccb); - if (tcw->w && (tcw->flags & TCW_FLAGS_OUTPUT_TIDA)) - count += calc_cbc_size(tidaw, num_tidaws); - if (tcw->r) - tcw->input_count = count; - else if (tcw->w) - tcw->output_count = count; - tcat->count = ALIGN(count, 4) + 4; - /* Calculate tccbl. */ - tcw->tccbl = (sizeof(struct tccb) + tca_size(tccb) + - sizeof(struct tccb_tcat) - 20) >> 2; -} -EXPORT_SYMBOL(tcw_finalize); - -/** - * tcw_set_intrg - set the interrogate tcw address of a tcw - * @tcw: the tcw address - * @intrg_tcw: the address of the interrogate tcw - * - * Set the address of the interrogate tcw in the specified tcw. - */ -void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw) -{ - tcw->intrg = (u32) ((addr_t) intrg_tcw); -} -EXPORT_SYMBOL(tcw_set_intrg); - -/** - * tcw_set_data - set data address and tida flag of a tcw - * @tcw: the tcw address - * @data: the data address - * @use_tidal: zero of the data address specifies a contiguous block of data, - * non-zero if it specifies a list if tidaws. - * - * Set the input/output data address of a tcw (depending on the value of the - * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag - * is set as well. - */ -void tcw_set_data(struct tcw *tcw, void *data, int use_tidal) -{ - if (tcw->r) { - tcw->input = (u64) ((addr_t) data); - if (use_tidal) - tcw->flags |= TCW_FLAGS_INPUT_TIDA; - } else if (tcw->w) { - tcw->output = (u64) ((addr_t) data); - if (use_tidal) - tcw->flags |= TCW_FLAGS_OUTPUT_TIDA; - } -} -EXPORT_SYMBOL(tcw_set_data); - -/** - * tcw_set_tccb - set tccb address of a tcw - * @tcw: the tcw address - * @tccb: the tccb address - * - * Set the address of the tccb in the specified tcw. - */ -void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb) -{ - tcw->tccb = (u64) ((addr_t) tccb); -} -EXPORT_SYMBOL(tcw_set_tccb); - -/** - * tcw_set_tsb - set tsb address of a tcw - * @tcw: the tcw address - * @tsb: the tsb address - * - * Set the address of the tsb in the specified tcw. - */ -void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb) -{ - tcw->tsb = (u64) ((addr_t) tsb); -} -EXPORT_SYMBOL(tcw_set_tsb); - -/** - * tccb_init - initialize tccb - * @tccb: the tccb address - * @size: the maximum size of the tccb - * @sac: the service-action-code to be user - * - * Initialize the header of the specified tccb by resetting all values to zero - * and filling in defaults for format, sac and initial tcal fields. - */ -void tccb_init(struct tccb *tccb, size_t size, u32 sac) -{ - memset(tccb, 0, size); - tccb->tcah.format = TCCB_FORMAT_DEFAULT; - tccb->tcah.sac = sac; - tccb->tcah.tcal = 12; -} -EXPORT_SYMBOL(tccb_init); - -/** - * tsb_init - initialize tsb - * @tsb: the tsb address - * - * Initialize the specified tsb by resetting all values to zero. - */ -void tsb_init(struct tsb *tsb) -{ - memset(tsb, 0, sizeof(tsb)); -} -EXPORT_SYMBOL(tsb_init); - -/** - * tccb_add_dcw - add a dcw to the tccb - * @tccb: the tccb address - * @tccb_size: the maximum tccb size - * @cmd: the dcw command - * @flags: flags for the dcw - * @cd: pointer to control data for this dcw or NULL if none is required - * @cd_count: number of control data bytes for this dcw - * @count: number of data bytes for this dcw - * - * Add a new dcw to the specified tccb by writing the dcw information specified - * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return - * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw - * would exceed the available space as defined by @tccb_size. - * - * Note: the tcal field of the tccb header will be updates to reflect added - * content. - */ -struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags, - void *cd, u8 cd_count, u32 count) -{ - struct dcw *dcw; - int size; - int tca_offset; - - /* Check for space. */ - tca_offset = tca_size(tccb); - size = ALIGN(sizeof(struct dcw) + cd_count, 4); - if (sizeof(struct tccb_tcah) + tca_offset + size + - sizeof(struct tccb_tcat) > tccb_size) - return ERR_PTR(-ENOSPC); - /* Add dcw to tca. */ - dcw = (struct dcw *) &tccb->tca[tca_offset]; - memset(dcw, 0, size); - dcw->cmd = cmd; - dcw->flags = flags; - dcw->count = count; - dcw->cd_count = cd_count; - if (cd) - memcpy(&dcw->cd[0], cd, cd_count); - tccb->tcah.tcal += size; - return dcw; -} -EXPORT_SYMBOL(tccb_add_dcw); - -/** - * tcw_add_tidaw - add a tidaw to a tcw - * @tcw: the tcw address - * @num_tidaws: the current number of tidaws - * @flags: flags for the new tidaw - * @addr: address value for the new tidaw - * @count: count value for the new tidaw - * - * Add a new tidaw to the input/output data tidaw-list of the specified tcw - * (depending on the value of the r-flag and w-flag) and return a pointer to - * the new tidaw. - * - * Note: the tidaw-list is assumed to be contiguous with no ttics. The caller - * must ensure that there is enough space for the new tidaw. The last-tidaw - * flag for the last tidaw in the list will be set by tcw_finalize. - */ -struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags, - void *addr, u32 count) -{ - struct tidaw *tidaw; - - /* Add tidaw to tidaw-list. */ - tidaw = ((struct tidaw *) tcw_get_data(tcw)) + num_tidaws; - memset(tidaw, 0, sizeof(struct tidaw)); - tidaw->flags = flags; - tidaw->count = count; - tidaw->addr = (u64) ((addr_t) addr); - return tidaw; -} -EXPORT_SYMBOL(tcw_add_tidaw); diff --git a/trunk/drivers/s390/cio/idset.h b/trunk/drivers/s390/cio/idset.h index 528065cb5021..144466ab8c15 100644 --- a/trunk/drivers/s390/cio/idset.h +++ b/trunk/drivers/s390/cio/idset.h @@ -8,7 +8,7 @@ #ifndef S390_IDSET_H #define S390_IDSET_H S390_IDSET_H -#include +#include "schid.h" struct idset; diff --git a/trunk/drivers/s390/cio/io_sch.h b/trunk/drivers/s390/cio/io_sch.h index 3f8f1cf69c76..8c613160bfce 100644 --- a/trunk/drivers/s390/cio/io_sch.h +++ b/trunk/drivers/s390/cio/io_sch.h @@ -1,12 +1,12 @@ #ifndef S390_IO_SCH_H #define S390_IO_SCH_H -#include +#include "schid.h" /* - * command-mode operation request block + * operation request block */ -struct cmd_orb { +struct orb { u32 intparm; /* interruption parameter */ u32 key : 4; /* flags, like key, suspend control, etc. */ u32 spnd : 1; /* suspend control */ @@ -28,36 +28,8 @@ struct cmd_orb { u32 cpa; /* channel program address */ } __attribute__ ((packed, aligned(4))); -/* - * transport-mode operation request block - */ -struct tm_orb { - u32 intparm; - u32 key:4; - u32 :9; - u32 b:1; - u32 :2; - u32 lpm:8; - u32 :7; - u32 x:1; - u32 tcw; - u32 prio:8; - u32 :8; - u32 rsvpgm:8; - u32 :8; - u32 :32; - u32 :32; - u32 :32; - u32 :32; -} __attribute__ ((packed, aligned(4))); - -union orb { - struct cmd_orb cmd; - struct tm_orb tm; -} __attribute__ ((packed, aligned(4))); - struct io_subchannel_private { - union orb orb; /* operation request block */ + struct orb orb; /* operation request block */ struct ccw1 sense_ccw; /* static ccw for sense command */ } __attribute__ ((aligned(8))); @@ -123,18 +95,16 @@ struct ccw_device_private { void *cmb_wait; /* deferred cmb enable/disable */ }; -static inline int ssch(struct subchannel_id schid, volatile union orb *addr) +static inline int ssch(struct subchannel_id schid, volatile struct orb *addr) { register struct subchannel_id reg1 asm("1") = schid; - int ccode = -EIO; + int ccode; asm volatile( " ssch 0(%2)\n" - "0: ipm %0\n" - " srl %0,28\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); + " ipm %0\n" + " srl %0,28" + : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); return ccode; } diff --git a/trunk/drivers/s390/cio/ioasm.h b/trunk/drivers/s390/cio/ioasm.h index 9fa2ac13ac85..652ea3625f9d 100644 --- a/trunk/drivers/s390/cio/ioasm.h +++ b/trunk/drivers/s390/cio/ioasm.h @@ -2,7 +2,7 @@ #define S390_CIO_IOASM_H #include -#include +#include "schid.h" /* * TPI info structure diff --git a/trunk/drivers/s390/cio/isc.c b/trunk/drivers/s390/cio/isc.c deleted file mode 100644 index c592087be0f1..000000000000 --- a/trunk/drivers/s390/cio/isc.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Functions for registration of I/O interruption subclasses on s390. - * - * Copyright IBM Corp. 2008 - * Authors: Sebastian Ott - */ - -#include -#include -#include - -static unsigned int isc_refs[MAX_ISC + 1]; -static DEFINE_SPINLOCK(isc_ref_lock); - - -/** - * isc_register - register an I/O interruption subclass. - * @isc: I/O interruption subclass to register - * - * The number of users for @isc is increased. If this is the first user to - * register @isc, the corresponding I/O interruption subclass mask is enabled. - * - * Context: - * This function must not be called in interrupt context. - */ -void isc_register(unsigned int isc) -{ - if (isc > MAX_ISC) { - WARN_ON(1); - return; - } - - spin_lock(&isc_ref_lock); - if (isc_refs[isc] == 0) - ctl_set_bit(6, 31 - isc); - isc_refs[isc]++; - spin_unlock(&isc_ref_lock); -} -EXPORT_SYMBOL_GPL(isc_register); - -/** - * isc_unregister - unregister an I/O interruption subclass. - * @isc: I/O interruption subclass to unregister - * - * The number of users for @isc is decreased. If this is the last user to - * unregister @isc, the corresponding I/O interruption subclass mask is - * disabled. - * Note: This function must not be called if isc_register() hasn't been called - * before by the driver for @isc. - * - * Context: - * This function must not be called in interrupt context. - */ -void isc_unregister(unsigned int isc) -{ - spin_lock(&isc_ref_lock); - /* check for misuse */ - if (isc > MAX_ISC || isc_refs[isc] == 0) { - WARN_ON(1); - goto out_unlock; - } - if (isc_refs[isc] == 1) - ctl_clear_bit(6, 31 - isc); - isc_refs[isc]--; -out_unlock: - spin_unlock(&isc_ref_lock); -} -EXPORT_SYMBOL_GPL(isc_unregister); diff --git a/trunk/drivers/s390/cio/itcw.c b/trunk/drivers/s390/cio/itcw.c deleted file mode 100644 index 17da9ab932ed..000000000000 --- a/trunk/drivers/s390/cio/itcw.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Functions for incremental construction of fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * struct itcw - incremental tcw helper data type - * - * This structure serves as a handle for the incremental construction of a - * tcw and associated tccb, tsb, data tidaw-list plus an optional interrogate - * tcw and associated data. The data structures are contained inside a single - * contiguous buffer provided by the user. - * - * The itcw construction functions take care of overall data integrity: - * - reset unused fields to zero - * - fill in required pointers - * - ensure required alignment for data structures - * - prevent data structures to cross 4k-byte boundary where required - * - calculate tccb-related length fields - * - optionally provide ready-made interrogate tcw and associated structures - * - * Restrictions apply to the itcws created with these construction functions: - * - tida only supported for data address, not for tccb - * - only contiguous tidaw-lists (no ttic) - * - total number of bytes required per itcw may not exceed 4k bytes - * - either read or write operation (may not work with r=0 and w=0) - * - * Example: - * struct itcw *itcw; - * void *buffer; - * size_t size; - * - * size = itcw_calc_size(1, 2, 0); - * buffer = kmalloc(size, GFP_DMA); - * if (!buffer) - * return -ENOMEM; - * itcw = itcw_init(buffer, size, ITCW_OP_READ, 1, 2, 0); - * if (IS_ERR(itcw)) - * return PTR_ER(itcw); - * itcw_add_dcw(itcw, 0x2, 0, NULL, 0, 72); - * itcw_add_tidaw(itcw, 0, 0x30000, 20); - * itcw_add_tidaw(itcw, 0, 0x40000, 52); - * itcw_finalize(itcw); - * - */ -struct itcw { - struct tcw *tcw; - struct tcw *intrg_tcw; - int num_tidaws; - int max_tidaws; - int intrg_num_tidaws; - int intrg_max_tidaws; -}; - -/** - * itcw_get_tcw - return pointer to tcw associated with the itcw - * @itcw: address of the itcw - * - * Return pointer to the tcw associated with the itcw. - */ -struct tcw *itcw_get_tcw(struct itcw *itcw) -{ - return itcw->tcw; -} -EXPORT_SYMBOL(itcw_get_tcw); - -/** - * itcw_calc_size - return the size of an itcw with the given parameters - * @intrg: if non-zero, add an interrogate tcw - * @max_tidaws: maximum number of tidaws to be used for data addressing or zero - * if no tida is to be used. - * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing - * by the interrogate tcw, if specified - * - * Calculate and return the number of bytes required to hold an itcw with the - * given parameters and assuming tccbs with maximum size. - * - * Note that the resulting size also contains bytes needed for alignment - * padding as well as padding to ensure that data structures don't cross a - * 4k-boundary where required. - */ -size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws) -{ - size_t len; - - /* Main data. */ - len = sizeof(struct itcw); - len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE + - /* TSB */ sizeof(struct tsb) + - /* TIDAL */ max_tidaws * sizeof(struct tidaw); - /* Interrogate data. */ - if (intrg) { - len += /* TCW */ sizeof(struct tcw) + /* TCCB */ TCCB_MAX_SIZE + - /* TSB */ sizeof(struct tsb) + - /* TIDAL */ intrg_max_tidaws * sizeof(struct tidaw); - } - /* Maximum required alignment padding. */ - len += /* Initial TCW */ 63 + /* Interrogate TCCB */ 7; - /* Maximum padding for structures that may not cross 4k boundary. */ - if ((max_tidaws > 0) || (intrg_max_tidaws > 0)) - len += max(max_tidaws, intrg_max_tidaws) * - sizeof(struct tidaw) - 1; - return len; -} -EXPORT_SYMBOL(itcw_calc_size); - -#define CROSS4K(x, l) (((x) & ~4095) != ((x + l) & ~4095)) - -static inline void *fit_chunk(addr_t *start, addr_t end, size_t len, - int align, int check_4k) -{ - addr_t addr; - - addr = ALIGN(*start, align); - if (check_4k && CROSS4K(addr, len)) { - addr = ALIGN(addr, 4096); - addr = ALIGN(addr, align); - } - if (addr + len > end) - return ERR_PTR(-ENOSPC); - *start = addr + len; - return (void *) addr; -} - -/** - * itcw_init - initialize incremental tcw data structure - * @buffer: address of buffer to use for data structures - * @size: number of bytes in buffer - * @op: %ITCW_OP_READ for a read operation tcw, %ITCW_OP_WRITE for a write - * operation tcw - * @intrg: if non-zero, add and initialize an interrogate tcw - * @max_tidaws: maximum number of tidaws to be used for data addressing or zero - * if no tida is to be used. - * @intrg_max_tidaws: maximum number of tidaws to be used for data addressing - * by the interrogate tcw, if specified - * - * Prepare the specified buffer to be used as an incremental tcw, i.e. a - * helper data structure that can be used to construct a valid tcw by - * successive calls to other helper functions. Note: the buffer needs to be - * located below the 2G address limit. The resulting tcw has the following - * restrictions: - * - no tccb tidal - * - input/output tidal is contiguous (no ttic) - * - total data should not exceed 4k - * - tcw specifies either read or write operation - * - * On success, return pointer to the resulting incremental tcw data structure, - * ERR_PTR otherwise. - */ -struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, - int max_tidaws, int intrg_max_tidaws) -{ - struct itcw *itcw; - void *chunk; - addr_t start; - addr_t end; - - /* Check for 2G limit. */ - start = (addr_t) buffer; - end = start + size; - if (end > (1 << 31)) - return ERR_PTR(-EINVAL); - memset(buffer, 0, size); - /* ITCW. */ - chunk = fit_chunk(&start, end, sizeof(struct itcw), 1, 0); - if (IS_ERR(chunk)) - return chunk; - itcw = chunk; - itcw->max_tidaws = max_tidaws; - itcw->intrg_max_tidaws = intrg_max_tidaws; - /* Main TCW. */ - chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); - if (IS_ERR(chunk)) - return chunk; - itcw->tcw = chunk; - tcw_init(itcw->tcw, (op == ITCW_OP_READ) ? 1 : 0, - (op == ITCW_OP_WRITE) ? 1 : 0); - /* Interrogate TCW. */ - if (intrg) { - chunk = fit_chunk(&start, end, sizeof(struct tcw), 64, 0); - if (IS_ERR(chunk)) - return chunk; - itcw->intrg_tcw = chunk; - tcw_init(itcw->intrg_tcw, 1, 0); - tcw_set_intrg(itcw->tcw, itcw->intrg_tcw); - } - /* Data TIDAL. */ - if (max_tidaws > 0) { - chunk = fit_chunk(&start, end, sizeof(struct tidaw) * - max_tidaws, 16, 1); - if (IS_ERR(chunk)) - return chunk; - tcw_set_data(itcw->tcw, chunk, 1); - } - /* Interrogate data TIDAL. */ - if (intrg && (intrg_max_tidaws > 0)) { - chunk = fit_chunk(&start, end, sizeof(struct tidaw) * - intrg_max_tidaws, 16, 1); - if (IS_ERR(chunk)) - return chunk; - tcw_set_data(itcw->intrg_tcw, chunk, 1); - } - /* TSB. */ - chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0); - if (IS_ERR(chunk)) - return chunk; - tsb_init(chunk); - tcw_set_tsb(itcw->tcw, chunk); - /* Interrogate TSB. */ - if (intrg) { - chunk = fit_chunk(&start, end, sizeof(struct tsb), 8, 0); - if (IS_ERR(chunk)) - return chunk; - tsb_init(chunk); - tcw_set_tsb(itcw->intrg_tcw, chunk); - } - /* TCCB. */ - chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0); - if (IS_ERR(chunk)) - return chunk; - tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_DEFAULT); - tcw_set_tccb(itcw->tcw, chunk); - /* Interrogate TCCB. */ - if (intrg) { - chunk = fit_chunk(&start, end, TCCB_MAX_SIZE, 8, 0); - if (IS_ERR(chunk)) - return chunk; - tccb_init(chunk, TCCB_MAX_SIZE, TCCB_SAC_INTRG); - tcw_set_tccb(itcw->intrg_tcw, chunk); - tccb_add_dcw(chunk, TCCB_MAX_SIZE, DCW_CMD_INTRG, 0, NULL, - sizeof(struct dcw_intrg_data), 0); - tcw_finalize(itcw->intrg_tcw, 0); - } - return itcw; -} -EXPORT_SYMBOL(itcw_init); - -/** - * itcw_add_dcw - add a dcw to the itcw - * @itcw: address of the itcw - * @cmd: the dcw command - * @flags: flags for the dcw - * @cd: address of control data for this dcw or NULL if none is required - * @cd_count: number of control data bytes for this dcw - * @count: number of data bytes for this dcw - * - * Add a new dcw to the specified itcw by writing the dcw information specified - * by @cmd, @flags, @cd, @cd_count and @count to the tca of the tccb. Return - * a pointer to the newly added dcw on success or -%ENOSPC if the new dcw - * would exceed the available space. - * - * Note: the tcal field of the tccb header will be updated to reflect added - * content. - */ -struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd, - u8 cd_count, u32 count) -{ - return tccb_add_dcw(tcw_get_tccb(itcw->tcw), TCCB_MAX_SIZE, cmd, - flags, cd, cd_count, count); -} -EXPORT_SYMBOL(itcw_add_dcw); - -/** - * itcw_add_tidaw - add a tidaw to the itcw - * @itcw: address of the itcw - * @flags: flags for the new tidaw - * @addr: address value for the new tidaw - * @count: count value for the new tidaw - * - * Add a new tidaw to the input/output data tidaw-list of the specified itcw - * (depending on the value of the r-flag and w-flag). Return a pointer to - * the new tidaw on success or -%ENOSPC if the new tidaw would exceed the - * available space. - * - * Note: the tidaw-list is assumed to be contiguous with no ttics. The - * last-tidaw flag for the last tidaw in the list will be set by itcw_finalize. - */ -struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, u32 count) -{ - if (itcw->num_tidaws >= itcw->max_tidaws) - return ERR_PTR(-ENOSPC); - return tcw_add_tidaw(itcw->tcw, itcw->num_tidaws++, flags, addr, count); -} -EXPORT_SYMBOL(itcw_add_tidaw); - -/** - * itcw_set_data - set data address and tida flag of the itcw - * @itcw: address of the itcw - * @addr: the data address - * @use_tidal: zero of the data address specifies a contiguous block of data, - * non-zero if it specifies a list if tidaws. - * - * Set the input/output data address of the itcw (depending on the value of the - * r-flag and w-flag). If @use_tidal is non-zero, the corresponding tida flag - * is set as well. - */ -void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal) -{ - tcw_set_data(itcw->tcw, addr, use_tidal); -} -EXPORT_SYMBOL(itcw_set_data); - -/** - * itcw_finalize - calculate length and count fields of the itcw - * @itcw: address of the itcw - * - * Calculate tcw input-/output-count and tccbl fields and add a tcat the tccb. - * In case input- or output-tida is used, the tidaw-list must be stored in - * continuous storage (no ttic). The tcal field in the tccb must be - * up-to-date. - */ -void itcw_finalize(struct itcw *itcw) -{ - tcw_finalize(itcw->tcw, itcw->num_tidaws); -} -EXPORT_SYMBOL(itcw_finalize); diff --git a/trunk/drivers/s390/cio/qdio.c b/trunk/drivers/s390/cio/qdio.c index 2bf36e14b102..445cf364e461 100644 --- a/trunk/drivers/s390/cio/qdio.c +++ b/trunk/drivers/s390/cio/qdio.c @@ -2082,6 +2082,7 @@ qdio_timeout_handler(struct ccw_device *cdev) default: BUG(); } + ccw_device_set_timeout(cdev, 0); wake_up(&cdev->private->wait_q); } @@ -2120,8 +2121,6 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) case -EIO: QDIO_PRINT_ERR("i/o error on device %s\n", cdev->dev.bus_id); - qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR); - wake_up(&cdev->private->wait_q); return; case -ETIMEDOUT: qdio_timeout_handler(cdev); @@ -2140,8 +2139,8 @@ qdio_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) QDIO_DBF_TEXT4(0, trace, dbf_text); #endif /* CONFIG_QDIO_DEBUG */ - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; switch (irq_ptr->state) { case QDIO_IRQ_STATE_INACTIVE: @@ -2354,6 +2353,9 @@ tiqdio_check_chsc_availability(void) { char dbf_text[15]; + if (!css_characteristics_avail) + return -EIO; + /* Check for bit 41. */ if (!css_general_characteristics.aif) { QDIO_PRINT_WARN("Adapter interruption facility not " \ @@ -2665,12 +2667,12 @@ qdio_shutdown(struct ccw_device *cdev, int how) spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); } else if (rc == 0) { qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP); + ccw_device_set_timeout(cdev, timeout); spin_unlock_irqrestore(get_ccwdev_lock(cdev),flags); - wait_event_interruptible_timeout(cdev->private->wait_q, - irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || - irq_ptr->state == QDIO_IRQ_STATE_ERR, - timeout); + wait_event(cdev->private->wait_q, + irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || + irq_ptr->state == QDIO_IRQ_STATE_ERR); } else { QDIO_PRINT_INFO("ccw_device_{halt,clear} returned %d for " "device %s\n", result, cdev->dev.bus_id); @@ -2690,6 +2692,7 @@ qdio_shutdown(struct ccw_device *cdev, int how) /* Ignore errors. */ qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); + ccw_device_set_timeout(cdev, 0); out: up(&irq_ptr->setting_up_sema); return result; @@ -2904,10 +2907,13 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat) QDIO_DBF_TEXT0(0,setup,dbf_text); QDIO_DBF_TEXT0(0,trace,dbf_text); - if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) + if (qdio_establish_irq_check_for_errors(cdev, cstat, dstat)) { + ccw_device_set_timeout(cdev, 0); return; + } qdio_set_state(irq_ptr,QDIO_IRQ_STATE_ESTABLISHED); + ccw_device_set_timeout(cdev, 0); } int @@ -3190,6 +3196,8 @@ qdio_establish(struct qdio_initialize *init_data) irq_ptr->schid.ssid, irq_ptr->schid.sch_no, result, result2); result=result2; + if (result) + ccw_device_set_timeout(cdev, 0); } spin_unlock_irqrestore(get_ccwdev_lock(cdev),saveflags); @@ -3271,6 +3279,7 @@ qdio_activate(struct ccw_device *cdev, int flags) spin_lock_irqsave(get_ccwdev_lock(cdev),saveflags); + ccw_device_set_timeout(cdev, 0); ccw_device_set_options(cdev, CCWDEV_REPORT_ALL); result=ccw_device_start(cdev,&irq_ptr->ccw,QDIO_DOING_ACTIVATE, 0, DOIO_DENY_PREFETCH); @@ -3713,8 +3722,7 @@ tiqdio_register_thinints(void) char dbf_text[20]; tiqdio_ind = - s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL, - TIQDIO_THININT_ISC); + s390_register_adapter_interrupt(&tiqdio_thinint_handler, NULL); if (IS_ERR(tiqdio_ind)) { sprintf(dbf_text, "regthn%lx", PTR_ERR(tiqdio_ind)); QDIO_DBF_TEXT0(0,setup,dbf_text); @@ -3730,8 +3738,7 @@ static void tiqdio_unregister_thinints(void) { if (tiqdio_ind) - s390_unregister_adapter_interrupt(tiqdio_ind, - TIQDIO_THININT_ISC); + s390_unregister_adapter_interrupt(tiqdio_ind); } static int @@ -3892,7 +3899,6 @@ init_QDIO(void) qdio_mempool_alloc, qdio_mempool_free, NULL); - isc_register(QDIO_AIRQ_ISC); if (tiqdio_check_chsc_availability()) QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n"); @@ -3905,7 +3911,6 @@ static void __exit cleanup_QDIO(void) { tiqdio_unregister_thinints(); - isc_unregister(QDIO_AIRQ_ISC); qdio_remove_procfs_entry(); qdio_release_qdio_memory(); qdio_unregister_dbf_views(); diff --git a/trunk/drivers/s390/cio/qdio.h b/trunk/drivers/s390/cio/qdio.h index 7656081a24d2..c3df6b2c38b7 100644 --- a/trunk/drivers/s390/cio/qdio.h +++ b/trunk/drivers/s390/cio/qdio.h @@ -2,8 +2,8 @@ #define _CIO_QDIO_H #include -#include -#include + +#include "schid.h" #ifdef CONFIG_QDIO_DEBUG #define QDIO_VERBOSE_LEVEL 9 @@ -26,7 +26,7 @@ */ #define IQDIO_FILL_LEVEL_TO_POLL 4 -#define TIQDIO_THININT_ISC QDIO_AIRQ_ISC +#define TIQDIO_THININT_ISC 3 #define TIQDIO_DELAY_TARGET 0 #define QDIO_BUSY_BIT_PATIENCE 100 /* in microsecs */ #define QDIO_BUSY_BIT_GIVE_UP 10000000 /* 10 seconds */ diff --git a/trunk/include/asm-s390/schid.h b/trunk/drivers/s390/cio/schid.h similarity index 65% rename from trunk/include/asm-s390/schid.h rename to trunk/drivers/s390/cio/schid.h index 5017ffa78e04..54328fec5ade 100644 --- a/trunk/include/asm-s390/schid.h +++ b/trunk/drivers/s390/cio/schid.h @@ -1,14 +1,12 @@ -#ifndef ASM_SCHID_H -#define ASM_SCHID_H +#ifndef S390_SCHID_H +#define S390_SCHID_H struct subchannel_id { - __u32 cssid : 8; - __u32 : 4; - __u32 m : 1; - __u32 ssid : 2; - __u32 one : 1; - __u32 sch_no : 16; -} __attribute__ ((packed, aligned(4))); + __u32 reserved:13; + __u32 ssid:2; + __u32 one:1; + __u32 sch_no:16; +} __attribute__ ((packed,aligned(4))); /* Helper function for sane state of pre-allocated subchannel_id. */ @@ -25,4 +23,4 @@ schid_equal(struct subchannel_id *schid1, struct subchannel_id *schid2) return !memcmp(schid1, schid2, sizeof(struct subchannel_id)); } -#endif /* ASM_SCHID_H */ +#endif /* S390_SCHID_H */ diff --git a/trunk/drivers/s390/cio/scsw.c b/trunk/drivers/s390/cio/scsw.c deleted file mode 100644 index f8da25ab576d..000000000000 --- a/trunk/drivers/s390/cio/scsw.c +++ /dev/null @@ -1,843 +0,0 @@ -/* - * Helper functions for scsw access. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#include -#include -#include -#include "css.h" -#include "chsc.h" - -/** - * scsw_is_tm - check for transport mode scsw - * @scsw: pointer to scsw - * - * Return non-zero if the specified scsw is a transport mode scsw, zero - * otherwise. - */ -int scsw_is_tm(union scsw *scsw) -{ - return css_general_characteristics.fcx && (scsw->tm.x == 1); -} -EXPORT_SYMBOL(scsw_is_tm); - -/** - * scsw_key - return scsw key field - * @scsw: pointer to scsw - * - * Return the value of the key field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.key; - else - return scsw->cmd.key; -} -EXPORT_SYMBOL(scsw_key); - -/** - * scsw_eswf - return scsw eswf field - * @scsw: pointer to scsw - * - * Return the value of the eswf field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.eswf; - else - return scsw->cmd.eswf; -} -EXPORT_SYMBOL(scsw_eswf); - -/** - * scsw_cc - return scsw cc field - * @scsw: pointer to scsw - * - * Return the value of the cc field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cc; - else - return scsw->cmd.cc; -} -EXPORT_SYMBOL(scsw_cc); - -/** - * scsw_ectl - return scsw ectl field - * @scsw: pointer to scsw - * - * Return the value of the ectl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.ectl; - else - return scsw->cmd.ectl; -} -EXPORT_SYMBOL(scsw_ectl); - -/** - * scsw_pno - return scsw pno field - * @scsw: pointer to scsw - * - * Return the value of the pno field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.pno; - else - return scsw->cmd.pno; -} -EXPORT_SYMBOL(scsw_pno); - -/** - * scsw_fctl - return scsw fctl field - * @scsw: pointer to scsw - * - * Return the value of the fctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.fctl; - else - return scsw->cmd.fctl; -} -EXPORT_SYMBOL(scsw_fctl); - -/** - * scsw_actl - return scsw actl field - * @scsw: pointer to scsw - * - * Return the value of the actl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.actl; - else - return scsw->cmd.actl; -} -EXPORT_SYMBOL(scsw_actl); - -/** - * scsw_stctl - return scsw stctl field - * @scsw: pointer to scsw - * - * Return the value of the stctl field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.stctl; - else - return scsw->cmd.stctl; -} -EXPORT_SYMBOL(scsw_stctl); - -/** - * scsw_dstat - return scsw dstat field - * @scsw: pointer to scsw - * - * Return the value of the dstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.dstat; - else - return scsw->cmd.dstat; -} -EXPORT_SYMBOL(scsw_dstat); - -/** - * scsw_cstat - return scsw cstat field - * @scsw: pointer to scsw - * - * Return the value of the cstat field of the specified scsw, regardless of - * whether it is a transport mode or command mode scsw. - */ -u32 scsw_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw->tm.cstat; - else - return scsw->cmd.cstat; -} -EXPORT_SYMBOL(scsw_cstat); - -/** - * scsw_cmd_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_key(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_key); - -/** - * scsw_cmd_is_valid_sctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_sctl(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_sctl); - -/** - * scsw_cmd_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_eswf(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_eswf); - -/** - * scsw_cmd_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cc); - -/** - * scsw_cmd_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fmt(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fmt); - -/** - * scsw_cmd_is_valid_pfch - check pfch field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pfch field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pfch(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pfch); - -/** - * scsw_cmd_is_valid_isic - check isic field validity - * @scsw: pointer to scsw - * - * Return non-zero if the isic field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_isic(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_isic); - -/** - * scsw_cmd_is_valid_alcc - check alcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the alcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_alcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_alcc); - -/** - * scsw_cmd_is_valid_ssi - check ssi field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ssi field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ssi(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ssi); - -/** - * scsw_cmd_is_valid_zcc - check zcc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the zcc field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_zcc(union scsw *scsw) -{ - return (scsw->cmd.fctl & SCSW_FCTL_START_FUNC) && - (scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_zcc); - -/** - * scsw_cmd_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_ectl(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_ectl); - -/** - * scsw_cmd_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_pno(union scsw *scsw) -{ - return (scsw->cmd.fctl != 0) && - (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->cmd.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->cmd.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_pno); - -/** - * scsw_cmd_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_fctl); - -/** - * scsw_cmd_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_actl); - -/** - * scsw_cmd_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_cmd_is_valid_stctl); - -/** - * scsw_cmd_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_dstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_dstat); - -/** - * scsw_cmd_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified command mode scsw is - * valid, zero otherwise. - */ -int scsw_cmd_is_valid_cstat(union scsw *scsw) -{ - return (scsw->cmd.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->cmd.cc != 3); -} -EXPORT_SYMBOL(scsw_cmd_is_valid_cstat); - -/** - * scsw_tm_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_key(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC); -} -EXPORT_SYMBOL(scsw_tm_is_valid_key); - -/** - * scsw_tm_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_eswf(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_eswf); - -/** - * scsw_tm_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cc(union scsw *scsw) -{ - return (scsw->tm.fctl & SCSW_FCTL_START_FUNC) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cc); - -/** - * scsw_tm_is_valid_fmt - check fmt field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fmt field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fmt(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fmt); - -/** - * scsw_tm_is_valid_x - check x field validity - * @scsw: pointer to scsw - * - * Return non-zero if the x field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_x(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_x); - -/** - * scsw_tm_is_valid_q - check q field validity - * @scsw: pointer to scsw - * - * Return non-zero if the q field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_q(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_q); - -/** - * scsw_tm_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_ectl(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - !(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.stctl & SCSW_STCTL_ALERT_STATUS); -} -EXPORT_SYMBOL(scsw_tm_is_valid_ectl); - -/** - * scsw_tm_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_pno(union scsw *scsw) -{ - return (scsw->tm.fctl != 0) && - (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (!(scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) || - ((scsw->tm.stctl & SCSW_STCTL_INTER_STATUS) && - (scsw->tm.actl & SCSW_ACTL_SUSPENDED))); -} -EXPORT_SYMBOL(scsw_tm_is_valid_pno); - -/** - * scsw_tm_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fctl); - -/** - * scsw_tm_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_actl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_actl); - -/** - * scsw_tm_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_stctl(union scsw *scsw) -{ - /* Only valid if pmcw.dnv == 1*/ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_stctl); - -/** - * scsw_tm_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_dstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_dstat); - -/** - * scsw_tm_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_cstat(union scsw *scsw) -{ - return (scsw->tm.stctl & SCSW_STCTL_STATUS_PEND) && - (scsw->tm.cc != 3); -} -EXPORT_SYMBOL(scsw_tm_is_valid_cstat); - -/** - * scsw_tm_is_valid_fcxs - check fcxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fcxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_fcxs(union scsw *scsw) -{ - return 1; -} -EXPORT_SYMBOL(scsw_tm_is_valid_fcxs); - -/** - * scsw_tm_is_valid_schxs - check schxs field validity - * @scsw: pointer to scsw - * - * Return non-zero if the schxs field of the specified transport mode scsw is - * valid, zero otherwise. - */ -int scsw_tm_is_valid_schxs(union scsw *scsw) -{ - return (scsw->tm.cstat & (SCHN_STAT_PROG_CHECK | - SCHN_STAT_INTF_CTRL_CHK | - SCHN_STAT_PROT_CHECK | - SCHN_STAT_CHN_DATA_CHK)); -} -EXPORT_SYMBOL(scsw_tm_is_valid_schxs); - -/** - * scsw_is_valid_actl - check actl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the actl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_actl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_actl(scsw); - else - return scsw_cmd_is_valid_actl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_actl); - -/** - * scsw_is_valid_cc - check cc field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cc field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cc(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cc(scsw); - else - return scsw_cmd_is_valid_cc(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cc); - -/** - * scsw_is_valid_cstat - check cstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the cstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_cstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_cstat(scsw); - else - return scsw_cmd_is_valid_cstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_cstat); - -/** - * scsw_is_valid_dstat - check dstat field validity - * @scsw: pointer to scsw - * - * Return non-zero if the dstat field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_dstat(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_dstat(scsw); - else - return scsw_cmd_is_valid_dstat(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_dstat); - -/** - * scsw_is_valid_ectl - check ectl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the ectl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_ectl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_ectl(scsw); - else - return scsw_cmd_is_valid_ectl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_ectl); - -/** - * scsw_is_valid_eswf - check eswf field validity - * @scsw: pointer to scsw - * - * Return non-zero if the eswf field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_eswf(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_eswf(scsw); - else - return scsw_cmd_is_valid_eswf(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_eswf); - -/** - * scsw_is_valid_fctl - check fctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the fctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_fctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_fctl(scsw); - else - return scsw_cmd_is_valid_fctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_fctl); - -/** - * scsw_is_valid_key - check key field validity - * @scsw: pointer to scsw - * - * Return non-zero if the key field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_key(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_key(scsw); - else - return scsw_cmd_is_valid_key(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_key); - -/** - * scsw_is_valid_pno - check pno field validity - * @scsw: pointer to scsw - * - * Return non-zero if the pno field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_pno(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_pno(scsw); - else - return scsw_cmd_is_valid_pno(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_pno); - -/** - * scsw_is_valid_stctl - check stctl field validity - * @scsw: pointer to scsw - * - * Return non-zero if the stctl field of the specified scsw is valid, - * regardless of whether it is a transport mode or command mode scsw. - * Return zero if the field does not contain a valid value. - */ -int scsw_is_valid_stctl(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_valid_stctl(scsw); - else - return scsw_cmd_is_valid_stctl(scsw); -} -EXPORT_SYMBOL(scsw_is_valid_stctl); - -/** - * scsw_cmd_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the command mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_cmd_is_solicited(union scsw *scsw) -{ - return (scsw->cmd.cc != 0) || (scsw->cmd.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_cmd_is_solicited); - -/** - * scsw_tm_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport mode scsw indicates that the associated - * status condition is solicited, zero if it is unsolicited. - */ -int scsw_tm_is_solicited(union scsw *scsw) -{ - return (scsw->tm.cc != 0) || (scsw->tm.stctl != - (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)); -} -EXPORT_SYMBOL(scsw_tm_is_solicited); - -/** - * scsw_is_solicited - check for solicited scsw - * @scsw: pointer to scsw - * - * Return non-zero if the transport or command mode scsw indicates that the - * associated status condition is solicited, zero if it is unsolicited. - */ -int scsw_is_solicited(union scsw *scsw) -{ - if (scsw_is_tm(scsw)) - return scsw_tm_is_solicited(scsw); - else - return scsw_cmd_is_solicited(scsw); -} -EXPORT_SYMBOL(scsw_is_solicited); diff --git a/trunk/drivers/s390/crypto/ap_bus.c b/trunk/drivers/s390/crypto/ap_bus.c index 62b6b55230d0..a1ab3e3efd11 100644 --- a/trunk/drivers/s390/crypto/ap_bus.c +++ b/trunk/drivers/s390/crypto/ap_bus.c @@ -34,15 +34,13 @@ #include #include #include -#include -#include #include "ap_bus.h" /* Some prototypes. */ static void ap_scan_bus(struct work_struct *); static void ap_poll_all(unsigned long); -static enum hrtimer_restart ap_poll_timeout(struct hrtimer *); +static void ap_poll_timeout(unsigned long); static int ap_poll_thread_start(void); static void ap_poll_thread_stop(void); static void ap_request_timeout(unsigned long); @@ -82,15 +80,12 @@ static DECLARE_WORK(ap_config_work, ap_scan_bus); /* * Tasklet & timer for AP request polling. */ +static struct timer_list ap_poll_timer = TIMER_INITIALIZER(ap_poll_timeout,0,0); 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 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_intructions_available() - Test if AP instructions are available. @@ -641,39 +636,11 @@ static ssize_t ap_poll_thread_store(struct bus_type *bus, static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store); -static ssize_t poll_timeout_show(struct bus_type *bus, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%llu\n", poll_timeout); -} - -static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, - size_t count) -{ - unsigned long long time; - ktime_t hr_time; - - /* 120 seconds = maximum poll interval */ - if (sscanf(buf, "%llu\n", &time) != 1 || time < 1 || time > 120000000000) - return -EINVAL; - poll_timeout = time; - hr_time = ktime_set(0, poll_timeout); - - if (!hrtimer_is_queued(&ap_poll_timer) || - !hrtimer_forward(&ap_poll_timer, ap_poll_timer.expires, hr_time)) { - ap_poll_timer.expires = hr_time; - hrtimer_start(&ap_poll_timer, hr_time, HRTIMER_MODE_ABS); - } - return count; -} - -static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); - static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_config_time, &bus_attr_poll_thread, - &bus_attr_poll_timeout, - NULL, + NULL }; /** @@ -928,10 +895,9 @@ ap_config_timeout(unsigned long ptr) */ static inline void ap_schedule_poll_timer(void) { - if (hrtimer_is_queued(&ap_poll_timer)) + if (timer_pending(&ap_poll_timer)) return; - hrtimer_start(&ap_poll_timer, ktime_set(0, poll_timeout), - HRTIMER_MODE_ABS); + mod_timer(&ap_poll_timer, jiffies + AP_POLL_TIME); } /** @@ -1149,14 +1115,13 @@ EXPORT_SYMBOL(ap_cancel_message); /** * ap_poll_timeout(): AP receive polling for finished AP requests. - * @unused: Unused pointer. + * @unused: Unused variable. * - * Schedules the AP tasklet using a high resolution timer. + * Schedules the AP tasklet. */ -static enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) +static void ap_poll_timeout(unsigned long unused) { tasklet_schedule(&ap_tasklet); - return HRTIMER_NORESTART; } /** @@ -1379,14 +1344,6 @@ int __init ap_module_init(void) ap_config_timer.expires = jiffies + ap_config_time * HZ; add_timer(&ap_config_timer); - /* Setup the high resultion poll timer. - * If we are running under z/VM adjust polling to z/VM polling rate. - */ - if (MACHINE_IS_VM) - poll_timeout = 1500000; - hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - ap_poll_timer.function = ap_poll_timeout; - /* Start the low priority AP bus poll thread. */ if (ap_thread_flag) { rc = ap_poll_thread_start(); @@ -1398,7 +1355,7 @@ int __init ap_module_init(void) out_work: del_timer_sync(&ap_config_timer); - hrtimer_cancel(&ap_poll_timer); + del_timer_sync(&ap_poll_timer); destroy_workqueue(ap_work_queue); out_root: s390_root_dev_unregister(ap_root_device); @@ -1429,7 +1386,7 @@ void ap_module_exit(void) ap_reset_domain(); ap_poll_thread_stop(); del_timer_sync(&ap_config_timer); - hrtimer_cancel(&ap_poll_timer); + del_timer_sync(&ap_poll_timer); destroy_workqueue(ap_work_queue); tasklet_kill(&ap_tasklet); s390_root_dev_unregister(ap_root_device); diff --git a/trunk/drivers/s390/crypto/ap_bus.h b/trunk/drivers/s390/crypto/ap_bus.h index 446378b308fc..c1e1200c43fc 100644 --- a/trunk/drivers/s390/crypto/ap_bus.h +++ b/trunk/drivers/s390/crypto/ap_bus.h @@ -92,8 +92,6 @@ struct ap_queue_status { #define AP_DEVICE_TYPE_PCIXCC 5 #define AP_DEVICE_TYPE_CEX2A 6 #define AP_DEVICE_TYPE_CEX2C 7 -#define AP_DEVICE_TYPE_CEX2A2 8 -#define AP_DEVICE_TYPE_CEX2C2 9 /* * AP reset flag states diff --git a/trunk/drivers/s390/crypto/zcrypt_api.c b/trunk/drivers/s390/crypto/zcrypt_api.c index 8a4964f3584b..4d36e805a234 100644 --- a/trunk/drivers/s390/crypto/zcrypt_api.c +++ b/trunk/drivers/s390/crypto/zcrypt_api.c @@ -1068,8 +1068,10 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer, #define LBUFSIZE 1200UL lbuf = kmalloc(LBUFSIZE, GFP_KERNEL); - if (!lbuf) + if (!lbuf) { + PRINTK("kmalloc failed!\n"); return 0; + } local_count = min(LBUFSIZE - 1, count); if (copy_from_user(lbuf, buffer, local_count) != 0) { @@ -1079,15 +1081,23 @@ static int zcrypt_status_write(struct file *file, const char __user *buffer, lbuf[local_count] = '\0'; ptr = strstr(lbuf, "Online devices"); - if (!ptr) + if (!ptr) { + PRINTK("Unable to parse data (missing \"Online devices\")\n"); goto out; + } ptr = strstr(ptr, "\n"); - if (!ptr) + if (!ptr) { + PRINTK("Unable to parse data (missing newline " + "after \"Online devices\")\n"); goto out; + } ptr++; - if (strstr(ptr, "Waiting work element counts") == NULL) + if (strstr(ptr, "Waiting work element counts") == NULL) { + PRINTK("Unable to parse data (missing " + "\"Waiting work element counts\")\n"); goto out; + } for (j = 0; j < 64 && *ptr; ptr++) { /* @@ -1187,12 +1197,16 @@ int __init zcrypt_api_init(void) /* Register the request sprayer. */ rc = misc_register(&zcrypt_misc_device); - if (rc < 0) + if (rc < 0) { + PRINTKW(KERN_ERR "misc_register (minor %d) failed with %d\n", + zcrypt_misc_device.minor, rc); goto out; + } /* Set up the proc file system */ zcrypt_entry = create_proc_entry("driver/z90crypt", 0644, NULL); if (!zcrypt_entry) { + PRINTK("Couldn't create z90crypt proc entry\n"); rc = -ENOMEM; goto out_misc; } diff --git a/trunk/drivers/s390/crypto/zcrypt_api.h b/trunk/drivers/s390/crypto/zcrypt_api.h index 1d1ec74dadb2..5c6e222b2ac4 100644 --- a/trunk/drivers/s390/crypto/zcrypt_api.h +++ b/trunk/drivers/s390/crypto/zcrypt_api.h @@ -30,6 +30,34 @@ #ifndef _ZCRYPT_API_H_ #define _ZCRYPT_API_H_ +/** + * Macro definitions + * + * PDEBUG debugs in the form "zcrypt: function_name -> message" + * + * PRINTK is like PDEBUG, except that it is always enabled + * PRINTKN is like PRINTK, except that it does not include the function name + * PRINTKW is like PRINTK, except that it uses KERN_WARNING + * PRINTKC is like PRINTK, except that it uses KERN_CRIT + */ +#define DEV_NAME "zcrypt" + +#define PRINTK(fmt, args...) \ + printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args) +#define PRINTKN(fmt, args...) \ + printk(KERN_DEBUG DEV_NAME ": " fmt, ## args) +#define PRINTKW(fmt, args...) \ + printk(KERN_WARNING DEV_NAME ": %s -> " fmt, __func__ , ## args) +#define PRINTKC(fmt, args...) \ + printk(KERN_CRIT DEV_NAME ": %s -> " fmt, __func__ , ## args) + +#ifdef ZCRYPT_DEBUG +#define PDEBUG(fmt, args...) \ + printk(KERN_DEBUG DEV_NAME ": %s -> " fmt, __func__ , ## args) +#else +#define PDEBUG(fmt, args...) do {} while (0) +#endif + #include "ap_bus.h" #include diff --git a/trunk/drivers/s390/crypto/zcrypt_cex2a.c b/trunk/drivers/s390/crypto/zcrypt_cex2a.c index 54f4cbc3be9e..08657f604b8c 100644 --- a/trunk/drivers/s390/crypto/zcrypt_cex2a.c +++ b/trunk/drivers/s390/crypto/zcrypt_cex2a.c @@ -49,7 +49,6 @@ static struct ap_device_id zcrypt_cex2a_ids[] = { { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX2A2) }, { /* end of list */ }, }; @@ -243,6 +242,9 @@ static int convert_response(struct zcrypt_device *zdev, return convert_type80(zdev, reply, outputdata, outputdatalength); default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_error.h b/trunk/drivers/s390/crypto/zcrypt_error.h index 03ba27f05f92..3e27fe77d207 100644 --- a/trunk/drivers/s390/crypto/zcrypt_error.h +++ b/trunk/drivers/s390/crypto/zcrypt_error.h @@ -92,6 +92,10 @@ static inline int convert_error(struct zcrypt_device *zdev, { struct error_hdr *ehdr = reply->message; + PRINTK("Hardware error : Type %02x Message Header: %08x%08x\n", + ehdr->type, *(unsigned int *) reply->message, + *(unsigned int *) (reply->message + 4)); + switch (ehdr->reply_code) { case REP82_ERROR_OPERAND_INVALID: case REP82_ERROR_OPERAND_SIZE: @@ -119,6 +123,8 @@ static inline int convert_error(struct zcrypt_device *zdev, zdev->online = 0; return -EAGAIN; default: + PRINTKW("unknown type %02x reply code = %d\n", + ehdr->type, ehdr->reply_code); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_pcica.c b/trunk/drivers/s390/crypto/zcrypt_pcica.c index 12da4815ba8e..6e93b4751782 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcica.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcica.c @@ -226,6 +226,9 @@ static int convert_response(struct zcrypt_device *zdev, return convert_type84(zdev, reply, outputdata, outputdatalength); default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_pcicc.c b/trunk/drivers/s390/crypto/zcrypt_pcicc.c index 779952cb19fc..17ea56ce1c11 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcicc.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcicc.c @@ -361,18 +361,26 @@ static int convert_type86(struct zcrypt_device *zdev, service_rc = le16_to_cpu(msg->cprb.ccp_rtcode); if (unlikely(service_rc != 0)) { service_rs = le16_to_cpu(msg->cprb.ccp_rscode); - if (service_rc == 8 && service_rs == 66) + if (service_rc == 8 && service_rs == 66) { + PDEBUG("Bad block format on PCICC\n"); return -EINVAL; - if (service_rc == 8 && service_rs == 65) + } + if (service_rc == 8 && service_rs == 65) { + PDEBUG("Probably an even modulus on PCICC\n"); return -EINVAL; + } if (service_rc == 8 && service_rs == 770) { + PDEBUG("Invalid key length on PCICC\n"); zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD; return -EAGAIN; } if (service_rc == 8 && service_rs == 783) { + PDEBUG("Extended bitlengths not enabled on PCICC\n"); zdev->max_mod_size = PCICC_MAX_MOD_SIZE_OLD; return -EAGAIN; } + PRINTK("Unknown service rc/rs (PCICC): %d/%d\n", + service_rc, service_rs); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -426,6 +434,9 @@ static int convert_response(struct zcrypt_device *zdev, outputdata, outputdatalength); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c index d8ad36f81540..0bc9b3188e64 100644 --- a/trunk/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/trunk/drivers/s390/crypto/zcrypt_pcixcc.c @@ -72,7 +72,6 @@ struct response_type { static struct ap_device_id zcrypt_pcixcc_ids[] = { { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) }, { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX2C2) }, { /* end of list */ }, }; @@ -290,19 +289,38 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, ap_msg->length = sizeof(struct type6_hdr) + CEIL4(xcRB->request_control_blk_length) + xcRB->request_data_length; - if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) + if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) { + PRINTK("Combined message is too large (%ld/%d/%d).\n", + sizeof(struct type6_hdr), + xcRB->request_control_blk_length, + xcRB->request_data_length); return -EFAULT; - if (CEIL4(xcRB->reply_control_blk_length) > PCIXCC_MAX_XCRB_REPLY_SIZE) + } + if (CEIL4(xcRB->reply_control_blk_length) > + PCIXCC_MAX_XCRB_REPLY_SIZE) { + PDEBUG("Reply CPRB length is too large (%d).\n", + xcRB->request_control_blk_length); return -EFAULT; - if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) + } + if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) { + PDEBUG("Reply data block length is too large (%d).\n", + xcRB->reply_data_length); return -EFAULT; + } replylen = CEIL4(xcRB->reply_control_blk_length) + CEIL4(xcRB->reply_data_length) + sizeof(struct type86_fmt2_msg); if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) { + PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE" + " (%d/%d/%d).\n", + sizeof(struct type86_fmt2_msg), + xcRB->reply_control_blk_length, + xcRB->reply_data_length); xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE - (sizeof(struct type86_fmt2_msg) + CEIL4(xcRB->reply_data_length)); + PDEBUG("Capping Reply CPRB length at %d\n", + xcRB->reply_control_blk_length); } /* prepare type6 header */ @@ -321,8 +339,11 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, xcRB->request_control_blk_length)) return -EFAULT; if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) > - xcRB->request_control_blk_length) + xcRB->request_control_blk_length) { + PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len, + xcRB->request_control_blk_length); return -EFAULT; + } function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); @@ -450,18 +471,29 @@ static int convert_type86_ica(struct zcrypt_device *zdev, service_rc = msg->cprbx.ccp_rtcode; if (unlikely(service_rc != 0)) { service_rs = msg->cprbx.ccp_rscode; - if (service_rc == 8 && service_rs == 66) + if (service_rc == 8 && service_rs == 66) { + PDEBUG("Bad block format on PCIXCC/CEX2C\n"); return -EINVAL; - if (service_rc == 8 && service_rs == 65) + } + if (service_rc == 8 && service_rs == 65) { + PDEBUG("Probably an even modulus on PCIXCC/CEX2C\n"); return -EINVAL; - if (service_rc == 8 && service_rs == 770) + } + if (service_rc == 8 && service_rs == 770) { + PDEBUG("Invalid key length on PCIXCC/CEX2C\n"); return -EINVAL; + } if (service_rc == 8 && service_rs == 783) { + PDEBUG("Extended bitlengths not enabled on PCIXCC/CEX2C\n"); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } - if (service_rc == 12 && service_rs == 769) + if (service_rc == 12 && service_rs == 769) { + PDEBUG("Invalid key on PCIXCC/CEX2C\n"); return -EINVAL; + } + PRINTK("Unknown service rc/rs (PCIXCC/CEX2C): %d/%d\n", + service_rc, service_rs); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -537,8 +569,11 @@ static int convert_type86_rng(struct zcrypt_device *zdev, } __attribute__((packed)) *msg = reply->message; char *data = reply->message; - if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) + if (msg->cprbx.ccp_rtcode != 0 || msg->cprbx.ccp_rscode != 0) { + PDEBUG("RNG response error on PCIXCC/CEX2C rc=%hu/rs=%hu\n", + rc, rs); return -EINVAL; + } memcpy(buffer, data + msg->fmt2.offset2, msg->fmt2.count2); return msg->fmt2.count2; } @@ -563,6 +598,9 @@ static int convert_response_ica(struct zcrypt_device *zdev, outputdata, outputdatalength); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -589,6 +627,9 @@ static int convert_response_xcrb(struct zcrypt_device *zdev, return convert_type86_xcrb(zdev, reply, xcRB); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ @@ -612,6 +653,9 @@ static int convert_response_rng(struct zcrypt_device *zdev, return convert_type86_rng(zdev, reply, data); /* no break, incorrect cprb version is an unknown response */ default: /* Unknown response type, this should NEVER EVER happen */ + PRINTK("Unrecognized Message Header: %08x%08x\n", + *(unsigned int *) reply->message, + *(unsigned int *) (reply->message+4)); zdev->online = 0; return -EAGAIN; /* repeat the request on a different device. */ } @@ -656,7 +700,10 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev, memcpy(msg->message, reply->message, length); break; default: - memcpy(msg->message, &error_reply, sizeof error_reply); + PRINTK("Invalid internal response type: %i\n", + resp_type->type); + memcpy(msg->message, &error_reply, + sizeof error_reply); } } else memcpy(msg->message, reply->message, sizeof error_reply); diff --git a/trunk/drivers/s390/net/claw.c b/trunk/drivers/s390/net/claw.c index c644669a75c2..04a1d7bf678c 100644 --- a/trunk/drivers/s390/net/claw.c +++ b/trunk/drivers/s390/net/claw.c @@ -703,8 +703,7 @@ claw_irq_handler(struct ccw_device *cdev, if (!cdev->dev.driver_data) { printk(KERN_WARNING "claw: unsolicited interrupt for device:" "%s received c-%02x d-%02x\n", - cdev->dev.bus_id, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + cdev->dev.bus_id,irb->scsw.cstat, irb->scsw.dstat); #ifdef FUNCTRACE printk(KERN_INFO "claw: %s() " "exit on line %d\n",__func__,__LINE__); @@ -733,23 +732,22 @@ claw_irq_handler(struct ccw_device *cdev, #ifdef IOTRACE printk(KERN_INFO "%s: interrupt for device: %04x " "received c-%02x d-%02x state-%02x\n", - dev->name, p_ch->devno, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat, p_ch->claw_state); + dev->name, p_ch->devno, irb->scsw.cstat, + irb->scsw.dstat, p_ch->claw_state); #endif /* Copy interruption response block. */ memcpy(p_ch->irb, irb, sizeof(struct irb)); /* Check for good subchannel return code, otherwise error message */ - if (irb->scsw.cmd.cstat && !(irb->scsw.cmd.cstat & SCHN_STAT_PCI)) { + if (irb->scsw.cstat && !(irb->scsw.cstat & SCHN_STAT_PCI)) { printk(KERN_INFO "%s: subchannel check for device: %04x -" " Sch Stat %02x Dev Stat %02x CPA - %04x\n", dev->name, p_ch->devno, - irb->scsw.cmd.cstat, irb->scsw.cmd.dstat, - irb->scsw.cmd.cpa); + irb->scsw.cstat, irb->scsw.dstat,irb->scsw.cpa); #ifdef IOTRACE dumpit((char *)irb,sizeof(struct irb)); - dumpit((char *)(unsigned long)irb->scsw.cmd.cpa, + dumpit((char *)(unsigned long)irb->scsw.cpa, sizeof(struct ccw1)); #endif #ifdef FUNCTRACE @@ -761,24 +759,22 @@ claw_irq_handler(struct ccw_device *cdev, } /* Check the reason-code of a unit check */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { ccw_check_unit_check(p_ch, irb->ecw[0]); + } /* State machine to bring the connection up, down and to restart */ - p_ch->last_dstat = irb->scsw.cmd.dstat; + p_ch->last_dstat = irb->scsw.dstat; switch (p_ch->claw_state) { case CLAW_STOP:/* HALT_IO by claw_release (halt sequence) */ #ifdef DEBUGMSG printk(KERN_INFO "%s: CLAW_STOP enter\n", dev->name); #endif - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); @@ -802,13 +798,10 @@ claw_irq_handler(struct ccw_device *cdev, printk(KERN_INFO "%s: process CLAW_STAT_HALT_IO\n", dev->name); #endif - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if (!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); @@ -835,8 +828,8 @@ claw_irq_handler(struct ccw_device *cdev, "interrupt for device:" "%s received c-%02x d-%02x\n", cdev->dev.bus_id, - irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + irb->scsw.cstat, + irb->scsw.dstat); return; } #ifdef DEBUGMSG @@ -851,7 +844,7 @@ claw_irq_handler(struct ccw_device *cdev, return; case CLAW_START_READ: CLAW_DBF_TEXT(4,trace,"ReadIRQ"); - if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { clear_bit(0, (void *)&p_ch->IO_active); if ((p_ch->irb->ecw[0] & 0x41) == 0x41 || (p_ch->irb->ecw[0] & 0x40) == 0x40 || @@ -870,8 +863,8 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"notrdy"); return; } - if ((p_ch->irb->scsw.cmd.cstat & SCHN_STAT_PCI) && - (p_ch->irb->scsw.cmd.dstat == 0)) { + if ((p_ch->irb->scsw.cstat & SCHN_STAT_PCI) && + (p_ch->irb->scsw.dstat==0)) { if (test_and_set_bit(CLAW_BH_ACTIVE, (void *)&p_ch->flag_a) == 0) { tasklet_schedule(&p_ch->tasklet); @@ -886,13 +879,10 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"PCI_read"); return; } - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); @@ -921,7 +911,7 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"RdIRQXit"); return; case CLAW_START_WRITE: - if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { printk(KERN_INFO "%s: Unit Check Occured in " "write channel\n",dev->name); clear_bit(0, (void *)&p_ch->IO_active); @@ -944,19 +934,16 @@ claw_irq_handler(struct ccw_device *cdev, CLAW_DBF_TEXT(4,trace,"rstrtwrt"); return; } - if (p_ch->irb->scsw.cmd.dstat & DEV_STAT_UNIT_EXCEP) { + if (p_ch->irb->scsw.dstat & DEV_STAT_UNIT_EXCEP) { clear_bit(0, (void *)&p_ch->IO_active); printk(KERN_INFO "%s: Unit Exception " "Occured in write channel\n", dev->name); } - if (!((p_ch->irb->scsw.cmd.stctl & - SCSW_STCTL_SEC_STATUS) || - (p_ch->irb->scsw.cmd.stctl == - SCSW_STCTL_STATUS_PEND) || - (p_ch->irb->scsw.cmd.stctl == - (SCSW_STCTL_ALERT_STATUS | - SCSW_STCTL_STATUS_PEND)))) { + if(!((p_ch->irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (p_ch->irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (p_ch->irb->scsw.stctl == + (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)))) { #ifdef FUNCTRACE printk(KERN_INFO "%s:%s Exit on line %d\n", dev->name,__func__,__LINE__); diff --git a/trunk/drivers/s390/net/ctcm_fsms.c b/trunk/drivers/s390/net/ctcm_fsms.c index 7e6bd387f4d8..2a106f3a076d 100644 --- a/trunk/drivers/s390/net/ctcm_fsms.c +++ b/trunk/drivers/s390/net/ctcm_fsms.c @@ -257,9 +257,9 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg) if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; - if (ch->irb->scsw.cmd.count != 0) + if (ch->irb->scsw.count != 0) ctcm_pr_debug("%s: TX not complete, remaining %d bytes\n", - dev->name, ch->irb->scsw.cmd.count); + dev->name, ch->irb->scsw.count); fsm_deltimer(&ch->timer); while ((skb = skb_dequeue(&ch->io_queue))) { priv->stats.tx_packets++; @@ -353,7 +353,7 @@ static void chx_rx(fsm_instance *fi, int event, void *arg) struct channel *ch = arg; struct net_device *dev = ch->netdev; struct ctcm_priv *priv = dev->priv; - int len = ch->max_bufsize - ch->irb->scsw.cmd.count; + int len = ch->max_bufsize - ch->irb->scsw.count; struct sk_buff *skb = ch->trans_skb; __u16 block_len = *((__u16 *)skb->data); int check_len; @@ -1234,9 +1234,9 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg) if (duration > ch->prof.tx_time) ch->prof.tx_time = duration; - if (ch->irb->scsw.cmd.count != 0) + if (ch->irb->scsw.count != 0) ctcm_pr_debug("%s: TX not complete, remaining %d bytes\n", - dev->name, ch->irb->scsw.cmd.count); + dev->name, ch->irb->scsw.count); fsm_deltimer(&ch->timer); while ((skb = skb_dequeue(&ch->io_queue))) { priv->stats.tx_packets++; @@ -1394,7 +1394,7 @@ static void ctcmpc_chx_rx(fsm_instance *fi, int event, void *arg) struct sk_buff *skb = ch->trans_skb; struct sk_buff *new_skb; unsigned long saveflags = 0; /* avoids compiler warning */ - int len = ch->max_bufsize - ch->irb->scsw.cmd.count; + int len = ch->max_bufsize - ch->irb->scsw.count; if (do_debug_data) { CTCM_DBF_TEXT_(TRACE, CTC_DBF_DEBUG, "mpc_ch_rx %s cp:%i %s\n", diff --git a/trunk/drivers/s390/net/ctcm_main.c b/trunk/drivers/s390/net/ctcm_main.c index 6b13c1c1beb8..d52843da4f55 100644 --- a/trunk/drivers/s390/net/ctcm_main.c +++ b/trunk/drivers/s390/net/ctcm_main.c @@ -1236,8 +1236,8 @@ static void ctcm_irq_handler(struct ccw_device *cdev, /* Check for unsolicited interrupts. */ if (cgdev == NULL) { ctcm_pr_warn("ctcm: Got unsolicited irq: %s c-%02x d-%02x\n", - cdev->dev.bus_id, irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + cdev->dev.bus_id, irb->scsw.cstat, + irb->scsw.dstat); return; } @@ -1266,40 +1266,40 @@ static void ctcm_irq_handler(struct ccw_device *cdev, "received c-%02x d-%02x\n", dev->name, ch->id, - irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); + irb->scsw.cstat, + irb->scsw.dstat); /* Copy interruption response block. */ memcpy(ch->irb, irb, sizeof(struct irb)); /* Check for good subchannel return code, otherwise error message */ - if (irb->scsw.cmd.cstat) { + if (irb->scsw.cstat) { 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); + dev->name, ch->id, irb->scsw.cstat, + irb->scsw.dstat); return; } /* Check the reason-code of a unit check */ - if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) { + if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { ccw_unit_check(ch, irb->ecw[0]); return; } - if (irb->scsw.cmd.dstat & DEV_STAT_BUSY) { - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) + if (irb->scsw.dstat & DEV_STAT_BUSY) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) fsm_event(ch->fsm, CTC_EVENT_ATTNBUSY, ch); else fsm_event(ch->fsm, CTC_EVENT_BUSY, ch); return; } - if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) { + if (irb->scsw.dstat & DEV_STAT_ATTENTION) { fsm_event(ch->fsm, CTC_EVENT_ATTN, ch); return; } - if ((irb->scsw.cmd.stctl & SCSW_STCTL_SEC_STATUS) || - (irb->scsw.cmd.stctl == SCSW_STCTL_STATUS_PEND) || - (irb->scsw.cmd.stctl == + if ((irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || + (irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || + (irb->scsw.stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) fsm_event(ch->fsm, CTC_EVENT_FINSTAT, ch); else diff --git a/trunk/drivers/s390/net/cu3088.c b/trunk/drivers/s390/net/cu3088.c index f4a32375c037..8e7697305a4c 100644 --- a/trunk/drivers/s390/net/cu3088.c +++ b/trunk/drivers/s390/net/cu3088.c @@ -36,6 +36,7 @@ const char *cu3088_type[] = { "CTC/A", "ESCON channel", "FICON channel", + "P390 LCS card", "OSA LCS card", "CLAW channel device", "unknown channel type", @@ -48,6 +49,7 @@ static struct ccw_device_id cu3088_ids[] = { { CCW_DEVICE(0x3088, 0x08), .driver_info = channel_type_parallel }, { CCW_DEVICE(0x3088, 0x1f), .driver_info = channel_type_escon }, { CCW_DEVICE(0x3088, 0x1e), .driver_info = channel_type_ficon }, + { CCW_DEVICE(0x3088, 0x01), .driver_info = channel_type_p390 }, { CCW_DEVICE(0x3088, 0x60), .driver_info = channel_type_osa2 }, { CCW_DEVICE(0x3088, 0x61), .driver_info = channel_type_claw }, { /* end of list */ } diff --git a/trunk/drivers/s390/net/cu3088.h b/trunk/drivers/s390/net/cu3088.h index d8558a7105a5..1753661f702a 100644 --- a/trunk/drivers/s390/net/cu3088.h +++ b/trunk/drivers/s390/net/cu3088.h @@ -17,6 +17,9 @@ enum channel_types { /* Device is a FICON channel */ channel_type_ficon, + /* Device is a P390 LCS card */ + channel_type_p390, + /* Device is a OSA2 card */ channel_type_osa2, diff --git a/trunk/drivers/s390/net/lcs.c b/trunk/drivers/s390/net/lcs.c index 6de28385b354..dd22f4b37037 100644 --- a/trunk/drivers/s390/net/lcs.c +++ b/trunk/drivers/s390/net/lcs.c @@ -1327,8 +1327,8 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb) char *sense; sense = (char *) irb->ecw; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | @@ -1388,13 +1388,11 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) else channel = &card->write; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; LCS_DBF_TEXT_(5, trace, "Rint%s",cdev->dev.bus_id); - LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.cstat, - irb->scsw.cmd.dstat); - LCS_DBF_TEXT_(5, trace, "%4x%4x", irb->scsw.cmd.fctl, - irb->scsw.cmd.actl); + LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.cstat, irb->scsw.dstat); + LCS_DBF_TEXT_(5, trace, "%4x%4x",irb->scsw.fctl, irb->scsw.actl); /* Check for channel and device errors presented */ rc = lcs_get_problem(cdev, irb); @@ -1412,11 +1410,11 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } /* How far in the ccw chain have we processed? */ if ((channel->state != LCS_CH_STATE_INIT) && - (irb->scsw.cmd.fctl & SCSW_FCTL_START_FUNC)) { - index = (struct ccw1 *) __va((addr_t) irb->scsw.cmd.cpa) + (irb->scsw.fctl & SCSW_FCTL_START_FUNC)) { + index = (struct ccw1 *) __va((addr_t) irb->scsw.cpa) - channel->ccws; - if ((irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED) || - (irb->scsw.cmd.cstat & SCHN_STAT_PCI)) + if ((irb->scsw.actl & SCSW_ACTL_SUSPENDED) || + (irb->scsw.cstat & SCHN_STAT_PCI)) /* Bloody io subsystem tells us lies about cpa... */ index = (index - 1) & (LCS_NUM_BUFFS - 1); while (channel->io_idx != index) { @@ -1427,24 +1425,25 @@ lcs_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) } } - if ((irb->scsw.cmd.dstat & DEV_STAT_DEV_END) || - (irb->scsw.cmd.dstat & DEV_STAT_CHN_END) || - (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)) + if ((irb->scsw.dstat & DEV_STAT_DEV_END) || + (irb->scsw.dstat & DEV_STAT_CHN_END) || + (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)) /* Mark channel as stopped. */ channel->state = LCS_CH_STATE_STOPPED; - else if (irb->scsw.cmd.actl & SCSW_ACTL_SUSPENDED) + else if (irb->scsw.actl & SCSW_ACTL_SUSPENDED) /* CCW execution stopped on a suspend bit. */ channel->state = LCS_CH_STATE_SUSPENDED; - if (irb->scsw.cmd.fctl & SCSW_FCTL_HALT_FUNC) { - if (irb->scsw.cmd.cc != 0) { + if (irb->scsw.fctl & SCSW_FCTL_HALT_FUNC) { + if (irb->scsw.cc != 0) { ccw_device_halt(channel->ccwdev, (addr_t) channel); return; } /* The channel has been stopped by halt_IO. */ channel->state = LCS_CH_STATE_HALTED; } - if (irb->scsw.cmd.fctl & SCSW_FCTL_CLEAR_FUNC) + if (irb->scsw.fctl & SCSW_FCTL_CLEAR_FUNC) { channel->state = LCS_CH_STATE_CLEARED; + } /* Do the rest in the tasklet. */ tasklet_schedule(&channel->irq_tasklet); } @@ -1762,7 +1761,7 @@ lcs_get_control(struct lcs_card *card, struct lcs_cmd *cmd) netif_carrier_off(card->dev); break; default: - LCS_DBF_TEXT(5, trace, "noLGWcmd"); + PRINT_INFO("UNRECOGNIZED LGW COMMAND\n"); break; } } else @@ -2043,12 +2042,13 @@ lcs_probe_device(struct ccwgroup_device *ccwgdev) LCS_DBF_TEXT(2, setup, "add_dev"); card = lcs_alloc_card(); if (!card) { - LCS_DBF_TEXT_(2, setup, " rc%d", -ENOMEM); + PRINT_ERR("Allocation of lcs card failed\n"); put_device(&ccwgdev->dev); return -ENOMEM; } ret = sysfs_create_group(&ccwgdev->dev.kobj, &lcs_attr_group); if (ret) { + PRINT_ERR("Creating attributes failed"); lcs_free_card(card); put_device(&ccwgdev->dev); return ret; @@ -2140,6 +2140,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) default: LCS_DBF_TEXT(3, setup, "errinit"); PRINT_ERR("LCS: Initialization failed\n"); + PRINT_ERR("LCS: No device found!\n"); goto out; } if (!dev) @@ -2268,6 +2269,7 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) if (!card) return; + PRINT_INFO("Removing lcs group device ....\n"); LCS_DBF_TEXT(3, setup, "remdev"); LCS_DBF_HEX(3, setup, &card, sizeof(void*)); if (ccwgdev->state == CCWGROUP_ONLINE) { diff --git a/trunk/drivers/s390/net/netiucv.c b/trunk/drivers/s390/net/netiucv.c index 9242b5acc66b..e4ba6a0372ac 100644 --- a/trunk/drivers/s390/net/netiucv.c +++ b/trunk/drivers/s390/net/netiucv.c @@ -625,6 +625,9 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, offset += header->next; header->next -= NETIUCV_HDRLEN; if (skb_tailroom(pskb) < header->next) { + PRINT_WARN("%s: Illegal next field in iucv header: " + "%d > %d\n", + dev->name, header->next, skb_tailroom(pskb)); IUCV_DBF_TEXT_(data, 2, "Illegal next field: %d > %d\n", header->next, skb_tailroom(pskb)); return; @@ -633,6 +636,8 @@ static void netiucv_unpack_skb(struct iucv_connection *conn, skb_reset_mac_header(pskb); skb = dev_alloc_skb(pskb->len); if (!skb) { + PRINT_WARN("%s Out of memory in netiucv_unpack_skb\n", + dev->name); IUCV_DBF_TEXT(data, 2, "Out of memory in netiucv_unpack_skb\n"); privptr->stats.rx_dropped++; @@ -669,6 +674,7 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) if (!conn->netdev) { iucv_message_reject(conn->path, msg); + PRINT_WARN("Received data for unlinked connection\n"); IUCV_DBF_TEXT(data, 2, "Received data for unlinked connection\n"); return; @@ -676,6 +682,8 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) if (msg->length > conn->max_buffsize) { iucv_message_reject(conn->path, msg); privptr->stats.rx_dropped++; + PRINT_WARN("msglen %d > max_buffsize %d\n", + msg->length, conn->max_buffsize); IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", msg->length, conn->max_buffsize); return; @@ -687,6 +695,7 @@ static void conn_action_rx(fsm_instance *fi, int event, void *arg) msg->length, NULL); if (rc || msg->length < 5) { privptr->stats.rx_errors++; + PRINT_WARN("iucv_receive returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); return; } @@ -769,6 +778,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg) fsm_newstate(fi, CONN_STATE_IDLE); if (privptr) privptr->stats.tx_errors += txpackets; + PRINT_WARN("iucv_send returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); } else { if (privptr) { @@ -796,6 +806,8 @@ static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) path->flags = 0; rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); if (rc) { + PRINT_WARN("%s: IUCV accept failed with error %d\n", + netdev->name, rc); IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc); return; } @@ -861,7 +873,7 @@ static void conn_action_start(fsm_instance *fi, int event, void *arg) IUCV_DBF_TEXT(trace, 3, __func__); fsm_newstate(fi, CONN_STATE_STARTWAIT); - IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n", + PRINT_DEBUG("%s('%s'): connecting ...\n", conn->netdev->name, conn->userid); /* @@ -956,8 +968,8 @@ static void conn_action_inval(fsm_instance *fi, int event, void *arg) struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - IUCV_DBF_TEXT_(data, 2, "%s('%s'): conn_action_inval called\n", - netdev->name, conn->userid); + PRINT_WARN("%s: Cannot connect without username\n", netdev->name); + IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); } static const fsm_node conn_fsm[] = { @@ -1065,6 +1077,9 @@ dev_action_connup(fsm_instance *fi, int event, void *arg) "connection is up and running\n"); break; case DEV_STATE_STOPWAIT: + PRINT_INFO( + "%s: got connection UP event during shutdown!\n", + dev->name); IUCV_DBF_TEXT(data, 2, "dev_action_connup: in DEV_STATE_STOPWAIT\n"); break; @@ -1159,6 +1174,8 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, nskb = alloc_skb(skb->len + NETIUCV_HDRLEN + NETIUCV_HDRLEN, GFP_ATOMIC | GFP_DMA); if (!nskb) { + PRINT_WARN("%s: Could not allocate tx_skb\n", + conn->netdev->name); IUCV_DBF_TEXT(data, 2, "alloc_skb failed\n"); rc = -ENOMEM; return rc; @@ -1206,6 +1223,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn, skb_pull(skb, NETIUCV_HDRLEN); skb_trim(skb, skb->len - NETIUCV_HDRLEN); } + PRINT_WARN("iucv_send returned %08x\n", rc); IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); } else { if (copied) @@ -1275,11 +1293,14 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) * Some sanity checks ... */ if (skb == NULL) { + PRINT_WARN("%s: NULL sk_buff passed\n", dev->name); IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb is NULL\n"); privptr->stats.tx_dropped++; return 0; } if (skb_headroom(skb) < NETIUCV_HDRLEN) { + PRINT_WARN("%s: Got sk_buff with head room < %ld bytes\n", + dev->name, NETIUCV_HDRLEN); IUCV_DBF_TEXT(data, 2, "netiucv_tx: skb_headroom < NETIUCV_HDRLEN\n"); dev_kfree_skb(skb); @@ -1372,6 +1393,7 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, IUCV_DBF_TEXT(trace, 3, __func__); if (count > 9) { + PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); IUCV_DBF_TEXT_(setup, 2, "%d is length of username\n", (int) count); return -EINVAL; @@ -1387,6 +1409,7 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, /* trailing lf, grr */ break; } + PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); IUCV_DBF_TEXT_(setup, 2, "username: invalid character %c\n", *p); return -EINVAL; @@ -1398,15 +1421,18 @@ static ssize_t user_write(struct device *dev, struct device_attribute *attr, if (memcmp(username, priv->conn->userid, 9) && (ndev->flags & (IFF_UP | IFF_RUNNING))) { /* username changed while the interface is active. */ + PRINT_WARN("netiucv: device %s active, connected to %s\n", + dev->bus_id, priv->conn->userid); + PRINT_WARN("netiucv: user cannot be updated\n"); IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); - return -EPERM; + return -EBUSY; } read_lock_bh(&iucv_connection_rwlock); list_for_each_entry(cp, &iucv_connection_list, list) { if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { read_unlock_bh(&iucv_connection_rwlock); - IUCV_DBF_TEXT_(setup, 2, "user_write: Connection " - "to %s already exists\n", username); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); return -EEXIST; } } @@ -1440,10 +1466,13 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, bs1 = simple_strtoul(buf, &e, 0); if (e && (!isspace(*e))) { + PRINT_WARN("netiucv: Invalid character in buffer!\n"); IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %c\n", *e); return -EINVAL; } if (bs1 > NETIUCV_BUFSIZE_MAX) { + PRINT_WARN("netiucv: Given buffer size %d too large.\n", + bs1); IUCV_DBF_TEXT_(setup, 2, "buffer_write: buffer size %d too large\n", bs1); @@ -1451,12 +1480,16 @@ static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, } if ((ndev->flags & IFF_RUNNING) && (bs1 < (ndev->mtu + NETIUCV_HDRLEN + 2))) { + PRINT_WARN("netiucv: Given buffer size %d too small.\n", + bs1); IUCV_DBF_TEXT_(setup, 2, "buffer_write: buffer size %d too small\n", bs1); return -EINVAL; } if (bs1 < (576 + NETIUCV_HDRLEN + NETIUCV_HDRLEN)) { + PRINT_WARN("netiucv: Given buffer size %d too small.\n", + bs1); IUCV_DBF_TEXT_(setup, 2, "buffer_write: buffer size %d too small\n", bs1); @@ -1930,6 +1963,7 @@ static ssize_t conn_write(struct device_driver *drv, IUCV_DBF_TEXT(trace, 3, __func__); if (count>9) { + PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n"); return -EINVAL; } @@ -1942,6 +1976,7 @@ static ssize_t conn_write(struct device_driver *drv, if (*p == '\n') /* trailing lf, grr */ break; + PRINT_WARN("netiucv: Invalid character in username!\n"); IUCV_DBF_TEXT_(setup, 2, "conn_write: invalid character %c\n", *p); return -EINVAL; @@ -1954,8 +1989,8 @@ static ssize_t conn_write(struct device_driver *drv, list_for_each_entry(cp, &iucv_connection_list, list) { if (!strncmp(username, cp->userid, 9)) { read_unlock_bh(&iucv_connection_rwlock); - IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection " - "to %s already exists\n", username); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); return -EEXIST; } } @@ -1963,6 +1998,9 @@ static ssize_t conn_write(struct device_driver *drv, dev = netiucv_init_netdevice(username); if (!dev) { + PRINT_WARN("netiucv: Could not allocate network device " + "structure for user '%s'\n", + netiucv_printname(username)); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); return -ENODEV; } @@ -1982,12 +2020,15 @@ static ssize_t conn_write(struct device_driver *drv, if (rc) goto out_unreg; + PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); return count; out_unreg: netiucv_unregister_device(priv->dev); out_free_ndev: + PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); + IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); netiucv_free_netdevice(dev); return rc; } @@ -2032,13 +2073,14 @@ static ssize_t remove_write (struct device_driver *drv, PRINT_WARN("netiucv: %s cannot be removed\n", ndev->name); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); - return -EPERM; + return -EBUSY; } unregister_netdev(ndev); netiucv_unregister_device(dev); return count; } read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: net device %s unknown\n", name); IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); return -EINVAL; } @@ -2106,6 +2148,7 @@ static int __init netiucv_init(void) netiucv_driver.groups = netiucv_drv_attr_groups; rc = driver_register(&netiucv_driver); if (rc) { + PRINT_ERR("NETIUCV: failed to register driver.\n"); IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); goto out_iucv; } diff --git a/trunk/drivers/s390/net/qeth_core_main.c b/trunk/drivers/s390/net/qeth_core_main.c index 0ac54dc638c2..9a71dae223e8 100644 --- a/trunk/drivers/s390/net/qeth_core_main.c +++ b/trunk/drivers/s390/net/qeth_core_main.c @@ -420,7 +420,7 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, QETH_DBF_TEXT(TRACE, 3, "urla"); break; default: - QETH_DBF_MESSAGE(2, "Received data is IPA " + PRINT_WARN("Received data is IPA " "but not a reply!\n"); break; } @@ -735,8 +735,8 @@ static int qeth_get_problem(struct ccw_device *cdev, struct irb *irb) char *sense; sense = (char *) irb->ecw; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; if (cstat & (SCHN_STAT_CHN_CTRL_CHK | SCHN_STAT_INTF_CTRL_CHK | SCHN_STAT_CHN_DATA_CHK | SCHN_STAT_CHAIN_CHECK | @@ -823,8 +823,8 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, if (__qeth_check_irb_error(cdev, intparm, irb)) return; - cstat = irb->scsw.cmd.cstat; - dstat = irb->scsw.cmd.dstat; + cstat = irb->scsw.cstat; + dstat = irb->scsw.dstat; card = CARD_FROM_CDEV(cdev); if (!card) @@ -842,10 +842,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, } atomic_set(&channel->irq_pending, 0); - if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_CLEAR_FUNC)) channel->state = CH_STATE_STOPPED; - if (irb->scsw.cmd.fctl & (SCSW_FCTL_HALT_FUNC)) + if (irb->scsw.fctl & (SCSW_FCTL_HALT_FUNC)) channel->state = CH_STATE_HALTED; /*let's wake up immediately on data channel*/ @@ -4092,6 +4092,7 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev) rc = qeth_determine_card_type(card); if (rc) { + PRINT_WARN("%s: not a valid card type\n", __func__); QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); goto err_card; } diff --git a/trunk/drivers/s390/net/qeth_l3_main.c b/trunk/drivers/s390/net/qeth_l3_main.c index 06deaee50f6d..999552c83bbe 100644 --- a/trunk/drivers/s390/net/qeth_l3_main.c +++ b/trunk/drivers/s390/net/qeth_l3_main.c @@ -944,8 +944,15 @@ static int qeth_l3_deregister_addr_entry(struct qeth_card *card, else rc = qeth_l3_send_setdelip(card, addr, IPA_CMD_DELIP, addr->del_flags); - if (rc) + if (rc) { QETH_DBF_TEXT(TRACE, 2, "failed"); + /* TODO: re-activate this warning as soon as we have a + * clean mirco code + qeth_ipaddr_to_string(addr->proto, (u8 *)&addr->u, buf); + PRINT_WARN("Could not deregister IP address %s (rc=%x)\n", + buf, rc); + */ + } return rc; } diff --git a/trunk/drivers/s390/net/smsgiucv.c b/trunk/drivers/s390/net/smsgiucv.c index 164e090c2625..8735a415a116 100644 --- a/trunk/drivers/s390/net/smsgiucv.c +++ b/trunk/drivers/s390/net/smsgiucv.c @@ -156,8 +156,11 @@ static int __init smsg_init(void) if (rc != 0) goto out; rc = iucv_register(&smsg_handler, 1); - if (rc) + if (rc) { + printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); + rc = -EIO; /* better errno ? */ goto out_driver; + } smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL); if (!smsg_path) { rc = -ENOMEM; @@ -165,8 +168,11 @@ static int __init smsg_init(void) } rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", NULL, NULL, NULL); - if (rc) + if (rc) { + printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); + rc = -EIO; /* better errno ? */ goto out_free; + } cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; diff --git a/trunk/drivers/s390/s390mach.c b/trunk/drivers/s390/s390mach.c index 834e9ee7e934..5bfbe7659830 100644 --- a/trunk/drivers/s390/s390mach.c +++ b/trunk/drivers/s390/s390mach.c @@ -2,10 +2,10 @@ * drivers/s390/s390mach.c * S/390 machine check handler * - * Copyright IBM Corp. 2000,2008 + * S390 version + * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Ingo Adlung (adlung@de.ibm.com) * Martin Schwidefsky (schwidefsky@de.ibm.com) - * Cornelia Huck */ #include @@ -18,6 +18,10 @@ #include #include #include +#include "cio/cio.h" +#include "cio/chsc.h" +#include "cio/css.h" +#include "cio/chp.h" #include "s390mach.h" static struct semaphore m_sem; @@ -32,40 +36,13 @@ s390_handle_damage(char *msg) for(;;); } -static crw_handler_t crw_handlers[NR_RSCS]; - -/** - * s390_register_crw_handler() - register a channel report word handler - * @rsc: reporting source code to handle - * @handler: handler to be registered - * - * Returns %0 on success and a negative error value otherwise. - */ -int s390_register_crw_handler(int rsc, crw_handler_t handler) -{ - if ((rsc < 0) || (rsc >= NR_RSCS)) - return -EINVAL; - if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) - return 0; - return -EBUSY; -} - -/** - * s390_unregister_crw_handler() - unregister a channel report word handler - * @rsc: reporting source code to handle - */ -void s390_unregister_crw_handler(int rsc) -{ - if ((rsc < 0) || (rsc >= NR_RSCS)) - return; - xchg(&crw_handlers[rsc], NULL); - synchronize_sched(); -} - /* * Retrieve CRWs and call function to handle event. + * + * Note : we currently process CRWs for io and chsc subchannels only */ -static int s390_collect_crw_info(void *param) +static int +s390_collect_crw_info(void *param) { struct crw crw[2]; int ccode; @@ -107,24 +84,57 @@ static int s390_collect_crw_info(void *param) crw[chain].rsid); /* Check for overflows. */ if (crw[chain].oflw) { - int i; - pr_debug("%s: crw overflow detected!\n", __func__); - for (i = 0; i < NR_RSCS; i++) { - if (crw_handlers[i]) - crw_handlers[i](NULL, NULL, 1); - } + css_schedule_eval_all(); chain = 0; continue; } - if (crw[0].chn && !chain) { - chain++; - continue; + switch (crw[chain].rsc) { + case CRW_RSC_SCH: + if (crw[0].chn && !chain) + break; + pr_debug("source is subchannel %04X\n", crw[0].rsid); + css_process_crw(crw[0].rsid, chain ? crw[1].rsid : 0); + break; + case CRW_RSC_MONITOR: + pr_debug("source is monitoring facility\n"); + break; + case CRW_RSC_CPATH: + pr_debug("source is channel path %02X\n", crw[0].rsid); + /* + * Check for solicited machine checks. These are + * created by reset channel path and need not be + * reported to the common I/O layer. + */ + if (crw[chain].slct) { + pr_debug("solicited machine check for " + "channel path %02X\n", crw[0].rsid); + break; + } + switch (crw[0].erc) { + case CRW_ERC_IPARM: /* Path has come. */ + chp_process_crw(crw[0].rsid, 1); + break; + case CRW_ERC_PERRI: /* Path has gone. */ + case CRW_ERC_PERRN: + chp_process_crw(crw[0].rsid, 0); + break; + default: + pr_debug("Don't know how to handle erc=%x\n", + crw[0].erc); + } + break; + case CRW_RSC_CONFIG: + pr_debug("source is configuration-alert facility\n"); + break; + case CRW_RSC_CSS: + pr_debug("source is channel subsystem\n"); + chsc_process_crw(); + break; + default: + pr_debug("unknown source\n"); + break; } - if (crw_handlers[crw[chain].rsc]) - crw_handlers[crw[chain].rsc](&crw[0], - chain ? &crw[1] : NULL, - 0); /* chain is always 0 or 1 here. */ chain = crw[chain].chn ? chain + 1 : 0; } @@ -458,10 +468,6 @@ s390_do_machine_check(struct pt_regs *regs) etr_sync_check(); if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH)) etr_switch_to_local(); - if (S390_lowcore.external_damage_code & (1U << ED_STP_SYNC)) - stp_sync_check(); - if (S390_lowcore.external_damage_code & (1U << ED_STP_ISLAND)) - stp_island_check(); } if (mci->se) diff --git a/trunk/drivers/s390/s390mach.h b/trunk/drivers/s390/s390mach.h index d39f8b697d27..ca681f9b67fc 100644 --- a/trunk/drivers/s390/s390mach.h +++ b/trunk/drivers/s390/s390mach.h @@ -72,13 +72,6 @@ struct crw { __u32 rsid : 16; /* reporting-source ID */ } __attribute__ ((packed)); -typedef void (*crw_handler_t)(struct crw *, struct crw *, int); - -extern int s390_register_crw_handler(int rsc, crw_handler_t handler); -extern void s390_unregister_crw_handler(int rsc); - -#define NR_RSCS 16 - #define CRW_RSC_MONITOR 0x2 /* monitoring facility */ #define CRW_RSC_SCH 0x3 /* subchannel */ #define CRW_RSC_CPATH 0x4 /* channel path */ @@ -112,9 +105,6 @@ static inline int stcrw(struct crw *pcrw ) #define ED_ETR_SYNC 12 /* External damage ETR sync check */ #define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ -#define ED_STP_SYNC 7 /* External damage STP sync check */ -#define ED_STP_ISLAND 6 /* External damage STP island check */ - struct pt_regs; void s390_handle_mcck(void); diff --git a/trunk/drivers/scsi/sg.c b/trunk/drivers/scsi/sg.c index fe694f0ee19a..ea0edd1b2e76 100644 --- a/trunk/drivers/scsi/sg.c +++ b/trunk/drivers/scsi/sg.c @@ -182,9 +182,8 @@ static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize); static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp); -static ssize_t sg_new_write(Sg_fd *sfp, struct file *file, - const char __user *buf, size_t count, int blocking, - int read_only, Sg_request **o_srp); +static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, + int blocking, int read_only, Sg_request ** o_srp); static int sg_common_write(Sg_fd * sfp, Sg_request * srp, unsigned char *cmnd, int timeout, int blocking); static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind, @@ -205,6 +204,7 @@ static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id); static Sg_request *sg_add_request(Sg_fd * sfp); static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); static int sg_res_in_use(Sg_fd * sfp); +static int sg_allow_access(unsigned char opcode, char dev_type); static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len); static Sg_device *sg_get_dev(int dev); #ifdef CONFIG_SCSI_PROC_FS @@ -544,7 +544,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) return -EFAULT; blocking = !(filp->f_flags & O_NONBLOCK); if (old_hdr.reply_len < 0) - return sg_new_write(sfp, filp, buf, count, blocking, 0, NULL); + return sg_new_write(sfp, buf, count, blocking, 0, NULL); if (count < (SZ_SG_HEADER + 6)) return -EIO; /* The minimum scsi command length is 6 bytes. */ @@ -621,9 +621,8 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) } static ssize_t -sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, - size_t count, int blocking, int read_only, - Sg_request **o_srp) +sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count, + int blocking, int read_only, Sg_request ** o_srp) { int k; Sg_request *srp; @@ -679,7 +678,8 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EFAULT; } - if (read_only && !blk_verify_command(file, cmnd)) { + if (read_only && + (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) { sg_remove_request(sfp, srp); return -EPERM; } @@ -799,7 +799,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) return -EFAULT; result = - sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, + sg_new_write(sfp, p, SZ_SG_IO_HDR, blocking, read_only, &srp); if (result < 0) return result; @@ -1048,7 +1048,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (copy_from_user(&opcode, siocp->data, 1)) return -EFAULT; - if (!blk_verify_command(filp, &opcode)) + if (!sg_allow_access(opcode, sdp->device->type)) return -EPERM; } return sg_scsi_ioctl(filp, sdp->device->request_queue, NULL, p); @@ -2502,6 +2502,30 @@ sg_page_free(struct page *page, int size) __free_pages(page, order); } +#ifndef MAINTENANCE_IN_CMD +#define MAINTENANCE_IN_CMD 0xa3 +#endif + +static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE, + INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12, + READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS, + SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD +}; + +static int +sg_allow_access(unsigned char opcode, char dev_type) +{ + int k; + + if (TYPE_SCANNER == dev_type) /* TYPE_ROM maybe burner */ + return 1; + for (k = 0; k < sizeof (allow_ops); ++k) { + if (opcode == allow_ops[k]) + return 1; + } + return 0; +} + #ifdef CONFIG_SCSI_PROC_FS static int sg_idr_max_id(int id, void *p, void *data) diff --git a/trunk/drivers/scsi/sr.c b/trunk/drivers/scsi/sr.c index 27f5bfd1def3..c82df8bd4d89 100644 --- a/trunk/drivers/scsi/sr.c +++ b/trunk/drivers/scsi/sr.c @@ -673,20 +673,24 @@ static int sr_probe(struct device *dev) static void get_sectorsize(struct scsi_cd *cd) { unsigned char cmd[10]; - unsigned char buffer[8]; + unsigned char *buffer; int the_result, retries = 3; int sector_size; struct request_queue *queue; + buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); + if (!buffer) + goto Enomem; + do { cmd[0] = READ_CAPACITY; memset((void *) &cmd[1], 0, 9); - memset(buffer, 0, sizeof(buffer)); + memset(buffer, 0, 8); /* Do the command and wait.. */ the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, - buffer, sizeof(buffer), NULL, - SR_TIMEOUT, MAX_RETRIES); + buffer, 8, NULL, SR_TIMEOUT, + MAX_RETRIES); retries--; @@ -741,8 +745,14 @@ static void get_sectorsize(struct scsi_cd *cd) queue = cd->device->request_queue; blk_queue_hardsect_size(queue, sector_size); - +out: + kfree(buffer); return; + +Enomem: + cd->capacity = 0x1fffff; + cd->device->sector_size = 2048; /* A guess, just in case */ + goto out; } static void get_capabilities(struct scsi_cd *cd) diff --git a/trunk/drivers/xen/xenbus/xenbus_client.c b/trunk/drivers/xen/xenbus/xenbus_client.c index 9678b3e98c63..0f86b0ff7879 100644 --- a/trunk/drivers/xen/xenbus/xenbus_client.c +++ b/trunk/drivers/xen/xenbus/xenbus_client.c @@ -117,7 +117,7 @@ int xenbus_watch_pathfmt(struct xenbus_device *dev, char *path; va_start(ap, pathfmt); - path = kvasprintf(GFP_NOIO | __GFP_HIGH, pathfmt, ap); + path = kvasprintf(GFP_KERNEL, pathfmt, ap); va_end(ap); if (!path) { diff --git a/trunk/drivers/xen/xenbus/xenbus_xs.c b/trunk/drivers/xen/xenbus/xenbus_xs.c index 7f2f91c0e11d..227d53b12a5c 100644 --- a/trunk/drivers/xen/xenbus/xenbus_xs.c +++ b/trunk/drivers/xen/xenbus/xenbus_xs.c @@ -283,9 +283,9 @@ static char *join(const char *dir, const char *name) char *buffer; if (strlen(name) == 0) - buffer = kasprintf(GFP_NOIO | __GFP_HIGH, "%s", dir); + buffer = kasprintf(GFP_KERNEL, "%s", dir); else - buffer = kasprintf(GFP_NOIO | __GFP_HIGH, "%s/%s", dir, name); + buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name); return (!buffer) ? ERR_PTR(-ENOMEM) : buffer; } @@ -297,7 +297,7 @@ static char **split(char *strings, unsigned int len, unsigned int *num) *num = count_strings(strings, len); /* Transfer to one big alloc for easy freeing. */ - ret = kmalloc(*num * sizeof(char *) + len, GFP_NOIO | __GFP_HIGH); + ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL); if (!ret) { kfree(strings); return ERR_PTR(-ENOMEM); @@ -751,7 +751,7 @@ static int process_msg(void) } - msg = kmalloc(sizeof(*msg), GFP_NOIO | __GFP_HIGH); + msg = kmalloc(sizeof(*msg), GFP_KERNEL); if (msg == NULL) { err = -ENOMEM; goto out; @@ -763,7 +763,7 @@ static int process_msg(void) goto out; } - body = kmalloc(msg->hdr.len + 1, GFP_NOIO | __GFP_HIGH); + body = kmalloc(msg->hdr.len + 1, GFP_KERNEL); if (body == NULL) { kfree(msg); err = -ENOMEM; diff --git a/trunk/fs/Makefile b/trunk/fs/Makefile index 277b079dec9e..1e7a11bd4da1 100644 --- a/trunk/fs/Makefile +++ b/trunk/fs/Makefile @@ -19,7 +19,6 @@ else obj-y += no-block.o endif -obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o obj-$(CONFIG_INOTIFY) += inotify.o obj-$(CONFIG_INOTIFY_USER) += inotify_user.o obj-$(CONFIG_EPOLL) += eventpoll.o diff --git a/trunk/fs/bio-integrity.c b/trunk/fs/bio-integrity.c deleted file mode 100644 index 63e2ee63058d..000000000000 --- a/trunk/fs/bio-integrity.c +++ /dev/null @@ -1,719 +0,0 @@ -/* - * bio-integrity.c - bio data integrity extensions - * - * Copyright (C) 2007, 2008 Oracle Corporation - * Written by: Martin K. Petersen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - */ - -#include -#include -#include -#include - -static struct kmem_cache *bio_integrity_slab __read_mostly; -static struct workqueue_struct *kintegrityd_wq; - -/** - * bio_integrity_alloc_bioset - Allocate integrity payload and attach it to bio - * @bio: bio to attach integrity metadata to - * @gfp_mask: Memory allocation mask - * @nr_vecs: Number of integrity metadata scatter-gather elements - * @bs: bio_set to allocate from - * - * Description: This function prepares a bio for attaching integrity - * metadata. nr_vecs specifies the maximum number of pages containing - * integrity metadata that can be attached. - */ -struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *bio, - gfp_t gfp_mask, - unsigned int nr_vecs, - struct bio_set *bs) -{ - struct bio_integrity_payload *bip; - struct bio_vec *iv; - unsigned long idx; - - BUG_ON(bio == NULL); - - bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask); - if (unlikely(bip == NULL)) { - printk(KERN_ERR "%s: could not alloc bip\n", __func__); - return NULL; - } - - memset(bip, 0, sizeof(*bip)); - - iv = bvec_alloc_bs(gfp_mask, nr_vecs, &idx, bs); - if (unlikely(iv == NULL)) { - printk(KERN_ERR "%s: could not alloc bip_vec\n", __func__); - mempool_free(bip, bs->bio_integrity_pool); - return NULL; - } - - bip->bip_pool = idx; - bip->bip_vec = iv; - bip->bip_bio = bio; - bio->bi_integrity = bip; - - return bip; -} -EXPORT_SYMBOL(bio_integrity_alloc_bioset); - -/** - * bio_integrity_alloc - Allocate integrity payload and attach it to bio - * @bio: bio to attach integrity metadata to - * @gfp_mask: Memory allocation mask - * @nr_vecs: Number of integrity metadata scatter-gather elements - * - * Description: This function prepares a bio for attaching integrity - * metadata. nr_vecs specifies the maximum number of pages containing - * integrity metadata that can be attached. - */ -struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, - gfp_t gfp_mask, - unsigned int nr_vecs) -{ - return bio_integrity_alloc_bioset(bio, gfp_mask, nr_vecs, fs_bio_set); -} -EXPORT_SYMBOL(bio_integrity_alloc); - -/** - * bio_integrity_free - Free bio integrity payload - * @bio: bio containing bip to be freed - * @bs: bio_set this bio was allocated from - * - * Description: Used to free the integrity portion of a bio. Usually - * called from bio_free(). - */ -void bio_integrity_free(struct bio *bio, struct bio_set *bs) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - - BUG_ON(bip == NULL); - - /* A cloned bio doesn't own the integrity metadata */ - if (!bio_flagged(bio, BIO_CLONED) && bip->bip_buf != NULL) - kfree(bip->bip_buf); - - mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]); - mempool_free(bip, bs->bio_integrity_pool); - - bio->bi_integrity = NULL; -} -EXPORT_SYMBOL(bio_integrity_free); - -/** - * bio_integrity_add_page - Attach integrity metadata - * @bio: bio to update - * @page: page containing integrity metadata - * @len: number of bytes of integrity metadata in page - * @offset: start offset within page - * - * Description: Attach a page containing integrity metadata to bio. - */ -int bio_integrity_add_page(struct bio *bio, struct page *page, - unsigned int len, unsigned int offset) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct bio_vec *iv; - - if (bip->bip_vcnt >= bvec_nr_vecs(bip->bip_pool)) { - printk(KERN_ERR "%s: bip_vec full\n", __func__); - return 0; - } - - iv = bip_vec_idx(bip, bip->bip_vcnt); - BUG_ON(iv == NULL); - BUG_ON(iv->bv_page != NULL); - - iv->bv_page = page; - iv->bv_len = len; - iv->bv_offset = offset; - bip->bip_vcnt++; - - return len; -} -EXPORT_SYMBOL(bio_integrity_add_page); - -/** - * bio_integrity_enabled - Check whether integrity can be passed - * @bio: bio to check - * - * Description: Determines whether bio_integrity_prep() can be called - * on this bio or not. bio data direction and target device must be - * set prior to calling. The functions honors the write_generate and - * read_verify flags in sysfs. - */ -int bio_integrity_enabled(struct bio *bio) -{ - /* Already protected? */ - if (bio_integrity(bio)) - return 0; - - return bdev_integrity_enabled(bio->bi_bdev, bio_data_dir(bio)); -} -EXPORT_SYMBOL(bio_integrity_enabled); - -/** - * bio_integrity_hw_sectors - Convert 512b sectors to hardware ditto - * @bi: blk_integrity profile for device - * @sectors: Number of 512 sectors to convert - * - * Description: The block layer calculates everything in 512 byte - * sectors but integrity metadata is done in terms of the hardware - * sector size of the storage device. Convert the block layer sectors - * to physical sectors. - */ -static inline unsigned int bio_integrity_hw_sectors(struct blk_integrity *bi, - unsigned int sectors) -{ - /* At this point there are only 512b or 4096b DIF/EPP devices */ - if (bi->sector_size == 4096) - return sectors >>= 3; - - return sectors; -} - -/** - * bio_integrity_tag_size - Retrieve integrity tag space - * @bio: bio to inspect - * - * Description: Returns the maximum number of tag bytes that can be - * attached to this bio. Filesystems can use this to determine how - * much metadata to attach to an I/O. - */ -unsigned int bio_integrity_tag_size(struct bio *bio) -{ - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - - BUG_ON(bio->bi_size == 0); - - return bi->tag_size * (bio->bi_size / bi->sector_size); -} -EXPORT_SYMBOL(bio_integrity_tag_size); - -int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len, int set) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; - - BUG_ON(bip->bip_buf == NULL); - - if (bi->tag_size == 0) - return -1; - - nr_sectors = bio_integrity_hw_sectors(bi, - DIV_ROUND_UP(len, bi->tag_size)); - - if (nr_sectors * bi->tuple_size > bip->bip_size) { - printk(KERN_ERR "%s: tag too big for bio: %u > %u\n", - __func__, nr_sectors * bi->tuple_size, bip->bip_size); - return -1; - } - - if (set) - bi->set_tag_fn(bip->bip_buf, tag_buf, nr_sectors); - else - bi->get_tag_fn(bip->bip_buf, tag_buf, nr_sectors); - - return 0; -} - -/** - * bio_integrity_set_tag - Attach a tag buffer to a bio - * @bio: bio to attach buffer to - * @tag_buf: Pointer to a buffer containing tag data - * @len: Length of the included buffer - * - * Description: Use this function to tag a bio by leveraging the extra - * space provided by devices formatted with integrity protection. The - * size of the integrity buffer must be <= to the size reported by - * bio_integrity_tag_size(). - */ -int bio_integrity_set_tag(struct bio *bio, void *tag_buf, unsigned int len) -{ - BUG_ON(bio_data_dir(bio) != WRITE); - - return bio_integrity_tag(bio, tag_buf, len, 1); -} -EXPORT_SYMBOL(bio_integrity_set_tag); - -/** - * bio_integrity_get_tag - Retrieve a tag buffer from a bio - * @bio: bio to retrieve buffer from - * @tag_buf: Pointer to a buffer for the tag data - * @len: Length of the target buffer - * - * Description: Use this function to retrieve the tag buffer from a - * completed I/O. The size of the integrity buffer must be <= to the - * size reported by bio_integrity_tag_size(). - */ -int bio_integrity_get_tag(struct bio *bio, void *tag_buf, unsigned int len) -{ - BUG_ON(bio_data_dir(bio) != READ); - - return bio_integrity_tag(bio, tag_buf, len, 0); -} -EXPORT_SYMBOL(bio_integrity_get_tag); - -/** - * bio_integrity_generate - Generate integrity metadata for a bio - * @bio: bio to generate integrity metadata for - * - * Description: Generates integrity metadata for a bio by calling the - * block device's generation callback function. The bio must have a - * bip attached with enough room to accommodate the generated - * integrity metadata. - */ -static void bio_integrity_generate(struct bio *bio) -{ - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - struct blk_integrity_exchg bix; - struct bio_vec *bv; - sector_t sector = bio->bi_sector; - unsigned int i, sectors, total; - void *prot_buf = bio->bi_integrity->bip_buf; - - total = 0; - bix.disk_name = bio->bi_bdev->bd_disk->disk_name; - bix.sector_size = bi->sector_size; - - bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page, KM_USER0); - bix.data_buf = kaddr + bv->bv_offset; - bix.data_size = bv->bv_len; - bix.prot_buf = prot_buf; - bix.sector = sector; - - bi->generate_fn(&bix); - - sectors = bv->bv_len / bi->sector_size; - sector += sectors; - prot_buf += sectors * bi->tuple_size; - total += sectors * bi->tuple_size; - BUG_ON(total > bio->bi_integrity->bip_size); - - kunmap_atomic(kaddr, KM_USER0); - } -} - -/** - * bio_integrity_prep - Prepare bio for integrity I/O - * @bio: bio to prepare - * - * Description: Allocates a buffer for integrity metadata, maps the - * pages and attaches them to a bio. The bio must have data - * direction, target device and start sector set priot to calling. In - * the WRITE case, integrity metadata will be generated using the - * block device's integrity function. In the READ case, the buffer - * will be prepared for DMA and a suitable end_io handler set up. - */ -int bio_integrity_prep(struct bio *bio) -{ - struct bio_integrity_payload *bip; - struct blk_integrity *bi; - struct request_queue *q; - void *buf; - unsigned long start, end; - unsigned int len, nr_pages; - unsigned int bytes, offset, i; - unsigned int sectors; - - bi = bdev_get_integrity(bio->bi_bdev); - q = bdev_get_queue(bio->bi_bdev); - BUG_ON(bi == NULL); - BUG_ON(bio_integrity(bio)); - - sectors = bio_integrity_hw_sectors(bi, bio_sectors(bio)); - - /* Allocate kernel buffer for protection data */ - len = sectors * blk_integrity_tuple_size(bi); - buf = kmalloc(len, GFP_NOIO | __GFP_NOFAIL | q->bounce_gfp); - if (unlikely(buf == NULL)) { - printk(KERN_ERR "could not allocate integrity buffer\n"); - return -EIO; - } - - end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - start = ((unsigned long) buf) >> PAGE_SHIFT; - nr_pages = end - start; - - /* Allocate bio integrity payload and integrity vectors */ - bip = bio_integrity_alloc(bio, GFP_NOIO, nr_pages); - if (unlikely(bip == NULL)) { - printk(KERN_ERR "could not allocate data integrity bioset\n"); - kfree(buf); - return -EIO; - } - - bip->bip_buf = buf; - bip->bip_size = len; - bip->bip_sector = bio->bi_sector; - - /* Map it */ - offset = offset_in_page(buf); - for (i = 0 ; i < nr_pages ; i++) { - int ret; - bytes = PAGE_SIZE - offset; - - if (len <= 0) - break; - - if (bytes > len) - bytes = len; - - ret = bio_integrity_add_page(bio, virt_to_page(buf), - bytes, offset); - - if (ret == 0) - return 0; - - if (ret < bytes) - break; - - buf += bytes; - len -= bytes; - offset = 0; - } - - /* Install custom I/O completion handler if read verify is enabled */ - if (bio_data_dir(bio) == READ) { - bip->bip_end_io = bio->bi_end_io; - bio->bi_end_io = bio_integrity_endio; - } - - /* Auto-generate integrity metadata if this is a write */ - if (bio_data_dir(bio) == WRITE) - bio_integrity_generate(bio); - - return 0; -} -EXPORT_SYMBOL(bio_integrity_prep); - -/** - * bio_integrity_verify - Verify integrity metadata for a bio - * @bio: bio to verify - * - * Description: This function is called to verify the integrity of a - * bio. The data in the bio io_vec is compared to the integrity - * metadata returned by the HBA. - */ -static int bio_integrity_verify(struct bio *bio) -{ - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - struct blk_integrity_exchg bix; - struct bio_vec *bv; - sector_t sector = bio->bi_integrity->bip_sector; - unsigned int i, sectors, total, ret; - void *prot_buf = bio->bi_integrity->bip_buf; - - ret = total = 0; - bix.disk_name = bio->bi_bdev->bd_disk->disk_name; - bix.sector_size = bi->sector_size; - - bio_for_each_segment(bv, bio, i) { - void *kaddr = kmap_atomic(bv->bv_page, KM_USER0); - bix.data_buf = kaddr + bv->bv_offset; - bix.data_size = bv->bv_len; - bix.prot_buf = prot_buf; - bix.sector = sector; - - ret = bi->verify_fn(&bix); - - if (ret) { - kunmap_atomic(kaddr, KM_USER0); - break; - } - - sectors = bv->bv_len / bi->sector_size; - sector += sectors; - prot_buf += sectors * bi->tuple_size; - total += sectors * bi->tuple_size; - BUG_ON(total > bio->bi_integrity->bip_size); - - kunmap_atomic(kaddr, KM_USER0); - } - - return ret; -} - -/** - * bio_integrity_verify_fn - Integrity I/O completion worker - * @work: Work struct stored in bio to be verified - * - * Description: This workqueue function is called to complete a READ - * request. The function verifies the transferred integrity metadata - * and then calls the original bio end_io function. - */ -static void bio_integrity_verify_fn(struct work_struct *work) -{ - struct bio_integrity_payload *bip = - container_of(work, struct bio_integrity_payload, bip_work); - struct bio *bio = bip->bip_bio; - int error = bip->bip_error; - - if (bio_integrity_verify(bio)) { - clear_bit(BIO_UPTODATE, &bio->bi_flags); - error = -EIO; - } - - /* Restore original bio completion handler */ - bio->bi_end_io = bip->bip_end_io; - - if (bio->bi_end_io) - bio->bi_end_io(bio, error); -} - -/** - * bio_integrity_endio - Integrity I/O completion function - * @bio: Protected bio - * @error: Pointer to errno - * - * Description: Completion for integrity I/O - * - * Normally I/O completion is done in interrupt context. However, - * verifying I/O integrity is a time-consuming task which must be run - * in process context. This function postpones completion - * accordingly. - */ -void bio_integrity_endio(struct bio *bio, int error) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - - BUG_ON(bip->bip_bio != bio); - - bip->bip_error = error; - INIT_WORK(&bip->bip_work, bio_integrity_verify_fn); - queue_work(kintegrityd_wq, &bip->bip_work); -} -EXPORT_SYMBOL(bio_integrity_endio); - -/** - * bio_integrity_mark_head - Advance bip_vec skip bytes - * @bip: Integrity vector to advance - * @skip: Number of bytes to advance it - */ -void bio_integrity_mark_head(struct bio_integrity_payload *bip, - unsigned int skip) -{ - struct bio_vec *iv; - unsigned int i; - - bip_for_each_vec(iv, bip, i) { - if (skip == 0) { - bip->bip_idx = i; - return; - } else if (skip >= iv->bv_len) { - skip -= iv->bv_len; - } else { /* skip < iv->bv_len) */ - iv->bv_offset += skip; - iv->bv_len -= skip; - bip->bip_idx = i; - return; - } - } -} - -/** - * bio_integrity_mark_tail - Truncate bip_vec to be len bytes long - * @bip: Integrity vector to truncate - * @len: New length of integrity vector - */ -void bio_integrity_mark_tail(struct bio_integrity_payload *bip, - unsigned int len) -{ - struct bio_vec *iv; - unsigned int i; - - bip_for_each_vec(iv, bip, i) { - if (len == 0) { - bip->bip_vcnt = i; - return; - } else if (len >= iv->bv_len) { - len -= iv->bv_len; - } else { /* len < iv->bv_len) */ - iv->bv_len = len; - len = 0; - } - } -} - -/** - * bio_integrity_advance - Advance integrity vector - * @bio: bio whose integrity vector to update - * @bytes_done: number of data bytes that have been completed - * - * Description: This function calculates how many integrity bytes the - * number of completed data bytes correspond to and advances the - * integrity vector accordingly. - */ -void bio_integrity_advance(struct bio *bio, unsigned int bytes_done) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; - - BUG_ON(bip == NULL); - BUG_ON(bi == NULL); - - nr_sectors = bio_integrity_hw_sectors(bi, bytes_done >> 9); - bio_integrity_mark_head(bip, nr_sectors * bi->tuple_size); -} -EXPORT_SYMBOL(bio_integrity_advance); - -/** - * bio_integrity_trim - Trim integrity vector - * @bio: bio whose integrity vector to update - * @offset: offset to first data sector - * @sectors: number of data sectors - * - * Description: Used to trim the integrity vector in a cloned bio. - * The ivec will be advanced corresponding to 'offset' data sectors - * and the length will be truncated corresponding to 'len' data - * sectors. - */ -void bio_integrity_trim(struct bio *bio, unsigned int offset, - unsigned int sectors) -{ - struct bio_integrity_payload *bip = bio->bi_integrity; - struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); - unsigned int nr_sectors; - - BUG_ON(bip == NULL); - BUG_ON(bi == NULL); - BUG_ON(!bio_flagged(bio, BIO_CLONED)); - - nr_sectors = bio_integrity_hw_sectors(bi, sectors); - bip->bip_sector = bip->bip_sector + offset; - bio_integrity_mark_head(bip, offset * bi->tuple_size); - bio_integrity_mark_tail(bip, sectors * bi->tuple_size); -} -EXPORT_SYMBOL(bio_integrity_trim); - -/** - * bio_integrity_split - Split integrity metadata - * @bio: Protected bio - * @bp: Resulting bio_pair - * @sectors: Offset - * - * Description: Splits an integrity page into a bio_pair. - */ -void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors) -{ - struct blk_integrity *bi; - struct bio_integrity_payload *bip = bio->bi_integrity; - unsigned int nr_sectors; - - if (bio_integrity(bio) == 0) - return; - - bi = bdev_get_integrity(bio->bi_bdev); - BUG_ON(bi == NULL); - BUG_ON(bip->bip_vcnt != 1); - - nr_sectors = bio_integrity_hw_sectors(bi, sectors); - - bp->bio1.bi_integrity = &bp->bip1; - bp->bio2.bi_integrity = &bp->bip2; - - bp->iv1 = bip->bip_vec[0]; - bp->iv2 = bip->bip_vec[0]; - - bp->bip1.bip_vec = &bp->iv1; - bp->bip2.bip_vec = &bp->iv2; - - bp->iv1.bv_len = sectors * bi->tuple_size; - bp->iv2.bv_offset += sectors * bi->tuple_size; - bp->iv2.bv_len -= sectors * bi->tuple_size; - - bp->bip1.bip_sector = bio->bi_integrity->bip_sector; - bp->bip2.bip_sector = bio->bi_integrity->bip_sector + nr_sectors; - - bp->bip1.bip_vcnt = bp->bip2.bip_vcnt = 1; - bp->bip1.bip_idx = bp->bip2.bip_idx = 0; -} -EXPORT_SYMBOL(bio_integrity_split); - -/** - * bio_integrity_clone - Callback for cloning bios with integrity metadata - * @bio: New bio - * @bio_src: Original bio - * @bs: bio_set to allocate bip from - * - * Description: Called to allocate a bip when cloning a bio - */ -int bio_integrity_clone(struct bio *bio, struct bio *bio_src, - struct bio_set *bs) -{ - struct bio_integrity_payload *bip_src = bio_src->bi_integrity; - struct bio_integrity_payload *bip; - - BUG_ON(bip_src == NULL); - - bip = bio_integrity_alloc_bioset(bio, GFP_NOIO, bip_src->bip_vcnt, bs); - - if (bip == NULL) - return -EIO; - - memcpy(bip->bip_vec, bip_src->bip_vec, - bip_src->bip_vcnt * sizeof(struct bio_vec)); - - bip->bip_sector = bip_src->bip_sector; - bip->bip_vcnt = bip_src->bip_vcnt; - bip->bip_idx = bip_src->bip_idx; - - return 0; -} -EXPORT_SYMBOL(bio_integrity_clone); - -int bioset_integrity_create(struct bio_set *bs, int pool_size) -{ - bs->bio_integrity_pool = mempool_create_slab_pool(pool_size, - bio_integrity_slab); - if (!bs->bio_integrity_pool) - return -1; - - return 0; -} -EXPORT_SYMBOL(bioset_integrity_create); - -void bioset_integrity_free(struct bio_set *bs) -{ - if (bs->bio_integrity_pool) - mempool_destroy(bs->bio_integrity_pool); -} -EXPORT_SYMBOL(bioset_integrity_free); - -void __init bio_integrity_init_slab(void) -{ - bio_integrity_slab = KMEM_CACHE(bio_integrity_payload, - SLAB_HWCACHE_ALIGN|SLAB_PANIC); -} -EXPORT_SYMBOL(bio_integrity_init_slab); - -static int __init integrity_init(void) -{ - kintegrityd_wq = create_workqueue("kintegrityd"); - - if (!kintegrityd_wq) - panic("Failed to create kintegrityd\n"); - - return 0; -} -subsys_initcall(integrity_init); diff --git a/trunk/fs/bio.c b/trunk/fs/bio.c index 88322b066acb..78562574cb52 100644 --- a/trunk/fs/bio.c +++ b/trunk/fs/bio.c @@ -28,10 +28,25 @@ #include #include /* for struct sg_iovec */ +#define BIO_POOL_SIZE 2 + static struct kmem_cache *bio_slab __read_mostly; +#define BIOVEC_NR_POOLS 6 + +/* + * a small number of entries is fine, not going to be performance critical. + * basically we just need to survive + */ +#define BIO_SPLIT_ENTRIES 2 mempool_t *bio_split_pool __read_mostly; +struct biovec_slab { + int nr_vecs; + char *name; + struct kmem_cache *slab; +}; + /* * if you change this list, also change bvec_alloc or things will * break badly! cannot be bigger than what you can fit into an @@ -44,18 +59,24 @@ static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = { }; #undef BV +/* + * bio_set is used to allow other portions of the IO system to + * allocate their own private memory pools for bio and iovec structures. + * These memory pools in turn all allocate from the bio_slab + * and the bvec_slabs[]. + */ +struct bio_set { + mempool_t *bio_pool; + mempool_t *bvec_pools[BIOVEC_NR_POOLS]; +}; + /* * fs_bio_set is the bio_set containing bio and iovec memory pools used by * IO code that does not need private memory pools. */ -struct bio_set *fs_bio_set; - -unsigned int bvec_nr_vecs(unsigned short idx) -{ - return bvec_slabs[idx].nr_vecs; -} +static struct bio_set *fs_bio_set; -struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs) +static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs) { struct bio_vec *bvl; @@ -96,9 +117,6 @@ void bio_free(struct bio *bio, struct bio_set *bio_set) mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]); } - if (bio_integrity(bio)) - bio_integrity_free(bio, bio_set); - mempool_free(bio, bio_set->bio_pool); } @@ -257,19 +275,9 @@ struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask) { struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set); - if (!b) - return NULL; - - b->bi_destructor = bio_fs_destructor; - __bio_clone(b, bio); - - if (bio_integrity(bio)) { - int ret; - - ret = bio_integrity_clone(b, bio, fs_bio_set); - - if (ret < 0) - return NULL; + if (b) { + b->bi_destructor = bio_fs_destructor; + __bio_clone(b, bio); } return b; @@ -325,19 +333,10 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page if (page == prev->bv_page && offset == prev->bv_offset + prev->bv_len) { prev->bv_len += len; - - if (q->merge_bvec_fn) { - struct bvec_merge_data bvm = { - .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size, - .bi_rw = bio->bi_rw, - }; - - if (q->merge_bvec_fn(q, &bvm, prev) < len) { - prev->bv_len -= len; - return 0; - } + if (q->merge_bvec_fn && + q->merge_bvec_fn(q, bio, prev) < len) { + prev->bv_len -= len; + return 0; } goto done; @@ -378,18 +377,11 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page * queue to get further control */ if (q->merge_bvec_fn) { - struct bvec_merge_data bvm = { - .bi_bdev = bio->bi_bdev, - .bi_sector = bio->bi_sector, - .bi_size = bio->bi_size, - .bi_rw = bio->bi_rw, - }; - /* * merge_bvec_fn() returns number of bytes it can accept * at this offset */ - if (q->merge_bvec_fn(q, &bvm, bvec) < len) { + if (q->merge_bvec_fn(q, bio, bvec) < len) { bvec->bv_page = NULL; bvec->bv_len = 0; bvec->bv_offset = 0; @@ -1257,9 +1249,6 @@ struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors) bp->bio1.bi_private = bi; bp->bio2.bi_private = pool; - if (bio_integrity(bi)) - bio_integrity_split(bi, bp, first_sectors); - return bp; } @@ -1301,7 +1290,6 @@ void bioset_free(struct bio_set *bs) if (bs->bio_pool) mempool_destroy(bs->bio_pool); - bioset_integrity_free(bs); biovec_free_pools(bs); kfree(bs); @@ -1318,9 +1306,6 @@ struct bio_set *bioset_create(int bio_pool_size, int bvec_pool_size) if (!bs->bio_pool) goto bad; - if (bioset_integrity_create(bs, bio_pool_size)) - goto bad; - if (!biovec_create_pools(bs, bvec_pool_size)) return bs; @@ -1347,7 +1332,6 @@ static int __init init_bio(void) { bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC); - bio_integrity_init_slab(); biovec_init_slabs(); fs_bio_set = bioset_create(BIO_POOL_SIZE, 2); diff --git a/trunk/fs/ramfs/file-mmu.c b/trunk/fs/ramfs/file-mmu.c index 78f613cb9c76..9590b9024300 100644 --- a/trunk/fs/ramfs/file-mmu.c +++ b/trunk/fs/ramfs/file-mmu.c @@ -45,7 +45,6 @@ const struct file_operations ramfs_file_operations = { .mmap = generic_file_mmap, .fsync = simple_sync_file, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, .llseek = generic_file_llseek, }; diff --git a/trunk/fs/ramfs/file-nommu.c b/trunk/fs/ramfs/file-nommu.c index 52312ec93ff4..0989bc2c2f69 100644 --- a/trunk/fs/ramfs/file-nommu.c +++ b/trunk/fs/ramfs/file-nommu.c @@ -43,7 +43,6 @@ const struct file_operations ramfs_file_operations = { .aio_write = generic_file_aio_write, .fsync = simple_sync_file, .splice_read = generic_file_splice_read, - .splice_write = generic_file_splice_write, .llseek = generic_file_llseek, }; diff --git a/trunk/fs/splice.c b/trunk/fs/splice.c index 399442179d89..aa5f6f60b305 100644 --- a/trunk/fs/splice.c +++ b/trunk/fs/splice.c @@ -379,22 +379,13 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, lock_page(page); /* - * Page was truncated, or invalidated by the - * filesystem. Redo the find/create, but this time the - * page is kept locked, so there's no chance of another - * race with truncate/invalidate. + * page was truncated, stop here. if this isn't the + * first page, we'll just complete what we already + * added */ if (!page->mapping) { unlock_page(page); - page = find_or_create_page(mapping, index, - mapping_gfp_mask(mapping)); - - if (!page) { - error = -ENOMEM; - break; - } - page_cache_release(pages[page_nr]); - pages[page_nr] = page; + break; } /* * page was already under io and is now done, great diff --git a/trunk/include/asm-s390/Kbuild b/trunk/include/asm-s390/Kbuild index 09f312501eb5..13c9805349f1 100644 --- a/trunk/include/asm-s390/Kbuild +++ b/trunk/include/asm-s390/Kbuild @@ -8,9 +8,6 @@ header-y += ucontext.h header-y += vtoc.h header-y += zcrypt.h header-y += kvm.h -header-y += schid.h -header-y += chsc.h unifdef-y += cmb.h unifdef-y += debug.h -unifdef-y += chpid.h diff --git a/trunk/include/asm-s390/airq.h b/trunk/include/asm-s390/airq.h index 1ac80d6b0588..41d028cb52a4 100644 --- a/trunk/include/asm-s390/airq.h +++ b/trunk/include/asm-s390/airq.h @@ -13,7 +13,7 @@ typedef void (*adapter_int_handler_t)(void *, void *); -void *s390_register_adapter_interrupt(adapter_int_handler_t, void *, u8); -void s390_unregister_adapter_interrupt(void *, u8); +void *s390_register_adapter_interrupt(adapter_int_handler_t, void *); +void s390_unregister_adapter_interrupt(void *); #endif /* _ASM_S390_AIRQ_H */ diff --git a/trunk/include/asm-s390/ccwdev.h b/trunk/include/asm-s390/ccwdev.h index ba007d8df941..066aa70518ce 100644 --- a/trunk/include/asm-s390/ccwdev.h +++ b/trunk/include/asm-s390/ccwdev.h @@ -12,7 +12,6 @@ #include #include -#include /* structs from asm/cio.h */ struct irb; @@ -158,17 +157,6 @@ extern int ccw_device_start_timeout_key(struct ccw_device *, struct ccw1 *, extern int ccw_device_resume(struct ccw_device *); extern int ccw_device_halt(struct ccw_device *, unsigned long); extern int ccw_device_clear(struct ccw_device *, unsigned long); -int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, - unsigned long intparm, u8 lpm, u8 key); -int ccw_device_tm_start_key(struct ccw_device *, struct tcw *, - unsigned long, u8, u8); -int ccw_device_tm_start_timeout_key(struct ccw_device *, struct tcw *, - unsigned long, u8, u8, int); -int ccw_device_tm_start(struct ccw_device *, struct tcw *, - unsigned long, u8); -int ccw_device_tm_start_timeout(struct ccw_device *, struct tcw *, - unsigned long, u8, int); -int ccw_device_tm_intrg(struct ccw_device *cdev); extern int ccw_device_set_online(struct ccw_device *cdev); extern int ccw_device_set_offline(struct ccw_device *cdev); diff --git a/trunk/include/asm-s390/chpid.h b/trunk/include/asm-s390/chpid.h index 606844d0a5c3..b203336fd892 100644 --- a/trunk/include/asm-s390/chpid.h +++ b/trunk/include/asm-s390/chpid.h @@ -10,6 +10,7 @@ #include #include +#include #define __MAX_CHPID 255 @@ -40,9 +41,6 @@ static inline void chp_id_next(struct chp_id *chpid) } } -#ifdef __KERNEL__ -#include - static inline int chp_id_is_valid(struct chp_id *chpid) { return (chpid->cssid <= __MAX_CSSID); @@ -51,6 +49,5 @@ static inline int chp_id_is_valid(struct chp_id *chpid) #define chp_id_for_each(c) \ for (chp_id_init(c); chp_id_is_valid(c); chp_id_next(c)) -#endif /* __KERNEL */ #endif /* _ASM_S390_CHPID_H */ diff --git a/trunk/include/asm-s390/chsc.h b/trunk/include/asm-s390/chsc.h deleted file mode 100644 index d38d0cf62d4b..000000000000 --- a/trunk/include/asm-s390/chsc.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ioctl interface for /dev/chsc - * - * Copyright 2008 IBM Corp. - * Author(s): Cornelia Huck - */ - -#ifndef _ASM_CHSC_H -#define _ASM_CHSC_H - -#include -#include - -struct chsc_async_header { - __u16 length; - __u16 code; - __u32 cmd_dependend; - __u32 key : 4; - __u32 : 28; - struct subchannel_id sid; -} __attribute__ ((packed)); - -struct chsc_async_area { - struct chsc_async_header header; - __u8 data[PAGE_SIZE - 16 /* size of chsc_async_header */]; -} __attribute__ ((packed)); - - -struct chsc_response_struct { - __u16 length; - __u16 code; - __u32 parms; - __u8 data[PAGE_SIZE - 8]; -} __attribute__ ((packed)); - -struct chsc_chp_cd { - struct chp_id chpid; - int m; - int fmt; - struct chsc_response_struct cpcb; -}; - -struct chsc_cu_cd { - __u16 cun; - __u8 cssid; - int m; - int fmt; - struct chsc_response_struct cucb; -}; - -struct chsc_sch_cud { - struct subchannel_id schid; - int fmt; - struct chsc_response_struct scub; -}; - -struct conf_id { - int m; - __u8 cssid; - __u8 ssid; -}; - -struct chsc_conf_info { - struct conf_id id; - int fmt; - struct chsc_response_struct scid; -}; - -struct ccl_parm_chpid { - int m; - struct chp_id chp; -}; - -struct ccl_parm_cssids { - __u8 f_cssid; - __u8 l_cssid; -}; - -struct chsc_comp_list { - struct { - enum { - CCL_CU_ON_CHP = 1, - CCL_CHP_TYPE_CAP = 2, - CCL_CSS_IMG = 4, - CCL_CSS_IMG_CONF_CHAR = 5, - CCL_IOP_CHP = 6, - } ctype; - int fmt; - struct ccl_parm_chpid chpid; - struct ccl_parm_cssids cssids; - } req; - struct chsc_response_struct sccl; -}; - -struct chsc_dcal { - struct { - enum { - DCAL_CSS_IID_PN = 4, - } atype; - __u32 list_parm[2]; - int fmt; - } req; - struct chsc_response_struct sdcal; -}; - -struct chsc_cpd_info { - struct chp_id chpid; - int m; - int fmt; - int rfmt; - int c; - struct chsc_response_struct chpdb; -}; - -#define CHSC_IOCTL_MAGIC 'c' - -#define CHSC_START _IOWR(CHSC_IOCTL_MAGIC, 0x81, struct chsc_async_area) -#define CHSC_INFO_CHANNEL_PATH _IOWR(CHSC_IOCTL_MAGIC, 0x82, \ - struct chsc_chp_cd) -#define CHSC_INFO_CU _IOWR(CHSC_IOCTL_MAGIC, 0x83, struct chsc_cu_cd) -#define CHSC_INFO_SCH_CU _IOWR(CHSC_IOCTL_MAGIC, 0x84, struct chsc_sch_cud) -#define CHSC_INFO_CI _IOWR(CHSC_IOCTL_MAGIC, 0x85, struct chsc_conf_info) -#define CHSC_INFO_CCL _IOWR(CHSC_IOCTL_MAGIC, 0x86, struct chsc_comp_list) -#define CHSC_INFO_CPD _IOWR(CHSC_IOCTL_MAGIC, 0x87, struct chsc_cpd_info) -#define CHSC_INFO_DCAL _IOWR(CHSC_IOCTL_MAGIC, 0x88, struct chsc_dcal) - -#endif diff --git a/trunk/include/asm-s390/cio.h b/trunk/include/asm-s390/cio.h index 6dccb071aec3..0818ecd30ca6 100644 --- a/trunk/include/asm-s390/cio.h +++ b/trunk/include/asm-s390/cio.h @@ -16,7 +16,7 @@ #define __MAX_CSSID 0 /** - * struct cmd_scsw - command-mode subchannel status word + * struct scsw - subchannel status word * @key: subchannel key * @sctl: suspend control * @eswf: esw format @@ -38,7 +38,7 @@ * @cstat: subchannel status * @count: residual count */ -struct cmd_scsw { +struct scsw { __u32 key : 4; __u32 sctl : 1; __u32 eswf : 1; @@ -61,114 +61,6 @@ struct cmd_scsw { __u32 count : 16; } __attribute__ ((packed)); -/** - * struct tm_scsw - transport-mode subchannel status word - * @key: subchannel key - * @eswf: esw format - * @cc: deferred condition code - * @fmt: format - * @x: IRB-format control - * @q: interrogate-complete - * @ectl: extended control - * @pno: path not operational - * @fctl: function control - * @actl: activity control - * @stctl: status control - * @tcw: TCW address - * @dstat: device status - * @cstat: subchannel status - * @fcxs: FCX status - * @schxs: subchannel-extended status - */ -struct tm_scsw { - u32 key:4; - u32 :1; - u32 eswf:1; - u32 cc:2; - u32 fmt:3; - u32 x:1; - u32 q:1; - u32 :1; - u32 ectl:1; - u32 pno:1; - u32 :1; - u32 fctl:3; - u32 actl:7; - u32 stctl:5; - u32 tcw; - u32 dstat:8; - u32 cstat:8; - u32 fcxs:8; - u32 schxs:8; -} __attribute__ ((packed)); - -/** - * union scsw - subchannel status word - * @cmd: command-mode SCSW - * @tm: transport-mode SCSW - */ -union scsw { - struct cmd_scsw cmd; - struct tm_scsw tm; -} __attribute__ ((packed)); - -int scsw_is_tm(union scsw *scsw); -u32 scsw_key(union scsw *scsw); -u32 scsw_eswf(union scsw *scsw); -u32 scsw_cc(union scsw *scsw); -u32 scsw_ectl(union scsw *scsw); -u32 scsw_pno(union scsw *scsw); -u32 scsw_fctl(union scsw *scsw); -u32 scsw_actl(union scsw *scsw); -u32 scsw_stctl(union scsw *scsw); -u32 scsw_dstat(union scsw *scsw); -u32 scsw_cstat(union scsw *scsw); -int scsw_is_solicited(union scsw *scsw); -int scsw_is_valid_key(union scsw *scsw); -int scsw_is_valid_eswf(union scsw *scsw); -int scsw_is_valid_cc(union scsw *scsw); -int scsw_is_valid_ectl(union scsw *scsw); -int scsw_is_valid_pno(union scsw *scsw); -int scsw_is_valid_fctl(union scsw *scsw); -int scsw_is_valid_actl(union scsw *scsw); -int scsw_is_valid_stctl(union scsw *scsw); -int scsw_is_valid_dstat(union scsw *scsw); -int scsw_is_valid_cstat(union scsw *scsw); -int scsw_cmd_is_valid_key(union scsw *scsw); -int scsw_cmd_is_valid_sctl(union scsw *scsw); -int scsw_cmd_is_valid_eswf(union scsw *scsw); -int scsw_cmd_is_valid_cc(union scsw *scsw); -int scsw_cmd_is_valid_fmt(union scsw *scsw); -int scsw_cmd_is_valid_pfch(union scsw *scsw); -int scsw_cmd_is_valid_isic(union scsw *scsw); -int scsw_cmd_is_valid_alcc(union scsw *scsw); -int scsw_cmd_is_valid_ssi(union scsw *scsw); -int scsw_cmd_is_valid_zcc(union scsw *scsw); -int scsw_cmd_is_valid_ectl(union scsw *scsw); -int scsw_cmd_is_valid_pno(union scsw *scsw); -int scsw_cmd_is_valid_fctl(union scsw *scsw); -int scsw_cmd_is_valid_actl(union scsw *scsw); -int scsw_cmd_is_valid_stctl(union scsw *scsw); -int scsw_cmd_is_valid_dstat(union scsw *scsw); -int scsw_cmd_is_valid_cstat(union scsw *scsw); -int scsw_cmd_is_solicited(union scsw *scsw); -int scsw_tm_is_valid_key(union scsw *scsw); -int scsw_tm_is_valid_eswf(union scsw *scsw); -int scsw_tm_is_valid_cc(union scsw *scsw); -int scsw_tm_is_valid_fmt(union scsw *scsw); -int scsw_tm_is_valid_x(union scsw *scsw); -int scsw_tm_is_valid_q(union scsw *scsw); -int scsw_tm_is_valid_ectl(union scsw *scsw); -int scsw_tm_is_valid_pno(union scsw *scsw); -int scsw_tm_is_valid_fctl(union scsw *scsw); -int scsw_tm_is_valid_actl(union scsw *scsw); -int scsw_tm_is_valid_stctl(union scsw *scsw); -int scsw_tm_is_valid_dstat(union scsw *scsw); -int scsw_tm_is_valid_cstat(union scsw *scsw); -int scsw_tm_is_valid_fcxs(union scsw *scsw); -int scsw_tm_is_valid_schxs(union scsw *scsw); -int scsw_tm_is_solicited(union scsw *scsw); - #define SCSW_FCTL_CLEAR_FUNC 0x1 #define SCSW_FCTL_HALT_FUNC 0x2 #define SCSW_FCTL_START_FUNC 0x4 @@ -411,7 +303,7 @@ struct esw3 { * if applicable). */ struct irb { - union scsw scsw; + struct scsw scsw; union { struct esw0 esw0; struct esw1 esw1; diff --git a/trunk/include/asm-s390/elf.h b/trunk/include/asm-s390/elf.h index 3cad56923815..b3ac262c4582 100644 --- a/trunk/include/asm-s390/elf.h +++ b/trunk/include/asm-s390/elf.h @@ -113,9 +113,6 @@ typedef s390_fp_regs elf_fpregset_t; typedef s390_regs elf_gregset_t; -typedef s390_fp_regs compat_elf_fpregset_t; -typedef s390_compat_regs compat_elf_gregset_t; - #include /* for task_struct */ #include /* for save_access_regs */ #include @@ -126,10 +123,6 @@ typedef s390_compat_regs compat_elf_gregset_t; #define elf_check_arch(x) \ (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ && (x)->e_ident[EI_CLASS] == ELF_CLASS) -#define compat_elf_check_arch(x) \ - (((x)->e_machine == EM_S390 || (x)->e_machine == EM_S390_OLD) \ - && (x)->e_ident[EI_CLASS] == ELF_CLASS) -#define compat_start_thread start_thread31 /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ @@ -138,7 +131,6 @@ typedef s390_compat_regs compat_elf_gregset_t; _r->gprs[14] = 0; \ } while (0) -#define CORE_DUMP_USE_REGSET #define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 @@ -148,6 +140,44 @@ typedef s390_compat_regs compat_elf_gregset_t; that it will "exec", and that there is sufficient room for the brk. */ #define ELF_ET_DYN_BASE (STACK_TOP / 3 * 2) +/* Wow, the "main" arch needs arch dependent functions too.. :) */ + +/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is + now struct_user_regs, they are different) */ + +static inline int dump_regs(struct pt_regs *ptregs, elf_gregset_t *regs) +{ + memcpy(®s->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs)); + save_access_regs(regs->acrs); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +#define ELF_CORE_COPY_REGS(pr_reg, regs) dump_regs(regs, &pr_reg); + +static inline int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) +{ + struct pt_regs *ptregs = task_pt_regs(tsk); + memcpy(®s->psw, &ptregs->psw, sizeof(regs->psw)+sizeof(regs->gprs)); + memcpy(regs->acrs, tsk->thread.acrs, sizeof(regs->acrs)); + regs->orig_gpr2 = ptregs->orig_gpr2; + return 1; +} + +#define ELF_CORE_COPY_TASK_REGS(tsk, regs) dump_task_regs(tsk, regs) + +static inline int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +{ + if (tsk == current) + save_fp_regs(fpregs); + else + memcpy(fpregs, &tsk->thread.fp_regs, sizeof(elf_fpregset_t)); + return 1; +} + +#define ELF_CORE_COPY_FPREGS(tsk, fpregs) dump_task_fpu(tsk, fpregs) + + /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. */ @@ -174,10 +204,7 @@ do { \ set_personality(PER_SVR4); \ else if (current->personality != PER_LINUX32) \ set_personality(PER_LINUX); \ - if ((ex).e_ident[EI_CLASS] == ELFCLASS32) \ - set_thread_flag(TIF_31BIT); \ - else \ - clear_thread_flag(TIF_31BIT); \ + clear_thread_flag(TIF_31BIT); \ } while (0) #endif /* __s390x__ */ diff --git a/trunk/include/asm-s390/etr.h b/trunk/include/asm-s390/etr.h index 80ef58c61970..b498f19bb9a7 100644 --- a/trunk/include/asm-s390/etr.h +++ b/trunk/include/asm-s390/etr.h @@ -122,7 +122,7 @@ struct etr_aib { } __attribute__ ((packed,aligned(8))); /* ETR interruption parameter */ -struct etr_irq_parm { +struct etr_interruption_parameter { unsigned int _pad0 : 8; unsigned int pc0 : 1; /* port 0 state change */ unsigned int pc1 : 1; /* port 1 state change */ @@ -213,46 +213,7 @@ static inline int etr_ptff(void *ptff_block, unsigned int func) #define ETR_PTFF_SGS 0x43 /* set gross steering rate */ /* Functions needed by the machine check handler */ -void etr_switch_to_local(void); -void etr_sync_check(void); - -/* STP interruption parameter */ -struct stp_irq_parm { - unsigned int _pad0 : 14; - unsigned int tsc : 1; /* Timing status change */ - unsigned int lac : 1; /* Link availability change */ - unsigned int tcpc : 1; /* Time control parameter change */ - unsigned int _pad2 : 15; -} __attribute__ ((packed)); - -#define STP_OP_SYNC 1 -#define STP_OP_CTRL 3 - -struct stp_sstpi { - unsigned int rsvd0; - unsigned int rsvd1 : 8; - unsigned int stratum : 8; - unsigned int vbits : 16; - unsigned int leaps : 16; - unsigned int tmd : 4; - unsigned int ctn : 4; - unsigned int rsvd2 : 3; - unsigned int c : 1; - unsigned int tst : 4; - unsigned int tzo : 16; - unsigned int dsto : 16; - unsigned int ctrl : 16; - unsigned int rsvd3 : 16; - unsigned int tto; - unsigned int rsvd4; - unsigned int ctnid[3]; - unsigned int rsvd5; - unsigned int todoff[4]; - unsigned int rsvd6[48]; -} __attribute__ ((packed)); - -/* Functions needed by the machine check handler */ -void stp_sync_check(void); -void stp_island_check(void); +extern void etr_switch_to_local(void); +extern void etr_sync_check(void); #endif /* __S390_ETR_H */ diff --git a/trunk/include/asm-s390/fcx.h b/trunk/include/asm-s390/fcx.h deleted file mode 100644 index 8be1f3a58042..000000000000 --- a/trunk/include/asm-s390/fcx.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Functions for assembling fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#ifndef _ASM_S390_FCX_H -#define _ASM_S390_FCX_H _ASM_S390_FCX_H - -#include - -#define TCW_FORMAT_DEFAULT 0 -#define TCW_TIDAW_FORMAT_DEFAULT 0 -#define TCW_FLAGS_INPUT_TIDA 1 << (23 - 5) -#define TCW_FLAGS_TCCB_TIDA 1 << (23 - 6) -#define TCW_FLAGS_OUTPUT_TIDA 1 << (23 - 7) -#define TCW_FLAGS_TIDAW_FORMAT(x) ((x) & 3) << (23 - 9) -#define TCW_FLAGS_GET_TIDAW_FORMAT(x) (((x) >> (23 - 9)) & 3) - -/** - * struct tcw - Transport Control Word (TCW) - * @format: TCW format - * @flags: TCW flags - * @tccbl: Transport-Command-Control-Block Length - * @r: Read Operations - * @w: Write Operations - * @output: Output-Data Address - * @input: Input-Data Address - * @tsb: Transport-Status-Block Address - * @tccb: Transport-Command-Control-Block Address - * @output_count: Output Count - * @input_count: Input Count - * @intrg: Interrogate TCW Address - */ -struct tcw { - u32 format:2; - u32 :6; - u32 flags:24; - u32 :8; - u32 tccbl:6; - u32 r:1; - u32 w:1; - u32 :16; - u64 output; - u64 input; - u64 tsb; - u64 tccb; - u32 output_count; - u32 input_count; - u32 :32; - u32 :32; - u32 :32; - u32 intrg; -} __attribute__ ((packed, aligned(64))); - -#define TIDAW_FLAGS_LAST 1 << (7 - 0) -#define TIDAW_FLAGS_SKIP 1 << (7 - 1) -#define TIDAW_FLAGS_DATA_INT 1 << (7 - 2) -#define TIDAW_FLAGS_TTIC 1 << (7 - 3) -#define TIDAW_FLAGS_INSERT_CBC 1 << (7 - 4) - -/** - * struct tidaw - Transport-Indirect-Addressing Word (TIDAW) - * @flags: TIDAW flags. Can be an arithmetic OR of the following constants: - * %TIDAW_FLAGS_LAST, %TIDAW_FLAGS_SKIP, %TIDAW_FLAGS_DATA_INT, - * %TIDAW_FLAGS_TTIC, %TIDAW_FLAGS_INSERT_CBC - * @count: Count - * @addr: Address - */ -struct tidaw { - u32 flags:8; - u32 :24; - u32 count; - u64 addr; -} __attribute__ ((packed, aligned(16))); - -/** - * struct tsa_iostat - I/O-Status Transport-Status Area (IO-Stat TSA) - * @dev_time: Device Time - * @def_time: Defer Time - * @queue_time: Queue Time - * @dev_busy_time: Device-Busy Time - * @dev_act_time: Device-Active-Only Time - * @sense: Sense Data (if present) - */ -struct tsa_iostat { - u32 dev_time; - u32 def_time; - u32 queue_time; - u32 dev_busy_time; - u32 dev_act_time; - u8 sense[32]; -} __attribute__ ((packed)); - -/** - * struct tsa_ddpcs - Device-Detected-Program-Check Transport-Status Area (DDPC TSA) - * @rc: Reason Code - * @rcq: Reason Code Qualifier - * @sense: Sense Data (if present) - */ -struct tsa_ddpc { - u32 :24; - u32 rc:8; - u8 rcq[16]; - u8 sense[32]; -} __attribute__ ((packed)); - -#define TSA_INTRG_FLAGS_CU_STATE_VALID 1 << (7 - 0) -#define TSA_INTRG_FLAGS_DEV_STATE_VALID 1 << (7 - 1) -#define TSA_INTRG_FLAGS_OP_STATE_VALID 1 << (7 - 2) - -/** - * struct tsa_intrg - Interrogate Transport-Status Area (Intrg. TSA) - * @format: Format - * @flags: Flags. Can be an arithmetic OR of the following constants: - * %TSA_INTRG_FLAGS_CU_STATE_VALID, %TSA_INTRG_FLAGS_DEV_STATE_VALID, - * %TSA_INTRG_FLAGS_OP_STATE_VALID - * @cu_state: Controle-Unit State - * @dev_state: Device State - * @op_state: Operation State - * @sd_info: State-Dependent Information - * @dl_id: Device-Level Identifier - * @dd_data: Device-Dependent Data - */ -struct tsa_intrg { - u32 format:8; - u32 flags:8; - u32 cu_state:8; - u32 dev_state:8; - u32 op_state:8; - u32 :24; - u8 sd_info[12]; - u32 dl_id; - u8 dd_data[28]; -} __attribute__ ((packed)); - -#define TSB_FORMAT_NONE 0 -#define TSB_FORMAT_IOSTAT 1 -#define TSB_FORMAT_DDPC 2 -#define TSB_FORMAT_INTRG 3 - -#define TSB_FLAGS_DCW_OFFSET_VALID 1 << (7 - 0) -#define TSB_FLAGS_COUNT_VALID 1 << (7 - 1) -#define TSB_FLAGS_CACHE_MISS 1 << (7 - 2) -#define TSB_FLAGS_TIME_VALID 1 << (7 - 3) -#define TSB_FLAGS_FORMAT(x) ((x) & 7) -#define TSB_FORMAT(t) ((t)->flags & 7) - -/** - * struct tsb - Transport-Status Block (TSB) - * @length: Length - * @flags: Flags. Can be an arithmetic OR of the following constants: - * %TSB_FLAGS_DCW_OFFSET_VALID, %TSB_FLAGS_COUNT_VALID, %TSB_FLAGS_CACHE_MISS, - * %TSB_FLAGS_TIME_VALID - * @dcw_offset: DCW Offset - * @count: Count - * @tsa: Transport-Status-Area - */ -struct tsb { - u32 length:8; - u32 flags:8; - u32 dcw_offset:16; - u32 count; - u32 :32; - union { - struct tsa_iostat iostat; - struct tsa_ddpc ddpc; - struct tsa_intrg intrg; - } __attribute__ ((packed)) tsa; -} __attribute__ ((packed, aligned(8))); - -#define DCW_INTRG_FORMAT_DEFAULT 0 - -#define DCW_INTRG_RC_UNSPECIFIED 0 -#define DCW_INTRG_RC_TIMEOUT 1 - -#define DCW_INTRG_RCQ_UNSPECIFIED 0 -#define DCW_INTRG_RCQ_PRIMARY 1 -#define DCW_INTRG_RCQ_SECONDARY 2 - -#define DCW_INTRG_FLAGS_MPM 1 < (7 - 0) -#define DCW_INTRG_FLAGS_PPR 1 < (7 - 1) -#define DCW_INTRG_FLAGS_CRIT 1 < (7 - 2) - -/** - * struct dcw_intrg_data - Interrogate DCW data - * @format: Format. Should be %DCW_INTRG_FORMAT_DEFAULT - * @rc: Reason Code. Can be one of %DCW_INTRG_RC_UNSPECIFIED, - * %DCW_INTRG_RC_TIMEOUT - * @rcq: Reason Code Qualifier: Can be one of %DCW_INTRG_RCQ_UNSPECIFIED, - * %DCW_INTRG_RCQ_PRIMARY, %DCW_INTRG_RCQ_SECONDARY - * @lpm: Logical-Path Mask - * @pam: Path-Available Mask - * @pim: Path-Installed Mask - * @timeout: Timeout - * @flags: Flags. Can be an arithmetic OR of %DCW_INTRG_FLAGS_MPM, - * %DCW_INTRG_FLAGS_PPR, %DCW_INTRG_FLAGS_CRIT - * @time: Time - * @prog_id: Program Identifier - * @prog_data: Program-Dependent Data - */ -struct dcw_intrg_data { - u32 format:8; - u32 rc:8; - u32 rcq:8; - u32 lpm:8; - u32 pam:8; - u32 pim:8; - u32 timeout:16; - u32 flags:8; - u32 :24; - u32 :32; - u64 time; - u64 prog_id; - u8 prog_data[0]; -} __attribute__ ((packed)); - -#define DCW_FLAGS_CC 1 << (7 - 1) - -#define DCW_CMD_WRITE 0x01 -#define DCW_CMD_READ 0x02 -#define DCW_CMD_CONTROL 0x03 -#define DCW_CMD_SENSE 0x04 -#define DCW_CMD_SENSE_ID 0xe4 -#define DCW_CMD_INTRG 0x40 - -/** - * struct dcw - Device-Command Word (DCW) - * @cmd: Command Code. Can be one of %DCW_CMD_WRITE, %DCW_CMD_READ, - * %DCW_CMD_CONTROL, %DCW_CMD_SENSE, %DCW_CMD_SENSE_ID, %DCW_CMD_INTRG - * @flags: Flags. Can be an arithmetic OR of %DCW_FLAGS_CC - * @cd_count: Control-Data Count - * @count: Count - * @cd: Control Data - */ -struct dcw { - u32 cmd:8; - u32 flags:8; - u32 :8; - u32 cd_count:8; - u32 count; - u8 cd[0]; -} __attribute__ ((packed)); - -#define TCCB_FORMAT_DEFAULT 0x7f -#define TCCB_MAX_DCW 30 -#define TCCB_MAX_SIZE (sizeof(struct tccb_tcah) + \ - TCCB_MAX_DCW * sizeof(struct dcw) + \ - sizeof(struct tccb_tcat)) -#define TCCB_SAC_DEFAULT 0xf901 -#define TCCB_SAC_INTRG 0xf902 - -/** - * struct tccb_tcah - Transport-Command-Area Header (TCAH) - * @format: Format. Should be %TCCB_FORMAT_DEFAULT - * @tcal: Transport-Command-Area Length - * @sac: Service-Action Code. Can be one of %TCCB_SAC_DEFAULT, %TCCB_SAC_INTRG - * @prio: Priority - */ -struct tccb_tcah { - u32 format:8; - u32 :24; - u32 :24; - u32 tcal:8; - u32 sac:16; - u32 :8; - u32 prio:8; - u32 :32; -} __attribute__ ((packed)); - -/** - * struct tccb_tcat - Transport-Command-Area Trailer (TCAT) - * @count: Transport Count - */ -struct tccb_tcat { - u32 :32; - u32 count; -} __attribute__ ((packed)); - -/** - * struct tccb - (partial) Transport-Command-Control Block (TCCB) - * @tcah: TCAH - * @tca: Transport-Command Area - */ -struct tccb { - struct tccb_tcah tcah; - u8 tca[0]; -} __attribute__ ((packed, aligned(8))); - -struct tcw *tcw_get_intrg(struct tcw *tcw); -void *tcw_get_data(struct tcw *tcw); -struct tccb *tcw_get_tccb(struct tcw *tcw); -struct tsb *tcw_get_tsb(struct tcw *tcw); - -void tcw_init(struct tcw *tcw, int r, int w); -void tcw_finalize(struct tcw *tcw, int num_tidaws); - -void tcw_set_intrg(struct tcw *tcw, struct tcw *intrg_tcw); -void tcw_set_data(struct tcw *tcw, void *data, int use_tidal); -void tcw_set_tccb(struct tcw *tcw, struct tccb *tccb); -void tcw_set_tsb(struct tcw *tcw, struct tsb *tsb); - -void tccb_init(struct tccb *tccb, size_t tccb_size, u32 sac); -void tsb_init(struct tsb *tsb); -struct dcw *tccb_add_dcw(struct tccb *tccb, size_t tccb_size, u8 cmd, u8 flags, - void *cd, u8 cd_count, u32 count); -struct tidaw *tcw_add_tidaw(struct tcw *tcw, int num_tidaws, u8 flags, - void *addr, u32 count); - -#endif /* _ASM_S390_FCX_H */ diff --git a/trunk/include/asm-s390/ipl.h b/trunk/include/asm-s390/ipl.h index eaca6dff5405..c1b2e50392bb 100644 --- a/trunk/include/asm-s390/ipl.h +++ b/trunk/include/asm-s390/ipl.h @@ -56,19 +56,15 @@ struct ipl_block_fcp { u8 scp_data[]; } __attribute__((packed)); -#define DIAG308_VMPARM_SIZE 64 - struct ipl_block_ccw { - u8 load_parm[8]; + u8 load_param[8]; u8 reserved1[84]; u8 reserved2[2]; u16 devno; u8 vm_flags; u8 reserved3[3]; u32 vm_parm_len; - u8 nss_name[8]; - u8 vm_parm[DIAG308_VMPARM_SIZE]; - u8 reserved4[8]; + u8 reserved4[80]; } __attribute__((packed)); struct ipl_parameter_block { @@ -77,7 +73,7 @@ struct ipl_parameter_block { struct ipl_block_fcp fcp; struct ipl_block_ccw ccw; } ipl_info; -} __attribute__((packed,aligned(4096))); +} __attribute__((packed)); /* * IPL validity flags @@ -90,8 +86,6 @@ extern void do_reipl(void); extern void do_halt(void); extern void do_poff(void); extern void ipl_save_parameters(void); -extern void ipl_update_parameters(void); -extern void get_ipl_vmparm(char *); enum { IPL_DEVNO_VALID = 1, @@ -153,11 +147,6 @@ enum diag308_flags { DIAG308_FLAGS_LP_VALID = 0x80, }; -enum diag308_vm_flags { - DIAG308_VM_FLAGS_NSS_VALID = 0x80, - DIAG308_VM_FLAGS_VP_VALID = 0x40, -}; - enum diag308_rc { DIAG308_RC_OK = 1, }; diff --git a/trunk/include/asm-s390/isc.h b/trunk/include/asm-s390/isc.h deleted file mode 100644 index 34bb8916db4f..000000000000 --- a/trunk/include/asm-s390/isc.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _ASM_S390_ISC_H -#define _ASM_S390_ISC_H - -#include - -/* - * I/O interruption subclasses used by drivers. - * Please add all used iscs here so that it is possible to distribute - * isc usage between drivers. - * Reminder: 0 is highest priority, 7 lowest. - */ -#define MAX_ISC 7 - -/* Regular I/O interrupts. */ -#define IO_SCH_ISC 3 /* regular I/O subchannels */ -#define CONSOLE_ISC 1 /* console I/O subchannel */ -#define CHSC_SCH_ISC 7 /* CHSC subchannels */ -/* Adapter interrupts. */ -#define QDIO_AIRQ_ISC IO_SCH_ISC /* I/O subchannel in qdio mode */ - -/* Functions for registration of I/O interruption subclasses */ -void isc_register(unsigned int isc); -void isc_unregister(unsigned int isc); - -#endif /* _ASM_S390_ISC_H */ diff --git a/trunk/include/asm-s390/itcw.h b/trunk/include/asm-s390/itcw.h deleted file mode 100644 index a9bc5c36b32a..000000000000 --- a/trunk/include/asm-s390/itcw.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Functions for incremental construction of fcx enabled I/O control blocks. - * - * Copyright IBM Corp. 2008 - * Author(s): Peter Oberparleiter - */ - -#ifndef _ASM_S390_ITCW_H -#define _ASM_S390_ITCW_H _ASM_S390_ITCW_H - -#include -#include - -#define ITCW_OP_READ 0 -#define ITCW_OP_WRITE 1 - -struct itcw; - -struct tcw *itcw_get_tcw(struct itcw *itcw); -size_t itcw_calc_size(int intrg, int max_tidaws, int intrg_max_tidaws); -struct itcw *itcw_init(void *buffer, size_t size, int op, int intrg, - int max_tidaws, int intrg_max_tidaws); -struct dcw *itcw_add_dcw(struct itcw *itcw, u8 cmd, u8 flags, void *cd, - u8 cd_count, u32 count); -struct tidaw *itcw_add_tidaw(struct itcw *itcw, u8 flags, void *addr, - u32 count); -void itcw_set_data(struct itcw *itcw, void *addr, int use_tidal); -void itcw_finalize(struct itcw *itcw); - -#endif /* _ASM_S390_ITCW_H */ diff --git a/trunk/include/asm-s390/pgtable.h b/trunk/include/asm-s390/pgtable.h index 0bdb704ae051..bd0ea191dfa9 100644 --- a/trunk/include/asm-s390/pgtable.h +++ b/trunk/include/asm-s390/pgtable.h @@ -29,7 +29,6 @@ * the S390 page table tree. */ #ifndef __ASSEMBLY__ -#include #include #include #include diff --git a/trunk/include/asm-s390/processor.h b/trunk/include/asm-s390/processor.h index 4af80af2a88f..a00f79dd323b 100644 --- a/trunk/include/asm-s390/processor.h +++ b/trunk/include/asm-s390/processor.h @@ -143,19 +143,11 @@ struct stack_frame { /* * Do necessary setup to start up a new thread. */ -#define start_thread(regs, new_psw, new_stackp) do { \ +#define start_thread(regs, new_psw, new_stackp) do { \ set_fs(USER_DS); \ regs->psw.mask = psw_user_bits; \ - regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ - regs->gprs[15] = new_stackp; \ -} while (0) - -#define start_thread31(regs, new_psw, new_stackp) do { \ - set_fs(USER_DS); \ - regs->psw.mask = psw_user32_bits; \ - regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ - regs->gprs[15] = new_stackp; \ - crst_table_downgrade(current->mm, 1UL << 31); \ + regs->psw.addr = new_psw | PSW_ADDR_AMODE; \ + regs->gprs[15] = new_stackp ; \ } while (0) /* Forward declaration, a strange C thing */ @@ -336,6 +328,16 @@ extern void (*s390_base_mcck_handler_fn)(void); extern void (*s390_base_pgm_handler_fn)(void); extern void (*s390_base_ext_handler_fn)(void); +/* + * CPU idle notifier chain. + */ +#define S390_CPU_IDLE 0 +#define S390_CPU_NOT_IDLE 1 + +struct notifier_block; +int register_idle_notifier(struct notifier_block *nb); +int unregister_idle_notifier(struct notifier_block *nb); + #define ARCH_LOW_ADDRESS_LIMIT 0x7fffffffUL #endif diff --git a/trunk/include/asm-s390/ptrace.h b/trunk/include/asm-s390/ptrace.h index af2c9ac28a07..d7d4e2eb3e6f 100644 --- a/trunk/include/asm-s390/ptrace.h +++ b/trunk/include/asm-s390/ptrace.h @@ -215,12 +215,6 @@ typedef struct unsigned long addr; } __attribute__ ((aligned(8))) psw_t; -typedef struct -{ - __u32 mask; - __u32 addr; -} __attribute__ ((aligned(8))) psw_compat_t; - #ifndef __s390x__ #define PSW_MASK_PER 0x40000000UL @@ -298,15 +292,6 @@ typedef struct unsigned long orig_gpr2; } s390_regs; -typedef struct -{ - psw_compat_t psw; - __u32 gprs[NUM_GPRS]; - __u32 acrs[NUM_ACRS]; - __u32 orig_gpr2; -} s390_compat_regs; - - #ifdef __KERNEL__ #include #include diff --git a/trunk/include/asm-s390/sclp.h b/trunk/include/asm-s390/sclp.h index fed7bee650a0..b5f2843013a3 100644 --- a/trunk/include/asm-s390/sclp.h +++ b/trunk/include/asm-s390/sclp.h @@ -45,9 +45,9 @@ struct sclp_cpu_info { int sclp_get_cpu_info(struct sclp_cpu_info *info); int sclp_cpu_configure(u8 cpu); int sclp_cpu_deconfigure(u8 cpu); +void sclp_read_info_early(void); void sclp_facilities_detect(void); -unsigned long long sclp_get_rnmax(void); -unsigned long long sclp_get_rzm(void); +unsigned long long sclp_memory_detect(void); int sclp_sdias_blk_count(void); int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); int sclp_chp_configure(struct chp_id chpid); diff --git a/trunk/include/asm-s390/setup.h b/trunk/include/asm-s390/setup.h index f09ee3f72977..ba69674012a7 100644 --- a/trunk/include/asm-s390/setup.h +++ b/trunk/include/asm-s390/setup.h @@ -8,16 +8,14 @@ #ifndef _ASM_S390_SETUP_H #define _ASM_S390_SETUP_H -#define COMMAND_LINE_SIZE 1024 - -#define ARCH_COMMAND_LINE_SIZE 896 +#define COMMAND_LINE_SIZE 896 #ifdef __KERNEL__ #include #define PARMAREA 0x10400 -#define MEMORY_CHUNKS 256 +#define MEMORY_CHUNKS 16 /* max 0x7fff */ #ifndef __ASSEMBLY__ @@ -38,14 +36,12 @@ struct mem_chunk { unsigned long addr; unsigned long size; - int type; + unsigned long type; }; extern struct mem_chunk memory_chunk[]; extern unsigned long real_memory_size; -void detect_memory_layout(struct mem_chunk chunk[]); - #ifdef CONFIG_S390_SWITCH_AMODE extern unsigned int switch_amode; #else @@ -65,6 +61,7 @@ extern unsigned long machine_flags; #define MACHINE_FLAG_VM (1UL << 0) #define MACHINE_FLAG_IEEE (1UL << 1) +#define MACHINE_FLAG_P390 (1UL << 2) #define MACHINE_FLAG_CSP (1UL << 3) #define MACHINE_FLAG_MVPG (1UL << 4) #define MACHINE_FLAG_DIAG44 (1UL << 5) @@ -100,6 +97,7 @@ extern unsigned long machine_flags; #define MACHINE_HAS_PFMF (machine_flags & MACHINE_FLAG_PFMF) #endif /* __s390x__ */ +#define MACHINE_HAS_SCLP (!MACHINE_IS_P390) #define ZFCPDUMP_HSA_SIZE (32UL<<20) /* diff --git a/trunk/include/asm-s390/sparsemem.h b/trunk/include/asm-s390/sparsemem.h index 545d219e6a2d..06dfdab6c0e8 100644 --- a/trunk/include/asm-s390/sparsemem.h +++ b/trunk/include/asm-s390/sparsemem.h @@ -1,15 +1,15 @@ #ifndef _ASM_S390_SPARSEMEM_H #define _ASM_S390_SPARSEMEM_H +#define SECTION_SIZE_BITS 25 + #ifdef CONFIG_64BIT -#define SECTION_SIZE_BITS 28 #define MAX_PHYSADDR_BITS 42 #define MAX_PHYSMEM_BITS 42 #else -#define SECTION_SIZE_BITS 25 #define MAX_PHYSADDR_BITS 31 #define MAX_PHYSMEM_BITS 31 diff --git a/trunk/include/asm-s390/timer.h b/trunk/include/asm-s390/timer.h index d98d79e35cd6..adb34860a543 100644 --- a/trunk/include/asm-s390/timer.h +++ b/trunk/include/asm-s390/timer.h @@ -48,18 +48,6 @@ extern int del_virt_timer(struct vtimer_list *timer); extern void init_cpu_vtimer(void); extern void vtime_init(void); -#ifdef CONFIG_VIRT_TIMER - -extern void vtime_start_cpu_timer(void); -extern void vtime_stop_cpu_timer(void); - -#else - -static inline void vtime_start_cpu_timer(void) { } -static inline void vtime_stop_cpu_timer(void) { } - -#endif /* CONFIG_VIRT_TIMER */ - #endif /* __KERNEL__ */ #endif /* _ASM_S390_TIMER_H */ diff --git a/trunk/include/asm-s390/zcrypt.h b/trunk/include/asm-s390/zcrypt.h index 00d3bbd44117..f228f1b86877 100644 --- a/trunk/include/asm-s390/zcrypt.h +++ b/trunk/include/asm-s390/zcrypt.h @@ -29,7 +29,7 @@ #define ZCRYPT_VERSION 2 #define ZCRYPT_RELEASE 1 -#define ZCRYPT_VARIANT 1 +#define ZCRYPT_VARIANT 0 #include #include diff --git a/trunk/include/linux/bio.h b/trunk/include/linux/bio.h index 0933a14e6414..61c15eaf3fb3 100644 --- a/trunk/include/linux/bio.h +++ b/trunk/include/linux/bio.h @@ -64,7 +64,6 @@ struct bio_vec { struct bio_set; struct bio; -struct bio_integrity_payload; typedef void (bio_end_io_t) (struct bio *, int); typedef void (bio_destructor_t) (struct bio *); @@ -113,9 +112,6 @@ struct bio { atomic_t bi_cnt; /* pin count */ void *bi_private; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - struct bio_integrity_payload *bi_integrity; /* data integrity */ -#endif bio_destructor_t *bi_destructor; /* destructor */ }; @@ -275,29 +271,6 @@ static inline void *bio_data(struct bio *bio) */ #define bio_get(bio) atomic_inc(&(bio)->bi_cnt) -#if defined(CONFIG_BLK_DEV_INTEGRITY) -/* - * bio integrity payload - */ -struct bio_integrity_payload { - struct bio *bip_bio; /* parent bio */ - struct bio_vec *bip_vec; /* integrity data vector */ - - sector_t bip_sector; /* virtual start sector */ - - void *bip_buf; /* generated integrity data */ - bio_end_io_t *bip_end_io; /* saved I/O completion fn */ - - int bip_error; /* saved I/O error */ - unsigned int bip_size; - - unsigned short bip_pool; /* pool the ivec came from */ - unsigned short bip_vcnt; /* # of integrity bio_vecs */ - unsigned short bip_idx; /* current bip_vec index */ - - struct work_struct bip_work; /* I/O completion */ -}; -#endif /* CONFIG_BLK_DEV_INTEGRITY */ /* * A bio_pair is used when we need to split a bio. @@ -310,14 +283,10 @@ struct bio_integrity_payload { * in bio2.bi_private */ struct bio_pair { - struct bio bio1, bio2; - struct bio_vec bv1, bv2; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - struct bio_integrity_payload bip1, bip2; - struct bio_vec iv1, iv2; -#endif - atomic_t cnt; - int error; + struct bio bio1, bio2; + struct bio_vec bv1, bv2; + atomic_t cnt; + int error; }; extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors); @@ -364,39 +333,6 @@ extern struct bio *bio_copy_user_iov(struct request_queue *, struct sg_iovec *, int, int); extern int bio_uncopy_user(struct bio *); void zero_fill_bio(struct bio *bio); -extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *); -extern unsigned int bvec_nr_vecs(unsigned short idx); - -/* - * bio_set is used to allow other portions of the IO system to - * allocate their own private memory pools for bio and iovec structures. - * These memory pools in turn all allocate from the bio_slab - * and the bvec_slabs[]. - */ -#define BIO_POOL_SIZE 2 -#define BIOVEC_NR_POOLS 6 - -struct bio_set { - mempool_t *bio_pool; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - mempool_t *bio_integrity_pool; -#endif - mempool_t *bvec_pools[BIOVEC_NR_POOLS]; -}; - -struct biovec_slab { - int nr_vecs; - char *name; - struct kmem_cache *slab; -}; - -extern struct bio_set *fs_bio_set; - -/* - * a small number of entries is fine, not going to be performance critical. - * basically we just need to survive - */ -#define BIO_SPLIT_ENTRIES 2 #ifdef CONFIG_HIGHMEM /* @@ -445,63 +381,5 @@ static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx, __bio_kmap_irq((bio), (bio)->bi_idx, (flags)) #define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -#define bip_vec_idx(bip, idx) (&(bip->bip_vec[(idx)])) -#define bip_vec(bip) bip_vec_idx(bip, 0) - -#define __bip_for_each_vec(bvl, bip, i, start_idx) \ - for (bvl = bip_vec_idx((bip), (start_idx)), i = (start_idx); \ - i < (bip)->bip_vcnt; \ - bvl++, i++) - -#define bip_for_each_vec(bvl, bip, i) \ - __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx) - -static inline int bio_integrity(struct bio *bio) -{ -#if defined(CONFIG_BLK_DEV_INTEGRITY) - return bio->bi_integrity != NULL; -#else - return 0; -#endif -} - -extern struct bio_integrity_payload *bio_integrity_alloc_bioset(struct bio *, gfp_t, unsigned int, struct bio_set *); -extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int); -extern void bio_integrity_free(struct bio *, struct bio_set *); -extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int); -extern int bio_integrity_enabled(struct bio *bio); -extern int bio_integrity_set_tag(struct bio *, void *, unsigned int); -extern int bio_integrity_get_tag(struct bio *, void *, unsigned int); -extern int bio_integrity_prep(struct bio *); -extern void bio_integrity_endio(struct bio *, int); -extern void bio_integrity_advance(struct bio *, unsigned int); -extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); -extern void bio_integrity_split(struct bio *, struct bio_pair *, int); -extern int bio_integrity_clone(struct bio *, struct bio *, struct bio_set *); -extern int bioset_integrity_create(struct bio_set *, int); -extern void bioset_integrity_free(struct bio_set *); -extern void bio_integrity_init_slab(void); - -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -#define bio_integrity(a) (0) -#define bioset_integrity_create(a, b) (0) -#define bio_integrity_prep(a) (0) -#define bio_integrity_enabled(a) (0) -#define bio_integrity_clone(a, b, c) (0) -#define bioset_integrity_free(a) do { } while (0) -#define bio_integrity_free(a, b) do { } while (0) -#define bio_integrity_endio(a, b) do { } while (0) -#define bio_integrity_advance(a, b) do { } while (0) -#define bio_integrity_trim(a, b, c) do { } while (0) -#define bio_integrity_split(a, b, c) do { } while (0) -#define bio_integrity_set_tag(a, b, c) do { } while (0) -#define bio_integrity_get_tag(a, b, c) do { } while (0) -#define bio_integrity_init_slab(a) do { } while (0) - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - #endif /* CONFIG_BLOCK */ #endif /* __LINUX_BIO_H */ diff --git a/trunk/include/linux/blkdev.h b/trunk/include/linux/blkdev.h index 1ffd8bfdc4c9..d2a1b71e93c3 100644 --- a/trunk/include/linux/blkdev.h +++ b/trunk/include/linux/blkdev.h @@ -23,6 +23,7 @@ struct scsi_ioctl_command; struct request_queue; +typedef struct request_queue request_queue_t __deprecated; struct elevator_queue; typedef struct elevator_queue elevator_t; struct request_pm_state; @@ -33,6 +34,12 @@ struct sg_io_hdr; #define BLKDEV_MIN_RQ 4 #define BLKDEV_MAX_RQ 128 /* Default maximum */ +int put_io_context(struct io_context *ioc); +void exit_io_context(void); +struct io_context *get_io_context(gfp_t gfp_flags, int node); +struct io_context *alloc_io_context(gfp_t gfp_flags, int node); +void copy_io_context(struct io_context **pdst, struct io_context **psrc); + struct request; typedef void (rq_end_io_fn)(struct request *, int); @@ -106,7 +113,6 @@ enum rq_flag_bits { __REQ_ALLOCED, /* request came from our alloc pool */ __REQ_RW_META, /* metadata io request */ __REQ_COPY_USER, /* contains copies of user pages */ - __REQ_INTEGRITY, /* integrity metadata has been remapped */ __REQ_NR_BITS, /* stops here */ }; @@ -129,7 +135,6 @@ enum rq_flag_bits { #define REQ_ALLOCED (1 << __REQ_ALLOCED) #define REQ_RW_META (1 << __REQ_RW_META) #define REQ_COPY_USER (1 << __REQ_COPY_USER) -#define REQ_INTEGRITY (1 << __REQ_INTEGRITY) #define BLK_MAX_CDB 16 @@ -254,14 +259,7 @@ typedef int (prep_rq_fn) (struct request_queue *, struct request *); typedef void (unplug_fn) (struct request_queue *); struct bio_vec; -struct bvec_merge_data { - struct block_device *bi_bdev; - sector_t bi_sector; - unsigned bi_size; - unsigned long bi_rw; -}; -typedef int (merge_bvec_fn) (struct request_queue *, struct bvec_merge_data *, - struct bio_vec *); +typedef int (merge_bvec_fn) (struct request_queue *, struct bio *, struct bio_vec *); typedef void (prepare_flush_fn) (struct request_queue *, struct request *); typedef void (softirq_done_fn)(struct request *); typedef int (dma_drain_needed_fn)(struct request *); @@ -428,32 +426,6 @@ static inline void queue_flag_set_unlocked(unsigned int flag, __set_bit(flag, &q->queue_flags); } -static inline int queue_flag_test_and_clear(unsigned int flag, - struct request_queue *q) -{ - WARN_ON_ONCE(!queue_is_locked(q)); - - if (test_bit(flag, &q->queue_flags)) { - __clear_bit(flag, &q->queue_flags); - return 1; - } - - return 0; -} - -static inline int queue_flag_test_and_set(unsigned int flag, - struct request_queue *q) -{ - WARN_ON_ONCE(!queue_is_locked(q)); - - if (!test_bit(flag, &q->queue_flags)) { - __set_bit(flag, &q->queue_flags); - return 0; - } - - return 1; -} - static inline void queue_flag_set(unsigned int flag, struct request_queue *q) { WARN_ON_ONCE(!queue_is_locked(q)); @@ -704,6 +676,7 @@ extern int blk_execute_rq(struct request_queue *, struct gendisk *, struct request *, int); extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, struct request *, int, rq_end_io_fn *); +extern int blk_verify_command(unsigned char *, int); extern void blk_unplug(struct request_queue *q); static inline struct request_queue *bdev_get_queue(struct block_device *bdev) @@ -776,7 +749,6 @@ extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); extern void blk_queue_hardsect_size(struct request_queue *, unsigned short); extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b); extern void blk_queue_dma_pad(struct request_queue *, unsigned int); -extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int); extern int blk_queue_dma_drain(struct request_queue *q, dma_drain_needed_fn *dma_drain_needed, void *buf, unsigned int size); @@ -830,15 +802,6 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, extern int blkdev_issue_flush(struct block_device *, sector_t *); -/* -* command filter functions -*/ -extern int blk_verify_command(struct file *file, unsigned char *cmd); -extern int blk_cmd_filter_verify_command(struct blk_scsi_cmd_filter *filter, - unsigned char *cmd, mode_t *f_mode); -extern int blk_register_filter(struct gendisk *disk); -extern void blk_unregister_filter(struct gendisk *disk); - #define MAX_PHYS_SEGMENTS 128 #define MAX_HW_SEGMENTS 128 #define SAFE_MAX_SECTORS 255 @@ -902,116 +865,28 @@ void kblockd_flush_work(struct work_struct *work); #define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \ MODULE_ALIAS("block-major-" __stringify(major) "-*") -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -#define INTEGRITY_FLAG_READ 2 /* verify data integrity on read */ -#define INTEGRITY_FLAG_WRITE 4 /* generate data integrity on write */ - -struct blk_integrity_exchg { - void *prot_buf; - void *data_buf; - sector_t sector; - unsigned int data_size; - unsigned short sector_size; - const char *disk_name; -}; - -typedef void (integrity_gen_fn) (struct blk_integrity_exchg *); -typedef int (integrity_vrfy_fn) (struct blk_integrity_exchg *); -typedef void (integrity_set_tag_fn) (void *, void *, unsigned int); -typedef void (integrity_get_tag_fn) (void *, void *, unsigned int); - -struct blk_integrity { - integrity_gen_fn *generate_fn; - integrity_vrfy_fn *verify_fn; - integrity_set_tag_fn *set_tag_fn; - integrity_get_tag_fn *get_tag_fn; - - unsigned short flags; - unsigned short tuple_size; - unsigned short sector_size; - unsigned short tag_size; - - const char *name; - - struct kobject kobj; -}; - -extern int blk_integrity_register(struct gendisk *, struct blk_integrity *); -extern void blk_integrity_unregister(struct gendisk *); -extern int blk_integrity_compare(struct block_device *, struct block_device *); -extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *); -extern int blk_rq_count_integrity_sg(struct request *); - -static inline unsigned short blk_integrity_tuple_size(struct blk_integrity *bi) -{ - if (bi) - return bi->tuple_size; - - return 0; -} -static inline struct blk_integrity *bdev_get_integrity(struct block_device *bdev) -{ - return bdev->bd_disk->integrity; -} +#else /* CONFIG_BLOCK */ +/* + * stubs for when the block layer is configured out + */ +#define buffer_heads_over_limit 0 -static inline unsigned int bdev_get_tag_size(struct block_device *bdev) +static inline long nr_blockdev_pages(void) { - struct blk_integrity *bi = bdev_get_integrity(bdev); - - if (bi) - return bi->tag_size; - return 0; } -static inline int bdev_integrity_enabled(struct block_device *bdev, int rw) +static inline void exit_io_context(void) { - struct blk_integrity *bi = bdev_get_integrity(bdev); - - if (bi == NULL) - return 0; - - if (rw == READ && bi->verify_fn != NULL && - (bi->flags & INTEGRITY_FLAG_READ)) - return 1; - - if (rw == WRITE && bi->generate_fn != NULL && - (bi->flags & INTEGRITY_FLAG_WRITE)) - return 1; - - return 0; } -static inline int blk_integrity_rq(struct request *rq) +struct io_context; +static inline int put_io_context(struct io_context *ioc) { - return bio_integrity(rq->bio); + return 1; } -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -#define blk_integrity_rq(rq) (0) -#define blk_rq_count_integrity_sg(a) (0) -#define blk_rq_map_integrity_sg(a, b) (0) -#define bdev_get_integrity(a) (0) -#define bdev_get_tag_size(a) (0) -#define blk_integrity_compare(a, b) (0) -#define blk_integrity_register(a, b) (0) -#define blk_integrity_unregister(a) do { } while (0); - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -#else /* CONFIG_BLOCK */ -/* - * stubs for when the block layer is configured out - */ -#define buffer_heads_over_limit 0 - -static inline long nr_blockdev_pages(void) -{ - return 0; -} #endif /* CONFIG_BLOCK */ diff --git a/trunk/include/linux/blktrace_api.h b/trunk/include/linux/blktrace_api.h index d084b8d227a5..e3ef903aae88 100644 --- a/trunk/include/linux/blktrace_api.h +++ b/trunk/include/linux/blktrace_api.h @@ -129,7 +129,6 @@ struct blk_trace { u32 dev; struct dentry *dir; struct dentry *dropped_file; - struct dentry *msg_file; atomic_t dropped; }; diff --git a/trunk/include/linux/genhd.h b/trunk/include/linux/genhd.h index e8787417f65a..ae7aec3cabee 100644 --- a/trunk/include/linux/genhd.h +++ b/trunk/include/linux/genhd.h @@ -110,14 +110,6 @@ struct hd_struct { #define GENHD_FL_SUPPRESS_PARTITION_INFO 32 #define GENHD_FL_FAIL 64 -#define BLK_SCSI_MAX_CMDS (256) -#define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) - -struct blk_scsi_cmd_filter { - unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; - unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; - struct kobject kobj; -}; struct gendisk { int major; /* major number of driver */ @@ -128,7 +120,6 @@ struct gendisk { struct hd_struct **part; /* [indexed by minor] */ struct block_device_operations *fops; struct request_queue *queue; - struct blk_scsi_cmd_filter cmd_filter; void *private_data; sector_t capacity; @@ -150,9 +141,6 @@ struct gendisk { struct disk_stats dkstats; #endif struct work_struct async_notify; -#ifdef CONFIG_BLK_DEV_INTEGRITY - struct blk_integrity *integrity; -#endif }; /* diff --git a/trunk/include/linux/iocontext.h b/trunk/include/linux/iocontext.h index 08b987bccf89..2b7a1187cb29 100644 --- a/trunk/include/linux/iocontext.h +++ b/trunk/include/linux/iocontext.h @@ -99,22 +99,4 @@ static inline struct io_context *ioc_task_link(struct io_context *ioc) return NULL; } -#ifdef CONFIG_BLOCK -int put_io_context(struct io_context *ioc); -void exit_io_context(void); -struct io_context *get_io_context(gfp_t gfp_flags, int node); -struct io_context *alloc_io_context(gfp_t gfp_flags, int node); -void copy_io_context(struct io_context **pdst, struct io_context **psrc); -#else -static inline void exit_io_context(void) -{ -} - -struct io_context; -static inline int put_io_context(struct io_context *ioc) -{ - return 1; -} -#endif - #endif diff --git a/trunk/include/linux/mod_devicetable.h b/trunk/include/linux/mod_devicetable.h index c4db5827963d..69b2342d5ebb 100644 --- a/trunk/include/linux/mod_devicetable.h +++ b/trunk/include/linux/mod_devicetable.h @@ -159,15 +159,6 @@ struct ap_device_id { #define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01 -/* s390 css bus devices (subchannels) */ -struct css_device_id { - __u8 match_flags; - __u8 type; /* subchannel type */ - __u16 pad2; - __u32 pad3; - kernel_ulong_t driver_data; -}; - #define ACPI_ID_LEN 16 /* only 9 bytes needed here, 16 bytes are used */ /* to workaround crosscompile issues */ diff --git a/trunk/include/pcmcia/bulkmem.h b/trunk/include/pcmcia/bulkmem.h new file mode 100644 index 000000000000..6bc7472293b2 --- /dev/null +++ b/trunk/include/pcmcia/bulkmem.h @@ -0,0 +1,41 @@ +/* + * bulkmem.h -- Definitions for bulk memory services + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + * (C) 1999 David A. Hinds + */ + +#ifndef _LINUX_BULKMEM_H +#define _LINUX_BULKMEM_H + +/* For GetFirstRegion and GetNextRegion */ +typedef struct region_info_t { + u_int Attributes; + u_int CardOffset; + u_int RegionSize; + u_int AccessSpeed; + u_int BlockSize; + u_int PartMultiple; + u_char JedecMfr, JedecInfo; + memory_handle_t next; +} region_info_t; + +#define REGION_TYPE 0x0001 +#define REGION_TYPE_CM 0x0000 +#define REGION_TYPE_AM 0x0001 +#define REGION_PREFETCH 0x0008 +#define REGION_CACHEABLE 0x0010 +#define REGION_BAR_MASK 0xe000 +#define REGION_BAR_SHIFT 13 + +int pcmcia_get_first_region(struct pcmcia_device *handle, region_info_t *rgn); +int pcmcia_get_next_region(struct pcmcia_device *handle, region_info_t *rgn); + +#endif /* _LINUX_BULKMEM_H */ diff --git a/trunk/include/pcmcia/cistpl.h b/trunk/include/pcmcia/cistpl.h index e2e10c1e9a06..d3bbb19caf81 100644 --- a/trunk/include/pcmcia/cistpl.h +++ b/trunk/include/pcmcia/cistpl.h @@ -595,7 +595,7 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple); int pccard_parse_tuple(tuple_t *tuple, cisparse_t *parse); -int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, unsigned int *count); +int pccard_validate_cis(struct pcmcia_socket *s, unsigned int function, cisinfo_t *info); /* ... but use these wrappers instead */ #define pcmcia_get_first_tuple(p_dev, tuple) \ diff --git a/trunk/include/pcmcia/cs.h b/trunk/include/pcmcia/cs.h index 45d84b275789..87a260e3699e 100644 --- a/trunk/include/pcmcia/cs.h +++ b/trunk/include/pcmcia/cs.h @@ -373,6 +373,9 @@ struct pcmcia_socket; int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg); int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config); +int pcmcia_get_first_window(window_handle_t *win, win_req_t *req); +int pcmcia_get_next_window(window_handle_t *win, win_req_t *req); +int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status); int pcmcia_get_mem_page(window_handle_t win, memreq_t *req); int pcmcia_map_mem_page(window_handle_t win, memreq_t *req); int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod); diff --git a/trunk/include/pcmcia/cs_types.h b/trunk/include/pcmcia/cs_types.h index f402a0f435b4..9a6bcc4952f0 100644 --- a/trunk/include/pcmcia/cs_types.h +++ b/trunk/include/pcmcia/cs_types.h @@ -21,8 +21,7 @@ #include #endif -#if defined(__arm__) || defined(__mips__) || defined(__avr32__) || \ - defined(__bfin__) +#if defined(__arm__) || defined(__mips__) || defined(__avr32__) /* This (ioaddr_t) is exposed to userspace & hence cannot be changed. */ typedef u_int ioaddr_t; #else @@ -34,6 +33,9 @@ typedef u_int event_t; typedef u_char cisdata_t; typedef u_short page_t; +struct pcmcia_device; +typedef struct pcmcia_device *client_handle_t; + struct window_t; typedef struct window_t *window_handle_t; diff --git a/trunk/include/pcmcia/ds.h b/trunk/include/pcmcia/ds.h index b316027c853d..f047a1fd64f8 100644 --- a/trunk/include/pcmcia/ds.h +++ b/trunk/include/pcmcia/ds.h @@ -20,6 +20,7 @@ #include #endif +#include #include #include @@ -50,24 +51,6 @@ typedef struct mtd_info_t { u_int CardOffset; } mtd_info_t; -typedef struct region_info_t { - u_int Attributes; - u_int CardOffset; - u_int RegionSize; - u_int AccessSpeed; - u_int BlockSize; - u_int PartMultiple; - u_char JedecMfr, JedecInfo; - memory_handle_t next; -} region_info_t; -#define REGION_TYPE 0x0001 -#define REGION_TYPE_CM 0x0000 -#define REGION_TYPE_AM 0x0001 -#define REGION_PREFETCH 0x0008 -#define REGION_CACHEABLE 0x0010 -#define REGION_BAR_MASK 0xe000 -#define REGION_BAR_SHIFT 13 - typedef union ds_ioctl_arg_t { adjust_t adjust; config_info_t config; diff --git a/trunk/include/pcmcia/ss.h b/trunk/include/pcmcia/ss.h index ed919dd9bb5c..f95dca077c1c 100644 --- a/trunk/include/pcmcia/ss.h +++ b/trunk/include/pcmcia/ss.h @@ -21,6 +21,7 @@ #include #include +#include #ifdef CONFIG_CARDBUS #include #endif @@ -135,14 +136,8 @@ struct pccard_resource_ops { struct resource* (*find_mem) (unsigned long base, unsigned long num, unsigned long align, int low, struct pcmcia_socket *s); - int (*add_io) (struct pcmcia_socket *s, - unsigned int action, - unsigned long r_start, - unsigned long r_end); - int (*add_mem) (struct pcmcia_socket *s, - unsigned int action, - unsigned long r_start, - unsigned long r_end); + int (*adjust_resource) (struct pcmcia_socket *s, + adjust_t *adj); int (*init) (struct pcmcia_socket *s); void (*exit) (struct pcmcia_socket *s); }; @@ -250,6 +245,7 @@ struct pcmcia_socket { struct task_struct *thread; struct completion thread_done; + wait_queue_head_t thread_wait; spinlock_t thread_lock; /* protects thread_events */ unsigned int thread_events; diff --git a/trunk/include/pcmcia/version.h b/trunk/include/pcmcia/version.h new file mode 100644 index 000000000000..5ad9c5e198b6 --- /dev/null +++ b/trunk/include/pcmcia/version.h @@ -0,0 +1,3 @@ +/* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */ + +/* This file will be removed, please don't include it */ diff --git a/trunk/kernel/exit.c b/trunk/kernel/exit.c index ceb258782835..8f6185e69b69 100644 --- a/trunk/kernel/exit.c +++ b/trunk/kernel/exit.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/kernel/fork.c b/trunk/kernel/fork.c index b71ccd09fc8d..19908b26cf80 100644 --- a/trunk/kernel/fork.c +++ b/trunk/kernel/fork.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include diff --git a/trunk/mm/Kconfig b/trunk/mm/Kconfig index 4242743b981b..3aa819d628c1 100644 --- a/trunk/mm/Kconfig +++ b/trunk/mm/Kconfig @@ -129,7 +129,7 @@ config MEMORY_HOTPLUG bool "Allow for memory hot-add" depends on SPARSEMEM || X86_64_ACPI_NUMA depends on HOTPLUG && !HIBERNATION && ARCH_ENABLE_MEMORY_HOTPLUG - depends on (IA64 || X86 || PPC64 || SUPERH || S390) + depends on (IA64 || X86 || PPC64 || SUPERH) comment "Memory hotplug is currently incompatible with Software Suspend" depends on SPARSEMEM && HOTPLUG && HIBERNATION diff --git a/trunk/mm/slub.c b/trunk/mm/slub.c index 5f6e2c4a2ba7..315c392253c7 100644 --- a/trunk/mm/slub.c +++ b/trunk/mm/slub.c @@ -431,8 +431,9 @@ static void print_track(const char *s, struct track *t) if (!t->addr) return; - printk(KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n", - s, t->addr, jiffies - t->when, t->cpu, t->pid); + printk(KERN_ERR "INFO: %s in ", s); + __print_symbol("%s", (unsigned long)t->addr); + printk(" age=%lu cpu=%u pid=%d\n", jiffies - t->when, t->cpu, t->pid); } static void print_tracking(struct kmem_cache *s, void *object) diff --git a/trunk/net/iucv/af_iucv.c b/trunk/net/iucv/af_iucv.c index bda71015885c..7b0038f45b16 100644 --- a/trunk/net/iucv/af_iucv.c +++ b/trunk/net/iucv/af_iucv.c @@ -1135,7 +1135,8 @@ static void iucv_callback_txdone(struct iucv_path *path, if (this) kfree_skb(this); } - BUG_ON(!this); + if (!this) + printk(KERN_ERR "AF_IUCV msg tag %u not found\n", msg->tag); if (sk->sk_state == IUCV_CLOSING) { if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { @@ -1195,7 +1196,7 @@ static int __init afiucv_init(void) } cpcmd("QUERY USERID", iucv_userid, sizeof(iucv_userid), &err); if (unlikely(err)) { - WARN_ON(err); + printk(KERN_ERR "AF_IUCV needs the VM userid\n"); err = -EPROTONOSUPPORT; goto out; } @@ -1209,6 +1210,7 @@ static int __init afiucv_init(void) err = sock_register(&iucv_sock_family_ops); if (err) goto out_proto; + printk(KERN_INFO "AF_IUCV lowlevel driver initialized\n"); return 0; out_proto: @@ -1224,6 +1226,8 @@ static void __exit afiucv_exit(void) sock_unregister(PF_IUCV); proto_unregister(&iucv_proto); iucv_unregister(&af_iucv_handler, 0); + + printk(KERN_INFO "AF_IUCV lowlevel driver unloaded\n"); } module_init(afiucv_init); diff --git a/trunk/net/iucv/iucv.c b/trunk/net/iucv/iucv.c index 7f82b7616212..918970762131 100644 --- a/trunk/net/iucv/iucv.c +++ b/trunk/net/iucv/iucv.c @@ -1559,11 +1559,16 @@ static void iucv_external_interrupt(u16 code) p = iucv_irq_data[smp_processor_id()]; if (p->ippathid >= iucv_max_pathid) { - WARN_ON(p->ippathid >= iucv_max_pathid); + printk(KERN_WARNING "iucv_do_int: Got interrupt with " + "pathid %d > max_connections (%ld)\n", + p->ippathid, iucv_max_pathid - 1); iucv_sever_pathid(p->ippathid, iucv_error_no_listener); return; } - BUG_ON(p->iptype < 0x01 || p->iptype > 0x09); + if (p->iptype < 0x01 || p->iptype > 0x09) { + printk(KERN_ERR "iucv_do_int: unknown iucv interrupt\n"); + return; + } work = kmalloc(sizeof(struct iucv_irq_list), GFP_ATOMIC); if (!work) { printk(KERN_WARNING "iucv_external_interrupt: out of memory\n"); diff --git a/trunk/scripts/mod/file2alias.c b/trunk/scripts/mod/file2alias.c index 37d5c363fbcd..cea4a790e1e9 100644 --- a/trunk/scripts/mod/file2alias.c +++ b/trunk/scripts/mod/file2alias.c @@ -304,14 +304,6 @@ static int do_ap_entry(const char *filename, return 1; } -/* looks like: "css:tN" */ -static int do_css_entry(const char *filename, - struct css_device_id *id, char *alias) -{ - sprintf(alias, "css:t%01X", id->type); - return 1; -} - /* Looks like: "serio:tyNprNidNexN" */ static int do_serio_entry(const char *filename, struct serio_device_id *id, char *alias) @@ -688,10 +680,6 @@ void handle_moddevtable(struct module *mod, struct elf_info *info, do_table(symval, sym->st_size, sizeof(struct ap_device_id), "ap", do_ap_entry, mod); - else if (sym_is(symname, "__mod_css_device_table")) - do_table(symval, sym->st_size, - sizeof(struct css_device_id), "css", - do_css_entry, mod); else if (sym_is(symname, "__mod_serio_device_table")) do_table(symval, sym->st_size, sizeof(struct serio_device_id), "serio", diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index 09b1661b8a3a..738b3b634d74 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -49,7 +49,7 @@ #include "tlv320aic3x.h" #define AUDIO_NAME "aic3x" -#define AIC3X_VERSION "0.1" +#define AIC3X_VERSION "0.2" /* codec private data */ struct aic3x_priv { @@ -648,81 +648,6 @@ static int aic3x_add_widgets(struct snd_soc_codec *codec) return 0; } -struct aic3x_rate_divs { - u32 mclk; - u32 rate; - u32 fsref_reg; - u8 sr_reg:4; - u8 pllj_reg; - u16 plld_reg; -}; - -/* AIC3X codec mclk clock divider coefficients */ -static const struct aic3x_rate_divs aic3x_divs[] = { - /* 8k */ - {12000000, 8000, 48000, 0xa, 16, 3840}, - {19200000, 8000, 48000, 0xa, 10, 2400}, - {22579200, 8000, 48000, 0xa, 8, 7075}, - {33868800, 8000, 48000, 0xa, 5, 8049}, - /* 11.025k */ - {12000000, 11025, 44100, 0x6, 15, 528}, - {19200000, 11025, 44100, 0x6, 9, 4080}, - {22579200, 11025, 44100, 0x6, 8, 0}, - {33868800, 11025, 44100, 0x6, 5, 3333}, - /* 16k */ - {12000000, 16000, 48000, 0x4, 16, 3840}, - {19200000, 16000, 48000, 0x4, 10, 2400}, - {22579200, 16000, 48000, 0x4, 8, 7075}, - {33868800, 16000, 48000, 0x4, 5, 8049}, - /* 22.05k */ - {12000000, 22050, 44100, 0x2, 15, 528}, - {19200000, 22050, 44100, 0x2, 9, 4080}, - {22579200, 22050, 44100, 0x2, 8, 0}, - {33868800, 22050, 44100, 0x2, 5, 3333}, - /* 32k */ - {12000000, 32000, 48000, 0x1, 16, 3840}, - {19200000, 32000, 48000, 0x1, 10, 2400}, - {22579200, 32000, 48000, 0x1, 8, 7075}, - {33868800, 32000, 48000, 0x1, 5, 8049}, - /* 44.1k */ - {12000000, 44100, 44100, 0x0, 15, 528}, - {19200000, 44100, 44100, 0x0, 9, 4080}, - {22579200, 44100, 44100, 0x0, 8, 0}, - {33868800, 44100, 44100, 0x0, 5, 3333}, - /* 48k */ - {12000000, 48000, 48000, 0x0, 16, 3840}, - {19200000, 48000, 48000, 0x0, 10, 2400}, - {22579200, 48000, 48000, 0x0, 8, 7075}, - {33868800, 48000, 48000, 0x0, 5, 8049}, - /* 64k */ - {12000000, 64000, 96000, 0x1, 16, 3840}, - {19200000, 64000, 96000, 0x1, 10, 2400}, - {22579200, 64000, 96000, 0x1, 8, 7075}, - {33868800, 64000, 96000, 0x1, 5, 8049}, - /* 88.2k */ - {12000000, 88200, 88200, 0x0, 15, 528}, - {19200000, 88200, 88200, 0x0, 9, 4080}, - {22579200, 88200, 88200, 0x0, 8, 0}, - {33868800, 88200, 88200, 0x0, 5, 3333}, - /* 96k */ - {12000000, 96000, 96000, 0x0, 16, 3840}, - {19200000, 96000, 96000, 0x0, 10, 2400}, - {22579200, 96000, 96000, 0x0, 8, 7075}, - {33868800, 96000, 96000, 0x0, 5, 8049}, -}; - -static inline int aic3x_get_divs(int mclk, int rate) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(aic3x_divs); i++) { - if (aic3x_divs[i].rate == rate && aic3x_divs[i].mclk == mclk) - return i; - } - - return 0; -} - static int aic3x_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { @@ -730,49 +655,107 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->codec; struct aic3x_priv *aic3x = codec->private_data; - int i; - u8 data, pll_p, pll_r, pll_j; - u16 pll_d; - - i = aic3x_get_divs(aic3x->sysclk, params_rate(params)); + int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0; + u8 data, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1; + u16 pll_d = 1; - /* Route Left DAC to left channel input and - * right DAC to right channel input */ - data = (LDAC2LCH | RDAC2RCH); - switch (aic3x_divs[i].fsref_reg) { - case 44100: - data |= FSREF_44100; + /* select data word length */ + data = + aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: break; - case 48000: - data |= FSREF_48000; + case SNDRV_PCM_FORMAT_S20_3LE: + data |= (0x01 << 4); break; - case 88200: - data |= FSREF_44100 | DUAL_RATE_MODE; + case SNDRV_PCM_FORMAT_S24_LE: + data |= (0x02 << 4); break; - case 96000: - data |= FSREF_48000 | DUAL_RATE_MODE; + case SNDRV_PCM_FORMAT_S32_LE: + data |= (0x03 << 4); break; } + aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); + + /* Fsref can be 44100 or 48000 */ + fsref = (params_rate(params) % 11025 == 0) ? 44100 : 48000; + + /* Try to find a value for Q which allows us to bypass the PLL and + * generate CODEC_CLK directly. */ + for (pll_q = 2; pll_q < 18; pll_q++) + if (aic3x->sysclk / (128 * pll_q) == fsref) { + bypass_pll = 1; + break; + } + + if (bypass_pll) { + pll_q &= 0xf; + aic3x_write(codec, AIC3X_PLL_PROGA_REG, pll_q << PLLQ_SHIFT); + aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_CLKDIV); + } else + aic3x_write(codec, AIC3X_GPIOB_REG, CODEC_CLKIN_PLLDIV); + + /* Route Left DAC to left channel input and + * right DAC to right channel input */ + data = (LDAC2LCH | RDAC2RCH); + data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000; + if (params_rate(params) >= 64000) + data |= DUAL_RATE_MODE; aic3x_write(codec, AIC3X_CODEC_DATAPATH_REG, data); /* codec sample rate select */ - data = aic3x_divs[i].sr_reg; + data = (fsref * 20) / params_rate(params); + if (params_rate(params) < 64000) + data /= 2; + data /= 5; + data -= 2; data |= (data << 4); aic3x_write(codec, AIC3X_SAMPLE_RATE_SEL_REG, data); - /* Use PLL for generation Fsref by equation: - * Fsref = (MCLK * K * R)/(2048 * P); - * Fix P = 2 and R = 1 and calculate K, if - * K = J.D, i.e. J - an interger portion of K and D is the fractional - * one with 4 digits of precision; - * Example: - * For MCLK = 22.5792 MHz and Fsref = 48kHz: - * Select P = 2, R= 1, K = 8.7074, which results in J = 8, D = 7074 + if (bypass_pll) + return 0; + + /* Use PLL + * find an apropriate setup for j, d, r and p by iterating over + * p and r - j and d are calculated for each fraction. + * Up to 128 values are probed, the closest one wins the game. + * The sysclk is divided by 1000 to prevent integer overflows. */ - pll_p = 2; - pll_r = 1; - pll_j = aic3x_divs[i].pllj_reg; - pll_d = aic3x_divs[i].plld_reg; + codec_clk = (2048 * fsref) / (aic3x->sysclk / 1000); + + for (r = 1; r <= 16; r++) + for (p = 1; p <= 8; p++) { + int clk, tmp = (codec_clk * pll_r * 10) / pll_p; + u8 j = tmp / 10000; + u16 d = tmp % 10000; + + if (j > 63) + continue; + + if (d != 0 && aic3x->sysclk < 10000000) + continue; + + /* This is actually 1000 * ((j + (d/10000)) * r) / p + * The term had to be converted to get rid of the + * division by 10000 */ + clk = ((10000 * j * r) + (d * r)) / (10 * p); + + /* check whether this values get closer than the best + * ones we had before */ + if (abs(codec_clk - clk) < abs(codec_clk - last_clk)) { + pll_j = j; pll_d = d; pll_r = r; pll_p = p; + last_clk = clk; + } + + /* Early exit for exact matches */ + if (clk == codec_clk) + break; + } + + if (last_clk == 0) { + printk(KERN_ERR "%s(): unable to setup PLL\n", __func__); + return -EINVAL; + } data = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG); aic3x_write(codec, AIC3X_PLL_PROGA_REG, data | (pll_p << PLLP_SHIFT)); @@ -782,24 +765,6 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream, aic3x_write(codec, AIC3X_PLL_PROGD_REG, (pll_d & 0x3F) << PLLD_LSB_SHIFT); - /* select data word length */ - data = - aic3x_read_reg_cache(codec, AIC3X_ASD_INTF_CTRLB) & (~(0x3 << 4)); - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - break; - case SNDRV_PCM_FORMAT_S20_3LE: - data |= (0x01 << 4); - break; - case SNDRV_PCM_FORMAT_S24_LE: - data |= (0x02 << 4); - break; - case SNDRV_PCM_FORMAT_S32_LE: - data |= (0x03 << 4); - break; - } - aic3x_write(codec, AIC3X_ASD_INTF_CTRLB, data); - return 0; } @@ -826,16 +791,8 @@ static int aic3x_set_dai_sysclk(struct snd_soc_codec_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; struct aic3x_priv *aic3x = codec->private_data; - switch (freq) { - case 12000000: - case 19200000: - case 22579200: - case 33868800: - aic3x->sysclk = freq; - return 0; - } - - return -EINVAL; + aic3x->sysclk = freq; + return 0; } static int aic3x_set_dai_fmt(struct snd_soc_codec_dai *codec_dai, diff --git a/trunk/sound/soc/codecs/tlv320aic3x.h b/trunk/sound/soc/codecs/tlv320aic3x.h index d0cdeeb629de..d49d001e6e4c 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.h +++ b/trunk/sound/soc/codecs/tlv320aic3x.h @@ -109,6 +109,7 @@ #define LLOPM_CTRL 86 #define RLOPM_CTRL 93 /* Clock generation control register */ +#define AIC3X_GPIOB_REG 101 #define AIC3X_CLKGEN_CTRL_REG 102 /* Page select register bits */ @@ -128,12 +129,15 @@ /* PLL registers bitfields */ #define PLLP_SHIFT 0 +#define PLLQ_SHIFT 3 #define PLLR_SHIFT 0 #define PLLJ_SHIFT 2 #define PLLD_MSB_SHIFT 0 #define PLLD_LSB_SHIFT 2 /* Clock generation register bits */ +#define CODEC_CLKIN_PLLDIV 0 +#define CODEC_CLKIN_CLKDIV 1 #define PLL_CLKIN_SHIFT 4 #define MCLK_SOURCE 0x0 #define PLL_CLKDIV_SHIFT 0