From 2b67fc46061b2171fb8fbb55d1ac717abd533569 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 5 Feb 2007 21:16:47 +0100 Subject: [S390] Get rid of a lot of sparse warnings. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 2 +- drivers/s390/block/dasd_diag.c | 4 ++-- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/block/dasd_genhd.c | 2 +- drivers/s390/block/dasd_proc.c | 2 +- drivers/s390/char/con3215.c | 2 +- drivers/s390/char/con3270.c | 3 +-- drivers/s390/char/defkeymap.c | 2 ++ drivers/s390/char/fs3270.c | 4 ++-- drivers/s390/char/keyboard.c | 2 ++ drivers/s390/char/raw3270.c | 4 ++-- drivers/s390/char/sclp_tty.c | 2 +- drivers/s390/char/sclp_vt220.c | 2 +- drivers/s390/char/tape_char.c | 8 ++++---- drivers/s390/char/tty3270.c | 13 +++++-------- drivers/s390/char/vmlogrdr.c | 5 ++--- drivers/s390/cio/blacklist.c | 2 +- drivers/s390/cio/chsc.h | 3 +++ drivers/s390/cio/css.c | 5 +---- drivers/s390/cio/css.h | 2 ++ drivers/s390/cio/device.c | 1 - drivers/s390/cio/device.h | 2 ++ drivers/s390/cio/device_fsm.c | 2 +- drivers/s390/cio/qdio.c | 3 +-- drivers/s390/crypto/zcrypt_api.c | 4 ++-- drivers/s390/crypto/zcrypt_pcixcc.c | 3 ++- drivers/s390/net/claw.c | 2 +- drivers/s390/net/cu3088.c | 2 +- drivers/s390/net/lcs.c | 6 +++--- drivers/s390/net/netiucv.c | 4 ++-- drivers/s390/net/qeth_sys.c | 2 +- drivers/s390/s390mach.c | 14 +++++--------- drivers/s390/scsi/zfcp_dbf.c | 6 +++--- drivers/s390/scsi/zfcp_erp.c | 7 +++---- drivers/s390/scsi/zfcp_ext.h | 4 ++-- drivers/s390/scsi/zfcp_scsi.c | 18 +++++++++--------- 36 files changed, 74 insertions(+), 77 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 492b68bcd7cc..5b48a9c0966b 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -37,6 +37,7 @@ */ debug_info_t *dasd_debug_area; struct dasd_discipline *dasd_diag_discipline_pointer; +void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); MODULE_AUTHOR("Holger Smolinski "); MODULE_DESCRIPTION("Linux on S/390 DASD device driver," @@ -51,7 +52,6 @@ static int dasd_alloc_queue(struct dasd_device * device); static void dasd_setup_queue(struct dasd_device * device); static void dasd_free_queue(struct dasd_device * device); static void dasd_flush_request_queue(struct dasd_device *); -static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *); static int dasd_flush_ccw_queue(struct dasd_device *, int); static void dasd_tasklet(struct dasd_device *); static void do_kick_device(struct work_struct *); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 53db58a68617..51cdc16a72c5 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); #define DIAG_MAX_RETRIES 32 #define DIAG_TIMEOUT 50 * HZ -struct dasd_discipline dasd_diag_discipline; +static struct dasd_discipline dasd_diag_discipline; struct dasd_diag_private { struct dasd_diag_characteristics rdc_data; @@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req, "dump sense not available for DIAG data"); } -struct dasd_discipline dasd_diag_discipline = { +static struct dasd_discipline dasd_diag_discipline = { .owner = THIS_MODULE, .name = "DIAG", .ebcname = "DIAG", diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index fdaa471e845f..b126be1b25a9 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -548,7 +548,7 @@ dasd_eckd_read_conf(struct dasd_device *device) /* * Build CP for Perform Subsystem Function - SSC. */ -struct dasd_ccw_req * +static struct dasd_ccw_req * dasd_eckd_build_psf_ssc(struct dasd_device *device) { struct dasd_ccw_req *cqr; diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index d163632101d2..47ba4462708d 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device) */ memset(&bpart, 0, sizeof(struct blkpg_partition)); memset(&barg, 0, sizeof(struct blkpg_ioctl_arg)); - barg.data = (void __user *) &bpart; + barg.data = (void __force __user *) &bpart; barg.op = BLKPG_DEL_PARTITION; for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--) ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg); diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index bfa010f6dab2..a9ff934d7e2b 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -168,7 +168,7 @@ dasd_calc_metrics(char *page, char **start, off_t off, } static inline char * -dasd_statistics_array(char *str, int *array, int shift) +dasd_statistics_array(char *str, unsigned int *array, int shift) { int i; diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 25b5d7a66417..9a328f14a641 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = { * 3215 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -int __init +static int __init tty3215_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index 7566be890688..8e7f2d7633d6 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c @@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *); /* * Setup timeout for a device. On timeout trigger an update. */ -void -con3270_set_timer(struct con3270 *cp, int expires) +static void con3270_set_timer(struct con3270 *cp, int expires) { if (expires == 0) { if (timer_pending(&cp->timer)) diff --git a/drivers/s390/char/defkeymap.c b/drivers/s390/char/defkeymap.c index 17027d918cf7..564baca01b7c 100644 --- a/drivers/s390/char/defkeymap.c +++ b/drivers/s390/char/defkeymap.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include u_short plain_map[NR_KEYS] = { 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 0893d306ae80..e1a746269c4c 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c @@ -23,7 +23,7 @@ #include "raw3270.h" #include "ctrlchar.h" -struct raw3270_fn fs3270_fn; +static struct raw3270_fn fs3270_fn; struct fs3270 { struct raw3270_view view; @@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view) } /* View to a 3270 device. Can be console, tty or fullscreen. */ -struct raw3270_fn fs3270_fn = { +static struct raw3270_fn fs3270_fn = { .activate = fs3270_activate, .deactivate = fs3270_deactivate, .intv = (void *) fs3270_irq, diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 3e86fd1756e5..f62f9a4e8950 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc) } } +#if 0 /* * Generate ebcdic -> ascii translation table from kbd_data. */ @@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc) } } } +#endif /* * We have a combining character DIACR here, followed by the character CH. diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 7a84014f2037..8facd14adb7c 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c @@ -29,7 +29,7 @@ #include #include -struct class *class3270; +static struct class *class3270; /* The main 3270 data structure. */ struct raw3270 { @@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue); /* * Encode array for 12 bit 3270 addresses. */ -unsigned char raw3270_ebcgraf[64] = { +static unsigned char raw3270_ebcgraf[64] = { 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 2d173e5c8a09..90536f60bf50 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -721,7 +721,7 @@ static const struct tty_operations sclp_ops = { .ioctl = sclp_tty_ioctl, }; -int __init +static int __init sclp_tty_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 723bf4191bfe..d8135cd4d7ab 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -669,7 +669,7 @@ static const struct tty_operations sclp_vt220_ops = { /* * Register driver with SCLP and Linux and initialize internal tty structures. */ -int __init +static int __init sclp_vt220_tty_init(void) { struct tty_driver *driver; diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index 31198c8f2718..fb65cf05d4de 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -137,7 +137,7 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size) /* * Tape device read function */ -ssize_t +static ssize_t tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; @@ -201,7 +201,7 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) /* * Tape device write function */ -ssize_t +static ssize_t tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos) { struct tape_device *device; @@ -291,7 +291,7 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t /* * Character frontend tape device open function. */ -int +static int tapechar_open (struct inode *inode, struct file *filp) { struct tape_device *device; @@ -326,7 +326,7 @@ tapechar_open (struct inode *inode, struct file *filp) * Character frontend tape device release function. */ -int +static int tapechar_release(struct inode *inode, struct file *filp) { struct tape_device *device; diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 09844621edc0..bc33068b9ce2 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -36,7 +36,7 @@ struct tty_driver *tty3270_driver; static int tty3270_max_index; -struct raw3270_fn tty3270_fn; +static struct raw3270_fn tty3270_fn; struct tty3270_cell { unsigned char character; @@ -119,8 +119,7 @@ static void tty3270_update(struct tty3270 *); /* * Setup timeout for a device. On timeout trigger an update. */ -void -tty3270_set_timer(struct tty3270 *tp, int expires) +static void tty3270_set_timer(struct tty3270 *tp, int expires) { if (expires == 0) { if (timer_pending(&tp->timer) && del_timer(&tp->timer)) @@ -841,7 +840,7 @@ tty3270_del_views(void) } } -struct raw3270_fn tty3270_fn = { +static struct raw3270_fn tty3270_fn = { .activate = tty3270_activate, .deactivate = tty3270_deactivate, .intv = (void *) tty3270_irq, @@ -1754,8 +1753,7 @@ static const struct tty_operations tty3270_ops = { .set_termios = tty3270_set_termios }; -void -tty3270_notifier(int index, int active) +static void tty3270_notifier(int index, int active) { if (active) tty_register_device(tty3270_driver, index, NULL); @@ -1767,8 +1765,7 @@ tty3270_notifier(int index, int active) * 3270 tty registration code called from tty_init(). * Most kernel services (incl. kmalloc) are available at this poimt. */ -int __init -tty3270_init(void) +static int __init tty3270_init(void) { struct tty_driver *driver; int ret; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 6cb23040954b..4f894dc2373b 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -128,9 +128,8 @@ static iucv_interrupt_ops_t vmlogrdr_iucvops = { .MessagePending = vmlogrdr_iucv_MessagePending, }; - -DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); -DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); +static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); +static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); /* * pointer to system service private structure diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 12c2d6b746e6..4ec1334014e9 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -126,7 +126,7 @@ confused: static inline int blacklist_parse_parameters (char *str, range_action action) { - unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid; + int from, to, from_id0, to_id0, from_ssid, to_ssid; while (*str != 0 && *str != '\n') { range_action ra = action; diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index a259245780ae..3e8ac8f7b5cd 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -47,6 +47,9 @@ struct channel_path { extern void s390_process_css( void ); extern void chsc_validate_chpids(struct subchannel *); extern void chpid_is_actually_online(int); +extern int css_get_ssd_info(struct subchannel *); +extern int chsc_process_crw(void); +extern int chp_process_crw(int, int); struct css_general_char { u64 : 41; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 9d6c02446863..2da01b7a3b0a 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -108,9 +108,6 @@ css_subchannel_release(struct device *dev) } } -extern int css_get_ssd_info(struct subchannel *sch); - - int css_sch_device_register(struct subchannel *sch) { int ret; @@ -417,7 +414,7 @@ static void reprobe_all(struct work_struct *unused) need_reprobe); } -DECLARE_WORK(css_reprobe_work, reprobe_all); +static DECLARE_WORK(css_reprobe_work, reprobe_all); /* Schedule reprobing of all unregistered subchannels. */ void css_schedule_reprobe(void) diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 3464c5b875c4..ca2bab932a8a 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h @@ -143,6 +143,8 @@ extern void css_sch_device_unregister(struct subchannel *); extern struct subchannel * get_subchannel_by_schid(struct subchannel_id); extern int css_init_done; extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *); +extern int css_process_crw(int, int); +extern void css_reiterate_subchannels(void); #define __MAX_SUBCHANNEL 65535 #define __MAX_SSID 3 diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 803579053c2f..78ed65bf2f99 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -138,7 +138,6 @@ struct bus_type ccw_bus_type; static int io_subchannel_probe (struct subchannel *); static int io_subchannel_remove (struct subchannel *); -void io_subchannel_irq (struct device *); static int io_subchannel_notify(struct device *, int); static void io_subchannel_verify(struct device *); static void io_subchannel_ioterm(struct device *); diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 29db6341d632..b66338b76579 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -74,6 +74,7 @@ extern struct workqueue_struct *ccw_device_notify_work; extern wait_queue_head_t ccw_device_init_wq; extern atomic_t ccw_device_init_count; +void io_subchannel_irq (struct device *pdev); void io_subchannel_recog_done(struct ccw_device *cdev); int ccw_device_cancel_halt_clear(struct ccw_device *); @@ -118,6 +119,7 @@ int ccw_device_stlck(struct ccw_device *); /* qdio needs this. */ void ccw_device_set_timeout(struct ccw_device *, int); extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *); +extern struct bus_type ccw_bus_type; /* Channel measurement facility related */ void retry_set_schib(struct ccw_device *cdev); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index eed14572fc3b..2f920d376c80 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -892,7 +892,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) /* * Got an interrupt for a basic sense. */ -void +static void ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) { struct irb *irb; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 6fd1940842eb..8551c51976c6 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -66,7 +66,6 @@ MODULE_LICENSE("GPL"); /******************** HERE WE GO ***********************************/ static const char version[] = "QDIO base support version 2"; -extern struct bus_type ccw_bus_type; static int qdio_performance_stats = 0; static int proc_perf_file_registration; @@ -3014,7 +3013,7 @@ qdio_allocate(struct qdio_initialize *init_data) return 0; } -int qdio_fill_irq(struct qdio_initialize *init_data) +static int qdio_fill_irq(struct qdio_initialize *init_data) { int i; char dbf_text[15]; diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 1edc10a7a6f2..843a65f31bc9 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -791,7 +791,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, return rc; } -long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, +static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { if (cmd == ICARSAMODEXPO) @@ -943,7 +943,7 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset, zcrypt_qdepth_mask(workarea); len += sprinthx("Waiting work element counts", resp_buff+len, workarea, AP_DEVICES); - zcrypt_perdev_reqcnt((unsigned int *) workarea); + zcrypt_perdev_reqcnt((int *) workarea); len += sprinthx4("Per-device successfully completed request counts", resp_buff+len,(unsigned int *) workarea, AP_DEVICES); *eof = 1; diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index b7153c1e15cd..252443b6bd1b 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -709,7 +709,8 @@ out_free: * PCIXCC/CEX2C device to the request distributor * @xcRB: pointer to the send_cprb request buffer */ -long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB) +static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, + struct ica_xcRB *xcRB) { struct ap_message ap_msg; struct response_type resp_type = { diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 95f4e105cb96..4313f316b8fa 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -121,7 +121,7 @@ MODULE_LICENSE("GPL"); #define DEBUG #endif - char debug_buffer[255]; +static char debug_buffer[255]; /** * Debug Facility Stuff */ diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c index e965f03a7291..76728ae4b843 100644 --- a/drivers/s390/net/cu3088.c +++ b/drivers/s390/net/cu3088.c @@ -57,7 +57,7 @@ static struct ccw_device_id cu3088_ids[] = { static struct ccw_driver cu3088_driver; -struct device *cu3088_root_dev; +static struct device *cu3088_root_dev; static ssize_t group_write(struct device_driver *drv, const char *buf, size_t count) diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index e5665b6743a1..b97dd15bdb9a 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -828,7 +828,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd) /** * Emit buffer of a lan comand. */ -void +static void lcs_lancmd_timeout(unsigned long data) { struct lcs_reply *reply, *list_reply, *r; @@ -1360,7 +1360,7 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb) return 0; } -void +static void lcs_schedule_recovery(struct lcs_card *card) { LCS_DBF_TEXT(2, trace, "startrec"); @@ -1990,7 +1990,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char } -DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); +static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store); static ssize_t lcs_dev_recover_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index d7d1cc0a5c8e..3346088f47e0 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -2053,7 +2053,7 @@ out_free_ndev: return ret; } -DRIVER_ATTR(connection, 0200, NULL, conn_write); +static DRIVER_ATTR(connection, 0200, NULL, conn_write); static ssize_t remove_write (struct device_driver *drv, const char *buf, size_t count) @@ -2112,7 +2112,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) return -EINVAL; } -DRIVER_ATTR(remove, 0200, NULL, remove_write); +static DRIVER_ATTR(remove, 0200, NULL, remove_write); static void netiucv_banner(void) diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index 5836737ac58f..fca523a2608d 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -998,7 +998,7 @@ struct device_attribute dev_attr_##_id = { \ .store = _store, \ }; -int +static int qeth_check_layer2(struct qeth_card *card) { if (card->options.layer2) diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index e088b5e28711..1d084691e71e 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -13,22 +13,18 @@ #include #include #include +#include #include #include - +#include +#include "cio/cio.h" +#include "cio/chsc.h" +#include "cio/css.h" #include "s390mach.h" static struct semaphore m_sem; -extern int css_process_crw(int, int); -extern int chsc_process_crw(void); -extern int chp_process_crw(int, int); -extern void css_reiterate_subchannels(void); - -extern struct workqueue_struct *slow_path_wq; -extern struct work_struct slow_path_work; - static NORET_TYPE void s390_handle_damage(char *msg) { diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 0aa3b1ac76af..fd33537d0b2b 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -469,7 +469,7 @@ zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view, return len; } -struct debug_view zfcp_hba_dbf_view = { +static struct debug_view zfcp_hba_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, @@ -693,7 +693,7 @@ zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view, return len; } -struct debug_view zfcp_san_dbf_view = { +static struct debug_view zfcp_san_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, @@ -884,7 +884,7 @@ zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view, return len; } -struct debug_view zfcp_scsi_dbf_view = { +static struct debug_view zfcp_scsi_dbf_view = { "structured", NULL, &zfcp_dbf_view_header, diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index c88babce9bca..88642dec080c 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -200,7 +200,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout) * returns: 0 - initiated action successfully * <0 - failed to initiate action */ -int +static int zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask) { int retval; @@ -295,7 +295,7 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask) * zfcp_erp_adisc - send ADISC ELS command * @port: port structure */ -int +static int zfcp_erp_adisc(struct zfcp_port *port) { struct zfcp_adapter *adapter = port->adapter; @@ -380,7 +380,7 @@ zfcp_erp_adisc(struct zfcp_port *port) * * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered. */ -void +static void zfcp_erp_adisc_handler(unsigned long data) { struct zfcp_send_els *send_els; @@ -3141,7 +3141,6 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter, break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: if (result != ZFCP_ERP_SUCCEEDED) { - struct zfcp_port *port; list_for_each_entry(port, &adapter->port_list_head, list) if (port->rport && !atomic_test_mask(ZFCP_STATUS_PORT_WKA, diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index b8794d77285d..cda0cc095ad1 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -119,8 +119,8 @@ extern int zfcp_adapter_scsi_register(struct zfcp_adapter *); extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *); extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t); extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *); -extern void set_host_byte(u32 *, char); -extern void set_driver_byte(u32 *, char); +extern void set_host_byte(int *, char); +extern void set_driver_byte(int *, char); extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *); extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 452d96f92a14..99db02062c3b 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -90,7 +90,7 @@ zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu) return fcp_sns_info_ptr; } -fcp_dl_t * +static fcp_dl_t * zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd) { int additional_length = fcp_cmd->add_fcp_cdb_length << 2; @@ -124,19 +124,19 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl) * regarding the specified byte */ static inline void -set_byte(u32 * result, char status, char pos) +set_byte(int *result, char status, char pos) { *result |= status << (pos * 8); } void -set_host_byte(u32 * result, char status) +set_host_byte(int *result, char status) { set_byte(result, status, 2); } void -set_driver_byte(u32 * result, char status) +set_driver_byte(int *result, char status) { set_byte(result, status, 3); } @@ -280,7 +280,7 @@ out: return retval; } -void +static void zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt) { struct completion *wait = (struct completion *) scpnt->SCp.ptr; @@ -324,7 +324,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt, * returns: 0 - success, SCSI command enqueued * !0 - failure */ -int +static int zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt, void (*done) (struct scsi_cmnd *)) { @@ -380,7 +380,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id, * will handle late commands. (Usually, the normal completion of late * commands is ignored with respect to the running abort operation.) */ -int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) +static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) { struct Scsi_Host *scsi_host; struct zfcp_adapter *adapter; @@ -445,7 +445,7 @@ int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) return retval; } -int +static int zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt) { int retval; @@ -541,7 +541,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags, /** * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset */ -int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) +static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt) { struct zfcp_unit *unit; struct zfcp_adapter *adapter; -- cgit v1.2.3 From b0f1779a878cf15b07181ef31394ecd33b40c470 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Mon, 5 Feb 2007 21:16:49 +0100 Subject: [S390] Check the return value of kthread_run(). Signed-off-by: Akinobu Mita Signed-off-by: Martin Schwidefsky --- drivers/s390/s390mach.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 1d084691e71e..442d63470428 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -525,7 +525,11 @@ arch_initcall(machine_check_init); static int __init machine_check_crw_init (void) { - kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); + struct task_struct *task; + + task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck"); + if (IS_ERR(task)) + return PTR_ERR(task); ctl_set_bit(14, 28); /* enable channel report MCH */ return 0; } -- cgit v1.2.3 From 32c5b050927c515cea4083eb8f3a7177dc4279a1 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 5 Feb 2007 21:16:56 +0100 Subject: [S390] cio: Remove check for ssd in chpids_show(). Since ssd_info is now available before the subchannel is registered, we don't need to check whether it is available. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 78ed65bf2f99..eedf863c6c64 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -234,11 +234,8 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf) ssize_t ret = 0; int chp; - if (ssd) - for (chp = 0; chp < 8; chp++) - ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); - else - ret += sprintf (buf, "n/a"); + for (chp = 0; chp < 8; chp++) + ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]); ret += sprintf (buf+ret, "\n"); return min((ssize_t)PAGE_SIZE, ret); } -- cgit v1.2.3 From dbd8ae63065189b12c46bdc58799dc353e4b3a53 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 5 Feb 2007 21:17:00 +0100 Subject: [S390] sclp: invalid handling of temporary 'not operational' status Requests are aborted when the sclp interface reports 'not operational' even though they may still be active at the sclp, leading to concurrent writes to request memory by both the kernel and the sclp interface. Do not abort requests for which the sclp interface reports not operational status during request retry. Signed-off-by: Peter Oberparleiter 5A Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 70 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 21 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 8a056df09d6b..3457a9a31571 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t { /* Internal state: is a request active at the sclp? */ static volatile enum sclp_running_state_t { sclp_running_state_idle, - sclp_running_state_running + sclp_running_state_running, + sclp_running_state_reset_pending } sclp_running_state = sclp_running_state_idle; /* Internal state: is a read request pending? */ @@ -88,7 +89,7 @@ static volatile enum sclp_mask_state_t { /* Timeout intervals in seconds.*/ #define SCLP_BUSY_INTERVAL 10 -#define SCLP_RETRY_INTERVAL 15 +#define SCLP_RETRY_INTERVAL 30 static void sclp_process_queue(void); static int sclp_init_mask(int calculate); @@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb) return 0; } -/* Request timeout handler. Restart the request queue. If DATA is non-zero, - * force restart of running request. */ +static inline void __sclp_make_read_req(void); + static void -sclp_request_timeout(unsigned long data) +__sclp_queue_read_req(void) { - unsigned long flags; - - if (data) { - spin_lock_irqsave(&sclp_lock, flags); - sclp_running_state = sclp_running_state_idle; - spin_unlock_irqrestore(&sclp_lock, flags); + if (sclp_reading_state == sclp_reading_state_idle) { + sclp_reading_state = sclp_reading_state_reading; + __sclp_make_read_req(); + /* Add request to head of queue */ + list_add(&sclp_read_req.list, &sclp_req_queue); } - sclp_process_queue(); } /* Set up request retry timer. Called while sclp_lock is locked. */ @@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long), add_timer(&sclp_request_timer); } +/* Request timeout handler. Restart the request queue. If DATA is non-zero, + * force restart of running request. */ +static void +sclp_request_timeout(unsigned long data) +{ + unsigned long flags; + + spin_lock_irqsave(&sclp_lock, flags); + if (data) { + if (sclp_running_state == sclp_running_state_running) { + /* Break running state and queue NOP read event request + * to get a defined interface state. */ + __sclp_queue_read_req(); + sclp_running_state = sclp_running_state_idle; + } + } else { + __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ, + sclp_request_timeout, 0); + } + spin_unlock_irqrestore(&sclp_lock, flags); + sclp_process_queue(); +} + /* Try to start a request. Return zero if the request was successfully * started or if it will be started at a later time. Return non-zero otherwise. * Called while sclp_lock is locked. */ @@ -191,7 +213,15 @@ sclp_process_queue(void) rc = __sclp_start_request(req); if (rc == 0) break; - /* Request failed. */ + /* Request failed */ + if (req->start_count > 1) { + /* Cannot abort already submitted request - could still + * be active at the SCLP */ + __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ, + sclp_request_timeout, 0); + break; + } + /* Post-processing for aborted request */ list_del(&req->list); if (req->callback) { spin_unlock_irqrestore(&sclp_lock, flags); @@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req) list_add_tail(&req->list, &sclp_req_queue); rc = 0; /* Start if request is first in list */ - if (req->list.prev == &sclp_req_queue) { + if (sclp_running_state == sclp_running_state_idle && + req->list.prev == &sclp_req_queue) { rc = __sclp_start_request(req); if (rc) list_del(&req->list); @@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code) finished_sccb = S390_lowcore.ext_params & 0xfffffff8; evbuf_pending = S390_lowcore.ext_params & 0x3; if (finished_sccb) { + del_timer(&sclp_request_timer); + sclp_running_state = sclp_running_state_reset_pending; req = __sclp_find_req(finished_sccb); if (req) { /* Request post-processing */ @@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code) sclp_running_state = sclp_running_state_idle; } if (evbuf_pending && sclp_receive_mask != 0 && - sclp_reading_state == sclp_reading_state_idle && - sclp_activation_state == sclp_activation_state_active ) { - sclp_reading_state = sclp_reading_state_reading; - __sclp_make_read_req(); - /* Add request to head of queue */ - list_add(&sclp_read_req.list, &sclp_req_queue); - } + sclp_activation_state == sclp_activation_state_active) + __sclp_queue_read_req(); spin_unlock(&sclp_lock); sclp_process_queue(); } -- cgit v1.2.3 From e3c699b38ef3c59521fdd1732efcaaa789d81440 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Mon, 5 Feb 2007 21:17:04 +0100 Subject: [S390] dasd: fix bug in dasd initialization cleanup The initialization of the dasd_eer code is one of the last steps of the dasd driver initialization. When initialization fails in one of the earlier steps, the dasd_exit function is called to clean up what has been done so far. So the dasd_eer_exit function may be called, although the dasd_eer_init function wasn't called before and dasd_eer_exit tries to unregister a misc device that wasn't registered, which results in a BUG. Make sure that dasd_eer_exit can be called without initialization. Use a dynamically allocated struct miscdevice instead of a static one, so we only try to unregister the device if it exists and was actually registered. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eer.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index e0bf30ebb215..6cedc914077e 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = { .owner = THIS_MODULE, }; -static struct miscdevice dasd_eer_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "dasd_eer", - .fops = &dasd_eer_fops, -}; +static struct miscdevice *dasd_eer_dev = NULL; int __init dasd_eer_init(void) { int rc; - rc = misc_register(&dasd_eer_dev); + dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL); + if (!dasd_eer_dev) + return -ENOMEM; + + dasd_eer_dev->minor = MISC_DYNAMIC_MINOR; + dasd_eer_dev->name = "dasd_eer"; + dasd_eer_dev->fops = &dasd_eer_fops; + + rc = misc_register(dasd_eer_dev); if (rc) { + kfree(dasd_eer_dev); + dasd_eer_dev = NULL; MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " "register misc device"); return rc; @@ -680,5 +686,9 @@ int __init dasd_eer_init(void) void dasd_eer_exit(void) { - WARN_ON(misc_deregister(&dasd_eer_dev) != 0); + if (dasd_eer_dev) { + WARN_ON(misc_deregister(dasd_eer_dev) != 0); + kfree(dasd_eer_dev); + dasd_eer_dev = NULL; + } } -- cgit v1.2.3 From 18374d376c7eb30b6359759e767cd99397b377d2 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 5 Feb 2007 21:17:09 +0100 Subject: [S390] cio: Restart path verification after unsolicited interrupt. If we try to start path verification when an unsolicited interrupt is already pending, stctl shows status pending and we delay path verification again. We need to check for the doverify bit when the unsolicited interrupt comes in and then do path verification. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/device_fsm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 2f920d376c80..da575365b134 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -842,6 +842,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) call_handler_unsol: if (cdev->handler) cdev->handler (cdev, 0, irb); + if (cdev->private->flags.doverify) + ccw_device_online_verify(cdev, 0); return; } /* Accumulate status and find out if a basic sense is needed. */ -- cgit v1.2.3 From 444f0e5489e7ac4bca5c4748d7d846c352a5cd03 Mon Sep 17 00:00:00 2001 From: Gerald Schaefer Date: Mon, 5 Feb 2007 21:17:11 +0100 Subject: [S390] Show loaded DCSS segments under /proc/iomem. Currently loaded DCSS segments are now listed in /proc/iomem with their name followed by a trailing "(DCSS)". Signed-off-by: Gerald Schaefer Signed-off-by: Martin Schwidefsky --- arch/s390/mm/extmem.c | 64 +++++++++++++++++++++++++++++++++++++------- drivers/s390/block/dcssblk.c | 4 +-- 2 files changed, 56 insertions(+), 12 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 775bf19e742b..8bffadb5e537 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ struct qin64 { struct dcss_segment { struct list_head list; char dcss_name[8]; + char res_name[15]; unsigned long start_addr; unsigned long end; atomic_t ref_count; @@ -77,6 +79,7 @@ struct dcss_segment { unsigned int vm_segtype; struct qrange range[6]; int segcnt; + struct resource *res; }; static DEFINE_MUTEX(dcss_lock); @@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long goto out_free; } + seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL); + if (seg->res == NULL) { + rc = -ENOMEM; + goto out_shared; + } + seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; + seg->res->start = seg->start_addr; + seg->res->end = seg->end; + memcpy(&seg->res_name, seg->dcss_name, 8); + EBCASC(seg->res_name, 8); + seg->res_name[8] = '\0'; + strncat(seg->res_name, " (DCSS)", 7); + seg->res->name = seg->res_name; + rc = seg->vm_segtype; + if (rc == SEG_TYPE_SC || + ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared)) + seg->res->flags |= IORESOURCE_READONLY; + if (request_resource(&iomem_resource, seg->res)) { + rc = -EBUSY; + kfree(seg->res); + goto out_shared; + } + if (do_nonshared) dcss_command = DCSS_LOADNSR; else @@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long rc = dcss_diag_translate_rc (seg->end); dcss_diag(DCSS_PURGESEG, seg->dcss_name, &seg->start_addr, &seg->end); - goto out_shared; + goto out_resource; } seg->do_nonshared = do_nonshared; atomic_set(&seg->ref_count, 1); list_add(&seg->list, &dcss_list); - rc = seg->vm_segtype; *addr = seg->start_addr; *end = seg->end; if (do_nonshared) @@ -329,12 +354,16 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long "type %s in non-shared mode\n", name, (void*)seg->start_addr, (void*)seg->end, segtype_string[seg->vm_segtype]); - else + else { PRINT_INFO ("segment_load: loaded segment %s range %p .. %p " "type %s in shared mode\n", name, (void*)seg->start_addr, (void*)seg->end, segtype_string[seg->vm_segtype]); + } goto out; + out_resource: + release_resource(seg->res); + kfree(seg->res); out_shared: remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); out_free: @@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, * -ENOENT : no such segment (segment gone!) * -EAGAIN : segment is in use by other exploiters, try later * -EINVAL : no segment with the given name is currently loaded - name invalid + * -EBUSY : segment can temporarily not be used (overlaps with dcss) * 0 : operation succeeded */ int @@ -428,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared) rc = -EAGAIN; goto out_unlock; } - dcss_diag(DCSS_PURGESEG, seg->dcss_name, - &dummy, &dummy); - if (do_nonshared) + release_resource(seg->res); + if (do_nonshared) { dcss_command = DCSS_LOADNSR; - else - dcss_command = DCSS_LOADNOLY; + seg->res->flags &= ~IORESOURCE_READONLY; + } else { + dcss_command = DCSS_LOADNOLY; + if (seg->vm_segtype == SEG_TYPE_SR || + seg->vm_segtype == SEG_TYPE_ER) + seg->res->flags |= IORESOURCE_READONLY; + } + if (request_resource(&iomem_resource, seg->res)) { + PRINT_WARN("segment_modify_shared: could not reload segment %s" + " - overlapping resources\n", name); + rc = -EBUSY; + kfree(seg->res); + goto out_del; + } + dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); diag_cc = dcss_diag(dcss_command, seg->dcss_name, &seg->start_addr, &seg->end); if (diag_cc > 1) { @@ -446,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared) rc = 0; goto out_unlock; out_del: + remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); - dcss_diag(DCSS_PURGESEG, seg->dcss_name, - &dummy, &dummy); + dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); kfree(seg); out_unlock: mutex_unlock(&dcss_lock); @@ -478,6 +520,8 @@ segment_unload(char *name) } if (atomic_dec_return(&seg->ref_count) != 0) goto out_unlock; + release_resource(seg->res); + kfree(seg->res); remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1); list_del(&seg->list); dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy); diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index be9b05347b4f..bd1b66a54c21 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch SEGMENT_SHARED); if (rc < 0) { BUG_ON(rc == -EINVAL); - if (rc == -EIO || rc == -ENOENT) + if (rc != -EAGAIN) goto removeseg; } else { dev_info->is_shared = 1; @@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch SEGMENT_EXCLUSIVE); if (rc < 0) { BUG_ON(rc == -EINVAL); - if (rc == -EIO || rc == -ENOENT) + if (rc != -EAGAIN) goto removeseg; } else { dev_info->is_shared = 0; -- cgit v1.2.3 From c59d744bd8a0e283daf6726881e4c9aa4bd25261 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 5 Feb 2007 21:17:16 +0100 Subject: [S390] sclp: don't call local_bh_disable/_local_bh_enable if in_interrupt() local_bh_disable/_local_bh_enable must not be called if in_irq() is true. Besides that if in_interrupt() is true bottom halves are disabled anyway. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 3457a9a31571..027cdc18df31 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -402,6 +402,7 @@ sclp_sync_wait(void) unsigned long flags; unsigned long cr0, cr0_sync; u64 timeout; + int irq_context; /* We'll be disabling timer interrupts, so we need a custom timeout * mechanism */ @@ -414,7 +415,9 @@ sclp_sync_wait(void) } local_irq_save(flags); /* Prevent bottom half from executing once we force interrupts open */ - local_bh_disable(); + irq_context = in_interrupt(); + if (!irq_context) + local_bh_disable(); /* Enable service-signal interruption, disable timer interrupts */ trace_hardirqs_on(); __ctl_store(cr0, 0, 0); @@ -435,7 +438,8 @@ sclp_sync_wait(void) } local_irq_disable(); __ctl_load(cr0, 0, 0); - _local_bh_enable(); + if (!irq_context) + _local_bh_enable(); local_irq_restore(flags); } -- cgit v1.2.3 From 1125b4640fea29aafe9bf24672e2da9672f6592e Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 5 Feb 2007 21:17:18 +0100 Subject: [S390] cio: Use device_{create,remove}_bin_file. Create/remove the channel measurement binary files with device_{create,remove}_bin_file instead of sysfs_{create,remove}_bin_file. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index cbab8d2ce5cf..15b0e6329cf3 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -967,8 +967,8 @@ static struct bin_attribute chp_measurement_attr = { static void chsc_remove_chp_cmg_attr(struct channel_path *chp) { - sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr); - sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_attr); } static int @@ -976,14 +976,12 @@ chsc_add_chp_cmg_attr(struct channel_path *chp) { int ret; - ret = sysfs_create_bin_file(&chp->dev.kobj, - &chp_measurement_chars_attr); + ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr); if (ret) return ret; - ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr); + ret = device_create_bin_file(&chp->dev, &chp_measurement_attr); if (ret) - sysfs_remove_bin_file(&chp->dev.kobj, - &chp_measurement_chars_attr); + device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr); return ret; } -- cgit v1.2.3 From c48e09131bd7c632c80a3245688d2d29dbc4f6b5 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 5 Feb 2007 21:17:20 +0100 Subject: [S390] Small barrier() and cpu_relax() cleanup. cpu_relax() has barrier() semantics hence there is no need to use both of them in conjunction in sclp_sync_wait(). Also change cpu_relax() so it's more obvious that it has barrier semantics. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/char/sclp.c | 1 - include/asm-s390/processor.h | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 027cdc18df31..c1dd19bb7bf8 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -433,7 +433,6 @@ sclp_sync_wait(void) get_clock() > timeout && del_timer(&sclp_request_timer)) sclp_request_timer.function(sclp_request_timer.data); - barrier(); cpu_relax(); } local_irq_disable(); diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index cbbedc63ba25..5dc6b938895f 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -201,9 +201,8 @@ unsigned long get_wchan(struct task_struct *p); static inline void cpu_relax(void) { if (MACHINE_HAS_DIAG44) - asm volatile("diag 0,0,68" : : : "memory"); - else - barrier(); + asm volatile("diag 0,0,68"); + barrier(); } /* -- cgit v1.2.3 From db2738197b52f02f4c599c1ae3f66ae1894406cd Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Mon, 5 Feb 2007 21:17:22 +0100 Subject: [S390] Remove dasd_ccw_log function. Logging of relevant information is already done by disciplines dump_sense function. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_3990_erp.c | 5 ---- drivers/s390/block/dasd_erp.c | 61 -------------------------------------- drivers/s390/block/dasd_int.h | 1 - 3 files changed, 67 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 4d01040c2c63..8b9d68f6e016 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb) /* log the erp chain if fatal error occurred */ if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) { dasd_log_sense(cqr, irb); - dasd_log_ccw(cqr, 0, irb->scsw.cpa); } return era; @@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) struct dasd_ccw_req *erp = NULL; struct dasd_device *device = cqr->device; - __u32 cpa = cqr->irb.scsw.cpa; struct dasd_ccw_req *temp_erp = NULL; if (device->features & DASD_FEATURE_ERPLOG) { @@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr) } } - if (erp->status == DASD_CQR_FAILED) - dasd_log_ccw(erp, 1, cpa); - /* enqueue added ERP request */ if (erp->status == DASD_CQR_FILLED) { erp->status = DASD_CQR_QUEUED; diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 58a65097922b..abf7cefb29c2 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -182,69 +182,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) device->discipline->dump_sense(device, cqr, irb); } -void -dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa) -{ - struct dasd_device *device; - struct dasd_ccw_req *lcqr; - struct ccw1 *ccw; - int cplength; - - device = cqr->device; - /* log the channel program */ - for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) { - DEV_MESSAGE(KERN_ERR, device, - "(%s) ERP chain report for req: %p", - caller == 0 ? "EXAMINE" : "ACTION", lcqr); - hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req)); - - cplength = 1; - ccw = lcqr->cpaddr; - while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC)) - cplength++; - - if (cplength > 40) { /* log only parts of the CP */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Start of channel program:"); - hex_dump_memory(device, lcqr->cpaddr, - 40*sizeof(struct ccw1)); - - DEV_MESSAGE(KERN_ERR, device, "%s", - "End of channel program:"); - hex_dump_memory(device, lcqr->cpaddr + cplength - 10, - 10*sizeof(struct ccw1)); - } else { /* log the whole CP */ - DEV_MESSAGE(KERN_ERR, device, "%s", - "Channel program (complete):"); - hex_dump_memory(device, lcqr->cpaddr, - cplength*sizeof(struct ccw1)); - } - - if (lcqr != cqr) - continue; - - /* - * Log bytes arround failed CCW but only if we did - * not log the whole CP of the CCW is outside the - * logged CP. - */ - if (cplength > 40 || - ((addr_t) cpa < (addr_t) lcqr->cpaddr && - (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) { - - DEV_MESSAGE(KERN_ERR, device, - "Failed CCW (%p) (area):", - (void *) (long) cpa); - hex_dump_memory(device, cqr->cpaddr - 10, - 20*sizeof(struct ccw1)); - } - } - -} /* end log_erp_chain */ - EXPORT_SYMBOL(dasd_default_erp_action); EXPORT_SYMBOL(dasd_default_erp_postaction); EXPORT_SYMBOL(dasd_alloc_erp_request); EXPORT_SYMBOL(dasd_free_erp_request); EXPORT_SYMBOL(dasd_log_sense); -EXPORT_SYMBOL(dasd_log_ccw); diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index fb725e3b08fe..a2cc69e11410 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h @@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int, struct dasd_device *); void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *); void dasd_log_sense(struct dasd_ccw_req *, struct irb *); -void dasd_log_ccw(struct dasd_ccw_req *, int, __u32); /* externals in dasd_3370_erp.c */ dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *); -- cgit v1.2.3 From 336c340b682daa283acf9202a07c4fd5c28e53a5 Mon Sep 17 00:00:00 2001 From: Horst Hummel Date: Mon, 5 Feb 2007 21:17:24 +0100 Subject: [S390] dasd: fix unconditional reserve handling. The reserve/release IOCTLs sometimes do not work. If second system does a 'steal lock' the pending unit check (Format 3 Msg F) is delivered. Since ERP is disabled for reserve/release, the IOCTL call fails. We have to allow basic ERP (retries) for reserve/release IOCTLs. Signed-off-by: Horst Hummel Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd.c | 6 +++--- drivers/s390/block/dasd_eckd.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 5b48a9c0966b..f208940c463c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm, irb->scsw.cstat == 0 && !irb->esw.esw0.erw.cons) era = dasd_era_none; - else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags)) - era = dasd_era_fatal; /* don't recover this request */ else if (irb->esw.esw0.erw.cons) era = device->discipline->examine_error(cqr, irb); else @@ -1127,7 +1125,9 @@ restart: cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); } else { - if (cqr->irb.esw.esw0.erw.cons) { + if (cqr->irb.esw.esw0.erw.cons && + test_bit(DASD_CQR_FLAGS_USE_ERP, + &cqr->flags)) { erp_fn = device->discipline-> erp_action(cqr); erp_fn(cqr); diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index b126be1b25a9..d59115cce6dc 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -1380,7 +1380,7 @@ dasd_eckd_release(struct dasd_device *device) cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1420,7 +1420,7 @@ dasd_eckd_reserve(struct dasd_device *device) cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; @@ -1459,7 +1459,7 @@ dasd_eckd_steal_lock(struct dasd_device *device) cqr->device = device; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags); - cqr->retries = 0; + cqr->retries = 2; /* set retry counter to enable basic ERP */ cqr->expires = 2 * HZ; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; -- cgit v1.2.3 From 758976f9a55cb22ddc602a0690d67f9546e3e43f Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 5 Feb 2007 21:17:36 +0100 Subject: [S390] cio: Catch operand exceptions on stsch. If we have a subchannel id which has been generated via for_each_subchannel(), it might contain an invalid subchannel set id. We need to catch the ensuing operand exception by using stsch_err() instead of stsch() in all possible cases. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 2 +- drivers/s390/cio/css.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 15b0e6329cf3..514daeaba705 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -608,7 +608,7 @@ __chp_add_new_sch(struct subchannel_id schid) struct schib schib; int ret; - if (stsch(schid, &schib)) + if (stsch_err(schid, &schib)) /* We're through */ return need_rescan ? -EAGAIN : -ENXIO; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 2da01b7a3b0a..bdf13699fe0d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -296,7 +296,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) /* Will be done on the slow path. */ return -EAGAIN; } - if (stsch(schid, &schib) || !schib.pmcw.dnv) { + if (stsch_err(schid, &schib) || !schib.pmcw.dnv) { /* Unusable - ignore. */ return 0; } -- cgit v1.2.3 From 0f008aa300f1a48144a1b988a85db9d330f884b7 Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 5 Feb 2007 21:17:40 +0100 Subject: [S390] cio: declare hardware structures packed. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 16 ++++++++-------- drivers/s390/cio/chsc.h | 8 ++++---- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 514daeaba705..0260f12231e0 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -93,7 +93,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page) u16 sch; /* subchannel */ u8 chpid[8]; /* chpids 0-7 */ u16 fla[8]; /* full link addresses 0-7 */ - } *ssd_area; + } __attribute__ ((packed)) *ssd_area; ssd_area = page; @@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data) u32 andesc[28]; /* incident-specific information */ u32 isinfo[28]; - } *lir; + } __attribute__ ((packed)) *lir; lir = data; if (!(lir->iq&0x80)) @@ -483,7 +483,7 @@ chsc_process_crw(void) u32 reserved6; u32 ccdf[96]; /* content-code dependent field */ /* ccdf has to be big enough for a link-incident record */ - } *sei_area; + } __attribute__ ((packed)) *sei_area; if (!sei_page) return 0; @@ -1040,7 +1040,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) u32 : 4; u32 fmt : 4; u32 : 16; - } *secm_area; + } __attribute__ ((packed)) *secm_area; int ret, ccode; secm_area = page; @@ -1251,7 +1251,7 @@ chsc_determine_channel_path_description(int chpid, struct chsc_header response; u32 zeroes2; struct channel_path_desc desc; - } *scpd_area; + } __attribute__ ((packed)) *scpd_area; scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scpd_area) @@ -1348,7 +1348,7 @@ chsc_get_channel_measurement_chars(struct channel_path *chp) u32 cmg : 8; u32 zeroes3; u32 data[NR_MEASUREMENT_CHARS]; - } *scmc_area; + } __attribute__ ((packed)) *scmc_area; scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scmc_area) @@ -1515,7 +1515,7 @@ chsc_enable_facility(int operation_code) u32 reserved5:4; u32 format2:4; u32 reserved6:24; - } *sda_area; + } __attribute__ ((packed)) *sda_area; sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA); if (!sda_area) @@ -1567,7 +1567,7 @@ chsc_determine_css_characteristics(void) u32 reserved4; u32 general_char[510]; u32 chsc_char[518]; - } *scsc_area; + } __attribute__ ((packed)) *scsc_area; scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA); if (!scsc_area) { diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 3e8ac8f7b5cd..0fb2b024208f 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -10,17 +10,17 @@ struct chsc_header { u16 length; u16 code; -}; +} __attribute__ ((packed)); #define NR_MEASUREMENT_CHARS 5 struct cmg_chars { u32 values[NR_MEASUREMENT_CHARS]; -}; +} __attribute__ ((packed)); #define NR_MEASUREMENT_ENTRIES 8 struct cmg_entry { u32 values[NR_MEASUREMENT_ENTRIES]; -}; +} __attribute__ ((packed)); struct channel_path_desc { u8 flags; @@ -31,7 +31,7 @@ struct channel_path_desc { u8 zeroes; u8 chla; u8 chpp; -}; +} __attribute__ ((packed)); struct channel_path { int id; -- cgit v1.2.3 From 184357a59669e2b1f9bb684c598458717207793b Mon Sep 17 00:00:00 2001 From: Peter Oberparleiter Date: Mon, 5 Feb 2007 21:17:42 +0100 Subject: [S390] Cleanup of CHSC event handling. Change CHSC event handling to be more easily extensible. Signed-off-by: Peter Oberparleiter Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/chsc.c | 232 +++++++++++++++++++++++------------------------- 1 file changed, 112 insertions(+), 120 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 0260f12231e0..c6db7f44689a 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -461,144 +461,136 @@ __get_chpid_from_lir(void *data) return (u16) (lir->indesc[0]&0x000000ff); } -int -chsc_process_crw(void) +struct chsc_sei_area { + struct chsc_header request; + u32 reserved1; + u32 reserved2; + u32 reserved3; + struct chsc_header response; + u32 reserved4; + u8 flags; + u8 vf; /* validity flags */ + u8 rs; /* reporting source */ + u8 cc; /* content code */ + u16 fla; /* full link address */ + u16 rsid; /* reporting source id */ + u32 reserved5; + u32 reserved6; + u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */ + /* ccdf has to be big enough for a link-incident record */ +} __attribute__ ((packed)); + +static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) +{ + int chpid; + + CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n", + sei_area->rs, sei_area->rsid); + if (sei_area->rs != 4) + return 0; + chpid = __get_chpid_from_lir(sei_area->ccdf); + if (chpid < 0) + CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n"); + else + s390_set_chpid_offline(chpid); + + return 0; +} + +static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) { - int chpid, ret; struct res_acc_data res_data; - struct { - struct chsc_header request; - u32 reserved1; - u32 reserved2; - u32 reserved3; - struct chsc_header response; - u32 reserved4; - u8 flags; - u8 vf; /* validity flags */ - u8 rs; /* reporting source */ - u8 cc; /* content code */ - u16 fla; /* full link address */ - u16 rsid; /* reporting source id */ - u32 reserved5; - u32 reserved6; - u32 ccdf[96]; /* content-code dependent field */ - /* ccdf has to be big enough for a link-incident record */ - } __attribute__ ((packed)) *sei_area; + struct device *dev; + int status; + int rc; + + CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, " + "rs_id=%04x)\n", sei_area->rs, sei_area->rsid); + if (sei_area->rs != 4) + return 0; + /* allocate a new channel path structure, if needed */ + status = get_chp_status(sei_area->rsid); + if (status < 0) + new_channel_path(sei_area->rsid); + else if (!status) + return 0; + dev = get_device(&css[0]->chps[sei_area->rsid]->dev); + memset(&res_data, 0, sizeof(struct res_acc_data)); + res_data.chp = to_channelpath(dev); + if ((sei_area->vf & 0xc0) != 0) { + res_data.fla = sei_area->fla; + if ((sei_area->vf & 0xc0) == 0xc0) + /* full link address */ + res_data.fla_mask = 0xffff; + else + /* link address */ + res_data.fla_mask = 0xff00; + } + rc = s390_process_res_acc(&res_data); + put_device(dev); + + return rc; +} + +static int chsc_process_sei(struct chsc_sei_area *sei_area) +{ + int rc; + + /* Check if we might have lost some information. */ + if (sei_area->flags & 0x40) + CIO_CRW_EVENT(2, "chsc: event overflow\n"); + /* which kind of information was stored? */ + rc = 0; + switch (sei_area->cc) { + case 1: /* link incident*/ + rc = chsc_process_sei_link_incident(sei_area); + break; + case 2: /* i/o resource accessibiliy */ + rc = chsc_process_sei_res_acc(sei_area); + break; + default: /* other stuff */ + CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n", + sei_area->cc); + break; + } + + return rc; +} + +int chsc_process_crw(void) +{ + struct chsc_sei_area *sei_area; + int ret; + int rc; if (!sei_page) return 0; - /* - * build the chsc request block for store event information - * and do the call - * This function is only called by the machine check handler thread, - * so we don't need locking for the sei_page. - */ + /* 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"); ret = 0; do { - int ccode, status; - struct device *dev; memset(sei_area, 0, sizeof(*sei_area)); - memset(&res_data, 0, sizeof(struct res_acc_data)); sei_area->request.length = 0x0010; sei_area->request.code = 0x000e; + if (chsc(sei_area)) + break; - ccode = chsc(sei_area); - if (ccode > 0) - return 0; - - switch (sei_area->response.code) { - /* for debug purposes, check for problems */ - case 0x0001: - CIO_CRW_EVENT(4, "chsc_process_crw: event information " - "successfully stored\n"); - break; /* everything ok */ - case 0x0002: - CIO_CRW_EVENT(2, - "chsc_process_crw: invalid command!\n"); - return 0; - case 0x0003: - CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc " - "request block!\n"); - return 0; - case 0x0005: - CIO_CRW_EVENT(2, "chsc_process_crw: no event " - "information stored\n"); - return 0; - default: - CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n", + if (sei_area->response.code == 0x0001) { + CIO_CRW_EVENT(4, "chsc: sei successful\n"); + rc = chsc_process_sei(sei_area); + if (rc) + ret = rc; + } else { + CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n", sei_area->response.code); - return 0; - } - - /* Check if we might have lost some information. */ - if (sei_area->flags & 0x40) - CIO_CRW_EVENT(2, "chsc_process_crw: Event information " - "has been lost due to overflow!\n"); - - if (sei_area->rs != 4) { - CIO_CRW_EVENT(2, "chsc_process_crw: reporting source " - "(%04X) isn't a chpid!\n", - sei_area->rsid); - continue; - } - - /* which kind of information was stored? */ - switch (sei_area->cc) { - case 1: /* link incident*/ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports link incident," - " reporting source is chpid %x\n", - sei_area->rsid); - chpid = __get_chpid_from_lir(sei_area->ccdf); - if (chpid < 0) - CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n", - __FUNCTION__); - else - s390_set_chpid_offline(chpid); - break; - - case 2: /* i/o resource accessibiliy */ - CIO_CRW_EVENT(4, "chsc_process_crw: " - "channel subsystem reports some I/O " - "devices may have become accessible\n"); - pr_debug("Data received after sei: \n"); - pr_debug("Validity flags: %x\n", sei_area->vf); - - /* allocate a new channel path structure, if needed */ - status = get_chp_status(sei_area->rsid); - if (status < 0) - new_channel_path(sei_area->rsid); - else if (!status) - break; - dev = get_device(&css[0]->chps[sei_area->rsid]->dev); - res_data.chp = to_channelpath(dev); - pr_debug("chpid: %x", sei_area->rsid); - if ((sei_area->vf & 0xc0) != 0) { - res_data.fla = sei_area->fla; - if ((sei_area->vf & 0xc0) == 0xc0) { - pr_debug(" full link addr: %x", - sei_area->fla); - res_data.fla_mask = 0xffff; - } else { - pr_debug(" link addr: %x", - sei_area->fla); - res_data.fla_mask = 0xff00; - } - } - ret = s390_process_res_acc(&res_data); - pr_debug("\n\n"); - put_device(dev); - break; - - default: /* other stuff */ - CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n", - sei_area->cc); + ret = 0; break; } } while (sei_area->flags & 0x80); + return ret; } -- cgit v1.2.3 From 347d59d7e9739ff2acbaa751b6225ecb335c3f29 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Mon, 5 Feb 2007 21:17:56 +0100 Subject: [S390] cio: Don't spam debug feature. Lower priority of "Blacklisted device detected" messages so we don't overwrite more useful messages. Signed-off-by: Cornelia Huck Signed-off-by: Martin Schwidefsky --- drivers/s390/cio/cio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/s390') diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index ae1bf231d089..07a4cbfc2436 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -585,7 +585,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) * This device must not be known to Linux. So we simply * say that there is no device and return ENODEV. */ - CIO_MSG_EVENT(0, "Blacklisted device detected " + CIO_MSG_EVENT(4, "Blacklisted device detected " "at devno %04X, subchannel set %x\n", sch->schib.pmcw.dev, sch->schid.ssid); err = -ENODEV; -- cgit v1.2.3 From d54853ef8cb17296ac7bce9c77430fb7c80532d0 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 5 Feb 2007 21:18:19 +0100 Subject: [S390] ETR support. This patch adds support for clock synchronization to an external time reference (ETR). The external time reference sends an oscillator signal and a synchronization signal every 2^20 microseconds to keep the TOD clocks of all connected servers in sync. For availability two ETR units can be connected to a machine. If the clock deviates for more than the sync-check tolerance all cpus get a machine check that indicates that the clock is out of sync. For the lovely details how to get the clock back in sync see the code below. Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/s390_ext.c | 8 +- arch/s390/kernel/smp.c | 3 +- arch/s390/kernel/time.c | 1179 +++++++++++++++++++++++++++++++++++++--- arch/s390/kernel/vtime.c | 8 +- arch/s390/lib/delay.c | 48 +- drivers/s390/block/dasd.c | 13 + drivers/s390/block/dasd_eckd.c | 44 +- drivers/s390/cio/cio.c | 17 +- drivers/s390/s390mach.c | 17 +- drivers/s390/s390mach.h | 3 + include/asm-s390/etr.h | 219 ++++++++ include/asm-s390/hardirq.h | 2 +- include/asm-s390/timex.h | 36 ++ 13 files changed, 1488 insertions(+), 109 deletions(-) create mode 100644 include/asm-s390/etr.h (limited to 'drivers/s390') diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index bc5beaa8f98e..acf93dba7727 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c @@ -125,14 +125,12 @@ void do_extint(struct pt_regs *regs, unsigned short code) * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(); + account_ticks(S390_lowcore.int_clock); kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; index = ext_hash(code); for (p = ext_int_hash[index]; p; p = p->next) { - if (likely(p->code == code)) { - if (likely(p->handler)) - p->handler(code); - } + if (likely(p->code == code)) + p->handler(code); } irq_exit(); set_irq_regs(old_regs); diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index cb155d9fd749..08f9a4dfb18b 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -457,9 +457,10 @@ int __devinit start_secondary(void *cpuvoid) /* Setup the cpu */ cpu_init(); preempt_disable(); - /* init per CPU timer */ + /* Enable TOD clock interrupts on the secondary cpu. */ init_cpu_timer(); #ifdef CONFIG_VIRT_TIMER + /* Enable cpu timer interrupts on the secondary cpu. */ init_cpu_vtimer(); #endif /* Enable pfault pseudo page faults on this cpu. */ diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 5d4a190fa307..39a72d3cb89a 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -37,11 +37,15 @@ #include #include #include +#include /* change this if you have some constant time drift */ #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) +/* The value of the TOD clock for 1.1.1970. */ +#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL + /* * Create a small time difference between the timer interrupts * on the different cpus to avoid lock contention. @@ -51,6 +55,7 @@ #define TICK_SIZE tick static ext_int_info_t ext_int_info_cc; +static ext_int_info_t ext_int_etr_cc; static u64 init_timer_cc; static u64 jiffies_timer_cc; static u64 xtime_cc; @@ -89,29 +94,21 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime) #define s390_do_profile() do { ; } while(0) #endif /* CONFIG_PROFILING */ - /* - * timer_interrupt() needs to keep up the real-time clock, - * as well as call the "do_timer()" routine every clocktick + * Advance the per cpu tick counter up to the time given with the + * "time" argument. The per cpu update consists of accounting + * the virtual cpu time, calling update_process_times and calling + * the profiling hook. If xtime is before time it is advanced as well. */ -void account_ticks(void) +void account_ticks(u64 time) { - __u64 tmp; __u32 ticks; + __u64 tmp; /* Calculate how many ticks have passed. */ - if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) { - /* - * We have to program the clock comparator even if - * no tick has passed. That happens if e.g. an i/o - * interrupt wakes up an idle processor that has - * switched off its hz timer. - */ - tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (tmp)); + if (time < S390_lowcore.jiffy_timer) return; - } - tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; + tmp = time - S390_lowcore.jiffy_timer; if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */ ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1; S390_lowcore.jiffy_timer += @@ -124,10 +121,6 @@ void account_ticks(void) S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; } - /* set clock comparator for next tick */ - tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (tmp)); - #ifdef CONFIG_SMP /* * Do not rely on the boot cpu to do the calls to do_timer. @@ -210,7 +203,7 @@ static inline void stop_hz_timer(void) if (timer >= jiffies_timer_cc) todval = timer; } - asm volatile ("SCKC %0" : : "m" (todval)); + set_clock_comparator(todval); } /* @@ -223,7 +216,8 @@ static inline void start_hz_timer(void) if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) return; - account_ticks(); + account_ticks(get_clock()); + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); cpu_clear(smp_processor_id(), nohz_cpu_mask); } @@ -254,21 +248,56 @@ static void __init nohz_init(void) #endif /* - * Start the clock comparator on the current CPU. + * Set up per cpu jiffy timer and set the clock comparator. + */ +static void setup_jiffy_timer(void) +{ + /* Set up clock comparator to next jiffy. */ + S390_lowcore.jiffy_timer = + jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY; + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); +} + +/* + * Set up lowcore and control register of the current cpu to + * enable TOD clock and clock comparator interrupts. */ void init_cpu_timer(void) { - unsigned long cr0; - __u64 timer; + setup_jiffy_timer(); + + /* Enable clock comparator timer interrupt. */ + __ctl_set_bit(0,11); + + /* Always allow ETR external interrupts, even without an ETR. */ + __ctl_set_bit(0, 4); +} + +static void clock_comparator_interrupt(__u16 code) +{ + /* set clock comparator for next tick */ + set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); +} + +static void etr_reset(void); +static void etr_init(void); +static void etr_ext_handler(__u16); + +/* + * Get the TOD clock running. + */ +static u64 __init reset_tod_clock(void) +{ + u64 time; + + etr_reset(); + if (store_clock(&time) == 0) + return time; + /* TOD clock not running. Set the clock to Unix Epoch. */ + if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0) + panic("TOD clock not operational."); - timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY; - S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY; - timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION; - asm volatile ("SCKC %0" : : "m" (timer)); - /* allow clock comparator timer interrupt */ - __ctl_store(cr0, 0, 0); - cr0 |= 0x800; - __ctl_load(cr0, 0, 0); + return TOD_UNIX_EPOCH; } static cycle_t read_tod_clock(void) @@ -293,48 +322,31 @@ static struct clocksource clocksource_tod = { */ void __init time_init(void) { - __u64 set_time_cc; - int cc; - - /* kick the TOD clock */ - asm volatile( - " stck 0(%2)\n" - " ipm %0\n" - " srl %0,28" - : "=d" (cc), "=m" (init_timer_cc) - : "a" (&init_timer_cc) : "cc"); - switch (cc) { - case 0: /* clock in set state: all is fine */ - break; - case 1: /* clock in non-set state: FIXME */ - printk("time_init: TOD clock in non-set state\n"); - break; - case 2: /* clock in error state: FIXME */ - printk("time_init: TOD clock in error state\n"); - break; - case 3: /* clock in stopped or not-operational state: FIXME */ - printk("time_init: TOD clock stopped/non-operational\n"); - break; - } + init_timer_cc = reset_tod_clock(); + xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY; /* set xtime */ - xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; - set_time_cc = init_timer_cc - 0x8126d60e46000000LL + - (0x3c26700LL*1000000*4096); - tod_to_timeval(set_time_cc, &xtime); + tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime); set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); /* request the clock comparator external interrupt */ - if (register_early_external_interrupt(0x1004, NULL, + if (register_early_external_interrupt(0x1004, + clock_comparator_interrupt, &ext_int_info_cc) != 0) panic("Couldn't request external interrupt 0x1004"); if (clocksource_register(&clocksource_tod) != 0) panic("Could not register TOD clock source"); - init_cpu_timer(); + /* 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"); + + /* Enable TOD clock interrupts on the boot cpu. */ + init_cpu_timer(); #ifdef CONFIG_NO_IDLE_HZ nohz_init(); @@ -343,5 +355,1048 @@ void __init time_init(void) #ifdef CONFIG_VIRT_TIMER vtime_init(); #endif + etr_init(); +} + +/* + * External Time Reference (ETR) code. + */ +static int etr_port0_online; +static int etr_port1_online; + +static int __init early_parse_etr(char *p) +{ + if (strncmp(p, "off", 3) == 0) + etr_port0_online = etr_port1_online = 0; + else if (strncmp(p, "port0", 5) == 0) + etr_port0_online = 1; + else if (strncmp(p, "port1", 5) == 0) + etr_port1_online = 1; + else if (strncmp(p, "on", 2) == 0) + etr_port0_online = etr_port1_online = 1; + return 0; +} +early_param("etr", early_parse_etr); + +enum etr_event { + ETR_EVENT_PORT0_CHANGE, + ETR_EVENT_PORT1_CHANGE, + ETR_EVENT_PORT_ALERT, + ETR_EVENT_SYNC_CHECK, + ETR_EVENT_SWITCH_LOCAL, + 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 + * 0 0 x 0 0 0 0 0 initial, disabled state + * 0 0 x 0 1 1 0 0 port 1 online + * 0 0 x 1 0 1 0 0 port 0 online + * 0 0 x 1 1 1 0 0 both ports online + * 0 1 x 0 1 1 0 0 port 1 online and usable, ETR or PPS mode + * 0 1 x 0 1 1 0 1 port 1 online, usable and ETR mode + * 0 1 x 0 1 1 1 0 port 1 online, usable, PPS mode, in-sync + * 0 1 x 0 1 1 1 1 port 1 online, usable, ETR mode, in-sync + * 0 1 x 1 1 1 0 0 both ports online, port 1 usable + * 0 1 x 1 1 1 1 0 both ports online, port 1 usable, PPS mode, in-sync + * 0 1 x 1 1 1 1 1 both ports online, port 1 usable, ETR mode, in-sync + * 1 0 x 1 0 1 0 0 port 0 online and usable, ETR or PPS mode + * 1 0 x 1 0 1 0 1 port 0 online, usable and ETR mode + * 1 0 x 1 0 1 1 0 port 0 online, usable, PPS mode, in-sync + * 1 0 x 1 0 1 1 1 port 0 online, usable, ETR mode, in-sync + * 1 0 x 1 1 1 0 0 both ports online, port 0 usable + * 1 0 x 1 1 1 1 0 both ports online, port 0 usable, PPS mode, in-sync + * 1 0 x 1 1 1 1 1 both ports online, port 0 usable, ETR mode, in-sync + * 1 1 x 1 1 1 1 0 both ports online & usable, ETR, in-sync + * 1 1 x 1 1 1 1 1 both ports online & usable, ETR, in-sync + */ +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 struct tasklet_struct etr_tasklet; +static DEFINE_PER_CPU(atomic_t, etr_sync_word); + +static void etr_timeout(unsigned long dummy); +static void etr_tasklet_fn(unsigned long dummy); + +/* + * 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. + */ +static void etr_reset(void) +{ + etr_eacr = (struct etr_eacr) { + .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) + etr_tolec = get_clock(); + 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; + } + } +} + +static void etr_init(void) +{ + struct etr_aib aib; + + if (test_bit(ETR_FLAG_ENOSYS, &etr_flags)) + return; + /* Check if this machine has the steai instruction. */ + if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0) + set_bit(ETR_FLAG_STEAI, &etr_flags); + setup_timer(&etr_timer, etr_timeout, 0UL); + tasklet_init(&etr_tasklet, etr_tasklet_fn, 0); + 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); + tasklet_hi_schedule(&etr_tasklet); + } + if (etr_port1_online) { + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } +} + +/* + * Two sorts of ETR machine checks. The architecture reads: + * "When a machine-check niterruption occurs and if a switch-to-local or + * ETR-sync-check interrupt request is pending but disabled, this pending + * disabled interruption request is indicated and is cleared". + * Which means that we can get etr_switch_to_local events from the machine + * check handler although the interruption condition is disabled. Lovely.. + */ + +/* + * Switch to local machine check. This is called when the last usable + * ETR port goes inactive. After switch to local the clock is not in sync. + */ +void etr_switch_to_local(void) +{ + if (!etr_eacr.sl) + return; + etr_disable_sync_clock(NULL); + set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * ETR sync check machine check. This is called when the ETR OTE and the + * local clock OTE are farther apart than the ETR sync check tolerance. + * After a ETR sync check the clock is not in sync. The machine check + * is broadcasted to all cpus at the same time. + */ +void etr_sync_check(void) +{ + if (!etr_eacr.es) + return; + etr_disable_sync_clock(NULL); + set_bit(ETR_EVENT_SYNC_CHECK, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * 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_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); + if (intparm->pc1) + /* ETR port 1 state change. */ + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + if (intparm->eai) + /* + * ETR port alert on either port 0, 1 or both. + * Both ports are not up-to-date now. + */ + set_bit(ETR_EVENT_PORT_ALERT, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +static void etr_timeout(unsigned long dummy) +{ + set_bit(ETR_EVENT_UPDATE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); +} + +/* + * Check if the etr mode is pss. + */ +static inline int etr_mode_is_pps(struct etr_eacr eacr) +{ + return eacr.es && !eacr.sl; +} + +/* + * Check if the etr mode is etr. + */ +static inline int etr_mode_is_etr(struct etr_eacr eacr) +{ + return eacr.es && eacr.sl; +} + +/* + * Check if the port can be used for TOD synchronization. + * For PPS mode the port has to receive OTEs. For ETR mode + * the port has to receive OTEs, the ETR stepping bit has to + * be zero and the validity bits for data frame 1, 2, and 3 + * have to be 1. + */ +static int etr_port_valid(struct etr_aib *aib, int port) +{ + unsigned int psc; + + /* Check that this port is receiving OTEs. */ + if (aib->tsp == 0) + return 0; + + psc = port ? aib->esw.psc1 : aib->esw.psc0; + if (psc == etr_lpsc_pps_mode) + return 1; + if (psc == etr_lpsc_operational_step) + return !aib->esw.y && aib->slsw.v1 && + aib->slsw.v2 && aib->slsw.v3; + return 0; +} + +/* + * Check if two ports are on the same network. + */ +static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2) +{ + // FIXME: any other fields we have to compare? + return aib1->edf1.net_id == aib2->edf1.net_id; +} + +/* + * Wrapper for etr_stei that converts physical port states + * to logical port states to be consistent with the output + * of stetr (see etr_psc vs. etr_lpsc). + */ +static void etr_steai_cv(struct etr_aib *aib, unsigned int func) +{ + BUG_ON(etr_steai(aib, func) != 0); + /* Convert port state to logical port state. */ + if (aib->esw.psc0 == 1) + aib->esw.psc0 = 2; + else if (aib->esw.psc0 == 0 && aib->esw.p == 0) + aib->esw.psc0 = 1; + if (aib->esw.psc1 == 1) + aib->esw.psc1 = 2; + else if (aib->esw.psc1 == 0 && aib->esw.p == 1) + aib->esw.psc1 = 1; +} + +/* + * Check if the aib a2 is still connected to the same attachment as + * aib a1, the etv values differ by one and a2 is valid. + */ +static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p) +{ + int state_a1, state_a2; + + /* Paranoia check: e0/e1 should better be the same. */ + if (a1->esw.eacr.e0 != a2->esw.eacr.e0 || + a1->esw.eacr.e1 != a2->esw.eacr.e1) + return 0; + + /* Still connected to the same etr ? */ + state_a1 = p ? a1->esw.psc1 : a1->esw.psc0; + state_a2 = p ? a2->esw.psc1 : a2->esw.psc0; + if (state_a1 == etr_lpsc_operational_step) { + if (state_a2 != etr_lpsc_operational_step || + a1->edf1.net_id != a2->edf1.net_id || + a1->edf1.etr_id != a2->edf1.etr_id || + a1->edf1.etr_pn != a2->edf1.etr_pn) + return 0; + } else if (state_a2 != etr_lpsc_pps_mode) + return 0; + + /* The ETV value of a2 needs to be ETV of a1 + 1. */ + if (a1->edf2.etv + 1 != a2->edf2.etv) + return 0; + + if (!etr_port_valid(a2, p)) + return 0; + + return 1; +} + +/* + * The time is "clock". xtime 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 void etr_adjust_time(unsigned long long clock, unsigned long long delay) +{ + unsigned long long delta, ticks; + struct timex adjust; + + /* + * We don't have to take the xtime lock because the cpu + * executing etr_adjust_time is running disabled in + * tasklet context and all other cpus are looping in + * etr_sync_cpu_start. + */ + if (clock > xtime_cc) { + /* It is later than we thought. */ + delta = ticks = clock - xtime_cc; + delta = ticks = (delta < delay) ? 0 : delta - delay; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + init_timer_cc = init_timer_cc + delta; + jiffies_timer_cc = jiffies_timer_cc + delta; + xtime_cc = xtime_cc + delta; + adjust.offset = ticks * (1000000 / HZ); + } else { + /* It is earlier than we thought. */ + delta = ticks = xtime_cc - clock; + delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); + init_timer_cc = init_timer_cc - delta; + jiffies_timer_cc = jiffies_timer_cc - delta; + xtime_cc = xtime_cc - delta; + adjust.offset = -ticks * (1000000 / HZ); + } + 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); + } +} + +static void etr_sync_cpu_start(void *dummy) +{ + int *in_sync = dummy; + + 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 (*in_sync == 0) + __udelay(1); + if (*in_sync != 1) + /* Didn't work. Clear per-cpu in sync bit again. */ + 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. + */ + setup_jiffy_timer(); +} + +static void etr_sync_cpu_end(void *dummy) +{ +} + +/* + * Sync the TOD clock using the port refered to by aibp. This port + * has to be enabled and the other port has to be disabled. The + * last eacr update has to be more than 1.6 seconds in the past. + */ +static int etr_sync_clock(struct etr_aib *aib, int port) +{ + struct etr_aib *sync_port; + unsigned long long clock, delay; + int in_sync, follows; + int rc; + + /* Check if the current aib is adjacent to the sync port aib. */ + sync_port = (port == 0) ? &etr_port0 : &etr_port1; + follows = etr_aib_follows(sync_port, aib, port); + memcpy(sync_port, aib, sizeof(*aib)); + if (!follows) + return -EAGAIN; + + /* + * 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 etr_sync_cpu_start. + */ + in_sync = 0; + preempt_disable(); + smp_call_function(etr_sync_cpu_start,&in_sync,0,0); + local_irq_disable(); + etr_enable_sync_clock(); + + /* Set clock to next OTE. */ + __ctl_set_bit(14, 21); + __ctl_set_bit(0, 29); + clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32; + if (set_clock(clock) == 0) { + __udelay(1); /* Wait for the clock to start. */ + __ctl_clear_bit(0, 29); + __ctl_clear_bit(14, 21); + etr_stetr(aib); + /* Adjust Linux timing variables. */ + delay = (unsigned long long) + (aib->edf2.etv - sync_port->edf2.etv) << 32; + etr_adjust_time(clock, delay); + setup_jiffy_timer(); + /* Verify that the clock is properly set. */ + if (!etr_aib_follows(sync_port, aib, port)) { + /* Didn't work. */ + etr_disable_sync_clock(NULL); + in_sync = -EAGAIN; + rc = -EAGAIN; + } else { + in_sync = 1; + rc = 0; + } + } else { + /* Could not set the clock ?!? */ + __ctl_clear_bit(0, 29); + __ctl_clear_bit(14, 21); + etr_disable_sync_clock(NULL); + in_sync = -EAGAIN; + rc = -EAGAIN; + } + local_irq_enable(); + smp_call_function(etr_sync_cpu_end,NULL,0,0); + preempt_enable(); + return rc; +} + +/* + * Handle the immediate effects of the different events. + * The port change event is used for online/offline changes. + */ +static struct etr_eacr etr_handle_events(struct etr_eacr eacr) +{ + if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events)) + eacr.es = 0; + if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events)) + eacr.es = eacr.sl = 0; + if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events)) + etr_port0_uptodate = etr_port1_uptodate = 0; + + if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) { + if (eacr.e0) + /* + * Port change of an enabled port. We have to + * assume that this can have caused an stepping + * port switch. + */ + etr_tolec = get_clock(); + eacr.p0 = etr_port0_online; + if (!eacr.p0) + eacr.e0 = 0; + etr_port0_uptodate = 0; + } + if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) { + if (eacr.e1) + /* + * Port change of an enabled port. We have to + * assume that this can have caused an stepping + * port switch. + */ + etr_tolec = get_clock(); + eacr.p1 = etr_port1_online; + if (!eacr.p1) + eacr.e1 = 0; + etr_port1_uptodate = 0; + } + clear_bit(ETR_EVENT_UPDATE, &etr_events); + return eacr; +} + +/* + * Set up a timer that expires after the etr_tolec + 1.6 seconds if + * one of the ports needs an update. + */ +static void etr_set_tolec_timeout(unsigned long long now) +{ + unsigned long micros; + + if ((!etr_eacr.p0 || etr_port0_uptodate) && + (!etr_eacr.p1 || etr_port1_uptodate)) + return; + micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0; + micros = (micros > 1600000) ? 0 : 1600000 - micros; + mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1); +} + +/* + * Set up a time that expires after 1/2 second. + */ +static void etr_set_sync_timeout(void) +{ + mod_timer(&etr_timer, jiffies + HZ/2); +} + +/* + * Update the aib information for one or both ports. + */ +static struct etr_eacr etr_handle_update(struct etr_aib *aib, + struct etr_eacr eacr) +{ + /* With both ports disabled the aib information is useless. */ + if (!eacr.e0 && !eacr.e1) + return eacr; + + /* Update port0 or port1 with aib stored in etr_tasklet_fn. */ + if (aib->esw.q == 0) { + /* Information for port 0 stored. */ + if (eacr.p0 && !etr_port0_uptodate) { + etr_port0 = *aib; + if (etr_port0_online) + etr_port0_uptodate = 1; + } + } else { + /* Information for port 1 stored. */ + if (eacr.p1 && !etr_port1_uptodate) { + etr_port1 = *aib; + if (etr_port0_online) + etr_port1_uptodate = 1; + } + } + + /* + * Do not try to get the alternate port aib if the clock + * is not in sync yet. + */ + if (!eacr.es) + return eacr; + + /* + * If steai is available we can get the information about + * the other port immediately. If only stetr is available the + * data-port bit toggle has to be used. + */ + 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; + } + if (eacr.p1 && !etr_port1_uptodate) { + etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1); + etr_port1_uptodate = 1; + } + } else { + /* + * One port was updated above, if the other + * port is not uptodate toggle dp bit. + */ + if ((eacr.p0 && !etr_port0_uptodate) || + (eacr.p1 && !etr_port1_uptodate)) + eacr.dp ^= 1; + else + eacr.dp = 0; + } + return eacr; +} + +/* + * Write new etr control register if it differs from the current one. + * Return 1 if etr_tolec has been updated as well. + */ +static void etr_update_eacr(struct etr_eacr eacr) +{ + int dp_changed; + + if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0) + /* No change, return. */ + return; + /* + * The disable of an active port of the change of the data port + * bit can/will cause a change in the data port. + */ + dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 || + (etr_eacr.dp ^ eacr.dp) != 0; + etr_eacr = eacr; + etr_setr(&etr_eacr); + if (dp_changed) + etr_tolec = get_clock(); +} + +/* + * ETR tasklet. In this function you'll find the main logic. In + * particular this is the only function that calls etr_update_eacr(), + * it "controls" the etr control register. + */ +static void etr_tasklet_fn(unsigned long dummy) +{ + unsigned long long now; + struct etr_eacr eacr; + struct etr_aib aib; + int sync_port; + + /* Create working copy of etr_eacr. */ + eacr = etr_eacr; + + /* Check for the different events and their immediate effects. */ + eacr = etr_handle_events(eacr); + + /* Check if ETR is supposed to be active. */ + eacr.ea = eacr.p0 || eacr.p1; + if (!eacr.ea) { + /* Both ports offline. Reset everything. */ + eacr.dp = eacr.es = eacr.sl = 0; + on_each_cpu(etr_disable_sync_clock, NULL, 0, 1); + del_timer_sync(&etr_timer); + etr_update_eacr(eacr); + set_bit(ETR_FLAG_EACCES, &etr_flags); + return; + } + + /* Store aib to get the current ETR status word. */ + BUG_ON(etr_stetr(&aib) != 0); + etr_port0.esw = etr_port1.esw = aib.esw; /* Copy status word. */ + now = get_clock(); + + /* + * Update the port information if the last stepping port change + * or data port change is older than 1.6 seconds. + */ + if (now >= etr_tolec + (1600000 << 12)) + eacr = etr_handle_update(&aib, eacr); + + /* + * Select ports to enable. The prefered synchronization mode is PPS. + * If a port can be enabled depends on a number of things: + * 1) The port needs to be online and uptodate. A port is not + * disabled just because it is not uptodate, but it is only + * enabled if it is uptodate. + * 2) The port needs to have the same mode (pps / etr). + * 3) The port needs to be usable -> etr_port_valid() == 1 + * 4) To enable the second port the clock needs to be in sync. + * 5) If both ports are useable and are ETR ports, the network id + * has to be the same. + * The eacr.sl bit is used to indicate etr mode vs. pps mode. + */ + if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) { + eacr.sl = 0; + eacr.e0 = 1; + if (!etr_mode_is_pps(etr_eacr)) + eacr.es = 0; + if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode) + eacr.e1 = 0; + // FIXME: uptodate checks ? + else if (etr_port0_uptodate && etr_port1_uptodate) + 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; + eacr.e1 = 1; + if (!etr_mode_is_pps(etr_eacr)) + 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; + if (!etr_mode_is_etr(etr_eacr)) + eacr.es = 0; + if (!eacr.es || !eacr.p1 || + aib.esw.psc1 != etr_lpsc_operational_alt) + eacr.e1 = 0; + else if (etr_port0_uptodate && etr_port1_uptodate && + etr_compare_network(&etr_port0, &etr_port1)) + 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; + eacr.e1 = 1; + if (!etr_mode_is_etr(etr_eacr)) + 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; + set_bit(ETR_FLAG_EACCES, &etr_flags); + } + + /* + * 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 (eacr.es || sync_port < 0) { + etr_update_eacr(eacr); + etr_set_tolec_timeout(now); + return; + } + + /* + * Prepare control register for clock syncing + * (reset data port bit, set sync check control. + */ + eacr.dp = 0; + eacr.es = 1; + + /* + * Update eacr and try to synchronize the clock. If the update + * of eacr caused a stepping port switch (or if we have to + * assume that a stepping port switch has occured) or the + * clock syncing failed, reset the sync check control bit + * and set up a timer to try again after 0.5 seconds + */ + etr_update_eacr(eacr); + 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); + etr_set_sync_timeout(); + } else + etr_set_tolec_timeout(now); +} + +/* + * Sysfs interface functions + */ +static struct sysdev_class etr_sysclass = { + set_kset_name("etr") +}; + +static struct sys_device etr_port0_dev = { + .id = 0, + .cls = &etr_sysclass, +}; + +static struct sys_device etr_port1_dev = { + .id = 1, + .cls = &etr_sysclass, +}; + +/* + * ETR class attributes + */ +static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf) +{ + return sprintf(buf, "%i\n", etr_port0.esw.p); +} + +static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL); + +static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf) +{ + char *mode_str; + + if (etr_mode_is_pps(etr_eacr)) + mode_str = "pps"; + else if (etr_mode_is_etr(etr_eacr)) + mode_str = "etr"; + else + mode_str = "local"; + return sprintf(buf, "%s\n", mode_str); +} + +static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL); + +/* + * ETR port attributes + */ +static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev) +{ + if (dev == &etr_port0_dev) + return etr_port0_online ? &etr_port0 : NULL; + else + return etr_port1_online ? &etr_port1 : NULL; +} + +static ssize_t etr_online_show(struct sys_device *dev, char *buf) +{ + unsigned int online; + + online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online; + return sprintf(buf, "%i\n", online); +} + +static ssize_t etr_online_store(struct sys_device *dev, + 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(ETR_FLAG_ENOSYS, &etr_flags)) + return -ENOSYS; + if (dev == &etr_port0_dev) { + if (etr_port0_online == value) + return count; /* Nothing to do. */ + etr_port0_online = value; + set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } else { + if (etr_port1_online == value) + return count; /* Nothing to do. */ + etr_port1_online = value; + set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events); + tasklet_hi_schedule(&etr_tasklet); + } + return count; +} + +static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store); + +static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf) +{ + return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ? + etr_eacr.e0 : etr_eacr.e1); +} + +static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL); + +static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf) +{ + if (!etr_port0_online && !etr_port1_online) + /* Status word is not uptodate if both ports are offline. */ + return -ENODATA; + return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ? + etr_port0.esw.psc0 : etr_port0.esw.psc1); +} + +static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL); + +static ssize_t etr_untuned_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.u); +} + +static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL); + +static ssize_t etr_network_id_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.net_id); +} + +static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL); + +static ssize_t etr_id_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.etr_id); +} + +static SYSDEV_ATTR(id, 0400, etr_id_show, NULL); + +static ssize_t etr_port_number_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v1) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf1.etr_pn); +} + +static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL); + +static ssize_t etr_coupled_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.c); +} + +static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL); + +static ssize_t etr_local_time_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.blto); +} + +static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL); + +static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf) +{ + struct etr_aib *aib = etr_aib_from_dev(dev); + + if (!aib || !aib->slsw.v3) + return -ENODATA; + return sprintf(buf, "%i\n", aib->edf3.buo); +} + +static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL); + +static struct sysdev_attribute *etr_port_attributes[] = { + &attr_online, + &attr_stepping_control, + &attr_state_code, + &attr_untuned, + &attr_network, + &attr_id, + &attr_port, + &attr_coupled, + &attr_local_time, + &attr_utc_offset, + NULL +}; + +static int __init etr_register_port(struct sys_device *dev) +{ + struct sysdev_attribute **attr; + int rc; + + rc = sysdev_register(dev); + if (rc) + goto out; + for (attr = etr_port_attributes; *attr; attr++) { + rc = sysdev_create_file(dev, *attr); + if (rc) + goto out_unreg; + } + return 0; +out_unreg: + for (; attr >= etr_port_attributes; attr--) + sysdev_remove_file(dev, *attr); + sysdev_unregister(dev); +out: + return rc; +} + +static void __init etr_unregister_port(struct sys_device *dev) +{ + struct sysdev_attribute **attr; + + for (attr = etr_port_attributes; *attr; attr++) + sysdev_remove_file(dev, *attr); + sysdev_unregister(dev); +} + +static int __init etr_init_sysfs(void) +{ + int rc; + + rc = sysdev_class_register(&etr_sysclass); + if (rc) + goto out; + rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port); + if (rc) + goto out_unreg_class; + rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode); + if (rc) + goto out_remove_stepping_port; + rc = etr_register_port(&etr_port0_dev); + if (rc) + goto out_remove_stepping_mode; + rc = etr_register_port(&etr_port1_dev); + if (rc) + goto out_remove_port0; + return 0; + +out_remove_port0: + etr_unregister_port(&etr_port0_dev); +out_remove_stepping_mode: + sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode); +out_remove_stepping_port: + sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port); +out_unreg_class: + sysdev_class_unregister(&etr_sysclass); +out: + return rc; } +device_initcall(etr_init_sysfs); diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index 01f3d29bdb06..9d5b02801b46 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c @@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer); void init_cpu_vtimer(void) { struct vtimer_queue *vt_list; - unsigned long cr0; /* kick the virtual timer */ S390_lowcore.exit_timer = VTIMER_MAX_SLICE; S390_lowcore.last_update_timer = VTIMER_MAX_SLICE; asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer)); asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock)); - __ctl_store(cr0, 0, 0); - cr0 |= 0x400; - __ctl_load(cr0, 0, 0); + + /* enable cpu timer interrupts */ + __ctl_set_bit(0,10); vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); INIT_LIST_HEAD(&vt_list->list); @@ -572,6 +571,7 @@ void __init vtime_init(void) 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/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 027c4742a001..02854449b74b 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -1,5 +1,5 @@ /* - * arch/s390/kernel/delay.c + * arch/s390/lib/delay.c * Precise Delay Loops for S390 * * S390 version @@ -13,10 +13,8 @@ #include #include - -#ifdef CONFIG_SMP -#include -#endif +#include +#include void __delay(unsigned long loops) { @@ -31,17 +29,39 @@ void __delay(unsigned long loops) } /* - * Waits for 'usecs' microseconds using the tod clock, giving up the time slice - * of the virtual PU inbetween to avoid congestion. + * Waits for 'usecs' microseconds using the TOD clock comparator. */ void __udelay(unsigned long usecs) { - uint64_t start_cc; + u64 end, time, jiffy_timer = 0; + unsigned long flags, cr0, mask, dummy; + + local_irq_save(flags); + if (raw_irqs_disabled_flags(flags)) { + jiffy_timer = S390_lowcore.jiffy_timer; + S390_lowcore.jiffy_timer = -1ULL - (4096 << 12); + __ctl_store(cr0, 0, 0); + dummy = (cr0 & 0xffff00e0) | 0x00000800; + __ctl_load(dummy , 0, 0); + mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; + } else + mask = psw_kernel_bits | PSW_MASK_WAIT | + PSW_MASK_EXT | PSW_MASK_IO; + + end = get_clock() + ((u64) usecs << 12); + do { + time = end < S390_lowcore.jiffy_timer ? + end : S390_lowcore.jiffy_timer; + set_clock_comparator(time); + trace_hardirqs_on(); + __load_psw_mask(mask); + local_irq_disable(); + } while (get_clock() < end); - if (usecs == 0) - return; - start_cc = get_clock(); - do { - cpu_relax(); - } while (((get_clock() - start_cc)/4096) < usecs); + if (raw_irqs_disabled_flags(flags)) { + __ctl_load(cr0, 0, 0); + S390_lowcore.jiffy_timer = jiffy_timer; + } + set_clock_comparator(S390_lowcore.jiffy_timer); + local_irq_restore(flags); } diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index f208940c463c..555e18a6b781 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device) if (IS_ERR(cqr)) { if (PTR_ERR(cqr) == -ENOMEM) break; /* terminate request queue loop */ + if (PTR_ERR(cqr) == -EAGAIN) { + /* + * The current request cannot be build right + * now, we have to try later. If this request + * is the head-of-queue we stop the device + * for 1/2 second. + */ + if (!list_empty(&device->ccw_queue)) + break; + device->stopped |= DASD_STOPPED_PENDING; + dasd_set_timer(device, HZ/2); + break; + } DBF_DEV_EVENT(DBF_ERR, device, "CCW creation failed (rc=%ld) " "on request %p", diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index d59115cce6dc..a17d73193aab 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -204,37 +204,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc, return 0; } -static inline void +static inline int check_XRC (struct ccw1 *de_ccw, struct DE_eckd_data *data, struct dasd_device *device) { struct dasd_eckd_private *private; + int rc; private = (struct dasd_eckd_private *) device->private; + if (!private->rdc_data.facilities.XRC_supported) + return 0; /* switch on System Time Stamp - needed for XRC Support */ - if (private->rdc_data.facilities.XRC_supported) { - - data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ - data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ - - data->ep_sys_time = get_clock (); - - de_ccw->count = sizeof (struct DE_eckd_data); - de_ccw->flags |= CCW_FLAG_SLI; - } + data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ + data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ - return; + rc = get_sync_clock(&data->ep_sys_time); + /* Ignore return code if sync clock is switched off. */ + if (rc == -ENOSYS || rc == -EACCES) + rc = 0; -} /* end check_XRC */ + de_ccw->count = sizeof (struct DE_eckd_data); + de_ccw->flags |= CCW_FLAG_SLI; + return rc; +} -static inline void +static inline int define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, int totrk, int cmd, struct dasd_device * device) { struct dasd_eckd_private *private; struct ch_t geo, beg, end; + int rc = 0; private = (struct dasd_eckd_private *) device->private; @@ -263,12 +265,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, case DASD_ECKD_CCW_WRITE_KD_MT: data->mask.perm = 0x02; data->attributes.operation = private->attrib.operation; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: data->attributes.operation = DASD_BYPASS_CACHE; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: @@ -276,7 +278,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, data->mask.perm = 0x3; data->mask.auth = 0x1; data->attributes.operation = DASD_BYPASS_CACHE; - check_XRC (ccw, data, device); + rc = check_XRC (ccw, data, device); break; default: DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd); @@ -312,6 +314,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, data->beg_ext.head = beg.head; data->end_ext.cyl = end.cyl; data->end_ext.head = end.head; + return rc; } static inline void @@ -1200,7 +1203,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req) return cqr; ccw = cqr->cpaddr; /* First ccw is define extent. */ - define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device); + if (define_extent(ccw++, cqr->data, first_trk, + last_trk, cmd, device) == -EAGAIN) { + /* Clock not in sync and XRC is enabled. Try again later. */ + dasd_sfree_request(cqr, device); + return ERR_PTR(-EAGAIN); + } /* Build locate_record+read/write/ccws. */ idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data)); LO_data = (struct LO_eckd_data *) (idaws + cidaw); diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 07a4cbfc2436..ad2b37929848 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -646,7 +646,7 @@ do_IRQ (struct pt_regs *regs) * Make sure that the i/o interrupt did not "overtake" * the last HZ timer interrupt. */ - account_ticks(); + account_ticks(S390_lowcore.int_clock); /* * Get interrupt information from lowcore */ @@ -850,6 +850,19 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) return -EBUSY; /* uhm... */ } +/* we can't use the normal udelay here, since it enables external interrupts */ + +static void udelay_reset(unsigned long usecs) +{ + uint64_t start_cc, end_cc; + + asm volatile ("STCK %0" : "=m" (start_cc)); + do { + cpu_relax(); + asm volatile ("STCK %0" : "=m" (end_cc)); + } while (((end_cc - start_cc)/4096) < usecs); +} + static inline int __clear_subchannel_easy(struct subchannel_id schid) { @@ -865,7 +878,7 @@ __clear_subchannel_easy(struct subchannel_id schid) if (schid_equal(&ti.schid, &schid)) return 0; } - udelay(100); + udelay_reset(100); } return -EBUSY; } diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 442d63470428..806bb1a921eb 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -15,7 +15,7 @@ #include #include #include - +#include #include #include #include "cio/cio.h" @@ -466,6 +466,19 @@ s390_do_machine_check(struct pt_regs *regs) s390_handle_damage("unable to revalidate registers."); } + if (mci->cd) { + /* Timing facility damage */ + s390_handle_damage("TOD clock damaged"); + } + + if (mci->ed && mci->ec) { + /* External damage */ + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC)) + etr_sync_check(); + if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH)) + etr_switch_to_local(); + } + if (mci->se) /* Storage error uncorrected */ s390_handle_damage("received storage error uncorrected " @@ -504,7 +517,7 @@ static int machine_check_init(void) { init_MUTEX_LOCKED(&m_sem); - ctl_clear_bit(14, 25); /* disable external damage MCH */ + ctl_set_bit(14, 25); /* enable external damage MCH */ ctl_set_bit(14, 27); /* enable system recovery MCH */ #ifdef CONFIG_MACHCHK_WARNING ctl_set_bit(14, 24); /* enable warning MCH */ diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h index 7abb42a09ae2..d3ca4281a494 100644 --- a/drivers/s390/s390mach.h +++ b/drivers/s390/s390mach.h @@ -102,4 +102,7 @@ static inline int stcrw(struct crw *pcrw ) return ccode; } +#define ED_ETR_SYNC 12 /* External damage ETR sync check */ +#define ED_ETR_SWITCH 13 /* External damage ETR switch to local */ + #endif /* __s390mach */ diff --git a/include/asm-s390/etr.h b/include/asm-s390/etr.h new file mode 100644 index 000000000000..b498f19bb9a7 --- /dev/null +++ b/include/asm-s390/etr.h @@ -0,0 +1,219 @@ +/* + * include/asm-s390/etr.h + * + * Copyright IBM Corp. 2006 + * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) + */ +#ifndef __S390_ETR_H +#define __S390_ETR_H + +/* ETR attachment control register */ +struct etr_eacr { + unsigned int e0 : 1; /* port 0 stepping control */ + unsigned int e1 : 1; /* port 1 stepping control */ + unsigned int _pad0 : 5; /* must be 00100 */ + unsigned int dp : 1; /* data port control */ + unsigned int p0 : 1; /* port 0 change recognition control */ + unsigned int p1 : 1; /* port 1 change recognition control */ + unsigned int _pad1 : 3; /* must be 000 */ + unsigned int ea : 1; /* ETR alert control */ + unsigned int es : 1; /* ETR sync check control */ + unsigned int sl : 1; /* switch to local control */ +} __attribute__ ((packed)); + +/* Port state returned by steai */ +enum etr_psc { + etr_psc_operational = 0, + etr_psc_semi_operational = 1, + etr_psc_protocol_error = 4, + etr_psc_no_symbols = 8, + etr_psc_no_signal = 12, + etr_psc_pps_mode = 13 +}; + +/* Logical port state returned by stetr */ +enum etr_lpsc { + etr_lpsc_operational_step = 0, + etr_lpsc_operational_alt = 1, + etr_lpsc_semi_operational = 2, + etr_lpsc_protocol_error = 4, + etr_lpsc_no_symbol_sync = 8, + etr_lpsc_no_signal = 12, + etr_lpsc_pps_mode = 13 +}; + +/* ETR status words */ +struct etr_esw { + struct etr_eacr eacr; /* attachment control register */ + unsigned int y : 1; /* stepping mode */ + unsigned int _pad0 : 5; /* must be 00000 */ + unsigned int p : 1; /* stepping port number */ + unsigned int q : 1; /* data port number */ + unsigned int psc0 : 4; /* port 0 state code */ + unsigned int psc1 : 4; /* port 1 state code */ +} __attribute__ ((packed)); + +/* Second level data register status word */ +struct etr_slsw { + unsigned int vv1 : 1; /* copy of validity bit data frame 1 */ + unsigned int vv2 : 1; /* copy of validity bit data frame 2 */ + unsigned int vv3 : 1; /* copy of validity bit data frame 3 */ + unsigned int vv4 : 1; /* copy of validity bit data frame 4 */ + unsigned int _pad0 : 19; /* must by all zeroes */ + unsigned int n : 1; /* EAF port number */ + unsigned int v1 : 1; /* validity bit ETR data frame 1 */ + unsigned int v2 : 1; /* validity bit ETR data frame 2 */ + unsigned int v3 : 1; /* validity bit ETR data frame 3 */ + unsigned int v4 : 1; /* validity bit ETR data frame 4 */ + unsigned int _pad1 : 4; /* must be 0000 */ +} __attribute__ ((packed)); + +/* ETR data frames */ +struct etr_edf1 { + unsigned int u : 1; /* untuned bit */ + unsigned int _pad0 : 1; /* must be 0 */ + unsigned int r : 1; /* service request bit */ + unsigned int _pad1 : 4; /* must be 0000 */ + unsigned int a : 1; /* time adjustment bit */ + unsigned int net_id : 8; /* ETR network id */ + unsigned int etr_id : 8; /* id of ETR which sends data frames */ + unsigned int etr_pn : 8; /* port number of ETR output port */ +} __attribute__ ((packed)); + +struct etr_edf2 { + unsigned int etv : 32; /* Upper 32 bits of TOD. */ +} __attribute__ ((packed)); + +struct etr_edf3 { + unsigned int rc : 8; /* failure reason code */ + unsigned int _pad0 : 3; /* must be 000 */ + unsigned int c : 1; /* ETR coupled bit */ + unsigned int tc : 4; /* ETR type code */ + unsigned int blto : 8; /* biased local time offset */ + /* (blto - 128) * 15 = minutes */ + unsigned int buo : 8; /* biased utc offset */ + /* (buo - 128) = leap seconds */ +} __attribute__ ((packed)); + +struct etr_edf4 { + unsigned int ed : 8; /* ETS device dependent data */ + unsigned int _pad0 : 1; /* must be 0 */ + unsigned int buc : 5; /* biased ut1 correction */ + /* (buc - 16) * 0.1 seconds */ + unsigned int em : 6; /* ETS error magnitude */ + unsigned int dc : 6; /* ETS drift code */ + unsigned int sc : 6; /* ETS steering code */ +} __attribute__ ((packed)); + +/* + * ETR attachment information block, two formats + * format 1 has 4 reserved words with a size of 64 bytes + * format 2 has 16 reserved words with a size of 96 bytes + */ +struct etr_aib { + struct etr_esw esw; + struct etr_slsw slsw; + unsigned long long tsp; + struct etr_edf1 edf1; + struct etr_edf2 edf2; + struct etr_edf3 edf3; + struct etr_edf4 edf4; + unsigned int reserved[16]; +} __attribute__ ((packed,aligned(8))); + +/* ETR interruption parameter */ +struct etr_interruption_parameter { + unsigned int _pad0 : 8; + unsigned int pc0 : 1; /* port 0 state change */ + unsigned int pc1 : 1; /* port 1 state change */ + unsigned int _pad1 : 3; + unsigned int eai : 1; /* ETR alert indication */ + unsigned int _pad2 : 18; +} __attribute__ ((packed)); + +/* Query TOD offset result */ +struct etr_ptff_qto { + unsigned long long physical_clock; + unsigned long long tod_offset; + unsigned long long logical_tod_offset; + unsigned long long tod_epoch_difference; +} __attribute__ ((packed)); + +/* Inline assembly helper functions */ +static inline int etr_setr(struct etr_eacr *ctrl) +{ + int rc = -ENOSYS; + + asm volatile( + " .insn s,0xb2160000,0(%2)\n" + "0: la %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) : "m" (*ctrl), "a" (ctrl)); + return rc; +} + +/* Stores a format 1 aib with 64 bytes */ +static inline int etr_stetr(struct etr_aib *aib) +{ + int rc = -ENOSYS; + + asm volatile( + " .insn s,0xb2170000,0(%2)\n" + "0: la %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) : "m" (*aib), "a" (aib)); + return rc; +} + +/* Stores a format 2 aib with 96 bytes for specified port */ +static inline int etr_steai(struct etr_aib *aib, unsigned int func) +{ + register unsigned int reg0 asm("0") = func; + int rc = -ENOSYS; + + asm volatile( + " .insn s,0xb2b30000,0(%2)\n" + "0: la %0,0\n" + "1:\n" + EX_TABLE(0b,1b) + : "+d" (rc) : "m" (*aib), "a" (aib), "d" (reg0)); + return rc; +} + +/* Function codes for the steai instruction. */ +#define ETR_STEAI_STEPPING_PORT 0x10 +#define ETR_STEAI_ALTERNATE_PORT 0x11 +#define ETR_STEAI_PORT_0 0x12 +#define ETR_STEAI_PORT_1 0x13 + +static inline int etr_ptff(void *ptff_block, unsigned int func) +{ + register unsigned int reg0 asm("0") = func; + register unsigned long reg1 asm("1") = (unsigned long) ptff_block; + int rc = -ENOSYS; + + asm volatile( + " .word 0x0104\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (rc), "=m" (ptff_block) + : "d" (reg0), "d" (reg1), "m" (ptff_block) : "cc"); + return rc; +} + +/* Function codes for the ptff instruction. */ +#define ETR_PTFF_QAF 0x00 /* query available functions */ +#define ETR_PTFF_QTO 0x01 /* query tod offset */ +#define ETR_PTFF_QSI 0x02 /* query steering information */ +#define ETR_PTFF_ATO 0x40 /* adjust tod offset */ +#define ETR_PTFF_STO 0x41 /* set tod offset */ +#define ETR_PTFF_SFS 0x42 /* set fine steering rate */ +#define ETR_PTFF_SGS 0x43 /* set gross steering rate */ + +/* Functions needed by the machine check handler */ +extern void etr_switch_to_local(void); +extern void etr_sync_check(void); + +#endif /* __S390_ETR_H */ diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index c2f6a8782d31..31beb18cb3d1 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -32,6 +32,6 @@ typedef struct { #define HARDIRQ_BITS 8 -extern void account_ticks(void); +extern void account_ticks(u64 time); #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h index 9ee5d8013796..5cbd55cb40ce 100644 --- a/include/asm-s390/timex.h +++ b/include/asm-s390/timex.h @@ -11,6 +11,41 @@ #ifndef _ASM_S390_TIMEX_H #define _ASM_S390_TIMEX_H +/* Inline functions for clock register access. */ +static inline int set_clock(__u64 time) +{ + int cc; + + asm volatile( + " sck 0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc) : "m" (time), "a" (&time) : "cc"); + return cc; +} + +static inline int store_clock(__u64 *time) +{ + int cc; + + asm volatile( + " stck 0(%2)\n" + " ipm %0\n" + " srl %0,28\n" + : "=d" (cc), "=m" (*time) : "a" (time) : "cc"); + return cc; +} + +static inline void set_clock_comparator(__u64 time) +{ + asm volatile("sckc 0(%1)" : : "m" (time), "a" (&time)); +} + +static inline void store_clock_comparator(__u64 *time) +{ + asm volatile("stckc 0(%1)" : "=m" (*time) : "a" (time)); +} + #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */ typedef unsigned long long cycles_t; @@ -32,6 +67,7 @@ static inline cycles_t get_cycles(void) return (cycles_t) get_clock() >> 2; } +int get_sync_clock(unsigned long long *clock); void init_cpu_timer(void); #endif -- cgit v1.2.3 From cced1dd42ebcebc7fa7f02fe487e48aa71752401 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Mon, 5 Feb 2007 21:18:26 +0100 Subject: [S390] Add crypto support for 3592 tape devices 3592 tape devices are able to write data encrpyted on tape mediums. This z/Linux device driver support includes the following functions: * ioctl to switch on/off encryption * ioctl to query encryption status of drive * ioctls to set and query key encrypting keys (kekls) * long busy interrupt handling Signed-off-by: Michael Holzheu Signed-off-by: Martin Schwidefsky --- drivers/s390/char/tape.h | 22 +- drivers/s390/char/tape_3590.c | 479 ++++++++++++++++++++++++++++++++++++++++-- drivers/s390/char/tape_3590.h | 53 ++++- drivers/s390/char/tape_char.c | 2 +- drivers/s390/char/tape_core.c | 53 ++++- include/asm-s390/tape390.h | 72 ++++++- 6 files changed, 645 insertions(+), 36 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index c9f1c4c8bb13..bb4ff537729d 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h @@ -3,7 +3,7 @@ * tape device driver for 3480/3490E/3590 tapes. * * S390 and zSeries version - * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Tuan Ngo-Anh * Martin Schwidefsky @@ -99,7 +99,11 @@ enum tape_op { TO_DIS, /* Tape display */ TO_ASSIGN, /* Assign tape to channel path */ TO_UNASSIGN, /* Unassign tape from channel path */ - TO_SIZE /* #entries in tape_op_t */ + TO_CRYPT_ON, /* Enable encrpytion */ + TO_CRYPT_OFF, /* Disable encrpytion */ + TO_KEKL_SET, /* Set KEK label */ + TO_KEKL_QUERY, /* Query KEK label */ + TO_SIZE, /* #entries in tape_op_t */ }; /* Forward declaration */ @@ -112,6 +116,7 @@ enum tape_request_status { TAPE_REQUEST_IN_IO, /* request is currently in IO */ TAPE_REQUEST_DONE, /* request is completed. */ TAPE_REQUEST_CANCEL, /* request should be canceled. */ + TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */ }; /* Tape CCW request */ @@ -164,10 +169,11 @@ struct tape_discipline { * The discipline irq function either returns an error code (<0) which * means that the request has failed with an error or one of the following: */ -#define TAPE_IO_SUCCESS 0 /* request successful */ -#define TAPE_IO_PENDING 1 /* request still running */ -#define TAPE_IO_RETRY 2 /* retry to current request */ -#define TAPE_IO_STOP 3 /* stop the running request */ +#define TAPE_IO_SUCCESS 0 /* request successful */ +#define TAPE_IO_PENDING 1 /* request still running */ +#define TAPE_IO_RETRY 2 /* retry to current request */ +#define TAPE_IO_STOP 3 /* stop the running request */ +#define TAPE_IO_LONG_BUSY 4 /* delay the running request */ /* Char Frontend Data */ struct tape_char_data { @@ -242,6 +248,10 @@ struct tape_device { /* Function to start or stop the next request later. */ struct delayed_work tape_dnr; + + /* Timer for long busy */ + struct timer_list lb_timeout; + }; /* Externals from tape_core.c */ diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index 9df912f63188..50f5edab83d7 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.c * tape device discipline for 3590 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001,2006 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -11,6 +11,7 @@ #include #include #include +#include #define TAPE_DBF_AREA tape_3590_dbf @@ -30,7 +31,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA); * - Read Device (buffered) log: BRA * - Read Library log: BRA * - Swap Devices: BRA - * - Long Busy: BRA + * - Long Busy: implemented * - Special Intercept: BRA * - Read Alternate: implemented *******************************************************************/ @@ -94,6 +95,332 @@ static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = { [0xae] = "Subsystem environmental alert", }; +static int crypt_supported(struct tape_device *device) +{ + return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device)); +} + +static int crypt_enabled(struct tape_device *device) +{ + return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device)); +} + +static void ext_to_int_kekl(struct tape390_kekl *in, + struct tape3592_kekl *out) +{ + int i; + + memset(out, 0, sizeof(*out)); + if (in->type == TAPE390_KEKL_TYPE_HASH) + out->flags |= 0x40; + if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH) + out->flags |= 0x80; + strncpy(out->label, in->label, 64); + for (i = strlen(in->label); i < sizeof(out->label); i++) + out->label[i] = ' '; + ASCEBC(out->label, sizeof(out->label)); +} + +static void int_to_ext_kekl(struct tape3592_kekl *in, + struct tape390_kekl *out) +{ + memset(out, 0, sizeof(*out)); + if(in->flags & 0x40) + out->type = TAPE390_KEKL_TYPE_HASH; + else + out->type = TAPE390_KEKL_TYPE_LABEL; + if(in->flags & 0x80) + out->type_on_tape = TAPE390_KEKL_TYPE_HASH; + else + out->type_on_tape = TAPE390_KEKL_TYPE_LABEL; + memcpy(out->label, in->label, sizeof(in->label)); + EBCASC(out->label, sizeof(in->label)); + strstrip(out->label); +} + +static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in, + struct tape390_kekl_pair *out) +{ + if (in->count == 0) { + out->kekl[0].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE; + } else if (in->count == 1) { + int_to_ext_kekl(&in->kekl[0], &out->kekl[0]); + out->kekl[1].type = TAPE390_KEKL_TYPE_NONE; + out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE; + } else if (in->count == 2) { + int_to_ext_kekl(&in->kekl[0], &out->kekl[0]); + int_to_ext_kekl(&in->kekl[1], &out->kekl[1]); + } else { + printk("Invalid KEKL number: %d\n", in->count); + BUG(); + } +} + +static int check_ext_kekl(struct tape390_kekl *kekl) +{ + if (kekl->type == TAPE390_KEKL_TYPE_NONE) + goto invalid; + if (kekl->type > TAPE390_KEKL_TYPE_HASH) + goto invalid; + if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE) + goto invalid; + if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH) + goto invalid; + if ((kekl->type == TAPE390_KEKL_TYPE_HASH) && + (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL)) + goto invalid; + + return 0; +invalid: + return -EINVAL; +} + +static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls) +{ + if (check_ext_kekl(&kekls->kekl[0])) + goto invalid; + if (check_ext_kekl(&kekls->kekl[1])) + goto invalid; + + return 0; +invalid: + return -EINVAL; +} + +/* + * Query KEKLs + */ +static int tape_3592_kekl_query(struct tape_device *device, + struct tape390_kekl_pair *ext_kekls) +{ + struct tape_request *request; + struct tape3592_kekl_query_order *order; + struct tape3592_kekl_query_data *int_kekls; + int rc; + + DBF_EVENT(6, "tape3592_kekl_query\n"); + int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA); + if (!int_kekls) + return -ENOMEM; + request = tape_alloc_request(2, sizeof(*order)); + if (IS_ERR(request)) { + rc = PTR_ERR(request); + goto fail_malloc; + } + order = request->cpdata; + memset(order,0,sizeof(*order)); + order->code = 0xe2; + order->max_count = 2; + request->op = TO_KEKL_QUERY; + tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order); + tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls), + int_kekls); + rc = tape_do_io(device, request); + if (rc) + goto fail_request; + int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls); + + rc = 0; +fail_request: + tape_free_request(request); +fail_malloc: + kfree(int_kekls); + return rc; +} + +/* + * IOCTL: Query KEKLs + */ +static int tape_3592_ioctl_kekl_query(struct tape_device *device, + unsigned long arg) +{ + int rc; + struct tape390_kekl_pair *ext_kekls; + + DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (!crypt_enabled(device)) + return -EUNATCH; + ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL); + if (!ext_kekls) + return -ENOMEM; + rc = tape_3592_kekl_query(device, ext_kekls); + if (rc != 0) + goto fail; + if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) { + rc = -EFAULT; + goto fail; + } + rc = 0; +fail: + kfree(ext_kekls); + return rc; +} + +static int tape_3590_mttell(struct tape_device *device, int mt_count); + +/* + * Set KEKLs + */ +static int tape_3592_kekl_set(struct tape_device *device, + struct tape390_kekl_pair *ext_kekls) +{ + struct tape_request *request; + struct tape3592_kekl_set_order *order; + + DBF_EVENT(6, "tape3592_kekl_set\n"); + if (check_ext_kekl_pair(ext_kekls)) { + DBF_EVENT(6, "invalid kekls\n"); + return -EINVAL; + } + if (tape_3590_mttell(device, 0) != 0) + return -EBADSLT; + request = tape_alloc_request(1, sizeof(*order)); + if (IS_ERR(request)) + return PTR_ERR(request); + order = request->cpdata; + memset(order, 0, sizeof(*order)); + order->code = 0xe3; + order->kekls.count = 2; + ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]); + ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]); + request->op = TO_KEKL_SET; + tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order); + + return tape_do_io_free(device, request); +} + +/* + * IOCTL: Set KEKLs + */ +static int tape_3592_ioctl_kekl_set(struct tape_device *device, + unsigned long arg) +{ + int rc; + struct tape390_kekl_pair *ext_kekls; + + DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (!crypt_enabled(device)) + return -EUNATCH; + ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL); + if (!ext_kekls) + return -ENOMEM; + if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) { + rc = -EFAULT; + goto out; + } + rc = tape_3592_kekl_set(device, ext_kekls); +out: + kfree(ext_kekls); + return rc; +} + +/* + * Enable encryption + */ +static int tape_3592_enable_crypt(struct tape_device *device) +{ + struct tape_request *request; + char *data; + + DBF_EVENT(6, "tape_3592_enable_crypt\n"); + if (!crypt_supported(device)) + return -ENOSYS; + request = tape_alloc_request(2, 72); + if (IS_ERR(request)) + return PTR_ERR(request); + data = request->cpdata; + memset(data,0,72); + + data[0] = 0x05; + data[36 + 0] = 0x03; + data[36 + 1] = 0x03; + data[36 + 4] = 0x40; + data[36 + 6] = 0x01; + data[36 + 14] = 0x2f; + data[36 + 18] = 0xc3; + data[36 + 35] = 0x72; + request->op = TO_CRYPT_ON; + tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); + tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); + return tape_do_io_free(device, request); +} + +/* + * Disable encryption + */ +static int tape_3592_disable_crypt(struct tape_device *device) +{ + struct tape_request *request; + char *data; + + DBF_EVENT(6, "tape_3592_disable_crypt\n"); + if (!crypt_supported(device)) + return -ENOSYS; + request = tape_alloc_request(2, 72); + if (IS_ERR(request)) + return PTR_ERR(request); + data = request->cpdata; + memset(data,0,72); + + data[0] = 0x05; + data[36 + 0] = 0x03; + data[36 + 1] = 0x03; + data[36 + 35] = 0x32; + + request->op = TO_CRYPT_OFF; + tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data); + tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36); + + return tape_do_io_free(device, request); +} + +/* + * IOCTL: Set encryption status + */ +static int tape_3592_ioctl_crypt_set(struct tape_device *device, + unsigned long arg) +{ + struct tape390_crypt_info info; + + DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n"); + if (!crypt_supported(device)) + return -ENOSYS; + if (copy_from_user(&info, (char __user *)arg, sizeof(info))) + return -EFAULT; + if (info.status & ~TAPE390_CRYPT_ON_MASK) + return -EINVAL; + if (info.status & TAPE390_CRYPT_ON_MASK) + return tape_3592_enable_crypt(device); + else + return tape_3592_disable_crypt(device); +} + +static int tape_3590_sense_medium(struct tape_device *device); + +/* + * IOCTL: Query enryption status + */ +static int tape_3592_ioctl_crypt_query(struct tape_device *device, + unsigned long arg) +{ + DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n"); + if (!crypt_supported(device)) + return -ENOSYS; + tape_3590_sense_medium(device); + if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device), + sizeof(TAPE_3590_CRYPT_INFO(device)))) + return -EFAULT; + else + return 0; +} + /* * 3590 IOCTL Overload */ @@ -109,6 +436,14 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg) return tape_std_display(device, &disp); } + case TAPE390_KEKL_SET: + return tape_3592_ioctl_kekl_set(device, arg); + case TAPE390_KEKL_QUERY: + return tape_3592_ioctl_kekl_query(device, arg); + case TAPE390_CRYPT_SET: + return tape_3592_ioctl_crypt_set(device, arg); + case TAPE390_CRYPT_QUERY: + return tape_3592_ioctl_crypt_query(device, arg); default: return -EINVAL; /* no additional ioctls */ } @@ -248,6 +583,12 @@ tape_3590_work_handler(struct work_struct *work) case TO_READ_ATTMSG: tape_3590_read_attmsg(p->device); break; + case TO_CRYPT_ON: + tape_3592_enable_crypt(p->device); + break; + case TO_CRYPT_OFF: + tape_3592_disable_crypt(p->device); + break; default: DBF_EVENT(3, "T3590: work handler undefined for " "operation 0x%02x\n", p->op); @@ -365,6 +706,33 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request) } #endif +static void tape_3590_med_state_set(struct tape_device *device, + struct tape_3590_med_sense *sense) +{ + struct tape390_crypt_info *c_info; + + c_info = &TAPE_3590_CRYPT_INFO(device); + + if (sense->masst == MSENSE_UNASSOCIATED) { + tape_med_state_set(device, MS_UNLOADED); + TAPE_3590_CRYPT_INFO(device).medium_status = 0; + return; + } + if (sense->masst != MSENSE_ASSOCIATED_MOUNT) { + PRINT_ERR("Unknown medium state: %x\n", sense->masst); + return; + } + tape_med_state_set(device, MS_LOADED); + c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK; + if (sense->flags & MSENSE_CRYPT_MASK) { + PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags); + c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK; + } else { + DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags); + c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK; + } +} + /* * The done handler is called at device/channel end and wakes up the sleeping * process @@ -372,9 +740,10 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request) static int tape_3590_done(struct tape_device *device, struct tape_request *request) { - struct tape_3590_med_sense *sense; + struct tape_3590_disc_data *disc_data; DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]); + disc_data = device->discdata; switch (request->op) { case TO_BSB: @@ -394,13 +763,20 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) break; case TO_RUN: tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); break; case TO_MSEN: - sense = (struct tape_3590_med_sense *) request->cpdata; - if (sense->masst == MSENSE_UNASSOCIATED) - tape_med_state_set(device, MS_UNLOADED); - if (sense->masst == MSENSE_ASSOCIATED_MOUNT) - tape_med_state_set(device, MS_LOADED); + tape_3590_med_state_set(device, request->cpdata); + break; + case TO_CRYPT_ON: + TAPE_3590_CRYPT_INFO(device).status + |= TAPE390_CRYPT_ON_MASK; + *(device->modeset_byte) |= 0x03; + break; + case TO_CRYPT_OFF: + TAPE_3590_CRYPT_INFO(device).status + &= ~TAPE390_CRYPT_ON_MASK; + *(device->modeset_byte) &= ~0x03; break; case TO_RBI: /* RBI seems to succeed even without medium loaded. */ case TO_NOP: /* Same to NOP. */ @@ -409,8 +785,9 @@ tape_3590_done(struct tape_device *device, struct tape_request *request) case TO_DIS: case TO_ASSIGN: case TO_UNASSIGN: - break; case TO_SIZE: + case TO_KEKL_SET: + case TO_KEKL_QUERY: break; } return TAPE_IO_SUCCESS; @@ -540,10 +917,8 @@ static int tape_3590_erp_long_busy(struct tape_device *device, struct tape_request *request, struct irb *irb) { - /* FIXME: how about WAITING for a minute ? */ - PRINT_WARN("(%s): Device is busy! Please wait a minute!\n", - device->cdev->dev.bus_id); - return tape_3590_erp_basic(device, request, irb, -EBUSY); + DBF_EVENT(6, "Device is busy\n"); + return TAPE_IO_LONG_BUSY; } /* @@ -951,6 +1326,34 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb) device->cdev->dev.bus_id, sense->mc); } +static int tape_3590_crypt_error(struct tape_device *device, + struct tape_request *request, struct irb *irb) +{ + u8 cu_rc, ekm_rc1; + u16 ekm_rc2; + u32 drv_rc; + char *bus_id, *sense; + + sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data; + bus_id = device->cdev->dev.bus_id; + cu_rc = sense[0]; + drv_rc = *((u32*) &sense[5]) & 0xffffff; + ekm_rc1 = sense[9]; + ekm_rc2 = *((u16*) &sense[10]); + if ((cu_rc == 0) && (ekm_rc2 == 0xee31)) + /* key not defined on EKM */ + return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED); + if ((cu_rc == 1) || (cu_rc == 2)) + /* No connection to EKM */ + return tape_3590_erp_basic(device, request, irb, -ENOTCONN); + + PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id); + PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc, + drv_rc, ekm_rc1, ekm_rc2); + + return tape_3590_erp_basic(device, request, irb, -ENOKEY); +} + /* * 3590 error Recovery routine: * If possible, it tries to recover from the error. If this is not possible, @@ -979,6 +1382,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, sense = (struct tape_3590_sense *) irb->ecw; + DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc); + /* * First check all RC-QRCs where we want to do something special * - "break": basic error recovery is done @@ -999,6 +1404,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, case 0x2231: tape_3590_print_era_msg(device, irb); return tape_3590_erp_special_interrupt(device, request, irb); + case 0x2240: + return tape_3590_crypt_error(device, request, irb); case 0x3010: DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n", @@ -1020,6 +1427,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, DBF_EVENT(2, "(%08x): Rewind Unload complete\n", device->cdev_id); tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, 0); case 0x4010: @@ -1030,9 +1438,15 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, PRINT_WARN("(%s): Tape operation when medium not loaded\n", device->cdev->dev.bus_id); tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x4012: /* Device Long Busy */ + /* XXX: Also use long busy handling here? */ + DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id); tape_3590_print_era_msg(device, irb); + return tape_3590_erp_basic(device, request, irb, -EBUSY); + case 0x4014: + DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id); return tape_3590_erp_long_busy(device, request, irb); case 0x5010: @@ -1064,6 +1478,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request, case 0x5120: case 0x1120: tape_med_state_set(device, MS_UNLOADED); + tape_3590_schedule_work(device, TO_CRYPT_OFF); return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM); case 0x6020: @@ -1142,21 +1557,47 @@ tape_3590_setup_device(struct tape_device *device) { int rc; struct tape_3590_disc_data *data; + char *rdc_data; DBF_EVENT(6, "3590 device setup\n"); - data = kmalloc(sizeof(struct tape_3590_disc_data), - GFP_KERNEL | GFP_DMA); + data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA); if (data == NULL) return -ENOMEM; data->read_back_op = READ_PREVIOUS; device->discdata = data; - if ((rc = tape_std_assign(device)) == 0) { - /* Try to find out if medium is loaded */ - if ((rc = tape_3590_sense_medium(device)) != 0) - DBF_LH(3, "3590 medium sense returned %d\n", rc); + rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA); + if (!rdc_data) { + rc = -ENOMEM; + goto fail_kmalloc; + } + rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64); + if (rc) { + DBF_LH(3, "Read device characteristics failed!\n"); + goto fail_kmalloc; + } + rc = tape_std_assign(device); + if (rc) + goto fail_rdc_data; + if (rdc_data[31] == 0x13) { + PRINT_INFO("Device has crypto support\n"); + data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK; + tape_3592_disable_crypt(device); + } else { + DBF_EVENT(6, "Device has NO crypto support\n"); } + /* Try to find out if medium is loaded */ + rc = tape_3590_sense_medium(device); + if (rc) { + DBF_LH(3, "3590 medium sense returned %d\n", rc); + goto fail_rdc_data; + } + return 0; +fail_rdc_data: + kfree(rdc_data); +fail_kmalloc: + kfree(data); return rc; } diff --git a/drivers/s390/char/tape_3590.h b/drivers/s390/char/tape_3590.h index cf274b9445a6..aa5138807af1 100644 --- a/drivers/s390/char/tape_3590.h +++ b/drivers/s390/char/tape_3590.h @@ -2,7 +2,7 @@ * drivers/s390/char/tape_3590.h * tape device discipline for 3590 tapes. * - * Copyright (C) IBM Corp. 2001,2006 + * Copyright IBM Corp. 2001,2006 * Author(s): Stefan Bader * Michael Holzheu * Martin Schwidefsky @@ -38,16 +38,22 @@ #define MSENSE_UNASSOCIATED 0x00 #define MSENSE_ASSOCIATED_MOUNT 0x01 #define MSENSE_ASSOCIATED_UMOUNT 0x02 +#define MSENSE_CRYPT_MASK 0x00000010 #define TAPE_3590_MAX_MSG 0xb0 /* Datatypes */ struct tape_3590_disc_data { - unsigned char modeset_byte; + struct tape390_crypt_info crypt_info; int read_back_op; }; +#define TAPE_3590_CRYPT_INFO(device) \ + ((struct tape_3590_disc_data*)(device->discdata))->crypt_info +#define TAPE_3590_READ_BACK_OP(device) \ + ((struct tape_3590_disc_data*)(device->discdata))->read_back_op + struct tape_3590_sense { unsigned int command_rej:1; @@ -118,7 +124,48 @@ struct tape_3590_sense { struct tape_3590_med_sense { unsigned int macst:4; unsigned int masst:4; - char pad[127]; + char pad1[7]; + unsigned int flags; + char pad2[116]; +} __attribute__ ((packed)); + +/* Datastructures for 3592 encryption support */ + +struct tape3592_kekl { + __u8 flags; + char label[64]; +} __attribute__ ((packed)); + +struct tape3592_kekl_pair { + __u8 count; + struct tape3592_kekl kekl[2]; +} __attribute__ ((packed)); + +struct tape3592_kekl_query_data { + __u16 len; + __u8 fmt; + __u8 mc; + __u32 id; + __u8 flags; + struct tape3592_kekl_pair kekls; + char reserved[116]; +} __attribute__ ((packed)); + +struct tape3592_kekl_query_order { + __u8 code; + __u8 flags; + char reserved1[2]; + __u8 max_count; + char reserved2[35]; +} __attribute__ ((packed)); + +struct tape3592_kekl_set_order { + __u8 code; + __u8 flags; + char reserved1[2]; + __u8 op; + struct tape3592_kekl_pair kekls; + char reserved2[120]; } __attribute__ ((packed)); #endif /* _TAPE_3590_H */ diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index fb65cf05d4de..04d93ef87b40 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -3,7 +3,7 @@ * character device frontend for tape device driver * * S390 and zSeries version - * Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index c6c2e918b990..8691bb985d00 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -3,7 +3,7 @@ * basic function of the tape device driver * * S390 and zSeries version - * Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright IBM Corp. 2001,2006 * Author(s): Carsten Otte * Michael Holzheu * Tuan Ngo-Anh @@ -26,9 +26,11 @@ #include "tape_std.h" #define PRINTK_HEADER "TAPE_CORE: " +#define LONG_BUSY_TIMEOUT 180 /* seconds */ static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *); static void tape_delayed_next_request(struct work_struct *); +static void tape_long_busy_timeout(unsigned long data); /* * One list to contain all tape devices of all disciplines, so @@ -69,7 +71,9 @@ const char *tape_op_verbose[TO_SIZE] = [TO_LOAD] = "LOA", [TO_READ_CONFIG] = "RCF", [TO_READ_ATTMSG] = "RAT", [TO_DIS] = "DIS", [TO_ASSIGN] = "ASS", - [TO_UNASSIGN] = "UAS" + [TO_UNASSIGN] = "UAS", [TO_CRYPT_ON] = "CON", + [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS", + [TO_KEKL_QUERY] = "KLQ", }; static inline int @@ -346,6 +350,9 @@ tape_generic_online(struct tape_device *device, return -EINVAL; } + init_timer(&device->lb_timeout); + device->lb_timeout.function = tape_long_busy_timeout; + /* Let the discipline have a go at the device. */ device->discipline = discipline; if (!try_module_get(discipline->owner)) { @@ -801,6 +808,22 @@ tape_delayed_next_request(struct work_struct *work) spin_unlock_irq(get_ccwdev_lock(device->cdev)); } +static void tape_long_busy_timeout(unsigned long data) +{ + struct tape_request *request; + struct tape_device *device; + + device = (struct tape_device *) data; + spin_lock_irq(get_ccwdev_lock(device->cdev)); + request = list_entry(device->req_queue.next, struct tape_request, list); + if (request->status != TAPE_REQUEST_LONG_BUSY) + BUG(); + DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id); + __tape_start_next_request(device); + device->lb_timeout.data = (unsigned long) tape_put_device(device); + spin_unlock_irq(get_ccwdev_lock(device->cdev)); +} + static inline void __tape_end_request( struct tape_device * device, @@ -1094,7 +1117,22 @@ __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.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; + req = list_entry(device->req_queue.next, + struct tape_request, list); + if (req->status == TAPE_REQUEST_LONG_BUSY) { + DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id); + if (del_timer(&device->lb_timeout)) { + device->lb_timeout.data = (unsigned long) + tape_put_device(device); + __tape_start_next_request(device); + } + return; + } + } if (irb->scsw.dstat != 0x0c) { /* Set the 'ONLINE' flag depending on sense byte 1 */ if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE) @@ -1142,6 +1180,15 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb) break; case TAPE_IO_PENDING: break; + case TAPE_IO_LONG_BUSY: + device->lb_timeout.data = + (unsigned long)tape_get_device_reference(device); + device->lb_timeout.expires = jiffies + + LONG_BUSY_TIMEOUT * HZ; + DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id); + add_timer(&device->lb_timeout); + request->status = TAPE_REQUEST_LONG_BUSY; + break; case TAPE_IO_RETRY: rc = __tape_start_io(device, request); if (rc) diff --git a/include/asm-s390/tape390.h b/include/asm-s390/tape390.h index f1d66ba0deef..884fba48f1ff 100644 --- a/include/asm-s390/tape390.h +++ b/include/asm-s390/tape390.h @@ -1,11 +1,11 @@ /************************************************************************* * * tape390.h - * enables user programs to display messages on the tape device + * enables user programs to display messages and control encryption + * on s390 tape devices * - * S390 and zSeries version - * Copyright (C) 2001 IBM Corporation - * Author(s): Despina Papadopoulou + * Copyright IBM Corp. 2001,2006 + * Author(s): Michael Holzheu * *************************************************************************/ @@ -36,4 +36,68 @@ typedef struct display_struct { char message2[8]; } display_struct; +/* + * Tape encryption support + */ + +struct tape390_crypt_info { + char capability; + char status; + char medium_status; +} __attribute__ ((packed)); + + +/* Macros for "capable" field */ +#define TAPE390_CRYPT_SUPPORTED_MASK 0x01 +#define TAPE390_CRYPT_SUPPORTED(x) \ + ((x.capability & TAPE390_CRYPT_SUPPORTED_MASK)) + +/* Macros for "status" field */ +#define TAPE390_CRYPT_ON_MASK 0x01 +#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK)) + +/* Macros for "medium status" field */ +#define TAPE390_MEDIUM_LOADED_MASK 0x01 +#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02 +#define TAPE390_MEDIUM_ENCRYPTED(x) \ + (((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK)) +#define TAPE390_MEDIUM_LOADED(x) \ + (((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK)) + +/* + * The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption. + * The "encryption_capable" and "tape_status" fields are ignored for this ioctl! + */ +#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info) + +/* + * The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state. + */ +#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info) + +/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */ +#define TAPE390_KEKL_TYPE_NONE 0 +#define TAPE390_KEKL_TYPE_LABEL 1 +#define TAPE390_KEKL_TYPE_HASH 2 + +struct tape390_kekl { + unsigned char type; + unsigned char type_on_tape; + char label[65]; +} __attribute__ ((packed)); + +struct tape390_kekl_pair { + struct tape390_kekl kekl[2]; +} __attribute__ ((packed)); + +/* + * The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels. + */ +#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair) + +/* + * The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels. + */ +#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair) + #endif -- cgit v1.2.3 From 31ee4b2f40994e8b21691f85cdd4052551a789b7 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Mon, 5 Feb 2007 21:18:31 +0100 Subject: [S390] Calibrate delay and bogomips. Preset the bogomips number to the cpu capacity value reported by store system information in SYSIB 1.2.2. This value is constant for a particular machine model and can be used to determine relative performance differences between machines. Signed-off-by: Martin Schwidefsky --- arch/s390/Kconfig | 4 --- arch/s390/kernel/setup.c | 1 + arch/s390/lib/Makefile | 2 +- arch/s390/lib/qrnnd.S | 77 +++++++++++++++++++++++++++++++++++++++++++ arch/s390/math-emu/Makefile | 2 +- arch/s390/math-emu/math.c | 2 +- arch/s390/math-emu/qrnnd.S | 77 ------------------------------------------- arch/s390/math-emu/sfp-util.h | 66 ------------------------------------- drivers/s390/Makefile | 2 ++ drivers/s390/sysinfo.c | 63 ++++++++++++++++++++++++++++++++++- include/asm-s390/processor.h | 1 + include/asm-s390/sfp-util.h | 66 +++++++++++++++++++++++++++++++++++++ 12 files changed, 212 insertions(+), 151 deletions(-) create mode 100644 arch/s390/lib/qrnnd.S delete mode 100644 arch/s390/math-emu/qrnnd.S delete mode 100644 arch/s390/math-emu/sfp-util.h create mode 100644 include/asm-s390/sfp-util.h (limited to 'drivers/s390') diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 5c7e981c115b..eaed402ad346 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -34,10 +34,6 @@ config GENERIC_HWEIGHT bool default y -config GENERIC_CALIBRATE_DELAY - bool - default y - config GENERIC_TIME def_bool y diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2569aafcc543..2fa866f6f711 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -938,6 +938,7 @@ static int show_cpuinfo(struct seq_file *m, void *v) struct cpuinfo_S390 *cpuinfo; unsigned long n = (unsigned long) v - 1; + s390_adjust_jiffies(); preempt_disable(); if (!n) { seq_printf(m, "vendor_id : IBM/S390\n" diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index b5f94cf3bde8..7a44fed21b35 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -4,7 +4,7 @@ EXTRA_AFLAGS := -traditional -lib-y += delay.o string.o uaccess_std.o uaccess_pt.o +lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o lib-$(CONFIG_32BIT) += div64.o lib-$(CONFIG_64BIT) += uaccess_mvcos.o lib-$(CONFIG_SMP) += spinlock.o diff --git a/arch/s390/lib/qrnnd.S b/arch/s390/lib/qrnnd.S new file mode 100644 index 000000000000..eb1df632e749 --- /dev/null +++ b/arch/s390/lib/qrnnd.S @@ -0,0 +1,77 @@ +# S/390 __udiv_qrnnd + +# r2 : &__r +# r3 : upper half of 64 bit word n +# r4 : lower half of 64 bit word n +# r5 : divisor d +# the reminder r of the division is to be stored to &__r and +# the quotient q is to be returned + + .text + .globl __udiv_qrnnd +__udiv_qrnnd: + st %r2,24(%r15) # store pointer to reminder for later + lr %r0,%r3 # reload n + lr %r1,%r4 + ltr %r2,%r5 # reload and test divisor + jp 5f + # divisor >= 0x80000000 + srdl %r0,2 # n/4 + srl %r2,1 # d/2 + slr %r1,%r2 # special case if last bit of d is set + brc 3,0f # (n/4) div (n/2) can overflow by 1 + ahi %r0,-1 # trick: subtract n/2, then divide +0: dr %r0,%r2 # signed division + ahi %r1,1 # trick part 2: add 1 to the quotient + # now (n >> 2) = (d >> 1) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r1 # test last bit of q + jz 1f + alr %r0,%r2 # add (d>>1) to r +1: srl %r1,1 # q >>= 1 + # now (n >> 2) = (d&-2) * %r1 + %r0 + lhi %r3,1 + nr %r3,%r5 # test last bit of d + jz 2f + slr %r0,%r1 # r -= q + brc 3,2f # borrow ? + alr %r0,%r5 # r += d + ahi %r1,-1 +2: # now (n >> 2) = d * %r1 + %r0 + alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,3f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +3: lhi %r3,2 + nr %r3,%r4 # test next to last bit of n + jz 4f + ahi %r0,1 # r += 1 +4: clr %r0,%r5 # r >= d ? + jl 6f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 + # now (n >> 1) = d * %r1 + %r0 + j 6f +5: # divisor < 0x80000000 + srdl %r0,1 + dr %r0,%r2 # signed division + # now (n >> 1) = d * %r1 + %r0 +6: alr %r1,%r1 # q <<= 1 + alr %r0,%r0 # r <<= 1 + brc 12,7f # overflow on r ? + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +7: lhi %r3,1 + nr %r3,%r4 # isolate last bit of n + alr %r0,%r3 # r += (n & 1) + clr %r0,%r5 # r >= d ? + jl 8f + slr %r0,%r5 # r -= d + ahi %r1,1 # q += 1 +8: # now n = d * %r1 + %r0 + l %r2,24(%r15) + st %r0,0(%r2) + lr %r2,%r1 + br %r14 + .end __udiv_qrnnd diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile index c10df144f2ab..73b3e72efc46 100644 --- a/arch/s390/math-emu/Makefile +++ b/arch/s390/math-emu/Makefile @@ -2,7 +2,7 @@ # Makefile for the FPU instruction emulation. # -obj-$(CONFIG_MATHEMU) := math.o qrnnd.o +obj-$(CONFIG_MATHEMU) := math.o EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w EXTRA_AFLAGS := -traditional diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c index 6b9aec5a2c18..3ee78ccb617d 100644 --- a/arch/s390/math-emu/math.c +++ b/arch/s390/math-emu/math.c @@ -15,7 +15,7 @@ #include #include -#include "sfp-util.h" +#include #include #include #include diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S deleted file mode 100644 index b01c2b648e22..000000000000 --- a/arch/s390/math-emu/qrnnd.S +++ /dev/null @@ -1,77 +0,0 @@ -# S/390 __udiv_qrnnd - -# r2 : &__r -# r3 : upper half of 64 bit word n -# r4 : lower half of 64 bit word n -# r5 : divisor d -# the reminder r of the division is to be stored to &__r and -# the quotient q is to be returned - - .text - .globl __udiv_qrnnd -__udiv_qrnnd: - st %r2,24(%r15) # store pointer to reminder for later - lr %r0,%r3 # reload n - lr %r1,%r4 - ltr %r2,%r5 # reload and test divisor - jp 5f - # divisor >= 0x80000000 - srdl %r0,2 # n/4 - srl %r2,1 # d/2 - slr %r1,%r2 # special case if last bit of d is set - brc 3,0f # (n/4) div (n/2) can overflow by 1 - ahi %r0,-1 # trick: subtract n/2, then divide -0: dr %r0,%r2 # signed division - ahi %r1,1 # trick part 2: add 1 to the quotient - # now (n >> 2) = (d >> 1) * %r1 + %r0 - lhi %r3,1 - nr %r3,%r1 # test last bit of q - jz 1f - alr %r0,%r2 # add (d>>1) to r -1: srl %r1,1 # q >>= 1 - # now (n >> 2) = (d&-2) * %r1 + %r0 - lhi %r3,1 - nr %r3,%r5 # test last bit of d - jz 2f - slr %r0,%r1 # r -= q - brc 3,2f # borrow ? - alr %r0,%r5 # r += d - ahi %r1,-1 -2: # now (n >> 2) = d * %r1 + %r0 - alr %r1,%r1 # q <<= 1 - alr %r0,%r0 # r <<= 1 - brc 12,3f # overflow on r ? - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -3: lhi %r3,2 - nr %r3,%r4 # test next to last bit of n - jz 4f - ahi %r0,1 # r += 1 -4: clr %r0,%r5 # r >= d ? - jl 6f - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 - # now (n >> 1) = d * %r1 + %r0 - j 6f -5: # divisor < 0x80000000 - srdl %r0,1 - dr %r0,%r2 # signed division - # now (n >> 1) = d * %r1 + %r0 -6: alr %r1,%r1 # q <<= 1 - alr %r0,%r0 # r <<= 1 - brc 12,7f # overflow on r ? - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -7: lhi %r3,1 - nr %r3,%r4 # isolate last bit of n - alr %r0,%r3 # r += (n & 1) - clr %r0,%r5 # r >= d ? - jl 8f - slr %r0,%r5 # r -= d - ahi %r1,1 # q += 1 -8: # now n = d * %r1 + %r0 - l %r2,24(%r15) - st %r0,0(%r2) - lr %r2,%r1 - br %r14 - .end __udiv_qrnnd diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h deleted file mode 100644 index 5b6ca4570ea4..000000000000 --- a/arch/s390/math-emu/sfp-util.h +++ /dev/null @@ -1,66 +0,0 @@ -#include -#include -#include -#include - -#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \ - unsigned int __sh = (ah); \ - unsigned int __sl = (al); \ - asm volatile( \ - " alr %1,%3\n" \ - " brc 12,0f\n" \ - " ahi %0,1\n" \ - "0: alr %0,%2" \ - : "+&d" (__sh), "+d" (__sl) \ - : "d" (bh), "d" (bl) : "cc"); \ - (sh) = __sh; \ - (sl) = __sl; \ -}) - -#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \ - unsigned int __sh = (ah); \ - unsigned int __sl = (al); \ - asm volatile( \ - " slr %1,%3\n" \ - " brc 3,0f\n" \ - " ahi %0,-1\n" \ - "0: slr %0,%2" \ - : "+&d" (__sh), "+d" (__sl) \ - : "d" (bh), "d" (bl) : "cc"); \ - (sh) = __sh; \ - (sl) = __sl; \ -}) - -/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */ -#define umul_ppmm(wh, wl, u, v) ({ \ - unsigned int __wh = u; \ - unsigned int __wl = v; \ - asm volatile( \ - " ltr 1,%0\n" \ - " mr 0,%1\n" \ - " jnm 0f\n" \ - " alr 0,%1\n" \ - "0: ltr %1,%1\n" \ - " jnm 1f\n" \ - " alr 0,%0\n" \ - "1: lr %0,0\n" \ - " lr %1,1\n" \ - : "+d" (__wh), "+d" (__wl) \ - : : "0", "1", "cc"); \ - wh = __wh; \ - wl = __wl; \ -}) - -#define udiv_qrnnd(q, r, n1, n0, d) \ - do { unsigned long __r; \ - (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ - (r) = __r; \ - } while (0) -extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long, - unsigned long , unsigned long); - -#define UDIV_NEEDS_NORMALIZATION 0 - -#define abort() return 0 - -#define __BYTE_ORDER __BIG_ENDIAN diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 9803c9352d78..5a888704a8d0 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -2,6 +2,8 @@ # Makefile for the S/390 specific device drivers # +CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w + obj-y += s390mach.o sysinfo.o s390_rdev.o obj-y += cio/ block/ char/ crypto/ net/ scsi/ diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index 1e788e815ce7..090743d2f914 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c @@ -9,8 +9,14 @@ #include #include #include +#include #include +/* Sigh, math-emu. Don't ask. */ +#include +#include +#include + struct sysinfo_1_1_1 { char reserved_0[32]; char manufacturer[16]; @@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) * if the higher order 8 bits are not zero. Printing * a floating point number in the kernel is a no-no, * always print the number as 32 bit unsigned integer. - * The user-space needs to know about the stange + * The user-space needs to know about the strange * encoding of the alternate cpu capability. */ len += sprintf(page + len, "Capability: %u %u\n", @@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(void) __initcall(create_proc_sysinfo); +/* + * CPU capability might have changed. Therefore recalculate loops_per_jiffy. + */ +void s390_adjust_jiffies(void) +{ + struct sysinfo_1_2_2 *info; + const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */ + FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); + FP_DECL_EX; + unsigned int capability; + + info = (void *) get_zeroed_page(GFP_KERNEL); + if (!info) + return; + + if (stsi(info, 1, 2, 2) != -ENOSYS) { + /* + * Major sigh. The cpu capability encoding is "special". + * If the first 9 bits of info->capability are 0 then it + * is a 32 bit unsigned integer in the range 0 .. 2^23. + * If the first 9 bits are != 0 then it is a 32 bit float. + * In addition a lower value indicates a proportionally + * higher cpu capacity. Bogomips are the other way round. + * To get to a halfway suitable number we divide 1e7 + * by the cpu capability number. Yes, that means a floating + * point division .. math-emu here we come :-) + */ + FP_UNPACK_SP(SA, &fmil); + if ((info->capability >> 23) == 0) + FP_FROM_INT_S(SB, info->capability, 32, int); + else + FP_UNPACK_SP(SB, &info->capability); + FP_DIV_S(SR, SA, SB); + FP_TO_INT_S(capability, SR, 32, 0); + } else + /* + * Really old machine without stsi block for basic + * cpu information. Report 42.0 bogomips. + */ + capability = 42; + loops_per_jiffy = capability * (500000/HZ); + free_page((unsigned long) info); +} + +/* + * calibrate the delay loop + */ +void __init calibrate_delay(void) +{ + s390_adjust_jiffies(); + /* Print the good old Bogomips line .. */ + printk(KERN_DEBUG "Calibrating delay loop (skipped)... " + "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ), + (loops_per_jiffy/(5000/HZ)) % 100); +} diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 5af853576cbd..cf71c5449240 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -50,6 +50,7 @@ struct cpuinfo_S390 unsigned long pgtable_cache_sz; }; +extern void s390_adjust_jiffies(void); extern void print_cpu_info(struct cpuinfo_S390 *); /* Lazy FPU handling on uni-processor */ diff --git a/include/asm-s390/sfp-util.h b/include/asm-s390/sfp-util.h new file mode 100644 index 000000000000..8cabcd23d976 --- /dev/null +++ b/include/asm-s390/sfp-util.h @@ -0,0 +1,66 @@ +#include +#include +#include +#include + +#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + asm volatile( \ + " alr %1,%3\n" \ + " brc 12,0f\n" \ + " ahi %0,1\n" \ + "0: alr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc"); \ + (sh) = __sh; \ + (sl) = __sl; \ +}) + +#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \ + unsigned int __sh = (ah); \ + unsigned int __sl = (al); \ + asm volatile( \ + " slr %1,%3\n" \ + " brc 3,0f\n" \ + " ahi %0,-1\n" \ + "0: slr %0,%2" \ + : "+&d" (__sh), "+d" (__sl) \ + : "d" (bh), "d" (bl) : "cc"); \ + (sh) = __sh; \ + (sl) = __sl; \ +}) + +/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */ +#define umul_ppmm(wh, wl, u, v) ({ \ + unsigned int __wh = u; \ + unsigned int __wl = v; \ + asm volatile( \ + " ltr 1,%0\n" \ + " mr 0,%1\n" \ + " jnm 0f\n" \ + " alr 0,%1\n" \ + "0: ltr %1,%1\n" \ + " jnm 1f\n" \ + " alr 0,%0\n" \ + "1: lr %0,0\n" \ + " lr %1,1\n" \ + : "+d" (__wh), "+d" (__wl) \ + : : "0", "1", "cc"); \ + wh = __wh; \ + wl = __wl; \ +}) + +#define udiv_qrnnd(q, r, n1, n0, d) \ + do { unsigned int __r; \ + (q) = __udiv_qrnnd (&__r, (n1), (n0), (d)); \ + (r) = __r; \ + } while (0) +extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int, + unsigned int , unsigned int); + +#define UDIV_NEEDS_NORMALIZATION 0 + +#define abort() return 0 + +#define __BYTE_ORDER __BIG_ENDIAN -- cgit v1.2.3 From ab14de6c37fae22911ba99f4171613e6d758050b Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 5 Feb 2007 21:18:37 +0100 Subject: [S390] Convert memory detection into C code. Hopefully this will make it more maintainable and less error prone. Code makes use of search_exception_tables(). Since it calls this function before the kernel exeception table is sorted, there is an early call to sort_main_extable(). This way it's easy to use the already present infrastructure of fixup sections. Also this would allows to easily convert the rest of head[31|64].S into C code. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/defconfig | 1 - arch/s390/kernel/Makefile | 2 +- arch/s390/kernel/base.S | 150 ++++++++++++++++++++ arch/s390/kernel/early.c | 307 +++++++++++++++++++++++++++++++++++++++++ arch/s390/kernel/head31.S | 164 +--------------------- arch/s390/kernel/head64.S | 175 ----------------------- arch/s390/kernel/ipl.c | 15 +- arch/s390/kernel/reset.S | 90 ------------ arch/s390/kernel/setup.c | 134 ------------------ drivers/s390/Kconfig | 8 -- drivers/s390/char/Makefile | 4 +- drivers/s390/char/sclp.c | 12 +- drivers/s390/char/sclp.h | 18 +-- drivers/s390/char/sclp_cpi.c | 2 +- drivers/s390/char/sclp_info.c | 57 ++++++++ drivers/s390/char/sclp_rw.c | 2 +- drivers/s390/char/sclp_vt220.c | 2 +- drivers/s390/cio/cio.c | 10 +- include/asm-s390/processor.h | 12 ++ include/asm-s390/reset.h | 3 - include/asm-s390/sclp.h | 39 ++++++ 21 files changed, 598 insertions(+), 609 deletions(-) create mode 100644 arch/s390/kernel/base.S create mode 100644 arch/s390/kernel/early.c delete mode 100644 arch/s390/kernel/reset.S create mode 100644 drivers/s390/char/sclp_info.c create mode 100644 include/asm-s390/sclp.h (limited to 'drivers/s390') diff --git a/arch/s390/defconfig b/arch/s390/defconfig index dbe3df4b0dab..7c621b8ef683 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -433,7 +433,6 @@ CONFIG_TN3270_CONSOLE=y CONFIG_TN3215=y CONFIG_TN3215_CONSOLE=y CONFIG_CCW_CONSOLE=y -CONFIG_SCLP=y CONFIG_SCLP_TTY=y CONFIG_SCLP_CONSOLE=y CONFIG_SCLP_VT220_TTY=y diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 2de811a71a39..5492d25d7d69 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -4,7 +4,7 @@ EXTRA_AFLAGS := -traditional -obj-y := bitmap.o traps.o time.o process.o reset.o \ +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 \ semaphore.o s390_ext.o debug.o irq.o ipl.o diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S new file mode 100644 index 000000000000..dc7e5259770f --- /dev/null +++ b/arch/s390/kernel/base.S @@ -0,0 +1,150 @@ +/* + * arch/s390/kernel/base.S + * + * Copyright IBM Corp. 2006,2007 + * Author(s): Heiko Carstens + * Michael Holzheu + */ + +#include +#include + +#ifdef CONFIG_64BIT + + .globl s390_base_mcck_handler +s390_base_mcck_handler: + basr %r13,0 +0: lg %r15,__LC_PANIC_STACK # load panic stack + aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_mcck_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 +1: la %r1,4095 + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) + lpswe __LC_MCK_OLD_PSW + + .section .bss + .globl s390_base_mcck_handler_fn +s390_base_mcck_handler_fn: + .quad 0 + .previous + + .globl s390_base_ext_handler +s390_base_ext_handler: + stmg %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_ext_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lmg %r0,%r15,__LC_SAVE_AREA + ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit + lpswe __LC_EXT_OLD_PSW + + .section .bss + .globl s390_base_ext_handler_fn +s390_base_ext_handler_fn: + .quad 0 + .previous + + .globl s390_base_pgm_handler +s390_base_pgm_handler: + stmg %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: aghi %r15,-STACK_FRAME_OVERHEAD + larl %r1,s390_base_pgm_handler_fn + lg %r1,0(%r1) + ltgr %r1,%r1 + jz 1f + basr %r14,%r1 + lmg %r0,%r15,__LC_SAVE_AREA + lpswe __LC_PGM_OLD_PSW +1: lpswe disabled_wait_psw-0b(%r13) + + .align 8 +disabled_wait_psw: + .quad 0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler + + .section .bss + .globl s390_base_pgm_handler_fn +s390_base_pgm_handler_fn: + .quad 0 + .previous + +#else /* CONFIG_64BIT */ + + .globl s390_base_mcck_handler +s390_base_mcck_handler: + basr %r13,0 +0: l %r15,__LC_PANIC_STACK # load panic stack + ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA + lpsw __LC_MCK_OLD_PSW + +2: .long s390_base_mcck_handler_fn + + .section .bss + .globl s390_base_mcck_handler_fn +s390_base_mcck_handler_fn: + .long 0 + .previous + + .globl s390_base_ext_handler +s390_base_ext_handler: + stm %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 +1: lm %r0,%r15,__LC_SAVE_AREA + ni __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit + lpsw __LC_EXT_OLD_PSW + +2: .long s390_base_ext_handler_fn + + .section .bss + .globl s390_base_ext_handler_fn +s390_base_ext_handler_fn: + .long 0 + .previous + + .globl s390_base_pgm_handler +s390_base_pgm_handler: + stm %r0,%r15,__LC_SAVE_AREA + basr %r13,0 +0: ahi %r15,-STACK_FRAME_OVERHEAD + l %r1,2f-0b(%r13) + l %r1,0(%r1) + ltr %r1,%r1 + jz 1f + basr %r14,%r1 + lm %r0,%r15,__LC_SAVE_AREA + lpsw __LC_PGM_OLD_PSW + +1: lpsw disabled_wait_psw-0b(%r13) + +2: .long s390_base_pgm_handler_fn + +disabled_wait_psw: + .align 8 + .long 0x000a0000,0x00000000 + s390_base_pgm_handler + + .section .bss + .globl s390_base_pgm_handler_fn +s390_base_pgm_handler_fn: + .long 0 + .previous + +#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c new file mode 100644 index 000000000000..40dd47970a33 --- /dev/null +++ b/arch/s390/kernel/early.c @@ -0,0 +1,307 @@ +/* + * arch/s390/kernel/early.c + * + * Copyright IBM Corp. 2007 + * Author(s): Hongjie Yang , + * Heiko Carstens + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Create a Kernel NSS if the SAVESYS= parameter is defined + */ +#define DEFSYS_CMD_SIZE 96 +#define SAVESYS_CMD_SIZE 32 + +extern int _eshared; +char kernel_nss_name[NSS_NAME_SIZE + 1]; + +#ifdef CONFIG_SHARED_KERNEL +static noinline __init void create_kernel_nss(void) +{ + unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; +#ifdef CONFIG_BLK_DEV_INITRD + unsigned int sinitrd_pfn, einitrd_pfn; +#endif + int response; + char *savesys_ptr; + char upper_command_line[COMMAND_LINE_SIZE]; + char defsys_cmd[DEFSYS_CMD_SIZE]; + char savesys_cmd[SAVESYS_CMD_SIZE]; + + /* Do nothing if we are not running under VM */ + if (!MACHINE_IS_VM) + return; + + /* Convert COMMAND_LINE to upper case */ + for (i = 0; i < strlen(COMMAND_LINE); i++) + upper_command_line[i] = toupper(COMMAND_LINE[i]); + + savesys_ptr = strstr(upper_command_line, "SAVESYS="); + + if (!savesys_ptr) + return; + + savesys_ptr += 8; /* Point to the beginning of the NSS name */ + for (i = 0; i < NSS_NAME_SIZE; i++) { + if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0') + break; + kernel_nss_name[i] = savesys_ptr[i]; + } + + stext_pfn = PFN_DOWN(__pa(&_stext)); + eshared_pfn = PFN_DOWN(__pa(&_eshared)); + end_pfn = PFN_UP(__pa(&_end)); + min_size = end_pfn << 2; + + sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", + kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, + eshared_pfn, end_pfn); + +#ifdef CONFIG_BLK_DEV_INITRD + if (INITRD_START && INITRD_SIZE) { + sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); + einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); + min_size = einitrd_pfn << 2; + sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, + sinitrd_pfn, einitrd_pfn); + } +#endif + + 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); + + __cpcmd(defsys_cmd, NULL, 0, &response); + + if (response != 0) + return; + + __cpcmd(savesys_cmd, NULL, 0, &response); + + if (response != strlen(savesys_cmd)) + return; + + ipl_flags = IPL_NSS_VALID; +} + +#else /* CONFIG_SHARED_KERNEL */ + +static inline void create_kernel_nss(void) { } + +#endif /* CONFIG_SHARED_KERNEL */ + +/* + * Clear bss memory + */ +static noinline __init void clear_bss_section(void) +{ + memset(__bss_start, 0, _end - __bss_start); +} + +/* + * Initialize storage key for kernel pages + */ +static noinline __init void init_kernel_storage_key(void) +{ + unsigned long end_pfn, init_pfn; + + end_pfn = PFN_UP(__pa(&_end)); + + for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) + page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); +} + +static noinline __init void detect_machine_type(void) +{ + struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; + + asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id)); + + /* Running under z/VM ? */ + if (cpuinfo->cpu_id.version == 0xff) + machine_flags |= 1; + + /* Running on a P/390 ? */ + if (cpuinfo->cpu_id.machine == 0x7490) + machine_flags |= 4; +} + +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; + return 0; +} + +#define ADDR2G (1UL << 31) + +static noinline __init unsigned long sclp_memory_detect(void) +{ + struct sclp_readinfo_sccb *sccb; + unsigned long long memsize; + + sccb = &s390_readinfo_sccb; + + if (sccb->header.response_code != 0x10) + return 0; + + if (sccb->rnsize) + memsize = sccb->rnsize << 20; + else + memsize = sccb->rnsize2 << 20; + if (sccb->rnmax) + memsize *= sccb->rnmax; + else + memsize *= sccb->rnmax2; +#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 + return (unsigned long) memsize; +} + +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) + +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; + cc = __tprot(addr); +#ifndef CONFIG_64BIT + if (addr == ADDR2G) + break; +#endif + } + + 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, unless + * - we reached the hsa -> skip it. + * - we know there must be more. + */ + if (cc == -1UL && !memsize && old_addr != ADDR2G) + break; + if (memsize && addr >= memsize) + break; + } +} + +static __init void early_pgm_check_handler(void) +{ + unsigned long addr; + const struct exception_table_entry *fixup; + + addr = S390_lowcore.program_old_psw.addr; + fixup = search_exception_tables(addr & PSW_ADDR_INSN); + if (!fixup) + disabled_wait(0); + S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE; +} + +static noinline __init void setup_lowcore_early(void) +{ + psw_t psw; + + psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY; + psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler; + S390_lowcore.external_new_psw = psw; + psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler; + S390_lowcore.program_new_psw = psw; + s390_base_pgm_handler_fn = early_pgm_check_handler; +} + +/* + * 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 memsize; + + ipl_save_parameters(); + clear_bss_section(); + init_kernel_storage_key(); + lockdep_init(); + lockdep_off(); + detect_machine_type(); + create_kernel_nss(); + sort_main_extable(); + setup_lowcore_early(); + sclp_readinfo_early(); + memsize = sclp_memory_detect(); + if (memory_fast_detect() < 0) + find_memory_chunks(memsize); + lockdep_on(); +} diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index b3dcdcdc80c0..453fd3b4edea 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S @@ -58,145 +58,6 @@ startup_continue: l %r14,.Lstartup_init-.LPG1(%r13) basr %r14,%r14 - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word -.Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - - stctl %r0, %r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - o %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - st %r1,.Lcr-.LPG1(%r13) - lctl %r0, %r0,.Lcr-.LPG1(%r13) # load modified cr0 - - mvc __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw - la %r1, .Lsclph-.LPG1(%r13) - a %r1,__LC_EXT_NEW_PSW+4 # set handler - st %r1,__LC_EXT_NEW_PSW+4 - - l %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff - lr %r1,%r4 # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3, %r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpsw .Lwaitsclp-.LPG1(%r13) -.Lsclph: - lh %r1,.Lsccbr-.Lsccb(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2, .Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) -.Lprocsccb: - lhi %r1,0 - icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 - jnz .Lscnd - lhi %r1,0x800 # otherwise report 2GB -.Lscnd: - lhi %r3,0x800 # limit reported memory size to 2GB - cr %r1,%r3 - jl .Lno2gb - lr %r1,%r3 -.Lno2gb: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-.Lsccb(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-.Lsccb(%r4) -.Lcompmem: - mr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) - - .align 4 -.Linittu: - .long init_thread_union -.Lstartup_init: - .long startup_init -.Lpmask: - .byte 0 - .align 8 -.Lpcext:.long 0x00080000,0x80000000 -.Lcr: - .long 0x00 # place holder for cr0 - .align 8 -.Lwaitsclp: - .long 0x010a0000,0x80000000 + .Lsclph -.Lrcp: - .int 0x00120001 # Read SCP forced code -.Lrcp2: - .int 0x00020001 # Read SCP code -.Lonemb: - .int 0x100000 -.Lfchunk: - -# -# find memory chunks. -# - lr %r9,%r3 # end of mem - mvc __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13) - la %r1,1 # test in increments of 128KB - sll %r1,17 - l %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array - slr %r4,%r4 # set start of chunk to zero - slr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10,MEMORY_CHUNKS # number of chunks -.Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - be .Lsame-.LPG1(%r13) - lhi %r8,0 # no program checks - b .Lsavchk-.LPG1(%r13) -.Lsame: - ar %r5,%r1 # add 128KB to end of chunk - bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop -.Lchkmem: # > 2GB or tprot got a program check - lhi %r8,1 # set program check flag -.Lsavchk: - clr %r4,%r5 # chunk size > 0? - be .Lchkloop-.LPG1(%r13) - st %r4,0(%r3) # store start address of chunk - lr %r0,%r5 - slr %r0,%r4 - st %r0,4(%r3) # store size of chunk - st %r6,8(%r3) # store type of chunk - la %r3,12(%r3) - ahi %r10,-1 # update chunk number -.Lchkloop: - lr %r6,%r7 # set access code to last cc - # we got an exception or we're starting a new - # chunk , we must check if we should - # still try to find valid memory (if we detected - # the amount of available storage), and if we - # have chunks left - xr %r0,%r0 - clr %r0,%r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10,0 # do we have chunks left? - je .Ldonemem - chi %r8,1 # program check ? - je .Lpgmchk - lr %r4,%r5 # potential new chunk - alr %r5,%r1 # add 128KB to end of chunk - j .Llpcnt -.Lpgmchk: - alr %r5,%r1 # add 128KB to end of chunk - lr %r4,%r5 # potential new chunk -.Llpcnt: - clr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags # # find out if we have an IEEE fpu @@ -273,7 +134,6 @@ startup_continue: .long 0 # cr15: linkage stack operations .Lduct: .long 0,0,0,0,0,0,0,0 .long 0,0,0,0,0,0,0,0 -.Lpcmem:.long 0x00080000,0x80000000 + .Lchkmem .Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu .Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg @@ -284,7 +144,9 @@ startup_continue: .Lbss_bgn: .long __bss_start .Lbss_end: .long _end .Lparmaddr: .long PARMAREA -.Lsccbaddr: .long .Lsccb +.Linittu: .long init_thread_union +.Lstartup_init: + .long startup_init .globl ipl_schib ipl_schib: @@ -300,26 +162,6 @@ ipl_devno: .word 0 .org 0x12000 -.globl s390_readinfo_sccb -s390_readinfo_sccb: -.Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set -.Lsccbr: - .hword 0x00 # response code -.Lscpincr1: - .hword 0x00 -.Lscpa1: - .byte 0x00 - .fill 89,1,0 -.Lscpa2: - .int 0x00 -.Lscpincr2: - .quad 0x00 - .fill 3984,1,0 - .org 0x13000 - #ifdef CONFIG_SHARED_KERNEL .org 0x100000 #endif diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 030a1c95f47c..b8fec4e5c5d4 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -65,162 +65,6 @@ startup_continue: brasl %r14,startup_init # set program check new psw mask mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) - larl %r1,.Lslowmemdetect # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - lghi %r1,0xc - diag %r0,%r1,0x260 # get memory size of virtual machine - cgr %r0,%r1 # different? -> old detection routine - jne .Lslowmemdetect - larl %r3,ipl_flags - llgt %r3,0(%r3) - chi %r3,4 # ipled from an kernel NSS - je .Lslowmemdetect - aghi %r1,1 # size is one more than end - larl %r2,memory_chunk - stg %r1,8(%r2) # store size of chunk - -.Lslowmemdetect: - l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word -.Lservicecall: - stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts - - stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0 - la %r1,0x200 # set bit 22 - og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1 - stg %r1,.Lcr-.LPG1(%r13) - lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0 - - mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw - larl %r1,.Lsclph - stg %r1,__LC_EXT_NEW_PSW+8 # set handler - - larl %r4,.Lsccb # %r4 is our index for sccb stuff - lgr %r1,%r4 # our sccb - .insn rre,0xb2200000,%r2,%r1 # service call - ipm %r1 - srl %r1,28 # get cc code - xr %r3,%r3 - chi %r1,3 - be .Lfchunk-.LPG1(%r13) # leave - chi %r1,2 - be .Lservicecall-.LPG1(%r13) - lpswe .Lwaitsclp-.LPG1(%r13) -.Lsclph: - lh %r1,.Lsccbr-.Lsccb(%r4) - chi %r1,0x10 # 0x0010 is the sucess code - je .Lprocsccb # let's process the sccb - chi %r1,0x1f0 - bne .Lfchunk-.LPG1(%r13) # unhandled error code - c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced - bne .Lfchunk-.LPG1(%r13) # if no, give up - l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP - b .Lservicecall-.LPG1(%r13) -.Lprocsccb: - lghi %r1,0 - icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0 - jnz .Lscnd - lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one -.Lscnd: - xr %r3,%r3 # same logic - ic %r3,.Lscpa1-.Lsccb(%r4) - chi %r3,0x00 - jne .Lcompmem - l %r3,.Lscpa2-.Lsccb(%r4) -.Lcompmem: - mlgr %r2,%r1 # mem in MB on 128-bit - l %r1,.Lonemb-.LPG1(%r13) - mlgr %r2,%r1 # mem size in bytes in %r3 - b .Lfchunk-.LPG1(%r13) - - .align 4 -.Lpmask: - .byte 0 - .align 8 -.Lcr: - .quad 0x00 # place holder for cr0 -.Lwaitsclp: - .quad 0x0102000180000000,.Lsclph -.Lrcp: - .int 0x00120001 # Read SCP forced code -.Lrcp2: - .int 0x00020001 # Read SCP code -.Lonemb: - .int 0x100000 - -.Lfchunk: - -# -# find memory chunks. -# - larl %r9,memory_chunk # skip tprot loop if diag260 - lg %r9,8(%r9) # memory detection was successful - ltgr %r9,%r9 - jne .Ldonemem - - lgr %r9,%r3 # end of mem - larl %r1,.Lchkmem # set program check address - stg %r1,__LC_PGM_NEW_PSW+8 - la %r1,1 # test in increments of 128KB - sllg %r1,%r1,17 - larl %r3,memory_chunk - slgr %r4,%r4 # set start of chunk to zero - slgr %r5,%r5 # set end of chunk to zero - slr %r6,%r6 # set access code to zero - la %r10,MEMORY_CHUNKS # number of chunks -.Lloop: - tprot 0(%r5),0 # test protection of first byte - ipm %r7 - srl %r7,28 - clr %r6,%r7 # compare cc with last access code - je .Lsame - lghi %r8,0 # no program checks - j .Lsavchk -.Lsame: - algr %r5,%r1 # add 128KB to end of chunk - # no need to check here, - brc 12,.Lloop # this is the same chunk -.Lchkmem: # > 16EB or tprot got a program check - lghi %r8,1 # set program check flag -.Lsavchk: - clgr %r4,%r5 # chunk size > 0? - je .Lchkloop - stg %r4,0(%r3) # store start address of chunk - lgr %r0,%r5 - slgr %r0,%r4 - stg %r0,8(%r3) # store size of chunk - st %r6,20(%r3) # store type of chunk - la %r3,24(%r3) - ahi %r10,-1 # update chunk number -.Lchkloop: - lr %r6,%r7 # set access code to last cc - # we got an exception or we're starting a new - # chunk , we must check if we should - # still try to find valid memory (if we detected - # the amount of available storage), and if we - # have chunks left - lghi %r4,1 - sllg %r4,%r4,31 - clgr %r5,%r4 - je .Lhsaskip - xr %r0, %r0 - clgr %r0, %r9 # did we detect memory? - je .Ldonemem # if not, leave - chi %r10, 0 # do we have chunks left? - je .Ldonemem -.Lhsaskip: - chi %r8,1 # program check ? - je .Lpgmchk - lgr %r4,%r5 # potential new chunk - algr %r5,%r1 # add 128KB to end of chunk - j .Llpcnt -.Lpgmchk: - algr %r5,%r1 # add 128KB to end of chunk - lgr %r4,%r5 # potential new chunk -.Llpcnt: - clgr %r5,%r9 # should we go on? - jl .Lloop -.Ldonemem: - larl %r12,machine_flags # # find out if we have the MVPG instruction @@ -324,25 +168,6 @@ ipl_devno: .word 0 .org 0x12000 -.globl s390_readinfo_sccb -s390_readinfo_sccb: -.Lsccb: - .hword 0x1000 # length, one page - .byte 0x00,0x00,0x00 - .byte 0x80 # variable response bit set -.Lsccbr: - .hword 0x00 # response code -.Lscpincr1: - .hword 0x00 -.Lscpa1: - .byte 0x00 - .fill 89,1,0 -.Lscpa2: - .int 0x00 -.Lscpincr2: - .quad 0x00 - .fill 3984,1,0 - .org 0x13000 #ifdef CONFIG_SHARED_KERNEL .org 0x100000 diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 13eacce62011..052259530651 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -20,14 +20,13 @@ #include #include #include +#include #define IPL_PARM_BLOCK_VERSION 0 -#define LOADPARM_LEN 8 -extern char s390_readinfo_sccb[]; -#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010) -#define SCCB_LOADPARM (&s390_readinfo_sccb[24]) -#define SCCB_FLAG (s390_readinfo_sccb[91]) +#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10) +#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm) +#define SCCB_FLAG (s390_readinfo_sccb.flags) enum ipl_type { IPL_TYPE_NONE = 1, @@ -1080,8 +1079,6 @@ static void do_reset_calls(void) reset->fn(); } -extern void reset_mcck_handler(void); -extern void reset_pgm_handler(void); extern __u32 dump_prefix_page; void s390_reset_system(void) @@ -1105,12 +1102,12 @@ void s390_reset_system(void) /* Set new machine check handler */ S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; S390_lowcore.mcck_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; + PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler; /* Set new program check handler */ S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK; S390_lowcore.program_new_psw.addr = - PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler; + PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler; do_reset_calls(); } diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S deleted file mode 100644 index 8a87355161fa..000000000000 --- a/arch/s390/kernel/reset.S +++ /dev/null @@ -1,90 +0,0 @@ -/* - * arch/s390/kernel/reset.S - * - * Copyright (C) IBM Corp. 2006 - * Author(s): Heiko Carstens - * Michael Holzheu - */ - -#include -#include - -#ifdef CONFIG_64BIT - - .globl reset_mcck_handler -reset_mcck_handler: - basr %r13,0 -0: lg %r15,__LC_PANIC_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - lg %r1,s390_reset_mcck_handler-0b(%r13) - ltgr %r1,%r1 - jz 1f - basr %r14,%r1 -1: la %r1,4095 - lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) - lpswe __LC_MCK_OLD_PSW - - .globl s390_reset_mcck_handler -s390_reset_mcck_handler: - .quad 0 - - .globl reset_pgm_handler -reset_pgm_handler: - stmg %r0,%r15,__LC_SAVE_AREA - basr %r13,0 -0: lg %r15,__LC_PANIC_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - lg %r1,s390_reset_pgm_handler-0b(%r13) - ltgr %r1,%r1 - jz 1f - basr %r14,%r1 - lmg %r0,%r15,__LC_SAVE_AREA - lpswe __LC_PGM_OLD_PSW -1: lpswe disabled_wait_psw-0b(%r13) - .globl s390_reset_pgm_handler -s390_reset_pgm_handler: - .quad 0 - .align 8 -disabled_wait_psw: - .quad 0x0002000180000000,0x0000000000000000 + reset_pgm_handler - -#else /* CONFIG_64BIT */ - - .globl reset_mcck_handler -reset_mcck_handler: - basr %r13,0 -0: l %r15,__LC_PANIC_STACK # load panic stack - ahi %r15,-STACK_FRAME_OVERHEAD - l %r1,s390_reset_mcck_handler-0b(%r13) - ltr %r1,%r1 - jz 1f - basr %r14,%r1 -1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA - lpsw __LC_MCK_OLD_PSW - - .globl s390_reset_mcck_handler -s390_reset_mcck_handler: - .long 0 - - .globl reset_pgm_handler -reset_pgm_handler: - stm %r0,%r15,__LC_SAVE_AREA - basr %r13,0 -0: l %r15,__LC_PANIC_STACK # load panic stack - ahi %r15,-STACK_FRAME_OVERHEAD - l %r1,s390_reset_pgm_handler-0b(%r13) - ltr %r1,%r1 - jz 1f - basr %r14,%r1 - lm %r0,%r15,__LC_SAVE_AREA - lpsw __LC_PGM_OLD_PSW - -1: lpsw disabled_wait_psw-0b(%r13) - .globl s390_reset_pgm_handler -s390_reset_pgm_handler: - .long 0 -disabled_wait_psw: - .align 8 - .long 0x000a0000,0x00000000 + reset_pgm_handler - -#endif /* CONFIG_64BIT */ diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2fa866f6f711..f73a11528217 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -284,140 +284,6 @@ static void __init conmode_default(void) } } -/* - * Create a Kernel NSS if the SAVESYS= parameter is defined -*/ -#define DEFSYS_CMD_SIZE 96 -#define SAVESYS_CMD_SIZE 32 - -extern int _eshared; -char kernel_nss_name[NSS_NAME_SIZE + 1]; - -#ifdef CONFIG_SHARED_KERNEL -static __init void create_kernel_nss(void) -{ - unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; -#ifdef CONFIG_BLK_DEV_INITRD - unsigned int sinitrd_pfn, einitrd_pfn; -#endif - int response; - char *savesys_ptr; - char upper_command_line[COMMAND_LINE_SIZE]; - char defsys_cmd[DEFSYS_CMD_SIZE]; - char savesys_cmd[SAVESYS_CMD_SIZE]; - - /* Do nothing if we are not running under VM */ - if (!MACHINE_IS_VM) - return; - - /* Convert COMMAND_LINE to upper case */ - for (i = 0; i < strlen(COMMAND_LINE); i++) - upper_command_line[i] = toupper(COMMAND_LINE[i]); - - savesys_ptr = strstr(upper_command_line, "SAVESYS="); - - if (!savesys_ptr) - return; - - savesys_ptr += 8; /* Point to the beginning of the NSS name */ - for (i = 0; i < NSS_NAME_SIZE; i++) { - if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0') - break; - kernel_nss_name[i] = savesys_ptr[i]; - } - - stext_pfn = PFN_DOWN(__pa(&_stext)); - eshared_pfn = PFN_DOWN(__pa(&_eshared)); - end_pfn = PFN_UP(__pa(&_end)); - min_size = end_pfn << 2; - - sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", - kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, - eshared_pfn, end_pfn); - -#ifdef CONFIG_BLK_DEV_INITRD - if (INITRD_START && INITRD_SIZE) { - sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); - einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); - min_size = einitrd_pfn << 2; - sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, - sinitrd_pfn, einitrd_pfn); - } -#endif - - 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); - - __cpcmd(defsys_cmd, NULL, 0, &response); - - if (response != 0) - return; - - __cpcmd(savesys_cmd, NULL, 0, &response); - - if (response != strlen(savesys_cmd)) - return; - - ipl_flags = IPL_NSS_VALID; -} - -#else /* CONFIG_SHARED_KERNEL */ - -static inline void create_kernel_nss(void) { } - -#endif /* CONFIG_SHARED_KERNEL */ - -/* - * Clear bss memory - */ -static __init void clear_bss_section(void) -{ - memset(__bss_start, 0, _end - __bss_start); -} - -/* - * Initialize storage key for kernel pages - */ -static __init void init_kernel_storage_key(void) -{ - unsigned long end_pfn, init_pfn; - - end_pfn = PFN_UP(__pa(&_end)); - - for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) - page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); -} - -static __init void detect_machine_type(void) -{ - struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; - - asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id)); - - /* Running under z/VM ? */ - if (cpuinfo->cpu_id.version == 0xff) - machine_flags |= 1; - - /* Running on a P/390 ? */ - if (cpuinfo->cpu_id.machine == 0x7490) - machine_flags |= 4; -} - -/* - * 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) -{ - ipl_save_parameters(); - clear_bss_section(); - init_kernel_storage_key(); - lockdep_init(); - detect_machine_type(); - create_kernel_nss(); -} - #ifdef CONFIG_SMP void (*_machine_restart)(char *command) = machine_restart_smp; void (*_machine_halt)(void) = machine_halt_smp; diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig index ae89b9b88743..165af398fdea 100644 --- a/drivers/s390/Kconfig +++ b/drivers/s390/Kconfig @@ -103,14 +103,8 @@ config CCW_CONSOLE depends on TN3215_CONSOLE || TN3270_CONSOLE default y -config SCLP - bool "Support for SCLP" - help - Include support for the SCLP interface to the service element. - config SCLP_TTY bool "Support for SCLP line mode terminal" - depends on SCLP help Include support for IBM SCLP line-mode terminals. @@ -123,7 +117,6 @@ config SCLP_CONSOLE config SCLP_VT220_TTY bool "Support for SCLP VT220-compatible terminal" - depends on SCLP help Include support for an IBM SCLP VT220-compatible terminal. @@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE config SCLP_CPI tristate "Control-Program Identification" - depends on SCLP help This option enables the hardware console interface for system identification. This is commonly used for workload management and diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index c3e97b4fc186..293e667b50f2 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -2,7 +2,8 @@ # S/390 character devices # -obj-y += ctrlchar.o keyboard.o defkeymap.o +obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \ + sclp_info.o obj-$(CONFIG_TN3270) += raw3270.o obj-$(CONFIG_TN3270_CONSOLE) += con3270.o @@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o obj-$(CONFIG_TN3215) += con3215.o -obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o obj-$(CONFIG_SCLP_TTY) += sclp_tty.o obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index c1dd19bb7bf8..6a83e2d722a8 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -96,8 +96,8 @@ static int sclp_init_mask(int calculate); static int sclp_init(void); /* Perform service call. Return 0 on success, non-zero otherwise. */ -static int -service_call(sclp_cmdw_t command, void *sccb) +int +sclp_service_call(sclp_cmdw_t command, void *sccb) { int cc; @@ -173,7 +173,7 @@ __sclp_start_request(struct sclp_req *req) if (sclp_running_state != sclp_running_state_idle) return 0; del_timer(&sclp_request_timer); - rc = service_call(req->command, req->sccb); + rc = sclp_service_call(req->command, req->sccb); req->start_count++; if (rc == 0) { @@ -325,7 +325,7 @@ __sclp_make_read_req(void) sccb = (struct sccb_header *) sclp_read_sccb; clear_page(sccb); memset(&sclp_read_req, 0, sizeof(struct sclp_req)); - sclp_read_req.command = SCLP_CMDW_READDATA; + sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA; sclp_read_req.status = SCLP_REQ_QUEUED; sclp_read_req.start_count = 0; sclp_read_req.callback = sclp_read_cb; @@ -628,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask) sccb = (struct init_sccb *) sclp_init_sccb; clear_page(sccb); memset(&sclp_init_req, 0, sizeof(struct sclp_req)); - sclp_init_req.command = SCLP_CMDW_WRITEMASK; + sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK; sclp_init_req.status = SCLP_REQ_FILLED; sclp_init_req.start_count = 0; sclp_init_req.callback = NULL; @@ -831,7 +831,7 @@ sclp_check_interface(void) for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) { __sclp_make_init_req(0, 0); sccb = (struct init_sccb *) sclp_init_req.sccb; - rc = service_call(sclp_init_req.command, sccb); + rc = sclp_service_call(sclp_init_req.command, sccb); if (rc == -EIO) break; sclp_init_req.status = SCLP_REQ_RUNNING; diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 2c71d6ee7b5b..7d29ab45a6ed 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -12,7 +12,7 @@ #include #include - +#include #include /* maximum number of pages concerning our own memory management */ @@ -49,9 +49,11 @@ typedef unsigned int sclp_cmdw_t; -#define SCLP_CMDW_READDATA 0x00770005 -#define SCLP_CMDW_WRITEDATA 0x00760005 -#define SCLP_CMDW_WRITEMASK 0x00780005 +#define SCLP_CMDW_READ_EVENT_DATA 0x00770005 +#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005 +#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005 +#define SCLP_CMDW_READ_SCP_INFO 0x00020001 +#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001 #define GDS_ID_MDSMU 0x1310 #define GDS_ID_MDSRouteInfo 0x1311 @@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t; typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ -struct sccb_header { - u16 length; - u8 function_code; - u8 control_mask[3]; - u16 response_code; -} __attribute__((packed)); - struct gds_subvector { u8 length; u8 key; @@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg); int sclp_remove_processed(struct sccb_header *sccb); int sclp_deactivate(void); int sclp_reactivate(void); +int sclp_service_call(sclp_cmdw_t command, void *sccb); /* useful inlines */ diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c index 4f873ae148b7..65aa2c85737f 100644 --- a/drivers/s390/char/sclp_cpi.c +++ b/drivers/s390/char/sclp_cpi.c @@ -169,7 +169,7 @@ cpi_prepare_req(void) } /* prepare request data structure presented to SCLP driver */ - req->command = SCLP_CMDW_WRITEDATA; + req->command = SCLP_CMDW_WRITE_EVENT_DATA; req->sccb = sccb; req->status = SCLP_REQ_FILLED; req->callback = cpi_callback; diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c new file mode 100644 index 000000000000..7bcbe643b087 --- /dev/null +++ b/drivers/s390/char/sclp_info.c @@ -0,0 +1,57 @@ +/* + * drivers/s390/char/sclp_info.c + * + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens + */ + +#include +#include +#include +#include +#include "sclp.h" + +struct sclp_readinfo_sccb s390_readinfo_sccb; + +void __init sclp_readinfo_early(void) +{ + sclp_cmdw_t command; + struct sccb_header *sccb; + int ret; + + __ctl_set_bit(0, 9); /* enable service signal subclass mask */ + + sccb = &s390_readinfo_sccb.header; + command = SCLP_CMDW_READ_SCP_INFO_FORCED; + while (1) { + u16 response; + + memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb)); + sccb->length = sizeof(s390_readinfo_sccb); + sccb->control_mask[2] = 0x80; + + ret = sclp_service_call(command, &s390_readinfo_sccb); + + if (ret == -EIO) + goto out; + if (ret == -EBUSY) + continue; + + __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT | + PSW_MASK_WAIT | PSW_DEFAULT_KEY); + local_irq_disable(); + barrier(); + + response = sccb->response_code; + + if (response == 0x10) + break; + + if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO) + break; + + command = SCLP_CMDW_READ_SCP_INFO; + } +out: + __ctl_clear_bit(0, 9); /* disable service signal subclass mask */ +} diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 0c92d3909cca..2486783ea58e 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer, sccb->msg_buf.header.type = EvTyp_PMsgCmd; else return -ENOSYS; - buffer->request.command = SCLP_CMDW_WRITEDATA; + buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA; buffer->request.status = SCLP_REQ_FILLED; buffer->request.callback = sclp_writedata_callback; buffer->request.callback_data = buffer; diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index d8135cd4d7ab..544f137d70d7 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -207,7 +207,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request) request->sclp_req.status = SCLP_REQ_FAILED; return -EIO; } - request->sclp_req.command = SCLP_CMDW_WRITEDATA; + request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA; request->sclp_req.status = SCLP_REQ_FILLED; request->sclp_req.callback = sclp_vt220_callback; request->sclp_req.callback_data = (void *) request; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index ad2b37929848..23e71a76cdab 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -895,11 +895,11 @@ static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr) int rc; pgm_check_occured = 0; - s390_reset_pgm_handler = cio_reset_pgm_check_handler; + s390_base_pgm_handler_fn = cio_reset_pgm_check_handler; rc = stsch(schid, addr); - s390_reset_pgm_handler = NULL; + s390_base_pgm_handler_fn = NULL; - /* The program check handler could have changed pgm_check_occured */ + /* The program check handler could have changed pgm_check_occured. */ barrier(); if (pgm_check_occured) @@ -957,7 +957,7 @@ static void css_reset(void) /* Reset subchannels. */ for_each_subchannel(__shutdown_subchannel_easy, NULL); /* Reset channel paths. */ - s390_reset_mcck_handler = s390_reset_chpids_mcck_handler; + s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler; /* Enable channel report machine checks. */ __ctl_set_bit(14, 28); /* Temporarily reenable machine checks. */ @@ -982,7 +982,7 @@ static void css_reset(void) local_mcck_disable(); /* Disable channel report machine checks. */ __ctl_clear_bit(14, 28); - s390_reset_mcck_handler = NULL; + s390_base_mcck_handler_fn = NULL; } static struct reset_call css_reset_call = { diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index cf71c5449240..4c1b73940351 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -330,6 +330,18 @@ static inline void disabled_wait(unsigned long code) #endif /* __s390x__ */ } +/* + * Basic Machine Check/Program Check Handler. + */ + +extern void s390_base_mcck_handler(void); +extern void s390_base_pgm_handler(void); +extern void s390_base_ext_handler(void); + +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. */ diff --git a/include/asm-s390/reset.h b/include/asm-s390/reset.h index 532e65a2aafc..f584f4a52581 100644 --- a/include/asm-s390/reset.h +++ b/include/asm-s390/reset.h @@ -18,7 +18,4 @@ struct reset_call { extern void register_reset_call(struct reset_call *reset); extern void unregister_reset_call(struct reset_call *reset); extern void s390_reset_system(void); -extern void (*s390_reset_mcck_handler)(void); -extern void (*s390_reset_pgm_handler)(void); - #endif /* _ASM_S390_RESET_H */ diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h new file mode 100644 index 000000000000..468b97018405 --- /dev/null +++ b/include/asm-s390/sclp.h @@ -0,0 +1,39 @@ +/* + * include/asm-s390/sclp.h + * + * Copyright IBM Corp. 2007 + * Author(s): Heiko Carstens + */ + +#ifndef _ASM_S390_SCLP_H +#define _ASM_S390_SCLP_H + +#include + +struct sccb_header { + u16 length; + u8 function_code; + u8 control_mask[3]; + u16 response_code; +} __attribute__((packed)); + +#define LOADPARM_LEN 8 + +struct sclp_readinfo_sccb { + struct sccb_header header; /* 0-7 */ + u16 rnmax; /* 8-9 */ + u8 rnsize; /* 10 */ + u8 _reserved0[24 - 11]; /* 11-23 */ + u8 loadparm[LOADPARM_LEN]; /* 24-31 */ + u8 _reserved1[91 - 32]; /* 32-90 */ + u8 flags; /* 91 */ + u8 _reserved2[100 - 92]; /* 92-99 */ + u32 rnsize2; /* 100-103 */ + u64 rnmax2; /* 104-111 */ + u8 _reserved3[4096 - 112]; /* 112-4095 */ +} __attribute__((packed, aligned(4096))); + +extern struct sclp_readinfo_sccb s390_readinfo_sccb; +extern void sclp_readinfo_early(void); + +#endif /* _ASM_S390_SCLP_H */ -- cgit v1.2.3 From 4d284cac76d0bfebc42d76b428c4e44d921200a9 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 5 Feb 2007 21:18:53 +0100 Subject: [S390] Avoid excessive inlining. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- arch/s390/kernel/binfmt_elf32.c | 2 +- arch/s390/kernel/module.c | 4 +- arch/s390/kernel/setup.c | 6 +-- arch/s390/kernel/smp.c | 8 ++-- arch/s390/kernel/stacktrace.c | 10 ++--- arch/s390/kernel/time.c | 4 +- arch/s390/lib/uaccess_pt.c | 10 ++--- arch/s390/mm/cmm.c | 2 +- arch/s390/mm/extmem.c | 2 +- drivers/s390/block/dasd.c | 12 ++--- drivers/s390/block/dasd_devmap.c | 6 +-- drivers/s390/block/dasd_diag.c | 4 +- drivers/s390/block/dasd_eckd.c | 47 +++---------------- drivers/s390/block/dasd_erp.c | 19 -------- drivers/s390/block/dasd_fba.c | 4 +- drivers/s390/block/dasd_proc.c | 6 +-- drivers/s390/block/dcssblk.c | 2 +- drivers/s390/char/monwriter.c | 4 +- drivers/s390/char/sclp.c | 2 +- drivers/s390/char/sclp_con.c | 2 +- drivers/s390/char/tape_block.c | 4 +- drivers/s390/char/tape_char.c | 17 +------ drivers/s390/char/tape_core.c | 16 +++---- drivers/s390/cio/blacklist.c | 8 ++-- drivers/s390/cio/ccwgroup.c | 6 +-- drivers/s390/cio/chsc.c | 10 ++--- drivers/s390/cio/cio.c | 8 ++-- drivers/s390/cio/cmf.c | 4 +- drivers/s390/cio/css.c | 6 +-- drivers/s390/cio/device.c | 4 +- drivers/s390/cio/device_fsm.c | 4 +- drivers/s390/cio/device_ops.c | 2 +- drivers/s390/cio/device_status.c | 8 ++-- drivers/s390/cio/qdio.c | 74 +++++++++++++++--------------- drivers/s390/crypto/ap_bus.c | 8 ++-- drivers/s390/crypto/zcrypt_api.c | 16 +++---- drivers/s390/crypto/zcrypt_pcica.c | 8 ++-- drivers/s390/net/claw.c | 14 +++--- drivers/s390/net/ctcmain.c | 8 ++-- drivers/s390/net/qeth_eddp.c | 28 ++++++------ drivers/s390/net/qeth_main.c | 92 +++++++++++++++++++------------------- drivers/s390/net/qeth_sys.c | 28 ++++++------ drivers/s390/scsi/zfcp_aux.c | 25 +++++------ drivers/s390/scsi/zfcp_dbf.c | 38 ++++++++-------- drivers/s390/scsi/zfcp_fsf.c | 2 +- drivers/s390/scsi/zfcp_qdio.c | 38 ++++++++-------- 46 files changed, 278 insertions(+), 354 deletions(-) (limited to 'drivers/s390') diff --git a/arch/s390/kernel/binfmt_elf32.c b/arch/s390/kernel/binfmt_elf32.c index 5c46054195cb..f1e40ca00d8d 100644 --- a/arch/s390/kernel/binfmt_elf32.c +++ b/arch/s390/kernel/binfmt_elf32.c @@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn "); #undef cputime_to_timeval #define cputime_to_timeval cputime_to_compat_timeval -static __inline__ void +static inline void cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value) { value->tv_usec = cputime % 1000000; diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index f5476f5c2e96..39d1dd752529 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -59,7 +59,7 @@ void module_free(struct module *mod, void *module_region) table entries. */ } -static inline void +static void check_rela(Elf_Rela *rela, struct module *me) { struct mod_arch_syminfo *info; @@ -182,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex, return -ENOEXEC; } -static inline int +static int apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, struct module *me) { diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index f73a11528217..03739813d3bf 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -129,7 +129,7 @@ char vmhalt_cmd[128] = ""; char vmpoff_cmd[128] = ""; static char vmpanic_cmd[128] = ""; -static inline void strncpy_skip_quote(char *dst, char *src, int n) +static void strncpy_skip_quote(char *dst, char *src, int n) { int sx, dx; @@ -396,8 +396,8 @@ early_param("ipldelay", early_parse_ipldelay); unsigned int switch_amode = 0; EXPORT_SYMBOL_GPL(switch_amode); -static inline void set_amode_and_uaccess(unsigned long user_amode, - unsigned long user32_amode) +static void set_amode_and_uaccess(unsigned long user_amode, + unsigned long user32_amode) { psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 08f9a4dfb18b..65b52320d145 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c @@ -194,7 +194,7 @@ int smp_call_function_on(void (*func) (void *info), void *info, } EXPORT_SYMBOL(smp_call_function_on); -static inline void do_send_stop(void) +static void do_send_stop(void) { int cpu, rc; @@ -208,7 +208,7 @@ static inline void do_send_stop(void) } } -static inline void do_store_status(void) +static void do_store_status(void) { int cpu, rc; @@ -224,7 +224,7 @@ static inline void do_store_status(void) } } -static inline void do_wait_for_stop(void) +static void do_wait_for_stop(void) { int cpu; @@ -534,7 +534,7 @@ smp_put_cpu(int cpu) spin_unlock_irqrestore(&smp_reserve_lock, flags); } -static inline int +static int cpu_stopped(int cpu) { __u32 status; diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index 0d14a4789bf2..2e5c65a1863e 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -11,11 +11,11 @@ #include #include -static inline unsigned long save_context_stack(struct stack_trace *trace, - unsigned int *skip, - unsigned long sp, - unsigned long low, - unsigned long high) +static unsigned long save_context_stack(struct stack_trace *trace, + unsigned int *skip, + unsigned long sp, + unsigned long low, + unsigned long high) { struct stack_frame *sf; struct pt_regs *regs; diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 39a72d3cb89a..3b91f27ab202 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -166,7 +166,7 @@ int sysctl_hz_timer = 1; * Stop the HZ tick on the current CPU. * Only cpu_idle may call this function. */ -static inline void stop_hz_timer(void) +static void stop_hz_timer(void) { unsigned long flags; unsigned long seq, next; @@ -210,7 +210,7 @@ static inline void stop_hz_timer(void) * Start the HZ tick on the current CPU. * Only cpu_idle may call this function. */ -static inline void start_hz_timer(void) +static void start_hz_timer(void) { BUG_ON(!in_interrupt()); diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 637192fa7c9a..63181671e3e3 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -15,8 +15,8 @@ #include #include "uaccess.h" -static inline int __handle_fault(struct mm_struct *mm, unsigned long address, - int write_access) +static int __handle_fault(struct mm_struct *mm, unsigned long address, + int write_access) { struct vm_area_struct *vma; int ret = -EFAULT; @@ -81,8 +81,8 @@ out_sigbus: return ret; } -static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, - size_t n, int write_user) +static size_t __user_copy_pt(unsigned long uaddr, void *kptr, + size_t n, int write_user) { struct mm_struct *mm = current->mm; unsigned long offset, pfn, done, size; @@ -139,7 +139,7 @@ fault: * Do DAT for user address by page table walk, return kernel address. * This function needs to be called with current->mm->page_table_lock held. */ -static inline unsigned long __dat_user_addr(unsigned long uaddr) +static unsigned long __dat_user_addr(unsigned long uaddr) { struct mm_struct *mm = current->mm; unsigned long pfn, ret; diff --git a/arch/s390/mm/cmm.c b/arch/s390/mm/cmm.c index fb87e2320eba..f93a056869bc 100644 --- a/arch/s390/mm/cmm.c +++ b/arch/s390/mm/cmm.c @@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds) cmm_set_timer(); } -static inline int +static int cmm_skip_blanks(char *cp, char **endp) { char *str; diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 8bffadb5e537..394980b05e6f 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -91,7 +91,7 @@ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", * Create the 8 bytes, ebcdic VM segment name from * an ascii name. */ -static void inline +static void dcss_mkname(char *name, char *dcss_name) { int i; diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 555e18a6b781..eb5dc62f0d9c 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c @@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF; /* * Add profiling information for cqr before execution. */ -static inline void +static void dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, struct request *req) { @@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr, /* * Add profiling information for cqr after execution. */ -static inline void +static void dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr, struct request *req) { @@ -1102,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr) /* * Process ccw request queue. */ -static inline void +static void __dasd_process_ccw_queue(struct dasd_device * device, struct list_head *final_queue) { @@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data) /* * Fetch requests from the block device queue. */ -static inline void +static void __dasd_process_blk_queue(struct dasd_device * device) { request_queue_t *queue; @@ -1267,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device) * Take a look at the first request on the ccw queue and check * if it reached its expire time. If so, terminate the IO. */ -static inline void +static void __dasd_check_expire(struct dasd_device * device) { struct dasd_ccw_req *cqr; @@ -1298,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device) * Take a look at the first request on the ccw queue and check * if it needs to be started. */ -static inline void +static void __dasd_start_head(struct dasd_device * device) { struct dasd_ccw_req *cqr; diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 5943266152f5..ed70852cc915 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup); /* * Read a device busid/devno from a string. */ -static inline int +static int dasd_busid(char **str, int *id0, int *id1, int *devno) { int val, old_style; @@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno) * only one: "ro" for read-only devices. The default feature set * is empty (value 0). */ -static inline int +static int dasd_feature_list(char *str, char **endp) { int features, len, rc; @@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) { return ERR_PTR(-EINVAL); } -static inline char * +static char * dasd_parse_next_element( char *parsestring ) { char * residual_str; residual_str = dasd_parse_keyword(parsestring); diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c index 51cdc16a72c5..ab782bb46ac1 100644 --- a/drivers/s390/block/dasd_diag.c +++ b/drivers/s390/block/dasd_diag.c @@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd) * block offset. On success, return zero and set end_block to contain the * number of blocks on the device minus the specified offset. Return non-zero * otherwise. */ -static __inline__ int +static inline int mdsk_init_io(struct dasd_device *device, unsigned int blocksize, blocknum_t offset, blocknum_t *end_block) { @@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize, /* Remove block I/O environment for device. Return zero on success, non-zero * otherwise. */ -static __inline__ int +static inline int mdsk_term_io(struct dasd_device * device) { struct dasd_diag_private *private; diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index a17d73193aab..cecab2274a6e 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2) return (d1 + (d2 - 1)) / d2; } -static inline int -bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl) -{ - unsigned int fl1, fl2, int1, int2; - int bpr; - - switch (rdc->formula) { - case 0x01: - fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc)); - fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0, - ECKD_F1(rdc)); - bpr = fl1 + fl2; - break; - case 0x02: - int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1); - int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1); - fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl + - ECKD_F6(rdc) + ECKD_F4(rdc) * int1, - ECKD_F1(rdc)); - fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl + - ECKD_F6(rdc) + ECKD_F4(rdc) * int2, - ECKD_F1(rdc)); - bpr = fl1 + fl2; - break; - default: - bpr = 0; - break; - } - return bpr; -} - -static inline unsigned int -bytes_per_track(struct dasd_eckd_characteristics *rdc) -{ - return *(unsigned int *) (rdc->byte_per_track) >> 8; -} - -static inline unsigned int +static unsigned int recs_per_track(struct dasd_eckd_characteristics * rdc, unsigned int kl, unsigned int dl) { @@ -204,7 +167,7 @@ recs_per_track(struct dasd_eckd_characteristics * rdc, return 0; } -static inline int +static int check_XRC (struct ccw1 *de_ccw, struct DE_eckd_data *data, struct dasd_device *device) @@ -230,7 +193,7 @@ check_XRC (struct ccw1 *de_ccw, return rc; } -static inline int +static int define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, int totrk, int cmd, struct dasd_device * device) { @@ -317,7 +280,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk, return rc; } -static inline void +static void locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk, int rec_on_trk, int no_rec, int cmd, struct dasd_device * device, int reclen) @@ -1617,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp) * Dump the range of CCWs into 'page' buffer * and return number of printed chars. */ -static inline int +static int dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page) { int len, count; diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index abf7cefb29c2..caa5d91420f8 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr) } /* end default_erp_postaction */ -/* - * Print the hex dump of the memory used by a request. This includes - * all error recovery ccws that have been chained in from of the - * real request. - */ -static inline void -hex_dump_memory(struct dasd_device *device, void *data, int len) -{ - int *pint; - - pint = (int *) data; - while (len > 0) { - DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x", - pint, pint[0], pint[1], pint[2], pint[3]); - pint += 4; - len -= 16; - } -} - void dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb) { diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index b857fd5893fd..be0909e39226 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c @@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = { .notify = dasd_generic_notify, }; -static inline void +static void define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, int blksize, int beg, int nr) { @@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw, data->ext_end = nr - 1; } -static inline void +static void locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw, int block_nr, int block_ct) { diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index a9ff934d7e2b..8b7e11815d70 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL; static struct proc_dir_entry *dasd_devices_entry = NULL; static struct proc_dir_entry *dasd_statistics_entry = NULL; -static inline char * +static char * dasd_get_user_string(const char __user *user_buf, size_t user_len) { char *buffer; @@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = { .release = seq_release, }; -static inline int +static int dasd_calc_metrics(char *page, char **start, off_t off, int count, int *eof, int len) { @@ -167,7 +167,7 @@ dasd_calc_metrics(char *page, char **start, off_t off, return len; } -static inline char * +static char * dasd_statistics_array(char *str, unsigned int *array, int shift) { int i; diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index bd1b66a54c21..1340451ea408 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev) * device needs to be enqueued before the semaphore is * freed. */ -static inline int +static int dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info) { int minor, found; diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index cdb24f528112..9e451acc6491 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn) return -EINVAL; } -static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, - struct monwrite_hdr *monhdr) +static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, + struct monwrite_hdr *monhdr) { struct mon_buf *entry, *next; diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 6a83e2d722a8..f171de3b0b11 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -445,7 +445,7 @@ sclp_sync_wait(void) EXPORT_SYMBOL(sclp_sync_wait); /* Dispatch changes in send and receive mask to registered listeners. */ -static inline void +static void sclp_dispatch_state_change(void) { struct list_head *l; diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 86864f641716..ead1043d788e 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c @@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc) } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); } -static inline void +static void sclp_conbuf_emit(void) { struct sclp_buffer* buffer; diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index c8a89b3b87d4..dd0ecaed592e 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -73,7 +73,7 @@ tapeblock_trigger_requeue(struct tape_device *device) /* * Post finished request. */ -static inline void +static void tapeblock_end_request(struct request *req, int uptodate) { if (end_that_request_first(req, uptodate, req->hard_nr_sectors)) @@ -108,7 +108,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data) /* * Feed the tape device CCW queue with requests supplied in a list. */ -static inline int +static int tapeblock_start_request(struct tape_device *device, struct request *req) { struct tape_request * ccw_req; diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index 04d93ef87b40..9faea04e11e9 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -89,22 +89,7 @@ tapechar_cleanup_device(struct tape_device *device) device->nt = NULL; } -/* - * Terminate write command (we write two TMs and skip backward over last) - * This ensures that the tape is always correctly terminated. - * When the user writes afterwards a new file, he will overwrite the - * second TM and therefore one TM will remain to separate the - * two files on the tape... - */ -static inline void -tapechar_terminate_write(struct tape_device *device) -{ - if (tape_mtop(device, MTWEOF, 1) == 0 && - tape_mtop(device, MTWEOF, 1) == 0) - tape_mtop(device, MTBSR, 1); -} - -static inline int +static int tapechar_check_idalbuffer(struct tape_device *device, size_t block_size) { struct idal_buffer *new; diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 8691bb985d00..e2a8a1a04bab 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c @@ -76,7 +76,7 @@ const char *tape_op_verbose[TO_SIZE] = [TO_KEKL_QUERY] = "KLQ", }; -static inline int +static int busid_to_int(char *bus_id) { int dec; @@ -256,7 +256,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate) /* * Stop running ccw. Has to be called with the device lock held. */ -static inline int +static int __tape_cancel_io(struct tape_device *device, struct tape_request *request) { int retries; @@ -392,7 +392,7 @@ out: return rc; } -static inline void +static void tape_cleanup_device(struct tape_device *device) { tapeblock_cleanup_device(device); @@ -570,7 +570,7 @@ tape_generic_probe(struct ccw_device *cdev) return ret; } -static inline void +static void __tape_discard_requests(struct tape_device *device) { struct tape_request * request; @@ -710,7 +710,7 @@ tape_free_request (struct tape_request * request) kfree(request); } -static inline int +static int __tape_start_io(struct tape_device *device, struct tape_request *request) { int rc; @@ -740,7 +740,7 @@ __tape_start_io(struct tape_device *device, struct tape_request *request) return rc; } -static inline void +static void __tape_start_next_request(struct tape_device *device) { struct list_head *l, *n; @@ -824,7 +824,7 @@ static void tape_long_busy_timeout(unsigned long data) spin_unlock_irq(get_ccwdev_lock(device->cdev)); } -static inline void +static void __tape_end_request( struct tape_device * device, struct tape_request * request, @@ -901,7 +901,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request, * and starts it if the tape is idle. Has to be called with * the device lock held. */ -static inline int +static int __tape_start_request(struct tape_device *device, struct tape_request *request) { int rc; diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 4ec1334014e9..aa65df4dfced 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -43,7 +43,7 @@ typedef enum {add, free} range_action; * Function: blacklist_range * (Un-)blacklist the devices from-to */ -static inline void +static void blacklist_range (range_action action, unsigned int from, unsigned int to, unsigned int ssid) { @@ -69,7 +69,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to, * Get devno/busid from given string. * Shamelessly grabbed from dasd_devmap.c. */ -static inline int +static int blacklist_busid(char **str, int *id0, int *ssid, int *devno) { int val, old_style; @@ -123,7 +123,7 @@ confused: return 1; } -static inline int +static int blacklist_parse_parameters (char *str, range_action action) { int from, to, from_id0, to_id0, from_ssid, to_ssid; @@ -227,7 +227,7 @@ is_blacklisted (int ssid, int devno) * Function: blacklist_parse_proc_parameters * parse the stuff which is piped to /proc/cio_ignore */ -static inline void +static void blacklist_parse_proc_parameters (char *buf) { if (strncmp (buf, "free ", 5) == 0) { diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 38954f5cd14c..d48e3ca4752c 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -53,7 +53,7 @@ ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer, static struct bus_type ccwgroup_bus_type; -static inline void +static void __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) { int i; @@ -104,7 +104,7 @@ ccwgroup_release (struct device *dev) kfree(gdev); } -static inline int +static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) { char str[8]; @@ -424,7 +424,7 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev) return 0; } -static inline struct ccwgroup_device * +static struct ccwgroup_device * __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) { struct ccwgroup_device *gdev; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index c6db7f44689a..6f05a44e3817 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -277,7 +277,7 @@ out_unreg: return 0; } -static inline void +static void s390_set_chpid_offline( __u8 chpid) { char dbf_txt[15]; @@ -338,7 +338,7 @@ s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch) return 0x80 >> chp; } -static inline int +static int s390_process_res_acc_new_sch(struct subchannel_id schid) { struct schib schib; @@ -594,7 +594,7 @@ int chsc_process_crw(void) return ret; } -static inline int +static int __chp_add_new_sch(struct subchannel_id schid) { struct schib schib; @@ -701,7 +701,7 @@ chp_process_crw(int chpid, int on) return chp_add(chpid); } -static inline int check_for_io_on_path(struct subchannel *sch, int index) +static int check_for_io_on_path(struct subchannel *sch, int index) { int cc; @@ -733,7 +733,7 @@ static void terminate_internal_io(struct subchannel *sch) sch->driver->termination(&sch->dev); } -static inline void +static void __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on) { int chp, old_lpm; diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 23e71a76cdab..b3a56dc5f68a 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -122,7 +122,7 @@ cio_get_options (struct subchannel *sch) * Use tpi to get a pending interrupt, call the interrupt handler and * return a pointer to the subchannel structure. */ -static inline int +static int cio_tpi(void) { struct tpi_info *tpi_info; @@ -152,7 +152,7 @@ cio_tpi(void) return 1; } -static inline int +static int cio_start_handle_notoper(struct subchannel *sch, __u8 lpm) { char dbf_text[15]; @@ -832,7 +832,7 @@ cio_get_console_subchannel(void) } #endif -static inline int +static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) { int retry, cc; @@ -863,7 +863,7 @@ static void udelay_reset(unsigned long usecs) } while (((end_cc - start_cc)/4096) < usecs); } -static inline int +static int __clear_subchannel_easy(struct subchannel_id schid) { int retry; diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index 828b2d334f0a..90b22faabbf7 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c @@ -519,8 +519,8 @@ struct cmb { /* insert a single device into the cmb_area list * called with cmb_area.lock held from alloc_cmb */ -static inline int alloc_cmb_single (struct ccw_device *cdev, - struct cmb_data *cmb_data) +static int alloc_cmb_single(struct ccw_device *cdev, + struct cmb_data *cmb_data) { struct cmb *cmb; struct ccw_device_private *node; diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index bdf13699fe0d..fe0ace7aece8 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -30,7 +30,7 @@ struct channel_subsystem *css[__MAX_CSSID + 1]; int css_characteristics_avail = 0; -inline int +int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data) { struct subchannel_id schid; @@ -184,7 +184,7 @@ get_subchannel_by_schid(struct subchannel_id schid) return dev ? to_subchannel(dev) : NULL; } -static inline int css_get_subchannel_status(struct subchannel *sch) +static int css_get_subchannel_status(struct subchannel *sch) { struct schib schib; @@ -575,7 +575,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store); -static inline int __init setup_css(int nr) +static int __init setup_css(int nr) { u32 tod_high; int ret; diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index eedf863c6c64..e322111fb369 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -548,13 +548,13 @@ static struct attribute_group ccwdev_attr_group = { .attrs = ccwdev_attrs, }; -static inline int +static int device_add_files (struct device *dev) { return sysfs_create_group(&dev->kobj, &ccwdev_attr_group); } -static inline void +static void device_remove_files(struct device *dev) { sysfs_remove_group(&dev->kobj, &ccwdev_attr_group); diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index da575365b134..51238e7555bb 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c @@ -206,7 +206,7 @@ ccw_device_handle_oper(struct ccw_device *cdev) * been varied online on the SE so we have to find out by magic (i. e. driving * the channel subsystem to device selection and updating our path masks). */ -static inline void +static void __recover_lost_chpids(struct subchannel *sch, int old_lpm) { int mask, i; @@ -387,7 +387,7 @@ ccw_device_done(struct ccw_device *cdev, int state) put_device (&cdev->dev); } -static inline int cmp_pgid(struct pgid *p1, struct pgid *p2) +static int cmp_pgid(struct pgid *p1, struct pgid *p2) { char *c1; char *c2; diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index d269607336ec..d7b25b8f71d2 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c @@ -302,7 +302,7 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb) wake_up(&cdev->private->wait_q); } -static inline int +static int __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm) { int ret; diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index bdcf930f7beb..6b1caea622ea 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c @@ -25,7 +25,7 @@ * Check for any kind of channel or interface control check but don't * issue the message for the console device */ -static inline void +static void ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb) { if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK | @@ -72,7 +72,7 @@ ccw_device_path_notoper(struct ccw_device *cdev) /* * Copy valid bits from the extended control word to device irb. */ -static inline void +static void ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) { /* @@ -94,7 +94,7 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb) /* * Check if extended status word is valid. */ -static inline int +static int ccw_device_accumulate_esw_valid(struct irb *irb) { if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) @@ -109,7 +109,7 @@ ccw_device_accumulate_esw_valid(struct irb *irb) /* * Copy valid bits from the extended status word to device irb. */ -static inline void +static void ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb) { struct irb *cdev_irb; diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 8551c51976c6..d726cd5777de 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c @@ -137,7 +137,7 @@ qdio_release_q(struct qdio_q *q) } /*check ccq */ -static inline int +static int qdio_check_ccq(struct qdio_q *q, unsigned int ccq) { char dbf_text[15]; @@ -152,7 +152,7 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq) return -EIO; } /* EQBS: extract buffer states */ -static inline int +static int qdio_do_eqbs(struct qdio_q *q, unsigned char *state, unsigned int *start, unsigned int *cnt) { @@ -187,7 +187,7 @@ again: } /* SQBS: set buffer states */ -static inline int +static int qdio_do_sqbs(struct qdio_q *q, unsigned char state, unsigned int *start, unsigned int *cnt) { @@ -314,7 +314,7 @@ __do_siga_output(struct qdio_q *q, unsigned int *busy_bit) * returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns * an access exception */ -static inline int +static int qdio_siga_output(struct qdio_q *q) { int cc; @@ -348,7 +348,7 @@ qdio_siga_output(struct qdio_q *q) return cc; } -static inline int +static int qdio_siga_input(struct qdio_q *q) { int cc; @@ -420,7 +420,7 @@ tiqdio_sched_tl(void) tasklet_hi_schedule(&tiqdio_tasklet); } -static inline void +static void qdio_mark_tiq(struct qdio_q *q) { unsigned long flags; @@ -470,7 +470,7 @@ qdio_mark_q(struct qdio_q *q) tasklet_schedule(&q->tasklet); } -static inline int +static int qdio_stop_polling(struct qdio_q *q) { #ifdef QDIO_USE_PROCESSING_STATE @@ -524,7 +524,7 @@ qdio_stop_polling(struct qdio_q *q) * sophisticated locking outside of unmark_q, so that we don't need to * disable the interrupts :-) */ -static inline void +static void qdio_unmark_q(struct qdio_q *q) { unsigned long flags; @@ -690,7 +690,7 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q) return q->first_to_check; } -static inline int +static int qdio_get_outbound_buffer_frontier(struct qdio_q *q) { struct qdio_irq *irq; @@ -773,7 +773,7 @@ out: } /* all buffers are processed */ -static inline int +static int qdio_is_outbound_q_done(struct qdio_q *q) { int no_used; @@ -795,7 +795,7 @@ qdio_is_outbound_q_done(struct qdio_q *q) return (no_used==0); } -static inline int +static int qdio_has_outbound_q_moved(struct qdio_q *q) { int i; @@ -815,7 +815,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q) } } -static inline void +static void qdio_kick_outbound_q(struct qdio_q *q) { int result; @@ -904,7 +904,7 @@ qdio_kick_outbound_q(struct qdio_q *q) } } -static inline void +static void qdio_kick_outbound_handler(struct qdio_q *q) { int start, end, real_end, count; @@ -941,7 +941,7 @@ qdio_kick_outbound_handler(struct qdio_q *q) q->error_status_flags=0; } -static inline void +static void __qdio_outbound_processing(struct qdio_q *q) { int siga_attempts; @@ -1001,7 +1001,7 @@ qdio_outbound_processing(struct qdio_q *q) /************************* INBOUND ROUTINES *******************************/ -static inline int +static int qdio_get_inbound_buffer_frontier(struct qdio_q *q) { struct qdio_irq *irq; @@ -1132,7 +1132,7 @@ out: return q->first_to_check; } -static inline int +static int qdio_has_inbound_q_moved(struct qdio_q *q) { int i; @@ -1166,7 +1166,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q) } /* means, no more buffers to be filled */ -static inline int +static int tiqdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1227,7 +1227,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q) return 0; } -static inline int +static int qdio_is_inbound_q_done(struct qdio_q *q) { int no_used; @@ -1295,7 +1295,7 @@ qdio_is_inbound_q_done(struct qdio_q *q) } } -static inline void +static void qdio_kick_inbound_handler(struct qdio_q *q) { int count, start, end, real_end, i; @@ -1342,7 +1342,7 @@ qdio_kick_inbound_handler(struct qdio_q *q) } } -static inline void +static void __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set) { struct qdio_irq *irq_ptr; @@ -1441,7 +1441,7 @@ tiqdio_inbound_processing(struct qdio_q *q) __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount)); } -static inline void +static void __qdio_inbound_processing(struct qdio_q *q) { int q_laps=0; @@ -1492,7 +1492,7 @@ qdio_inbound_processing(struct qdio_q *q) /************************* MAIN ROUTINES *******************************/ #ifdef QDIO_USE_PROCESSING_STATE -static inline int +static int tiqdio_reset_processing_state(struct qdio_q *q, int q_laps) { if (!q) { @@ -1544,7 +1544,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps) } #endif /* QDIO_USE_PROCESSING_STATE */ -static inline void +static void tiqdio_inbound_checks(void) { struct qdio_q *q; @@ -1948,7 +1948,7 @@ qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) mb(); } -static inline void +static void qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) { char dbf_text[15]; @@ -1965,7 +1965,7 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb) } -static inline void +static void qdio_handle_pci(struct qdio_irq *irq_ptr) { int i; @@ -2001,7 +2001,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr) static void qdio_establish_handle_irq(struct ccw_device*, int, int); -static inline void +static void qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm, int cstat, int dstat) { @@ -2228,7 +2228,7 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags, return cc; } -static inline void +static void qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, unsigned long token) { @@ -2739,7 +2739,7 @@ qdio_free(struct ccw_device *cdev) return 0; } -static inline void +static void qdio_allocate_do_dbf(struct qdio_initialize *init_data) { char dbf_text[20]; /* if a printf printed out more than 8 chars */ @@ -2772,7 +2772,7 @@ qdio_allocate_do_dbf(struct qdio_initialize *init_data) QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*)); } -static inline void +static void qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt) { irq_ptr->input_qs[i]->is_iqdio_q = iqfmt; @@ -2791,7 +2791,7 @@ qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt) irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY; } -static inline void +static void qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i, int j, int iqfmt) { @@ -2812,7 +2812,7 @@ qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i, } -static inline void +static void qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr) { int i; @@ -2838,7 +2838,7 @@ qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr) } } -static inline void +static void qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr) { int i; @@ -2864,7 +2864,7 @@ qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr) } } -static inline int +static int qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat, int dstat) { @@ -3366,7 +3366,7 @@ qdio_activate(struct ccw_device *cdev, int flags) } /* buffers filled forwards again to make Rick happy */ -static inline void +static void qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) { @@ -3385,7 +3385,7 @@ qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx, } } -static inline void +static void qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) { @@ -3406,7 +3406,7 @@ qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx, } } -static inline void +static void do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) @@ -3442,7 +3442,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags, qdio_mark_q(q); } -static inline void +static void do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags, unsigned int qidx, unsigned int count, struct qdio_buffer *buffers) diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 81b5899f4010..c7d1355237b6 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -465,7 +465,7 @@ static int ap_device_probe(struct device *dev) * Flush all requests from the request/pending queue of an AP device. * @ap_dev: pointer to the AP device. */ -static inline void __ap_flush_queue(struct ap_device *ap_dev) +static void __ap_flush_queue(struct ap_device *ap_dev) { struct ap_message *ap_msg, *next; @@ -587,7 +587,7 @@ static struct bus_attribute *const ap_bus_attrs[] = { /** * Pick one of the 16 ap domains. */ -static inline int ap_select_domain(void) +static int ap_select_domain(void) { int queue_depth, device_type, count, max_count, best_domain; int rc, i, j; @@ -825,7 +825,7 @@ static inline void ap_schedule_poll_timer(void) * required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */ -static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) +static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) { struct ap_queue_status status; struct ap_message *ap_msg; @@ -872,7 +872,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags) * required, bit 2^1 is set if the poll timer needs to get armed * Returns 0 if the device is still present, -ENODEV if not. */ -static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) +static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags) { struct ap_queue_status status; struct ap_message *ap_msg; diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 843a65f31bc9..b9e59bc9435a 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -833,8 +833,8 @@ static struct miscdevice zcrypt_misc_device = { */ static struct proc_dir_entry *zcrypt_entry; -static inline int sprintcl(unsigned char *outaddr, unsigned char *addr, - unsigned int len) +static int sprintcl(unsigned char *outaddr, unsigned char *addr, + unsigned int len) { int hl, i; @@ -845,8 +845,8 @@ static inline int sprintcl(unsigned char *outaddr, unsigned char *addr, return hl; } -static inline int sprintrw(unsigned char *outaddr, unsigned char *addr, - unsigned int len) +static int sprintrw(unsigned char *outaddr, unsigned char *addr, + unsigned int len) { int hl, inl, c, cx; @@ -865,8 +865,8 @@ static inline int sprintrw(unsigned char *outaddr, unsigned char *addr, return hl; } -static inline int sprinthx(unsigned char *title, unsigned char *outaddr, - unsigned char *addr, unsigned int len) +static int sprinthx(unsigned char *title, unsigned char *outaddr, + unsigned char *addr, unsigned int len) { int hl, inl, r, rx; @@ -885,8 +885,8 @@ static inline int sprinthx(unsigned char *title, unsigned char *outaddr, return hl; } -static inline int sprinthx4(unsigned char *title, unsigned char *outaddr, - unsigned int *array, unsigned int len) +static int sprinthx4(unsigned char *title, unsigned char *outaddr, + unsigned int *array, unsigned int len) { int hl, r; diff --git a/drivers/s390/crypto/zcrypt_pcica.c b/drivers/s390/crypto/zcrypt_pcica.c index 32e37014345c..818ffe05ac00 100644 --- a/drivers/s390/crypto/zcrypt_pcica.c +++ b/drivers/s390/crypto/zcrypt_pcica.c @@ -191,10 +191,10 @@ static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev, * * Returns 0 on success or -EFAULT. */ -static inline int convert_type84(struct zcrypt_device *zdev, - struct ap_message *reply, - char __user *outputdata, - unsigned int outputdatalength) +static int convert_type84(struct zcrypt_device *zdev, + struct ap_message *reply, + char __user *outputdata, + unsigned int outputdatalength) { struct type84_hdr *t84h = reply->message; char *data; diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 4313f316b8fa..7809a79feec7 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c @@ -223,16 +223,14 @@ static void claw_timer ( struct chbk * p_ch ); /* Functions */ static int add_claw_reads(struct net_device *dev, struct ccwbk* p_first, struct ccwbk* p_last); -static void inline ccw_check_return_code (struct ccw_device *cdev, - int return_code); -static void inline ccw_check_unit_check (struct chbk * p_ch, - unsigned char sense ); +static void ccw_check_return_code (struct ccw_device *cdev, int return_code); +static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense ); static int find_link(struct net_device *dev, char *host_name, char *ws_name ); static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid); static int init_ccw_bk(struct net_device *dev); static void probe_error( struct ccwgroup_device *cgdev); static struct net_device_stats *claw_stats(struct net_device *dev); -static int inline pages_to_order_of_mag(int num_of_pages); +static int pages_to_order_of_mag(int num_of_pages); static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr); #ifdef DEBUG static void dumpit (char *buf, int len); @@ -1310,7 +1308,7 @@ claw_timer ( struct chbk * p_ch ) * of magnitude get_free_pages() has an upper order of 9 * *--------------------------------------------------------------------*/ -static int inline +static int pages_to_order_of_mag(int num_of_pages) { int order_of_mag=1; /* assume 2 pages */ @@ -1482,7 +1480,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first, * * *-------------------------------------------------------------------*/ -static void inline +static void ccw_check_return_code(struct ccw_device *cdev, int return_code) { #ifdef FUNCTRACE @@ -1529,7 +1527,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code) * ccw_check_unit_check * *--------------------------------------------------------------------*/ -static void inline +static void ccw_check_unit_check(struct chbk * p_ch, unsigned char sense ) { struct net_device *dev = p_ch->ndev; diff --git a/drivers/s390/net/ctcmain.c b/drivers/s390/net/ctcmain.c index 03cc263fe0da..5a84fbbc6611 100644 --- a/drivers/s390/net/ctcmain.c +++ b/drivers/s390/net/ctcmain.c @@ -369,7 +369,7 @@ ctc_dump_skb(struct sk_buff *skb, int offset) * @param ch The channel where this skb has been received. * @param pskb The received skb. */ -static __inline__ void +static void ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb) { struct net_device *dev = ch->netdev; @@ -512,7 +512,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb) * @param ch The channel, the error belongs to. * @param return_code The error code to inspect. */ -static void inline +static void ccw_check_return_code(struct channel *ch, int return_code, char *msg) { DBF_TEXT(trace, 5, __FUNCTION__); @@ -547,7 +547,7 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg) * @param ch The channel, the sense code belongs to. * @param sense The sense code to inspect. */ -static void inline +static void ccw_unit_check(struct channel *ch, unsigned char sense) { DBF_TEXT(trace, 5, __FUNCTION__); @@ -603,7 +603,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q) } } -static __inline__ int +static int ctc_checkalloc_buffer(struct channel *ch, int warn) { DBF_TEXT(trace, 5, __FUNCTION__); diff --git a/drivers/s390/net/qeth_eddp.c b/drivers/s390/net/qeth_eddp.c index 6bb558a9a032..7c735e1fe063 100644 --- a/drivers/s390/net/qeth_eddp.c +++ b/drivers/s390/net/qeth_eddp.c @@ -49,7 +49,7 @@ qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue, return buffers_needed; } -static inline void +static void qeth_eddp_free_context(struct qeth_eddp_context *ctx) { int i; @@ -91,7 +91,7 @@ qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf) } } -static inline int +static int qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf, struct qeth_eddp_context *ctx) { @@ -196,7 +196,7 @@ out: return flush_cnt; } -static inline void +static void qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp, int data_len) { @@ -256,7 +256,7 @@ qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx, ctx->offset += eddp->thl; } -static inline void +static void qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len, __wsum *hcsum) { @@ -302,7 +302,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len, } } -static inline void +static void qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp, int data_len, __wsum hcsum) @@ -349,7 +349,7 @@ qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx, ((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum); } -static inline __wsum +static __wsum qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len) { __wsum phcsum; /* pseudo header checksum */ @@ -363,7 +363,7 @@ qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len) return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum); } -static inline __wsum +static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len) { __be32 proto; @@ -381,7 +381,7 @@ qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len) return phcsum; } -static inline struct qeth_eddp_data * +static struct qeth_eddp_data * qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl) { struct qeth_eddp_data *eddp; @@ -399,7 +399,7 @@ qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl) return eddp; } -static inline void +static void __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, struct qeth_eddp_data *eddp) { @@ -464,7 +464,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, } } -static inline int +static int qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, struct sk_buff *skb, struct qeth_hdr *qhdr) { @@ -505,7 +505,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx, return 0; } -static inline void +static void qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb, int hdr_len) { @@ -529,7 +529,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb, (skb_shinfo(skb)->gso_segs + 1); } -static inline struct qeth_eddp_context * +static struct qeth_eddp_context * qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb, int hdr_len) { @@ -581,7 +581,7 @@ qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb, return ctx; } -static inline struct qeth_eddp_context * +static struct qeth_eddp_context * qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *qhdr) { @@ -625,5 +625,3 @@ qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb, } return NULL; } - - diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index d2efa5ff125d..2257e45594b3 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -651,7 +651,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo, return 0; } -static inline int +static int __qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr, int same_type) { @@ -795,7 +795,7 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr) return rc; } -static inline void +static void __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags) { struct qeth_ipaddr *addr, *tmp; @@ -882,7 +882,7 @@ static void qeth_layer2_add_multicast(struct qeth_card *); static void qeth_add_multicast_ipv6(struct qeth_card *); #endif -static inline int +static int qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread) { unsigned long flags; @@ -920,7 +920,7 @@ qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread) wake_up(&card->wait_q); } -static inline int +static int __qeth_do_run_thread(struct qeth_card *card, unsigned long thread) { unsigned long flags; @@ -1764,9 +1764,9 @@ out: qeth_release_buffer(channel,iob); } -static inline void +static void qeth_prepare_control_data(struct qeth_card *card, int len, -struct qeth_cmd_buffer *iob) + struct qeth_cmd_buffer *iob) { qeth_setup_ccw(&card->write,iob->data,len); iob->callback = qeth_release_buffer; @@ -2160,7 +2160,7 @@ qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error, return 0; } -static inline struct sk_buff * +static struct sk_buff * qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) { struct sk_buff* skb; @@ -2179,7 +2179,7 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr) return skb; } -static inline struct sk_buff * +static struct sk_buff * qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer, struct qdio_buffer_element **__element, int *__offset, struct qeth_hdr **hdr) @@ -2264,7 +2264,7 @@ no_mem: return NULL; } -static inline __be16 +static __be16 qeth_type_trans(struct sk_buff *skb, struct net_device *dev) { struct qeth_card *card; @@ -2297,7 +2297,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev) return htons(ETH_P_802_2); } -static inline void +static void qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2351,7 +2351,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, fake_llc->ethertype = ETH_P_IP; } -static inline void +static void qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2420,7 +2420,7 @@ qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno; } -static inline __u16 +static __u16 qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr *hdr) { @@ -2476,7 +2476,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb, return vlan_id; } -static inline void +static void qeth_process_inbound_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf, int index) { @@ -2528,7 +2528,7 @@ qeth_process_inbound_buffer(struct qeth_card *card, } } -static inline struct qeth_buffer_pool_entry * +static struct qeth_buffer_pool_entry * qeth_get_buffer_pool_entry(struct qeth_card *card) { struct qeth_buffer_pool_entry *entry; @@ -2543,7 +2543,7 @@ qeth_get_buffer_pool_entry(struct qeth_card *card) return NULL; } -static inline void +static void qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) { struct qeth_buffer_pool_entry *pool_entry; @@ -2570,7 +2570,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf) buf->state = QETH_QDIO_BUF_EMPTY; } -static inline void +static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf) { @@ -2595,7 +2595,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY); } -static inline void +static void qeth_queue_input_buffer(struct qeth_card *card, int index) { struct qeth_qdio_q *queue = card->qdio.in_q; @@ -2699,7 +2699,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status, card->perf_stats.inbound_start_time; } -static inline int +static int qeth_handle_send_error(struct qeth_card *card, struct qeth_qdio_out_buffer *buffer, unsigned int qdio_err, unsigned int siga_err) @@ -2821,7 +2821,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, * Switched to packing state if the number of used buffers on a queue * reaches a certain limit. */ -static inline void +static void qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) { if (!queue->do_pack) { @@ -2842,7 +2842,7 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue) * In that case 1 is returned to inform the caller. If no buffer * has to be flushed, zero is returned. */ -static inline int +static int qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; @@ -2877,7 +2877,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue) * Checks if there is a packing buffer and prepares it to be flushed. * In that case returns 1, otherwise zero. */ -static inline int +static int qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) { struct qeth_qdio_out_buffer *buffer; @@ -2894,7 +2894,7 @@ qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue) return 0; } -static inline void +static void qeth_check_outbound_queue(struct qeth_qdio_out_q *queue) { int index; @@ -3594,7 +3594,7 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev, } } -static inline int +static int qeth_send_packet(struct qeth_card *, struct sk_buff *); static int @@ -3759,7 +3759,7 @@ qeth_stop(struct net_device *dev) return 0; } -static inline int +static int qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) { int cast_type = RTN_UNSPEC; @@ -3806,7 +3806,7 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb) return cast_type; } -static inline int +static int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, int ipv, int cast_type) { @@ -3853,7 +3853,7 @@ qeth_get_ip_version(struct sk_buff *skb) } } -static inline struct qeth_hdr * +static struct qeth_hdr * __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) { #ifdef CONFIG_QETH_VLAN @@ -3882,14 +3882,14 @@ __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv) qeth_push_skb(card, skb, sizeof(struct qeth_hdr))); } -static inline void +static void __qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb) { if (orig_skb != new_skb) dev_kfree_skb_any(new_skb); } -static inline struct sk_buff * +static struct sk_buff * qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, struct qeth_hdr **hdr, int ipv) { @@ -3940,7 +3940,7 @@ qeth_get_qeth_hdr_flags6(int cast_type) return ct | QETH_CAST_UNICAST; } -static inline void +static void qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb) { @@ -3977,7 +3977,7 @@ qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr, } } -static inline void +static void qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, struct sk_buff *skb, int cast_type) { @@ -4068,7 +4068,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, } } -static inline void +static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) { @@ -4112,7 +4112,7 @@ __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, *next_element_to_fill = element; } -static inline int +static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) @@ -4171,7 +4171,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue, return flush_cnt; } -static inline int +static int qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, @@ -4222,7 +4222,7 @@ out: return -EBUSY; } -static inline int +static int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, struct sk_buff *skb, struct qeth_hdr *hdr, int elements_needed, struct qeth_eddp_context *ctx) @@ -4328,7 +4328,7 @@ out: return rc; } -static inline int +static int qeth_get_elements_no(struct qeth_card *card, void *hdr, struct sk_buff *skb, int elems) { @@ -4349,7 +4349,7 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, } -static inline int +static int qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) { int ipv = 0; @@ -4536,7 +4536,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) } -static inline const char * +static const char * qeth_arp_get_error_cause(int *rc) { switch (*rc) { @@ -4597,7 +4597,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries) return rc; } -static inline void +static void qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo, struct qeth_arp_query_data *qdata, int entry_size, int uentry_size) @@ -5214,7 +5214,7 @@ qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) spin_unlock_irqrestore(&card->vlanlock, flags); } -static inline void +static void qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf, unsigned short vid) { @@ -5625,7 +5625,7 @@ qeth_delete_mc_addresses(struct qeth_card *card) spin_unlock_irqrestore(&card->ip_lock, flags); } -static inline void +static void qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev) { struct qeth_ipaddr *ipm; @@ -5711,7 +5711,7 @@ qeth_layer2_add_multicast(struct qeth_card *card) } #ifdef CONFIG_QETH_IPV6 -static inline void +static void qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev) { struct qeth_ipaddr *ipm; @@ -6022,7 +6022,7 @@ qeth_send_setdelmc(struct qeth_card *card, struct qeth_ipaddr *addr, int ipacmd) return rc; } -static inline void +static void qeth_fill_netmask(u8 *netmask, unsigned int len) { int i,j; @@ -6626,7 +6626,7 @@ qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode) return rc; } -static inline int +static int qeth_setadapter_hstr(struct qeth_card *card) { int rc; @@ -6889,7 +6889,7 @@ qeth_send_simple_setassparms(struct qeth_card *card, return rc; } -static inline int +static int qeth_start_ipa_arp_processing(struct qeth_card *card) { int rc; @@ -7529,7 +7529,7 @@ qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads, wake_up(&card->wait_q); } -static inline int +static int qeth_threads_running(struct qeth_card *card, unsigned long threads) { unsigned long flags; @@ -8118,7 +8118,7 @@ qeth_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto, spin_unlock_irqrestore(&card->ip_lock, flags); } -static inline void +static void qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len) { int i, j; diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index fca523a2608d..d518419cd0c6 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -328,7 +328,7 @@ qeth_dev_bufcnt_store(struct device *dev, struct device_attribute *attr, const c static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show, qeth_dev_bufcnt_store); -static inline ssize_t +static ssize_t qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route, char *buf) { @@ -368,7 +368,7 @@ qeth_dev_route4_show(struct device *dev, struct device_attribute *attr, char *bu return qeth_dev_route_show(card, &card->options.route4, buf); } -static inline ssize_t +static ssize_t qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route, enum qeth_prot_versions prot, const char *buf, size_t count) { @@ -1100,7 +1100,7 @@ static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644, qeth_dev_ipato_invert4_show, qeth_dev_ipato_invert4_store); -static inline ssize_t +static ssize_t qeth_dev_ipato_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1146,7 +1146,7 @@ qeth_dev_ipato_add4_show(struct device *dev, struct device_attribute *attr, char return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto, u8 *addr, int *mask_bits) { @@ -1178,7 +1178,7 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto, return 0; } -static inline ssize_t +static ssize_t qeth_dev_ipato_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1223,7 +1223,7 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644, qeth_dev_ipato_add4_show, qeth_dev_ipato_add4_store); -static inline ssize_t +static ssize_t qeth_dev_ipato_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1361,7 +1361,7 @@ static struct attribute_group qeth_device_ipato_group = { .attrs = (struct attribute **)qeth_ipato_device_attrs, }; -static inline ssize_t +static ssize_t qeth_dev_vipa_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1407,7 +1407,7 @@ qeth_dev_vipa_add4_show(struct device *dev, struct device_attribute *attr, char return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto, u8 *addr) { @@ -1418,7 +1418,7 @@ qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto, return 0; } -static inline ssize_t +static ssize_t qeth_dev_vipa_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1451,7 +1451,7 @@ static QETH_DEVICE_ATTR(vipa_add4, add4, 0644, qeth_dev_vipa_add4_show, qeth_dev_vipa_add4_store); -static inline ssize_t +static ssize_t qeth_dev_vipa_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1542,7 +1542,7 @@ static struct attribute_group qeth_device_vipa_group = { .attrs = (struct attribute **)qeth_vipa_device_attrs, }; -static inline ssize_t +static ssize_t qeth_dev_rxip_add_show(char *buf, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1588,7 +1588,7 @@ qeth_dev_rxip_add4_show(struct device *dev, struct device_attribute *attr, char return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4); } -static inline int +static int qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto, u8 *addr) { @@ -1599,7 +1599,7 @@ qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto, return 0; } -static inline ssize_t +static ssize_t qeth_dev_rxip_add_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { @@ -1632,7 +1632,7 @@ static QETH_DEVICE_ATTR(rxip_add4, add4, 0644, qeth_dev_rxip_add4_show, qeth_dev_rxip_add4_store); -static inline ssize_t +static ssize_t qeth_dev_rxip_del_store(const char *buf, size_t count, struct qeth_card *card, enum qeth_prot_versions proto) { diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 85093b71f9fa..39a885266790 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -47,13 +47,12 @@ static int __init zfcp_module_init(void); static void zfcp_ns_gid_pn_handler(unsigned long); /* miscellaneous */ -static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); -static inline void zfcp_sg_list_free(struct zfcp_sg_list *); -static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, - void __user *, size_t); -static inline int zfcp_sg_list_copy_to_user(void __user *, - struct zfcp_sg_list *, size_t); - +static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t); +static void zfcp_sg_list_free(struct zfcp_sg_list *); +static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *, + void __user *, size_t); +static int zfcp_sg_list_copy_to_user(void __user *, + struct zfcp_sg_list *, size_t); static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long); #define ZFCP_CFDC_IOC_MAGIC 0xDD @@ -605,7 +604,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command, * elements of the scatter-gather list. The maximum size of a single element * in the scatter-gather list is PAGE_SIZE. */ -static inline int +static int zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) { struct scatterlist *sg; @@ -652,7 +651,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size) * Memory for each element in the scatter-gather list is freed. * Finally sg_list->sg is freed itself and sg_list->count is reset. */ -static inline void +static void zfcp_sg_list_free(struct zfcp_sg_list *sg_list) { struct scatterlist *sg; @@ -697,7 +696,7 @@ zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count) * @size: number of bytes to be copied * Return: 0 on success, -EFAULT if copy_from_user fails. */ -static inline int +static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, void __user *user_buffer, size_t size) @@ -735,7 +734,7 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list, * @size: number of bytes to be copied * Return: 0 on success, -EFAULT if copy_to_user fails */ -static inline int +static int zfcp_sg_list_copy_to_user(void __user *user_buffer, struct zfcp_sg_list *sg_list, size_t size) @@ -1799,7 +1798,7 @@ static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = { * @code: reason code * @rc_table: table of reason codes and descriptions */ -static inline const char * +static const char * zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table) { const char *descr = "unknown reason code"; @@ -1847,7 +1846,7 @@ zfcp_check_ct_response(struct ct_hdr *rjt) * @rjt_par: reject parameter acc. to FC-PH/FC-FS * @rc_table: table of reason codes and descriptions */ -static inline void +static void zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par, const struct zfcp_rc_entry *rc_table) { diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index fd33537d0b2b..d8191d115c14 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -31,7 +31,7 @@ MODULE_PARM_DESC(dbfsize, #define ZFCP_LOG_AREA ZFCP_LOG_AREA_OTHER -static inline int +static int zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck) { unsigned long long sec; @@ -106,7 +106,7 @@ zfcp_dbf_view_dump(char *out_buf, const char *label, return len; } -static inline int +static int zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area, debug_entry_t * entry, char *out_buf) { @@ -130,7 +130,7 @@ zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area, return len; } -inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) +void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_qtcb *qtcb = fsf_req->qtcb; @@ -241,7 +241,7 @@ inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req) spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -inline void +void zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, struct fsf_status_read_buffer *status_buffer) { @@ -295,7 +295,7 @@ zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter, spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -inline void +void zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status, unsigned int qdio_error, unsigned int siga_error, int sbal_index, int sbal_count) @@ -316,7 +316,7 @@ zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status, spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags); } -static inline int +static int zfcp_hba_dbf_view_response(char *out_buf, struct zfcp_hba_dbf_record_response *rec) { @@ -403,7 +403,7 @@ zfcp_hba_dbf_view_response(char *out_buf, return len; } -static inline int +static int zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec) { int len = 0; @@ -424,7 +424,7 @@ zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec) return len; } -static inline int +static int zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec) { int len = 0; @@ -478,7 +478,7 @@ static struct debug_view zfcp_hba_dbf_view = { NULL }; -inline void +void _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, void *buffer, int buflen) { @@ -519,7 +519,7 @@ _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req, spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } -inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_port *port = ct->port; @@ -531,7 +531,7 @@ inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req) ct->req->length); } -inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data; struct zfcp_port *port = ct->port; @@ -543,7 +543,7 @@ inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req) ct->resp->length); } -static inline void +static void _zfcp_san_dbf_event_common_els(const char *tag, int level, struct zfcp_fsf_req *fsf_req, u32 s_id, u32 d_id, u8 ls_code, void *buffer, int buflen) @@ -585,7 +585,7 @@ _zfcp_san_dbf_event_common_els(const char *tag, int level, spin_unlock_irqrestore(&adapter->san_dbf_lock, flags); } -inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; @@ -597,7 +597,7 @@ inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req) els->req->length); } -inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) { struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data; @@ -608,7 +608,7 @@ inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req) els->resp->length); } -inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) +void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req) { struct zfcp_adapter *adapter = fsf_req->adapter; struct fsf_status_read_buffer *status_buffer = @@ -702,7 +702,7 @@ static struct debug_view zfcp_san_dbf_view = { NULL }; -static inline void +static void _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, @@ -786,7 +786,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level, spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags); } -inline void +void zfcp_scsi_dbf_event_result(const char *tag, int level, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, @@ -796,7 +796,7 @@ zfcp_scsi_dbf_event_result(const char *tag, int level, adapter, scsi_cmnd, fsf_req, 0); } -inline void +void zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, struct scsi_cmnd *scsi_cmnd, struct zfcp_fsf_req *new_fsf_req, @@ -806,7 +806,7 @@ zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter, adapter, scsi_cmnd, new_fsf_req, old_req_id); } -inline void +void zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit, struct scsi_cmnd *scsi_cmnd) { diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 067f1519eb04..4b3ae3f22e78 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -4563,7 +4563,7 @@ zfcp_fsf_req_sbal_check(unsigned long *flags, /* * set qtcb pointer in fsf_req and initialize QTCB */ -static inline void +static void zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req) { if (likely(fsf_req->qtcb != NULL)) { diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index dbd9f48e863e..1e12a78e8edd 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -21,22 +21,22 @@ #include "zfcp_ext.h" -static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); +static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int); static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get (struct zfcp_qdio_queue *, int, int); static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp (struct zfcp_fsf_req *, int, int); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain +static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain (struct zfcp_fsf_req *, unsigned long); -static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next +static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next (struct zfcp_fsf_req *, unsigned long); -static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); +static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int); static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *); -static inline void zfcp_qdio_sbale_fill +static void zfcp_qdio_sbale_fill (struct zfcp_fsf_req *, unsigned long, void *, int); -static inline int zfcp_qdio_sbals_from_segment +static int zfcp_qdio_sbals_from_segment (struct zfcp_fsf_req *, unsigned long, void *, unsigned long); -static inline int zfcp_qdio_sbals_from_buffer +static int zfcp_qdio_sbals_from_buffer (struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int); static qdio_handler_t zfcp_qdio_request_handler; @@ -201,7 +201,7 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter) * returns: error flag * */ -static inline int +static int zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status, unsigned int qdio_error, unsigned int siga_error, int first_element, int elements_processed) @@ -462,7 +462,7 @@ zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale) * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for * a struct zfcp_fsf_req */ -inline volatile struct qdio_buffer_element * +volatile struct qdio_buffer_element * zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) { return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue, @@ -484,7 +484,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale) * zfcp_qdio_sbale_curr - return current SBALE on request_queue for * a struct zfcp_fsf_req */ -inline volatile struct qdio_buffer_element * +volatile struct qdio_buffer_element * zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) { return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr, @@ -499,7 +499,7 @@ zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req) * * Note: We can assume at least one free SBAL in the request_queue when called. */ -static inline void +static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) { int count = atomic_read(&fsf_req->adapter->request_queue.free_count); @@ -517,7 +517,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals) * * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req. */ -static inline volatile struct qdio_buffer_element * +static volatile struct qdio_buffer_element * zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { volatile struct qdio_buffer_element *sbale; @@ -554,7 +554,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) /** * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed */ -static inline volatile struct qdio_buffer_element * +static volatile struct qdio_buffer_element * zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) { if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL) @@ -569,7 +569,7 @@ zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype) * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue * with zero from */ -static inline int +static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last) { struct qdio_buffer **buf = queue->buffer; @@ -603,7 +603,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req) * zfcp_qdio_sbale_fill - set address and lenght in current SBALE * on request_queue */ -static inline void +static void zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *addr, int length) { @@ -624,7 +624,7 @@ zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, * Alignment and length of the segment determine how many SBALEs are needed * for the memory segment. */ -static inline int +static int zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *start_addr, unsigned long total_length) { @@ -659,7 +659,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, * @sg_count: number of elements in scatter-gather list * @max_sbals: upper bound for number of SBALs to be used */ -inline int +int zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scatterlist *sg, int sg_count, int max_sbals) { @@ -707,7 +707,7 @@ out: * @length: length of buffer * @max_sbals: upper bound for number of SBALs to be used */ -static inline int +static int zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, void *buffer, unsigned long length, int max_sbals) { @@ -728,7 +728,7 @@ zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, * @scsi_cmnd: either scatter-gather list or buffer contained herein is used * to fill SBALs */ -inline int +int zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) { -- cgit v1.2.3 From 33a67fe898dbbe25589d2fca805cb68cfd7d311f Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 8 Feb 2007 13:36:44 -0800 Subject: [S390]: Rewrite of the IUCV base code, part 1 Remove the old IUCV code from drivers/s390/net Remove approprirate IUCV entries from drivers/s390/net/Makefile, drivers/s390/net/Kconfig and arch/s390/defconfig Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller --- arch/s390/defconfig | 1 - drivers/s390/net/Kconfig | 7 - drivers/s390/net/Makefile | 1 - drivers/s390/net/iucv.c | 2540 --------------------------------------------- drivers/s390/net/iucv.h | 849 --------------- 5 files changed, 3398 deletions(-) delete mode 100644 drivers/s390/net/iucv.c delete mode 100644 drivers/s390/net/iucv.h (limited to 'drivers/s390') diff --git a/arch/s390/defconfig b/arch/s390/defconfig index 7c621b8ef683..7729ca114cc9 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig @@ -508,7 +508,6 @@ CONFIG_NET_ETHERNET=y # CONFIG_LCS=m CONFIG_CTC=m -CONFIG_IUCV=m # CONFIG_NETIUCV is not set # CONFIG_SMSGIUCV is not set # CONFIG_CLAW is not set diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 52625153a4f0..f98fa465df0a 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig @@ -22,13 +22,6 @@ config CTC available. This option is also available as a module which will be called ctc.ko. If you do not know what it is, it's safe to say "Y". -config IUCV - tristate "IUCV support (VM only)" - help - Select this option if you want to use inter-user communication - under VM or VIF. If unsure, say "Y" to enable a fast communication - link between VM guests. - config NETIUCV tristate "IUCV network device support (VM only)" depends on IUCV && NETDEVICES diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 4777e36a922f..bbe3ab2e93d9 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -4,7 +4,6 @@ ctc-objs := ctcmain.o ctcdbug.o -obj-$(CONFIG_IUCV) += iucv.o obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o obj-$(CONFIG_SMSGIUCV) += smsgiucv.o obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c deleted file mode 100644 index 229aeb5fc399..000000000000 --- a/drivers/s390/net/iucv.c +++ /dev/null @@ -1,2540 +0,0 @@ -/* - * IUCV network driver - * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): - * Original source: - * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 - * Xenia Tkatschow (xenia@us.ibm.com) - * 2Gb awareness and general cleanup: - * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) - * - * Documentation used: - * The original source - * CP Programming Service, IBM document # SC24-5760 - * - * 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; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* #define DEBUG */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iucv.h" -#include -#include -#include -#include -#include - -/* FLAGS: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPSRCCLS - Indicates you have specified a source class - * IPFGMCL - Indicates you have specified a target class - * IPFGPID - Indicates you have specified a pathid - * IPFGMID - Indicates you have specified a message ID - * IPANSLST - Indicates that you are using an address list for - * reply data - * IPBUFLST - Indicates that you are using an address list for - * message data - */ - -#define IPSRCCLS 0x01 -#define IPFGMCL 0x01 -#define IPFGPID 0x02 -#define IPFGMID 0x04 -#define IPANSLST 0x08 -#define IPBUFLST 0x40 - -static int -iucv_bus_match (struct device *dev, struct device_driver *drv) -{ - return 0; -} - -struct bus_type iucv_bus = { - .name = "iucv", - .match = iucv_bus_match, -}; - -struct device *iucv_root; - -/* General IUCV interrupt structure */ -typedef struct { - __u16 ippathid; - __u8 res1; - __u8 iptype; - __u32 res2; - __u8 ipvmid[8]; - __u8 res3[24]; -} iucv_GeneralInterrupt; - -static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL; - -/* Spin Lock declaration */ - -static DEFINE_SPINLOCK(iucv_lock); - -static int messagesDisabled = 0; - -/***************INTERRUPT HANDLING ***************/ - -typedef struct { - struct list_head queue; - iucv_GeneralInterrupt data; -} iucv_irqdata; - -static struct list_head iucv_irq_queue; -static DEFINE_SPINLOCK(iucv_irq_queue_lock); - -/* - *Internal function prototypes - */ -static void iucv_tasklet_handler(unsigned long); -static void iucv_irq_handler(__u16); - -static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0); - -/************ FUNCTION ID'S ****************************/ - -#define ACCEPT 10 -#define CONNECT 11 -#define DECLARE_BUFFER 12 -#define PURGE 9 -#define QUERY 0 -#define QUIESCE 13 -#define RECEIVE 5 -#define REJECT 8 -#define REPLY 6 -#define RESUME 14 -#define RETRIEVE_BUFFER 2 -#define SEND 4 -#define SETMASK 16 -#define SEVER 15 - -/** - * Structure: handler - * members: list - list management. - * structure: id - * userid - 8 char array of machine identification - * user_data - 16 char array for user identification - * mask - 24 char array used to compare the 2 previous - * interrupt_table - vector of interrupt functions. - * pgm_data - ulong, application data that is passed - * to the interrupt handlers -*/ -typedef struct handler_t { - struct list_head list; - struct { - __u8 userid[8]; - __u8 user_data[16]; - __u8 mask[24]; - } id; - iucv_interrupt_ops_t *interrupt_table; - void *pgm_data; -} handler; - -/** - * iucv_handler_table: List of registered handlers. - */ -static struct list_head iucv_handler_table; - -/** - * iucv_pathid_table: an array of *handler pointing into - * iucv_handler_table for fast indexing by pathid; - */ -static handler **iucv_pathid_table; - -static unsigned long max_connections; - -/** - * iucv_cpuid: contains the logical cpu number of the cpu which - * has declared the iucv buffer by issuing DECLARE_BUFFER. - * If no cpu has done the initialization iucv_cpuid contains -1. - */ -static int iucv_cpuid = -1; -/** - * register_flag: is 0 when external interrupt has not been registered - */ -static int register_flag; - -/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/ -/* Data struct 1: iparml_control - * Used for iucv_accept - * iucv_connect - * iucv_quiesce - * iucv_resume - * iucv_sever - * iucv_retrieve_buffer - * Data struct 2: iparml_dpl (data in parameter list) - * Used for iucv_send_prmmsg - * iucv_send2way_prmmsg - * iucv_send2way_prmmsg_array - * iucv_reply_prmmsg - * Data struct 3: iparml_db (data in a buffer) - * Used for iucv_receive - * iucv_receive_array - * iucv_reject - * iucv_reply - * iucv_reply_array - * iucv_send - * iucv_send_array - * iucv_send2way - * iucv_send2way_array - * iucv_declare_buffer - * Data struct 4: iparml_purge - * Used for iucv_purge - * iucv_query - * Data struct 5: iparml_set_mask - * Used for iucv_set_mask - */ - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u16 ipmsglim; - __u16 res1; - __u8 ipvmid[8]; - __u8 ipuser[16]; - __u8 iptarget[8]; -} iparml_control; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u8 iprmmsg[8]; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_dpl; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u32 iptrgcls; - __u32 ipbfadr1; - __u32 ipbfln1f; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 ipbfadr2; - __u32 ipbfln2f; - __u32 res; -} iparml_db; - -typedef struct { - __u16 ippathid; - __u8 ipflags1; - __u8 iprcode; - __u32 ipmsgid; - __u8 ipaudit[3]; - __u8 res1[5]; - __u32 res2; - __u32 ipsrccls; - __u32 ipmsgtag; - __u32 res3[3]; -} iparml_purge; - -typedef struct { - __u8 ipmask; - __u8 res1[2]; - __u8 iprcode; - __u32 res2[9]; -} iparml_set_mask; - -typedef struct { - union { - iparml_control p_ctrl; - iparml_dpl p_dpl; - iparml_db p_db; - iparml_purge p_purge; - iparml_set_mask p_set_mask; - } param; - atomic_t in_use; - __u32 res; -} __attribute__ ((aligned(8))) iucv_param; -#define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param)) - -static iucv_param * iucv_param_pool; - -MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); -MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver"); -MODULE_LICENSE("GPL"); - -/* - * Debugging stuff - *******************************************************************************/ - - -#ifdef DEBUG -static int debuglevel = 0; - -module_param(debuglevel, int, 0); -MODULE_PARM_DESC(debuglevel, - "Specifies the debug level (0=off ... 3=all)"); - -static void -iucv_dumpit(char *title, void *buf, int len) -{ - int i; - __u8 *p = (__u8 *)buf; - - if (debuglevel < 3) - return; - - printk(KERN_DEBUG "%s\n", title); - printk(" "); - for (i = 0; i < len; i++) { - if (!(i % 16) && i != 0) - printk ("\n "); - else if (!(i % 4) && i != 0) - printk(" "); - printk("%02X", *p++); - } - if (len % 16) - printk ("\n"); - return; -} -#define iucv_debug(lvl, fmt, args...) \ -do { \ - if (debuglevel >= lvl) \ - printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \ -} while (0) - -#else - -#define iucv_debug(lvl, fmt, args...) do { } while (0) -#define iucv_dumpit(title, buf, len) do { } while (0) - -#endif - -/* - * Internal functions - *******************************************************************************/ - -/** - * print start banner - */ -static void -iucv_banner(void) -{ - printk(KERN_INFO "IUCV lowlevel driver initialized\n"); -} - -/** - * iucv_init - Initialization - * - * Allocates and initializes various data structures. - */ -static int -iucv_init(void) -{ - int ret; - - if (iucv_external_int_buffer) - return 0; - - if (!MACHINE_IS_VM) { - printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); - return -EPROTONOSUPPORT; - } - - ret = bus_register(&iucv_bus); - if (ret) { - printk(KERN_ERR "IUCV: failed to register bus.\n"); - return ret; - } - - iucv_root = s390_root_dev_register("iucv"); - if (IS_ERR(iucv_root)) { - printk(KERN_ERR "IUCV: failed to register iucv root.\n"); - bus_unregister(&iucv_bus); - return PTR_ERR(iucv_root); - } - - /* Note: GFP_DMA used used to get memory below 2G */ - iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt), - GFP_KERNEL|GFP_DMA); - if (!iucv_external_int_buffer) { - printk(KERN_WARNING - "%s: Could not allocate external interrupt buffer\n", - __FUNCTION__); - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize parameter pool */ - iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE, - GFP_KERNEL|GFP_DMA); - if (!iucv_param_pool) { - printk(KERN_WARNING "%s: Could not allocate param pool\n", - __FUNCTION__); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - return -ENOMEM; - } - - /* Initialize irq queue */ - INIT_LIST_HEAD(&iucv_irq_queue); - - /* Initialize handler table */ - INIT_LIST_HEAD(&iucv_handler_table); - - iucv_banner(); - return 0; -} - -/** - * iucv_exit - De-Initialization - * - * Frees everything allocated from iucv_init. - */ -static int iucv_retrieve_buffer (void); - -static void -iucv_exit(void) -{ - iucv_retrieve_buffer(); - kfree(iucv_external_int_buffer); - iucv_external_int_buffer = NULL; - kfree(iucv_param_pool); - iucv_param_pool = NULL; - s390_root_dev_unregister(iucv_root); - bus_unregister(&iucv_bus); - printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); -} - -/** - * grab_param: - Get a parameter buffer from the pre-allocated pool. - * - * This function searches for an unused element in the pre-allocated pool - * of parameter buffers. If one is found, it marks it "in use" and returns - * a pointer to it. The calling function is responsible for releasing it - * when it has finished its usage. - * - * Returns: A pointer to iucv_param. - */ -static __inline__ iucv_param * -grab_param(void) -{ - iucv_param *ptr; - static int hint = 0; - - ptr = iucv_param_pool + hint; - do { - ptr++; - if (ptr >= iucv_param_pool + PARAM_POOL_SIZE) - ptr = iucv_param_pool; - } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0); - hint = ptr - iucv_param_pool; - - memset(&ptr->param, 0, sizeof(ptr->param)); - return ptr; -} - -/** - * release_param - Release a parameter buffer. - * @p: A pointer to a struct iucv_param, previously obtained by calling - * grab_param(). - * - * This function marks the specified parameter buffer "unused". - */ -static __inline__ void -release_param(void *p) -{ - atomic_set(&((iucv_param *)p)->in_use, 0); -} - -/** - * iucv_add_handler: - Add a new handler - * @new_handler: handle that is being entered into chain. - * - * Places new handle on iucv_handler_table, if identical handler is not - * found. - * - * Returns: 0 on success, !0 on failure (handler already in chain). - */ -static int -iucv_add_handler (handler *new) -{ - ulong flags; - - iucv_debug(1, "entering"); - iucv_dumpit("handler:", new, sizeof(handler)); - - spin_lock_irqsave (&iucv_lock, flags); - if (!list_empty(&iucv_handler_table)) { - struct list_head *lh; - - /** - * Search list for handler with identical id. If one - * is found, the new handler is _not_ added. - */ - list_for_each(lh, &iucv_handler_table) { - handler *h = list_entry(lh, handler, list); - if (!memcmp(&new->id, &h->id, sizeof(h->id))) { - iucv_debug(1, "ret 1"); - spin_unlock_irqrestore (&iucv_lock, flags); - return 1; - } - } - } - /** - * If we get here, no handler was found. - */ - INIT_LIST_HEAD(&new->list); - list_add(&new->list, &iucv_handler_table); - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * b2f0: - * @code: identifier of IUCV call to CP. - * @parm: pointer to 40 byte iparml area passed to CP - * - * Calls CP to execute IUCV commands. - * - * Returns: return code from CP's IUCV call - */ -static inline ulong b2f0(__u32 code, void *parm) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param)); - - reg0 = code; - reg1 = virt_to_phys(parm); - asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1)); - - iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param)); - - return (unsigned long)*((__u8 *)(parm + 3)); -} - -/* - * Name: iucv_add_pathid - * Purpose: Adds a path id to the system. - * Input: pathid - pathid that is going to be entered into system - * handle - address of handler that the pathid will be associated - * with. - * pgm_data - token passed in by application. - * Output: 0: successful addition of pathid - * - EINVAL - pathid entry is being used by another application - * - ENOMEM - storage allocation for a new pathid table failed -*/ -static int -__iucv_add_pathid(__u16 pathid, handler *handler) -{ - - iucv_debug(1, "entering"); - - iucv_debug(1, "handler is pointing to %p", handler); - - if (pathid > (max_connections - 1)) - return -EINVAL; - - if (iucv_pathid_table[pathid]) { - iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]); - printk(KERN_WARNING - "%s: Pathid being used, error.\n", __FUNCTION__); - return -EINVAL; - } - iucv_pathid_table[pathid] = handler; - - iucv_debug(1, "exiting"); - return 0; -} /* end of add_pathid function */ - -static int -iucv_add_pathid(__u16 pathid, handler *handler) -{ - ulong flags; - int rc; - - spin_lock_irqsave (&iucv_lock, flags); - rc = __iucv_add_pathid(pathid, handler); - spin_unlock_irqrestore (&iucv_lock, flags); - return rc; -} - -static void -iucv_remove_pathid(__u16 pathid) -{ - ulong flags; - - if (pathid > (max_connections - 1)) - return; - - spin_lock_irqsave (&iucv_lock, flags); - iucv_pathid_table[pathid] = NULL; - spin_unlock_irqrestore (&iucv_lock, flags); -} - -/** - * iucv_declare_buffer_cpuid - * Register at VM for subsequent IUCV operations. This is executed - * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer(). - */ -static void -iucv_declare_buffer_cpuid (void *result) -{ - iparml_db *parm; - - parm = (iparml_db *)grab_param(); - parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); - if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1) - *((ulong *)result) = parm->iprcode; - release_param(parm); -} - -/** - * iucv_retrieve_buffer_cpuid: - * Unregister IUCV usage at VM. This is always executed on the same - * cpu that registered the buffer to VM. - * Called from iucv_retrieve_buffer(). - */ -static void -iucv_retrieve_buffer_cpuid (void *cpu) -{ - iparml_control *parm; - - parm = (iparml_control *)grab_param(); - b2f0(RETRIEVE_BUFFER, parm); - release_param(parm); -} - -/** - * Name: iucv_declare_buffer - * Purpose: Specifies the guests real address of an external - * interrupt. - * Input: void - * Output: iprcode - return code from b2f0 call - */ -static int -iucv_declare_buffer (void) -{ - unsigned long flags; - ulong b2f0_result; - - iucv_debug(1, "entering"); - b2f0_result = -ENODEV; - spin_lock_irqsave (&iucv_lock, flags); - if (iucv_cpuid == -1) { - /* Reserve any cpu for use by iucv. */ - iucv_cpuid = smp_get_cpu(CPU_MASK_ALL); - spin_unlock_irqrestore (&iucv_lock, flags); - smp_call_function_on(iucv_declare_buffer_cpuid, - &b2f0_result, 0, 1, iucv_cpuid); - if (b2f0_result) { - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer); - } else { - spin_unlock_irqrestore (&iucv_lock, flags); - b2f0_result = 0; - } - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_retrieve_buffer: - * - * Terminates all use of IUCV. - * Returns: return code from CP - */ -static int -iucv_retrieve_buffer (void) -{ - iucv_debug(1, "entering"); - if (iucv_cpuid != -1) { - smp_call_function_on(iucv_retrieve_buffer_cpuid, - NULL, 0, 1, iucv_cpuid); - /* Release the cpu reserved by iucv_declare_buffer. */ - smp_put_cpu(iucv_cpuid); - iucv_cpuid = -1; - } - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_remove_handler: - * @users_handler: handler to be removed - * - * Remove handler when application unregisters. - */ -static void -iucv_remove_handler(handler *handler) -{ - unsigned long flags; - - if ((!iucv_pathid_table) || (!handler)) - return; - - iucv_debug(1, "entering"); - - spin_lock_irqsave (&iucv_lock, flags); - list_del(&handler->list); - if (list_empty(&iucv_handler_table)) { - if (register_flag) { - unregister_external_interrupt(0x4000, iucv_irq_handler); - register_flag = 0; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_debug(1, "exiting"); - return; -} - -/** - * iucv_register_program: - * @pgmname: user identification - * @userid: machine identification - * @pgmmask: Indicates which bits in the pgmname and userid combined will be - * used to determine who is given control. - * @ops: Address of interrupt handler table. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * Registers an application with IUCV. - * Returns: - * The address of handler, or NULL on failure. - * NOTE on pgmmask: - * If pgmname, userid and pgmmask are provided, pgmmask is entered into the - * handler as is. - * If pgmmask is NULL, the internal mask is set to all 0xff's - * When userid is NULL, the first 8 bytes of the internal mask are forced - * to 0x00. - * If pgmmask and userid are NULL, the first 8 bytes of the internal mask - * are forced to 0x00 and the last 16 bytes to 0xff. - */ - -iucv_handle_t -iucv_register_program (__u8 pgmname[16], - __u8 userid[8], - __u8 pgmmask[24], - iucv_interrupt_ops_t * ops, void *pgm_data) -{ - ulong rc = 0; /* return code from function calls */ - handler *new_handler; - - iucv_debug(1, "entering"); - - if (ops == NULL) { - /* interrupt table is not defined */ - printk(KERN_WARNING "%s: Interrupt table is not defined, " - "exiting\n", __FUNCTION__); - return NULL; - } - if (!pgmname) { - printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__); - return NULL; - } - - /* Allocate handler entry */ - new_handler = kmalloc(sizeof(handler), GFP_ATOMIC); - if (new_handler == NULL) { - printk(KERN_WARNING "%s: storage allocation for new handler " - "failed.\n", __FUNCTION__); - return NULL; - } - - if (!iucv_pathid_table) { - if (iucv_init()) { - kfree(new_handler); - return NULL; - } - - max_connections = iucv_query_maxconn(); - iucv_pathid_table = kcalloc(max_connections, sizeof(handler *), - GFP_ATOMIC); - if (iucv_pathid_table == NULL) { - printk(KERN_WARNING "%s: iucv_pathid_table storage " - "allocation failed\n", __FUNCTION__); - kfree(new_handler); - return NULL; - } - } - memset(new_handler, 0, sizeof (handler)); - memcpy(new_handler->id.user_data, pgmname, - sizeof (new_handler->id.user_data)); - if (userid) { - memcpy (new_handler->id.userid, userid, - sizeof (new_handler->id.userid)); - ASCEBC (new_handler->id.userid, - sizeof (new_handler->id.userid)); - EBC_TOUPPER (new_handler->id.userid, - sizeof (new_handler->id.userid)); - - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - } else { - if (pgmmask) { - memcpy (new_handler->id.mask, pgmmask, - sizeof (new_handler->id.mask)); - } else { - memset (new_handler->id.mask, 0xFF, - sizeof (new_handler->id.mask)); - } - memset (new_handler->id.userid, 0x00, - sizeof (new_handler->id.userid)); - } - /* fill in the rest of handler */ - new_handler->pgm_data = pgm_data; - new_handler->interrupt_table = ops; - - /* - * Check if someone else is registered with same pgmname, userid - * and mask. If someone is already registered with same pgmname, - * userid and mask, registration will fail and NULL will be returned - * to the application. - * If identical handler not found, then handler is added to list. - */ - rc = iucv_add_handler(new_handler); - if (rc) { - printk(KERN_WARNING "%s: Someone already registered with same " - "pgmname, userid, pgmmask\n", __FUNCTION__); - kfree (new_handler); - return NULL; - } - - rc = iucv_declare_buffer(); - if (rc) { - char *err = "Unknown"; - iucv_remove_handler(new_handler); - kfree(new_handler); - switch(rc) { - case 0x03: - err = "Directory error"; - break; - case 0x0a: - err = "Invalid length"; - break; - case 0x13: - err = "Buffer already exists"; - break; - case 0x3e: - err = "Buffer overlap"; - break; - case 0x5c: - err = "Paging or storage error"; - break; - } - printk(KERN_WARNING "%s: iucv_declare_buffer " - "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err); - return NULL; - } - if (!register_flag) { - /* request the 0x4000 external interrupt */ - rc = register_external_interrupt (0x4000, iucv_irq_handler); - if (rc) { - iucv_remove_handler(new_handler); - kfree (new_handler); - printk(KERN_WARNING "%s: " - "register_external_interrupt returned %ld\n", - __FUNCTION__, rc); - return NULL; - - } - register_flag = 1; - } - iucv_debug(1, "exiting"); - return new_handler; -} /* end of register function */ - -/** - * iucv_unregister_program: - * @handle: address of handler - * - * Unregister application with IUCV. - * Returns: - * 0 on success, -EINVAL, if specified handle is invalid. - */ - -int -iucv_unregister_program (iucv_handle_t handle) -{ - handler *h = NULL; - struct list_head *lh; - int i; - ulong flags; - - iucv_debug(1, "entering"); - iucv_debug(1, "address of handler is %p", h); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - if (!h) { - spin_unlock_irqrestore (&iucv_lock, flags); - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - /** - * First, walk thru iucv_pathid_table and sever any pathid which is - * still pointing to the handler to be removed. - */ - for (i = 0; i < max_connections; i++) - if (iucv_pathid_table[i] == h) { - spin_unlock_irqrestore (&iucv_lock, flags); - iucv_sever(i, h->id.user_data); - spin_lock_irqsave(&iucv_lock, flags); - } - spin_unlock_irqrestore (&iucv_lock, flags); - - iucv_remove_handler(h); - kfree(h); - - iucv_debug(1, "exiting"); - return 0; -} - -/** - * iucv_accept: - * @pathid: Path identification number - * @msglim_reqstd: The number of outstanding messages requested. - * @user_data: Data specified by the iucv_connect function. - * @flags1: Contains options for this path. - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * @handle: Address of handler. - * @pgm_data: Application data passed to interrupt handlers. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * - * This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Returns: - * return code from CP - */ -int -iucv_accept(__u16 pathid, __u16 msglim_reqstd, - __u8 user_data[16], int flags1, - iucv_handle_t handle, void *pgm_data, - int *flags1_out, __u16 * msglim) -{ - ulong b2f0_result = 0; - ulong flags; - struct list_head *lh; - handler *h = NULL; - iparml_control *parm; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsglim = msglim_reqstd; - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(ACCEPT, parm); - - if (!b2f0_result) { - if (msglim) - *msglim = parm->ipmsglim; - if (pgm_data) - h->pgm_data = pgm_data; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - } - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_connect: - * @pathid: Path identification number - * @msglim_reqstd: Number of outstanding messages requested - * @user_data: 16-byte user data - * @userid: 8-byte of user identification - * @system_name: 8-byte identifying the system name - * @flags1: Specifies options for this path: - * - IPPRTY (0x20) Specifies if you want to send priority message. - * - IPRMDATA (0x80) Specifies whether your program can handle a message - * in the parameter list. - * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being - * established. - * - IPLOCAL (0x01) Allows an application to force the partner to be on the - * local system. If local is specified then target class - * cannot be specified. - * @flags1_out: Pointer to an int. If not NULL, on return the options for - * the path are stored at the given location: - * - IPPRTY (0x20) Indicates you may send a priority message. - * @msglim: Pointer to an __u16. If not NULL, on return the maximum - * number of outstanding messages is stored at the given - * location. - * @handle: Address of handler. - * @pgm_data: Application data to be passed to interrupt handlers. - * - * This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Returns: return code from CP, or one of the following - * - ENOMEM - * - return code from iucv_declare_buffer - * - EINVAL - invalid handle passed by application - * - EINVAL - pathid address is NULL - * - ENOMEM - pathid table storage allocation failed - * - return code from internal function add_pathid - */ -int -iucv_connect (__u16 *pathid, __u16 msglim_reqstd, - __u8 user_data[16], __u8 userid[8], - __u8 system_name[8], int flags1, - int *flags1_out, __u16 * msglim, - iucv_handle_t handle, void *pgm_data) -{ - iparml_control *parm; - iparml_control local_parm; - struct list_head *lh; - ulong b2f0_result = 0; - ulong flags; - int add_pathid_result = 0; - handler *h = NULL; - __u8 no_memory[16] = "NO MEMORY"; - - iucv_debug(1, "entering"); - - /* Checking if handle is valid */ - spin_lock_irqsave (&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - if ((handler *)handle == list_entry(lh, handler, list)) { - h = (handler *)handle; - break; - } - } - spin_unlock_irqrestore (&iucv_lock, flags); - - if (!h) { - if (handle) - printk(KERN_WARNING - "%s: Handler not found in iucv_handler_table.\n", - __FUNCTION__); - else - printk(KERN_WARNING - "%s: NULL handle passed by application.\n", - __FUNCTION__); - return -EINVAL; - } - - if (pathid == NULL) { - printk(KERN_WARNING "%s: NULL pathid pointer\n", - __FUNCTION__); - return -EINVAL; - } - - parm = (iparml_control *)grab_param(); - - parm->ipmsglim = msglim_reqstd; - - if (user_data) - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - - if (userid) { - memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid)); - ASCEBC(parm->ipvmid, sizeof(parm->ipvmid)); - EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid)); - } - - if (system_name) { - memcpy(parm->iptarget, system_name, sizeof(parm->iptarget)); - ASCEBC(parm->iptarget, sizeof(parm->iptarget)); - EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget)); - } - - /* In order to establish an IUCV connection, the procedure is: - * - * b2f0(CONNECT) - * take the ippathid from the b2f0 call - * register the handler to the ippathid - * - * Unfortunately, the ConnectionEstablished message gets sent after the - * b2f0(CONNECT) call but before the register is handled. - * - * In order for this race condition to be eliminated, the IUCV Control - * Interrupts must be disabled for the above procedure. - * - * David Kennedy - */ - - /* Enable everything but IUCV Control messages */ - iucv_setmask(~(AllInterrupts)); - messagesDisabled = 1; - - spin_lock_irqsave (&iucv_lock, flags); - parm->ipflags1 = (__u8)flags1; - b2f0_result = b2f0(CONNECT, parm); - memcpy(&local_parm, parm, sizeof(local_parm)); - release_param(parm); - parm = &local_parm; - if (!b2f0_result) - add_pathid_result = __iucv_add_pathid(parm->ippathid, h); - spin_unlock_irqrestore (&iucv_lock, flags); - - if (b2f0_result) { - iucv_setmask(~0); - messagesDisabled = 0; - return b2f0_result; - } - - *pathid = parm->ippathid; - - /* Enable everything again */ - iucv_setmask(IUCVControlInterruptsFlag); - - if (msglim) - *msglim = parm->ipmsglim; - if (flags1_out) - *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; - - if (add_pathid_result) { - iucv_sever(*pathid, no_memory); - printk(KERN_WARNING "%s: add_pathid failed with rc =" - " %d\n", __FUNCTION__, add_pathid_result); - return(add_pathid_result); - } - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_purge: - * @pathid: Path identification number - * @msgid: Message ID of message to purge. - * @srccls: Message class of the message to purge. - * @audit: Pointer to an __u32. If not NULL, on return, information about - * asynchronous errors that may have affected the normal completion - * of this message ist stored at the given location. - * - * Cancels a message you have sent. - * Returns: return code from CP - */ -int -iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit) -{ - iparml_purge *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_purge *)grab_param(); - - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->ipsrccls = srccls; - parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID); - b2f0_result = b2f0(PURGE, parm); - - if (!b2f0_result && audit) { - memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit)); - /* parm->ipaudit has only 3 bytes */ - *audit >>= 8; - } - - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/** - * iucv_query_generic: - * @want_maxconn: Flag, describing which value is to be returned. - * - * Helper function for iucv_query_maxconn() and iucv_query_bufsize(). - * - * Returns: The buffersize, if want_maxconn is 0; the maximum number of - * connections, if want_maxconn is 1 or an error-code < 0 on failure. - */ -static int -iucv_query_generic(int want_maxconn) -{ - register unsigned long reg0 asm ("0"); - register unsigned long reg1 asm ("1"); - iparml_purge *parm = (iparml_purge *)grab_param(); - int bufsize, maxconn; - int ccode; - - /** - * Call b2f0 and store R0 (max buffer size), - * R1 (max connections) and CC. - */ - reg0 = QUERY; - reg1 = virt_to_phys(parm); - asm volatile( - " .long 0xb2f01000\n" - " ipm %0\n" - " srl %0,28\n" - : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc"); - bufsize = reg0; - maxconn = reg1; - release_param(parm); - - if (ccode) - return -EPERM; - if (want_maxconn) - return maxconn; - return bufsize; -} - -/** - * iucv_query_maxconn: - * - * Determines the maximum number of connections thay may be established. - * - * Returns: Maximum number of connections that can be. - */ -ulong -iucv_query_maxconn(void) -{ - return iucv_query_generic(1); -} - -/** - * iucv_query_bufsize: - * - * Determines the size of the external interrupt buffer. - * - * Returns: Size of external interrupt buffer. - */ -ulong -iucv_query_bufsize (void) -{ - return iucv_query_generic(0); -} - -/** - * iucv_quiesce: - * @pathid: Path identification number - * @user_data: 16-byte user data - * - * Temporarily suspends incoming messages on an IUCV path. - * You can later reactivate the path by invoking the iucv_resume function. - * Returns: return code from CP - */ -int -iucv_quiesce (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(QUIESCE, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/** - * iucv_receive: - * @pathid: Path identification number. - * @buffer: Address of buffer to receive. Must be below 2G. - * @buflen: Length of buffer to receive. - * @msgid: Specifies the message ID. - * @trgcls: Specifies target class. - * @flags1_out: Receives options for path on return. - * - IPNORPY (0x10) Specifies whether a reply is required - * - IPPRTY (0x20) Specifies if you want to send priority message - * - IPRMDATA (0x80) Specifies the data is contained in the parameter list - * @residual_buffer: Receives the address of buffer updated by the number - * of bytes you have received on return. - * @residual_length: On return, receives one of the following values: - * - 0 If the receive buffer is the same length as - * the message. - * - Remaining bytes in buffer If the receive buffer is longer than the - * message. - * - Remaining bytes in message If the receive buffer is shorter than the - * message. - * - * This function receives messages that are being sent to you over established - * paths. - * Returns: return code from CP IUCV call; If the receive buffer is shorter - * than the message, always 5 - * -EINVAL - buffer address is pointing to NULL - */ -int -iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls, - void *buffer, ulong buflen, - int *flags1_out, ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int moved = 0; /* number of bytes moved from parmlist to buffer */ - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) (addr_t) buffer; - parm->ipbfln1f = (__u32) ((ulong) buflen); - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - } else { - moved = min_t (unsigned long, buflen, 8); - - memcpy ((char *) buffer, - (char *) &parm->ipbfadr1, moved); - - if (buflen < 8) - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) - *residual_buffer = (ulong) (buffer + moved); - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. - * Input: pathid - path identification number - * buffer - address of array of buffers - * buflen - total length of buffers - * msgid - specifies the message ID. - * trgcls - specifies target class - * Output: - * flags1_out: Options for path. - * IPNORPY - 0x10 specifies whether a reply is required - * IPPRTY - 0x20 specifies if you want to send priority message - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this case - * b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_receive_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - iucv_array_t * buffer, ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length) -{ - iparml_db *parm; - ulong b2f0_result; - int i = 0, moved = 0, need_to_move = 8, dyn_len; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; - parm->ipmsgid = msgid; - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL); - - b2f0_result = b2f0(RECEIVE, parm); - - if (!b2f0_result || b2f0_result == 5) { - - if (flags1_out) { - iucv_debug(2, "*flags1_out = %d", *flags1_out); - *flags1_out = (parm->ipflags1 & (~0x07)); - iucv_debug(2, "*flags1_out = %d", *flags1_out); - } - - if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ - - if (residual_length) - *residual_length = parm->ipbfln1f; - - if (residual_buffer) - *residual_buffer = parm->ipbfadr1; - - } else { - /* copy msg from parmlist to users array. */ - - while ((moved < 8) && (moved < buflen)) { - dyn_len = - min_t (unsigned int, - (buffer + i)->length, need_to_move); - - memcpy ((char *)((ulong)((buffer + i)->address)), - ((char *) &parm->ipbfadr1) + moved, - dyn_len); - - moved += dyn_len; - need_to_move -= dyn_len; - - (buffer + i)->address = - (__u32) - ((ulong)(__u8 *) ((ulong)(buffer + i)->address) - + dyn_len); - - (buffer + i)->length -= dyn_len; - i++; - } - - if (need_to_move) /* buflen < 8 bytes */ - b2f0_result = 5; - - if (residual_length) - *residual_length = abs (buflen - 8); - - if (residual_buffer) { - if (!moved) - *residual_buffer = (ulong) buffer; - else - *residual_buffer = - (ulong) (buffer + (i - 1)); - } - - } - } - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/** - * iucv_reject: - * @pathid: Path identification number. - * @msgid: Message ID of the message to reject. - * @trgcls: Target class of the message to reject. - * Returns: return code from CP - * - * Refuses a specified message. Between the time you are notified of a - * message and the time that you complete the message, the message may - * be rejected. - */ -int -iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls) -{ - iparml_db *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID); - - b2f0_result = b2f0(REJECT, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", b2f0_result); - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- 0x20 - specifies if you want to send priority message - * buffer - address of reply buffer - * buflen - length of reply buffer - * Output: ipbfadr2 - Address of buffer updated by the number - * of bytes you have moved. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_reply (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = (__u32) buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (__u8) flags1; /* priority message */ - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of reply buffers - * buflen - total length of reply buffers - * Output: ipbfadr2 - Address of buffer which IUCV is currently working on. - * ipbfln2f - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_reply_array (__u16 pathid, - __u32 msgid, __u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr2 = (__u32) ((ulong) buffer); - parm->ipbfln2f = buflen; /* length of message */ - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - parm->ipflags1 = (IPANSLST | flags1); - - b2f0_result = b2f0(REPLY, parm); - - if ((!b2f0_result) || (b2f0_result == 5)) { - - if (ipbfadr2) - *ipbfadr2 = parm->ipbfadr2; - if (ipbfln2f) - *ipbfln2f = parm->ipbfln2f; - } - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - path identification number - * msgid - specifies the message ID. - * trgcls - specifies target class - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter - * list. - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_reply_prmmsg (__u16 pathid, - __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->ipmsgid = msgid; - parm->iptrgcls = trgcls; - memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg)); - parm->ipflags1 = (IPRMDATA | flags1); - - b2f0_result = b2f0(REPLY, parm); - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/** - * iucv_resume: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function restores communication over a quiesced path. - * Returns: return code from CP - */ -int -iucv_resume (__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - iucv_debug(1, "pathid = %d", pathid); - - parm = (iparml_control *)grab_param(); - - memcpy (parm->ipuser, user_data, sizeof (*user_data)); - parm->ippathid = pathid; - - b2f0_result = b2f0(RESUME, parm); - release_param(parm); - - iucv_debug(1, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send - * Purpose: sends messages - * Input: pathid - ushort, pathid - * msgid - ulong *, id of message returned to caller - * trgcls - ulong, target message class - * srccls - ulong, source message class - * msgtag - ulong, message tag - * flags1 - Contains options for this path. - * IPPRTY - Ox20 - specifies if you want to send a priority message. - * buffer - pointer to buffer - * buflen - ulong, length of buffer - * Output: b2f0_result - return code from b2f0 call - * msgid - returns message id - */ -int -iucv_send (__u16 pathid, __u32 * msgid, - __u32 trgcls, __u32 srccls, - __u32 msgtag, int flags1, void *buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated witht the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPNORPY | IPBUFLST | flags1); - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into parameter list - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP -*/ -int -iucv_send_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8]) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPRMDATA | IPNORPY | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of send buffer - * buflen - length of send buffer - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer or ansbuf address is NULL - */ -int -iucv_send2way (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = flags1; /* priority message */ - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - spcifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * buffer - address of array of send buffers - * buflen - total length of send buffers - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL - */ -int -iucv_send2way_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen) -{ - iparml_db *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!buffer || !ansbuf) - return -EINVAL; - - parm = (iparml_db *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipbfadr1 = (__u32) ((ulong) buffer); - parm->ipbfln1f = (__u32) buflen; /* length of message */ - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipflags1 = (IPBUFLST | IPANSLST | flags1); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed in parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - buffer address is NULL -*/ -int -iucv_send2way_prmmsg (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */ - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - - b2f0_result = b2f0(SEND, parm); - - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - - return b2f0_result; -} - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - path identification number - * trgcls - specifies target class - * srccls - specifies the source message class - * msgtag - specifies a tag to be associated with the message - * flags1 - option for path - * IPPRTY- specifies if you want to send priority message - * prmmsg - 8-bytes of data to be placed into the parameter list - * ansbuf - address of buffer to reply with - * anslen - length of buffer to reply with - * Output: msgid - specifies the message ID. - * Return: b2f0_result - return code from CP - * (-EINVAL) - ansbuf address is NULL - */ -int -iucv_send2way_prmmsg_array (__u16 pathid, - __u32 * msgid, - __u32 trgcls, - __u32 srccls, - __u32 msgtag, - int flags1, - __u8 prmmsg[8], - iucv_array_t * ansbuf, ulong anslen) -{ - iparml_dpl *parm; - ulong b2f0_result; - - iucv_debug(2, "entering"); - - if (!ansbuf) - return -EINVAL; - - parm = (iparml_dpl *)grab_param(); - - parm->ippathid = pathid; - parm->iptrgcls = trgcls; - parm->ipsrccls = srccls; - parm->ipmsgtag = msgtag; - parm->ipbfadr2 = (__u32) ((ulong) ansbuf); - parm->ipbfln2f = (__u32) anslen; - parm->ipflags1 = (IPRMDATA | IPANSLST | flags1); - memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); - b2f0_result = b2f0(SEND, parm); - if ((!b2f0_result) && (msgid)) - *msgid = parm->ipmsgid; - release_param(parm); - - iucv_debug(2, "exiting"); - return b2f0_result; -} - -void -iucv_setmask_cpuid (void *result) -{ - iparml_set_mask *parm; - - iucv_debug(1, "entering"); - parm = (iparml_set_mask *)grab_param(); - parm->ipmask = *((__u8*)result); - *((ulong *)result) = b2f0(SETMASK, parm); - release_param(parm); - - iucv_debug(1, "b2f0_result = %ld", *((ulong *)result)); - iucv_debug(1, "exiting"); -} - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: b2f0_result - return code from CP -*/ -int -iucv_setmask (int SetMaskFlag) -{ - union { - ulong result; - __u8 param; - } u; - int cpu; - - u.param = SetMaskFlag; - cpu = get_cpu(); - smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid); - put_cpu(); - - return u.result; -} - -/** - * iucv_sever: - * @pathid: Path identification number - * @user_data: 16-byte of user data - * - * This function terminates an iucv path. - * Returns: return code from CP - */ -int -iucv_sever(__u16 pathid, __u8 user_data[16]) -{ - iparml_control *parm; - ulong b2f0_result = 0; - - iucv_debug(1, "entering"); - parm = (iparml_control *)grab_param(); - - memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); - parm->ippathid = pathid; - - b2f0_result = b2f0(SEVER, parm); - - if (!b2f0_result) - iucv_remove_pathid(pathid); - release_param(parm); - - iucv_debug(1, "exiting"); - return b2f0_result; -} - -/* - * Interrupt Handlers - *******************************************************************************/ - -/** - * iucv_irq_handler: - * @regs: Current registers - * @code: irq code - * - * Handles external interrupts coming in from CP. - * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler(). - */ -static void -iucv_irq_handler(__u16 code) -{ - iucv_irqdata *irqdata; - - irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC); - if (!irqdata) { - printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); - return; - } - - memcpy(&irqdata->data, iucv_external_int_buffer, - sizeof(iucv_GeneralInterrupt)); - - spin_lock(&iucv_irq_queue_lock); - list_add_tail(&irqdata->queue, &iucv_irq_queue); - spin_unlock(&iucv_irq_queue_lock); - - tasklet_schedule(&iucv_tasklet); -} - -/** - * iucv_do_int: - * @int_buf: Pointer to copy of external interrupt buffer - * - * The workhorse for handling interrupts queued by iucv_irq_handler(). - * This function is called from the bottom half iucv_tasklet_handler(). - */ -static void -iucv_do_int(iucv_GeneralInterrupt * int_buf) -{ - handler *h = NULL; - struct list_head *lh; - ulong flags; - iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */ - __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */ - int rc = 0, j = 0; - __u8 no_listener[16] = "NO LISTENER"; - - iucv_debug(2, "entering, pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - iucv_dumpit("External Interrupt Buffer:", - int_buf, sizeof(iucv_GeneralInterrupt)); - - ASCEBC (no_listener, 16); - - if (int_buf->iptype != 01) { - if ((int_buf->ippathid) > (max_connections - 1)) { - printk(KERN_WARNING "%s: Got interrupt with pathid %d" - " > max_connections (%ld)\n", __FUNCTION__, - int_buf->ippathid, max_connections - 1); - } else { - h = iucv_pathid_table[int_buf->ippathid]; - interrupt = h->interrupt_table; - iucv_dumpit("Handler:", h, sizeof(handler)); - } - } - - /* end of if statement */ - switch (int_buf->iptype) { - case 0x01: /* connection pending */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - spin_lock_irqsave(&iucv_lock, flags); - list_for_each(lh, &iucv_handler_table) { - h = list_entry(lh, handler, list); - memcpy(temp_buff1, &(int_buf->ipvmid), 24); - memcpy(temp_buff2, &(h->id.userid), 24); - for (j = 0; j < 24; j++) { - temp_buff1[j] &= (h->id.mask)[j]; - temp_buff2[j] &= (h->id.mask)[j]; - } - - iucv_dumpit("temp_buff1:", - temp_buff1, sizeof(temp_buff1)); - iucv_dumpit("temp_buff2", - temp_buff2, sizeof(temp_buff2)); - - if (!memcmp (temp_buff1, temp_buff2, 24)) { - - iucv_debug(2, - "found a matching handler"); - break; - } else - h = NULL; - } - spin_unlock_irqrestore (&iucv_lock, flags); - if (h) { - /* ADD PATH TO PATHID TABLE */ - rc = iucv_add_pathid(int_buf->ippathid, h); - if (rc) { - iucv_sever (int_buf->ippathid, - no_listener); - iucv_debug(1, - "add_pathid failed, rc = %d", - rc); - } else { - interrupt = h->interrupt_table; - if (interrupt->ConnectionPending) { - EBCASC (int_buf->ipvmid, 8); - interrupt->ConnectionPending( - (iucv_ConnectionPending *)int_buf, - h->pgm_data); - } else - iucv_sever(int_buf->ippathid, - no_listener); - } - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x02: /*connection complete */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionComplete) - { - interrupt->ConnectionComplete( - (iucv_ConnectionComplete *)int_buf, - h->pgm_data); - } - else - iucv_debug(1, - "ConnectionComplete not called"); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x03: /* connection severed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionSevered) - interrupt->ConnectionSevered( - (iucv_ConnectionSevered *)int_buf, - h->pgm_data); - - else - iucv_sever (int_buf->ippathid, no_listener); - } else - iucv_sever(int_buf->ippathid, no_listener); - break; - - case 0x04: /* connection quiesced */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionQuiesced) - interrupt->ConnectionQuiesced( - (iucv_ConnectionQuiesced *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionQuiesced not called"); - } - break; - - case 0x05: /* connection resumed */ - if (messagesDisabled) { - iucv_setmask(~0); - messagesDisabled = 0; - } - if (h) { - if (interrupt->ConnectionResumed) - interrupt->ConnectionResumed( - (iucv_ConnectionResumed *)int_buf, - h->pgm_data); - else - iucv_debug(1, - "ConnectionResumed not called"); - } - break; - - case 0x06: /* priority message complete */ - case 0x07: /* nonpriority message complete */ - if (h) { - if (interrupt->MessageComplete) - interrupt->MessageComplete( - (iucv_MessageComplete *)int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessageComplete not called"); - } - break; - - case 0x08: /* priority message pending */ - case 0x09: /* nonpriority message pending */ - if (h) { - if (interrupt->MessagePending) - interrupt->MessagePending( - (iucv_MessagePending *) int_buf, - h->pgm_data); - else - iucv_debug(2, - "MessagePending not called"); - } - break; - default: /* unknown iucv type */ - printk(KERN_WARNING "%s: unknown iucv interrupt\n", - __FUNCTION__); - break; - } /* end switch */ - - iucv_debug(2, "exiting pathid %d, type %02X", - int_buf->ippathid, int_buf->iptype); - - return; -} - -/** - * iucv_tasklet_handler: - * - * This function loops over the queue of irq buffers and runs iucv_do_int() - * on every queue element. - */ -static void -iucv_tasklet_handler(unsigned long ignored) -{ - struct list_head head; - struct list_head *next; - ulong flags; - - spin_lock_irqsave(&iucv_irq_queue_lock, flags); - list_add(&head, &iucv_irq_queue); - list_del_init(&iucv_irq_queue); - spin_unlock_irqrestore (&iucv_irq_queue_lock, flags); - - next = head.next; - while (next != &head) { - iucv_irqdata *p = list_entry(next, iucv_irqdata, queue); - - next = next->next; - iucv_do_int(&p->data); - kfree(p); - } - - return; -} - -subsys_initcall(iucv_init); -module_exit(iucv_exit); - -/** - * Export all public stuff - */ -EXPORT_SYMBOL (iucv_bus); -EXPORT_SYMBOL (iucv_root); -EXPORT_SYMBOL (iucv_accept); -EXPORT_SYMBOL (iucv_connect); -#if 0 -EXPORT_SYMBOL (iucv_purge); -EXPORT_SYMBOL (iucv_query_maxconn); -EXPORT_SYMBOL (iucv_query_bufsize); -EXPORT_SYMBOL (iucv_quiesce); -#endif -EXPORT_SYMBOL (iucv_receive); -#if 0 -EXPORT_SYMBOL (iucv_receive_array); -#endif -EXPORT_SYMBOL (iucv_reject); -#if 0 -EXPORT_SYMBOL (iucv_reply); -EXPORT_SYMBOL (iucv_reply_array); -EXPORT_SYMBOL (iucv_resume); -#endif -EXPORT_SYMBOL (iucv_reply_prmmsg); -EXPORT_SYMBOL (iucv_send); -EXPORT_SYMBOL (iucv_send2way); -EXPORT_SYMBOL (iucv_send2way_array); -EXPORT_SYMBOL (iucv_send2way_prmmsg); -EXPORT_SYMBOL (iucv_send2way_prmmsg_array); -#if 0 -EXPORT_SYMBOL (iucv_send_array); -EXPORT_SYMBOL (iucv_send_prmmsg); -EXPORT_SYMBOL (iucv_setmask); -#endif -EXPORT_SYMBOL (iucv_sever); -EXPORT_SYMBOL (iucv_register_program); -EXPORT_SYMBOL (iucv_unregister_program); diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h deleted file mode 100644 index 5b6b1b7241c9..000000000000 --- a/drivers/s390/net/iucv.h +++ /dev/null @@ -1,849 +0,0 @@ -/* - * drivers/s390/net/iucv.h - * IUCV base support. - * - * S390 version - * Copyright (C) 2000 IBM Corporation - * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) - * Xenia Tkatschow (xenia@us.ibm.com) - * - * - * Functionality: - * To explore any of the IUCV functions, one must first register - * their program using iucv_register_program(). Once your program has - * successfully completed a register, it can exploit the other functions. - * For furthur reference on all IUCV functionality, refer to the - * CP Programming Services book, also available on the web - * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - * Definition of Return Codes - * -All positive return codes including zero are reflected back - * from CP except for iucv_register_program. The definition of each - * return code can be found in CP Programming Services book. - * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 - * - Return Code of: - * (-EINVAL) Invalid value - * (-ENOMEM) storage allocation failed - * pgmask defined in iucv_register_program will be set depending on input - * paramters. - * - */ - -#include -#include - -/** - * Debug Facility stuff - */ -#define IUCV_DBF_SETUP_NAME "iucv_setup" -#define IUCV_DBF_SETUP_LEN 32 -#define IUCV_DBF_SETUP_PAGES 2 -#define IUCV_DBF_SETUP_NR_AREAS 1 -#define IUCV_DBF_SETUP_LEVEL 3 - -#define IUCV_DBF_DATA_NAME "iucv_data" -#define IUCV_DBF_DATA_LEN 128 -#define IUCV_DBF_DATA_PAGES 2 -#define IUCV_DBF_DATA_NR_AREAS 1 -#define IUCV_DBF_DATA_LEVEL 2 - -#define IUCV_DBF_TRACE_NAME "iucv_trace" -#define IUCV_DBF_TRACE_LEN 16 -#define IUCV_DBF_TRACE_PAGES 4 -#define IUCV_DBF_TRACE_NR_AREAS 1 -#define IUCV_DBF_TRACE_LEVEL 3 - -#define IUCV_DBF_TEXT(name,level,text) \ - do { \ - debug_text_event(iucv_dbf_##name,level,text); \ - } while (0) - -#define IUCV_DBF_HEX(name,level,addr,len) \ - do { \ - debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ - } while (0) - -DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); - -#define IUCV_DBF_TEXT_(name,level,text...) \ - do { \ - char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ - sprintf(iucv_dbf_txt_buf, text); \ - debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ - put_cpu_var(iucv_dbf_txt_buf); \ - } while (0) - -#define IUCV_DBF_SPRINTF(name,level,text...) \ - do { \ - debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ - debug_sprintf_event(iucv_dbf_trace, level, text ); \ - } while (0) - -/** - * some more debug stuff - */ -#define IUCV_HEXDUMP16(importance,header,ptr) \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ - *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ - *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ - *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ - *(((char*)ptr)+12),*(((char*)ptr)+13), \ - *(((char*)ptr)+14),*(((char*)ptr)+15)); \ -PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ - "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ - *(((char*)ptr)+16),*(((char*)ptr)+17), \ - *(((char*)ptr)+18),*(((char*)ptr)+19), \ - *(((char*)ptr)+20),*(((char*)ptr)+21), \ - *(((char*)ptr)+22),*(((char*)ptr)+23), \ - *(((char*)ptr)+24),*(((char*)ptr)+25), \ - *(((char*)ptr)+26),*(((char*)ptr)+27), \ - *(((char*)ptr)+28),*(((char*)ptr)+29), \ - *(((char*)ptr)+30),*(((char*)ptr)+31)); - -static inline void -iucv_hex_dump(unsigned char *buf, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (i && !(i % 16)) - printk("\n"); - printk("%02x ", *(buf + i)); - } - printk("\n"); -} -/** - * end of debug stuff - */ - -#define uchar unsigned char -#define ushort unsigned short -#define ulong unsigned long -#define iucv_handle_t void * - -/* flags1: - * All flags are defined in the field IPFLAGS1 of each function - * and can be found in CP Programming Services. - * IPLOCAL - Indicates the connect can only be satisfied on the - * local system - * IPPRTY - Indicates a priority message - * IPQUSCE - Indicates you do not want to receive messages on a - * path until an iucv_resume is issued - * IPRMDATA - Indicates that the message is in the parameter list - */ -#define IPLOCAL 0x01 -#define IPPRTY 0x20 -#define IPQUSCE 0x40 -#define IPRMDATA 0x80 - -/* flags1_out: - * All flags are defined in the output field of IPFLAGS1 for each function - * and can be found in CP Programming Services. - * IPNORPY - Specifies this is a one-way message and no reply is expected. - * IPPRTY - Indicates a priority message is permitted. Defined in flags1. - */ -#define IPNORPY 0x10 - -#define Nonpriority_MessagePendingInterruptsFlag 0x80 -#define Priority_MessagePendingInterruptsFlag 0x40 -#define Nonpriority_MessageCompletionInterruptsFlag 0x20 -#define Priority_MessageCompletionInterruptsFlag 0x10 -#define IUCVControlInterruptsFlag 0x08 -#define AllInterrupts 0xf8 -/* - * Mapping of external interrupt buffers should be used with the corresponding - * interrupt types. - * Names: iucv_ConnectionPending -> connection pending - * iucv_ConnectionComplete -> connection complete - * iucv_ConnectionSevered -> connection severed - * iucv_ConnectionQuiesced -> connection quiesced - * iucv_ConnectionResumed -> connection resumed - * iucv_MessagePending -> message pending - * iucv_MessageComplete -> message complete - */ -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar ipvmid[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionPending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u16 ipmsglim; - u16 res1; - uchar res2[8]; - uchar ipuser[16]; - u32 res3; - uchar ippollfg; - uchar res4[3]; -} iucv_ConnectionComplete; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionSevered; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionQuiesced; - -typedef struct { - u16 ippathid; - uchar res1; - uchar iptype; - u32 res2; - uchar res3[8]; - uchar ipuser[16]; - u32 res4; - uchar ippollfg; - uchar res5[3]; -} iucv_ConnectionResumed; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 iptrgcls; - union u2 { - u32 iprmmsg1_u32; - uchar iprmmsg1[4]; - } ln1msg1; - union u1 { - u32 ipbfln1f; - uchar iprmmsg2[4]; - } ln1msg2; - u32 res1[3]; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessagePending; - -typedef struct { - u16 ippathid; - uchar ipflags1; - uchar iptype; - u32 ipmsgid; - u32 ipaudit; - uchar iprmmsg[8]; - u32 ipsrccls; - u32 ipmsgtag; - u32 res; - u32 ipbfln2f; - uchar ippollfg; - uchar res2[3]; -} iucv_MessageComplete; - -/* - * iucv_interrupt_ops_t: Is a vector of functions that handle - * IUCV interrupts. - * Parameter list: - * eib - is a pointer to a 40-byte area described - * with one of the structures above. - * pgm_data - this data is strictly for the - * interrupt handler that is passed by - * the application. This may be an address - * or token. -*/ -typedef struct { - void (*ConnectionPending) (iucv_ConnectionPending * eib, - void *pgm_data); - void (*ConnectionComplete) (iucv_ConnectionComplete * eib, - void *pgm_data); - void (*ConnectionSevered) (iucv_ConnectionSevered * eib, - void *pgm_data); - void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib, - void *pgm_data); - void (*ConnectionResumed) (iucv_ConnectionResumed * eib, - void *pgm_data); - void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data); - void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data); -} iucv_interrupt_ops_t; - -/* - *iucv_array_t : Defines buffer array. - * Inside the array may be 31- bit addresses and 31-bit lengths. -*/ -typedef struct { - u32 address; - u32 length; -} iucv_array_t __attribute__ ((aligned (8))); - -extern struct bus_type iucv_bus; -extern struct device *iucv_root; - -/* -prototypes- */ -/* - * Name: iucv_register_program - * Purpose: Registers an application with IUCV - * Input: prmname - user identification - * userid - machine identification - * pgmmask - indicates which bits in the prmname and userid combined will be - * used to determine who is given control - * ops - address of vector of interrupt handlers - * pgm_data- application data passed to interrupt handlers - * Output: NA - * Return: address of handler - * (0) - Error occurred, registration not completed. - * NOTE: Exact cause of failure will be recorded in syslog. -*/ -iucv_handle_t iucv_register_program (uchar pgmname[16], - uchar userid[8], - uchar pgmmask[24], - iucv_interrupt_ops_t * ops, - void *pgm_data); - -/* - * Name: iucv_unregister_program - * Purpose: Unregister application with IUCV - * Input: address of handler - * Output: NA - * Return: (0) - Normal return - * (-EINVAL) - Internal error, wild pointer -*/ -int iucv_unregister_program (iucv_handle_t handle); - -/* - * Name: iucv_accept - * Purpose: This function is issued after the user receives a Connection Pending external - * interrupt and now wishes to complete the IUCV communication path. - * Input: pathid - u16 , Path identification number - * msglim_reqstd - u16, The number of outstanding messages requested. - * user_data - uchar[16], Data specified by the iucv_connect function. - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20- Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * handle - iucv_handle_t, Address of handler. - * pgm_data - void *, Application data passed to interrupt handlers. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - *u16, Number of outstanding messages. - * Output: return code from CP IUCV call. -*/ - -int iucv_accept (u16 pathid, - u16 msglim_reqstd, - uchar user_data[16], - int flags1, - iucv_handle_t handle, - void *pgm_data, int *flags1_out, u16 * msglim); - -/* - * Name: iucv_connect - * Purpose: This function establishes an IUCV path. Although the connect may complete - * successfully, you are not able to use the path until you receive an IUCV - * Connection Complete external interrupt. - * Input: pathid - u16 *, Path identification number - * msglim_reqstd - u16, Number of outstanding messages requested - * user_data - uchar[16], 16-byte user data - * userid - uchar[8], User identification - * system_name - uchar[8], 8-byte identifying the system name - * flags1 - int, Contains options for this path. - * -IPPRTY - 0x20, Specifies if you want to send priority message. - * -IPRMDATA - 0x80, Specifies whether your program can handle a message - * in the parameter list. - * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being - * established. - * -IPLOCAL - 0X01, Allows an application to force the partner to be on - * the local system. If local is specified then target class cannot be - * specified. - * flags1_out - int * Contains information about the path - * - IPPRTY - 0x20, Indicates you may send priority messages. - * msglim - * u16, Number of outstanding messages - * handle - iucv_handle_t, Address of handler - * pgm_data - void *, Application data passed to interrupt handlers - * Output: return code from CP IUCV call - * rc - return code from iucv_declare_buffer - * -EINVAL - Invalid handle passed by application - * -EINVAL - Pathid address is NULL - * add_pathid_result - Return code from internal function add_pathid -*/ -int - iucv_connect (u16 * pathid, - u16 msglim_reqstd, - uchar user_data[16], - uchar userid[8], - uchar system_name[8], - int flags1, - int *flags1_out, - u16 * msglim, iucv_handle_t handle, void *pgm_data); - -/* - * Name: iucv_purge - * Purpose: This function cancels a message that you have sent. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID of the message to be purged. - * srccls - Specifies the source message class. - * Output: audit - Contains information about asynchronous error - * that may have affected the normal completion - * of this message. - * Return: Return code from CP IUCV call. -*/ -int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit); -/* - * Name: iucv_query_maxconn - * Purpose: This function determines the maximum number of communication paths you - * may establish. - * Return: maxconn - ulong, Maximum number of connection the virtual machine may - * establish. -*/ -ulong iucv_query_maxconn (void); - -/* - * Name: iucv_query_bufsize - * Purpose: This function determines how large an external interrupt - * buffer IUCV requires to store information. - * Return: bufsize - ulong, Size of external interrupt buffer. - */ -ulong iucv_query_bufsize (void); - -/* - * Name: iucv_quiesce - * Purpose: This function temporarily suspends incoming messages on an - * IUCV path. You can later reactivate the path by invoking - * the iucv_resume function. - * Input: pathid - Path identification number - * user_data - 16-bytes of user data - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_quiesce (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_receive - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in buffer for length of - * buflen. - * Input: - * pathid - Path identification number. - * buffer - Address of buffer to receive. - * buflen - Length of buffer to receive. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address of buffer updated by the number - * of bytes you have received. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - buffer address is pointing to NULL -*/ -int iucv_receive (u16 pathid, - u32 msgid, - u32 trgcls, - void *buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - - /* - * Name: iucv_receive_array - * Purpose: This function receives messages that are being sent to you - * over established paths. Data will be returned in first buffer for - * length of first buffer. - * Input: pathid - Path identification number. - * msgid - specifies the message ID. - * trgcls - Specifies target class. - * buffer - Address of array of buffers. - * buflen - Total length of buffers. - * Output: - * flags1_out: int *, Contains information about this path. - * IPNORPY - 0x10 Specifies this is a one-way message and no reply is - * expected. - * IPPRTY - 0x20 Specifies if you want to send priority message. - * IPRMDATA - 0x80 specifies the data is contained in the parameter list - * residual_buffer - address points to the current list entry IUCV - * is working on. - * residual_length - - * Contains one of the following values, if the receive buffer is: - * The same length as the message, this field is zero. - * Longer than the message, this field contains the number of - * bytes remaining in the buffer. - * Shorter than the message, this field contains the residual - * count (that is, the number of bytes remaining in the - * message that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. - */ -int iucv_receive_array (u16 pathid, - u32 msgid, - u32 trgcls, - iucv_array_t * buffer, - ulong buflen, - int *flags1_out, - ulong * residual_buffer, ulong * residual_length); - -/* - * Name: iucv_reject - * Purpose: The reject function refuses a specified message. Between the - * time you are notified of a message and the time that you - * complete the message, the message may be rejected. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reject (u16 pathid, u32 msgid, u32 trgcls); - -/* - * Name: iucv_reply - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of reply buffer. - * buflen - Length of reply buffer. - * Output: residual_buffer - Address of buffer updated by the number - * of bytes you have moved. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - void *buffer, ulong buflen, ulong * residual_buffer, - ulong * residual_length); - -/* - * Name: iucv_reply_array - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * The array identifies a list of addresses and lengths of - * discontiguous buffers that contains the reply data. - * Input: pathid - Path identification number - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20, Specifies if you want to send priority message. - * buffer - Address of array of reply buffers. - * buflen - Total length of reply buffers. - * Output: residual_buffer - Address of buffer which IUCV is currently working on. - * residual_length - Contains one of the following values: - * If the answer buffer is the same length as the reply, this field - * contains zero. - * If the answer buffer is longer than the reply, this field contains - * the number of bytes remaining in the buffer. - * If the answer buffer is shorter than the reply, this field contains - * a residual count (that is, the number of bytes remianing in the - * reply that does not fit into the buffer. In this - * case b2f0_result = 5. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_reply_array (u16 pathid, - u32 msgid, - u32 trgcls, - int flags1, - iucv_array_t * buffer, - ulong buflen, ulong * residual_address, - ulong * residual_length); - -/* - * Name: iucv_reply_prmmsg - * Purpose: This function responds to the two-way messages that you - * receive. You must identify completely the message to - * which you wish to reply. ie, pathid, msgid, and trgcls. - * Prmmsg signifies the data is moved into the - * parameter list. - * Input: pathid - Path identification number. - * msgid - Specifies the message ID. - * trgcls - Specifies target class. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter. - * list. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_reply_prmmsg (u16 pathid, - u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_resume - * Purpose: This function restores communications over a quiesced path - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_resume (u16 pathid, uchar user_data[16]); - -/* - * Name: iucv_send - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer and this is a - * one-way message and the receiver will not reply to the - * message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen); - -/* - * Name: iucv_send_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated witht the message. - * flags1 - Option for path. - * IPPRTY- specifies if you want to send priority message. - * buffer - Address of array of send buffers. - * buflen - Total length of send buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, iucv_array_t * buffer, ulong buflen); - -/* - * Name: iucv_send_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a one-way message and the - * receiver will not reply to the message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into parameter list. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. -*/ -int iucv_send_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]); - -/* - * Name: iucv_send2way - * Purpose: This function transmits data to another application. - * Data to be transmitted is in a buffer. The receiver - * of the send is expected to reply to the message and - * a buffer is provided into which IUCV moves the reply - * to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Address of send buffer. - * buflen - Length of send buffer. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer or ansbuf address is NULL. -*/ -int iucv_send2way (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - void *buffer, ulong buflen, void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_array - * Purpose: This function transmits data to another application. - * The contents of buffer is the address of the array of - * addresses and lengths of discontiguous buffers that hold - * the message text. The receiver of the send is expected to - * reply to the message and a buffer is provided into which - * IUCV moves the reply to this message. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * buffer - Sddress of array of send buffers. - * buflen - Total length of send buffers. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - iucv_array_t * buffer, - ulong buflen, iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. - * Input: pathid - Rath identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 Specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed in parameter list. - * ansbuf - Address of buffer into which IUCV moves the reply of - * this message. - * anslen - Address of length of buffer. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Buffer address is NULL. -*/ -int iucv_send2way_prmmsg (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - ulong flags1, - uchar prmmsg[8], void *ansbuf, ulong anslen); - -/* - * Name: iucv_send2way_prmmsg_array - * Purpose: This function transmits data to another application. - * Prmmsg specifies that the 8-bytes of data are to be moved - * into the parameter list. This is a two-way message and the - * receiver of the message is expected to reply. A buffer - * is provided into which IUCV moves the reply to this - * message. The contents of ansbuf is the address of the - * array of addresses and lengths of discontiguous buffers - * that contain the reply. - * Input: pathid - Path identification number. - * trgcls - Specifies target class. - * srccls - Specifies the source message class. - * msgtag - Specifies a tag to be associated with the message. - * flags1 - Option for path. - * IPPRTY- 0x20 specifies if you want to send priority message. - * prmmsg - 8-bytes of data to be placed into the parameter list. - * ansbuf - Address of array of buffer into which IUCV moves the reply - * of this message. - * anslen - Address of length of reply buffers. - * Output: msgid - Specifies the message ID. - * Return: Return code from CP IUCV call. - * (-EINVAL) - Ansbuf address is NULL. -*/ -int iucv_send2way_prmmsg_array (u16 pathid, - u32 * msgid, - u32 trgcls, - u32 srccls, - u32 msgtag, - int flags1, - uchar prmmsg[8], - iucv_array_t * ansbuf, ulong anslen); - -/* - * Name: iucv_setmask - * Purpose: This function enables or disables the following IUCV - * external interruptions: Nonpriority and priority message - * interrupts, nonpriority and priority reply interrupts. - * Input: SetMaskFlag - options for interrupts - * 0x80 - Nonpriority_MessagePendingInterruptsFlag - * 0x40 - Priority_MessagePendingInterruptsFlag - * 0x20 - Nonpriority_MessageCompletionInterruptsFlag - * 0x10 - Priority_MessageCompletionInterruptsFlag - * 0x08 - IUCVControlInterruptsFlag - * Output: NA - * Return: Return code from CP IUCV call. -*/ -int iucv_setmask (int SetMaskFlag); - -/* - * Name: iucv_sever - * Purpose: This function terminates an IUCV path. - * Input: pathid - Path identification number. - * user_data - 16-bytes of user data. - * Output: NA - * Return: Return code from CP IUCV call. - * (-EINVAL) - Interal error, wild pointer. -*/ -int iucv_sever (u16 pathid, uchar user_data[16]); -- cgit v1.2.3 From c667aac8009b41ecaecb1fc72476553cf12d4732 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 8 Feb 2007 13:38:11 -0800 Subject: [S390]: Adapt monreader driver to new IUCV API Adapt monreader character device driver to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller --- drivers/s390/char/monreader.c | 218 +++++++++++++++++++----------------------- 1 file changed, 101 insertions(+), 117 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index a138b1510093..3a1a958fb5f2 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -3,7 +3,7 @@ * * Character device driver for reading z/VM *MONITOR service records. * - * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. + * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. * * Author: Gerald Schaefer */ @@ -22,7 +22,7 @@ #include #include #include -#include "../net/iucv.h" +#include //#define MON_DEBUG /* Debug messages on/off */ @@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\0"; struct mon_msg { u32 pos; u32 mca_offset; - iucv_MessagePending local_eib; + struct iucv_message msg; char msglim_reached; char replied_msglim; }; struct mon_private { - u16 pathid; - iucv_handle_t iucv_handle; + struct iucv_path *path; struct mon_msg *msg_array[MON_MSGLIM]; unsigned int write_index; unsigned int read_index; @@ -75,8 +74,6 @@ static unsigned long mon_dcss_end; static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue); static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue); -static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static u8 user_data_connect[16] = { /* Version code, must be 0x01 for shared mode */ 0x01, @@ -100,8 +97,7 @@ static u8 user_data_sever[16] = { * Create the 8 bytes EBCDIC DCSS segment name from * an ASCII name, incl. padding */ -static inline void -dcss_mkname(char *ascii_name, char *ebcdic_name) +static inline void dcss_mkname(char *ascii_name, char *ebcdic_name) { int i; @@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcdic_name) * print appropriate error message for segment_load()/segment_type() * return code */ -static void -mon_segment_warn(int rc, char* seg_name) +static void mon_segment_warn(int rc, char* seg_name) { switch (rc) { case -ENOENT: @@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name) } } -static inline unsigned long -mon_mca_start(struct mon_msg *monmsg) +static inline unsigned long mon_mca_start(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg1.iprmmsg1_u32; + return *(u32 *) &monmsg->msg.rmmsg; } -static inline unsigned long -mon_mca_end(struct mon_msg *monmsg) +static inline unsigned long mon_mca_end(struct mon_msg *monmsg) { - return monmsg->local_eib.ln1msg2.ipbfln1f; + return *(u32 *) &monmsg->msg.rmmsg[4]; } -static inline u8 -mon_mca_type(struct mon_msg *monmsg, u8 index) +static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index) { return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index); } -static inline u32 -mon_mca_size(struct mon_msg *monmsg) +static inline u32 mon_mca_size(struct mon_msg *monmsg) { return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1; } -static inline u32 -mon_rec_start(struct mon_msg *monmsg) +static inline u32 mon_rec_start(struct mon_msg *monmsg) { return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4)); } -static inline u32 -mon_rec_end(struct mon_msg *monmsg) +static inline u32 mon_rec_end(struct mon_msg *monmsg) { return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8)); } -static inline int -mon_check_mca(struct mon_msg *monmsg) +static inline int mon_check_mca(struct mon_msg *monmsg) { if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || (mon_rec_start(monmsg) < mon_dcss_start) || @@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg) return 0; } -static inline int -mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline int mon_send_reply(struct mon_msg *monmsg, + struct mon_private *monpriv) { - u8 prmmsg[8]; int rc; P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " "0x%08X\n\n", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); - rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid, - monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls, - 0, prmmsg); + 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); if (likely(!monmsg->msglim_reached)) { monmsg->pos = 0; @@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) return 0; } -static inline struct mon_private * -mon_alloc_mem(void) +static inline void mon_free_mem(struct mon_private *monpriv) +{ + int i; + + for (i = 0; i < MON_MSGLIM; i++) + if (monpriv->msg_array[i]) + kfree(monpriv->msg_array[i]); + kfree(monpriv); +} + +static inline struct mon_private *mon_alloc_mem(void) { - int i,j; + int i; struct mon_private *monpriv; monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); @@ -267,16 +261,15 @@ mon_alloc_mem(void) GFP_KERNEL); if (!monpriv->msg_array[i]) { P_ERROR("open, no memory for msg_array\n"); - for (j = 0; j < i; j++) - kfree(monpriv->msg_array[j]); + mon_free_mem(monpriv); return NULL; } } return monpriv; } -static inline void -mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) +static inline void mon_read_debug(struct mon_msg *monmsg, + struct mon_private *monpriv) { #ifdef MON_DEBUG u8 msg_type[2], mca_type; @@ -284,7 +277,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; - memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2); + memcpy(msg_type, &monmsg->msg.class, 2); EBCASC(msg_type, 2); mca_type = mon_mca_type(monmsg, 0); EBCASC(&mca_type, 1); @@ -292,8 +285,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) 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", - monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, - monmsg->local_eib.iptrgcls); + 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)); @@ -306,8 +298,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) #endif } -static inline void -mon_next_mca(struct mon_msg *monmsg) +static inline void mon_next_mca(struct mon_msg *monmsg) { if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) return; @@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg) monmsg->pos = 0; } -static inline struct mon_msg * -mon_next_message(struct mon_private *monpriv) +static inline struct mon_msg *mon_next_message(struct mon_private *monpriv) { struct mon_msg *monmsg; @@ -342,39 +332,37 @@ mon_next_message(struct mon_private *monpriv) /****************************************************************************** * IUCV handler * *****************************************************************************/ -static void -mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data) +static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + 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", - eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]); + ipuser[0], ipuser[1], ipuser[2]); atomic_set(&monpriv->iucv_connected, 1); wake_up(&mon_conn_wait_queue); } -static void -mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data) +static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; - P_ERROR("IUCV connection severed with rc = 0x%X\n", - (u8) eib->ipuser[0]); + P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); + iucv_path_sever(path, NULL); atomic_set(&monpriv->iucv_severed, 1); wake_up(&mon_conn_wait_queue); wake_up_interruptible(&mon_read_wait_queue); } -static void -mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) +static void mon_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct mon_private *monpriv = (struct mon_private *) pgm_data; + struct mon_private *monpriv = path->private; P_DEBUG("IUCV message pending\n"); - memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib, - sizeof(iucv_MessagePending)); + memcpy(&monpriv->msg_array[monpriv->write_index]->msg, + msg, sizeof(*msg)); if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { P_WARNING("IUCV message pending, message limit (%i) reached\n", MON_MSGLIM); @@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) wake_up_interruptible(&mon_read_wait_queue); } -static iucv_interrupt_ops_t mon_iucvops = { - .ConnectionComplete = mon_iucv_ConnectionComplete, - .ConnectionSevered = mon_iucv_ConnectionSevered, - .MessagePending = mon_iucv_MessagePending, +static struct iucv_handler monreader_iucv_handler = { + .path_complete = mon_iucv_path_complete, + .path_severed = mon_iucv_path_severed, + .message_pending = mon_iucv_message_pending, }; /****************************************************************************** * file operations * *****************************************************************************/ -static int -mon_open(struct inode *inode, struct file *filp) +static int mon_open(struct inode *inode, struct file *filp) { - int rc, i; struct mon_private *monpriv; + int rc; /* * only one user allowed */ + rc = -EBUSY; if (test_and_set_bit(MON_IN_USE, &mon_in_use)) - return -EBUSY; + goto out; + rc = -ENOMEM; monpriv = mon_alloc_mem(); if (!monpriv) - return -ENOMEM; + goto out_use; /* - * Register with IUCV and connect to *MONITOR service + * Connect to *MONITOR service */ - monpriv->iucv_handle = iucv_register_program("my_monreader ", - MON_SERVICE, - NULL, - &mon_iucvops, - monpriv); - if (!monpriv->iucv_handle) { - P_ERROR("failed to register with iucv driver\n"); - rc = -EIO; - goto out_error; - } - P_INFO("open, registered with IUCV\n"); - - rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect, - MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL, - monpriv->iucv_handle, NULL); + monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); + if (!monpriv->path) + goto out_priv; + rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, + MON_SERVICE, NULL, user_data_connect, monpriv); if (rc) { P_ERROR("iucv connection to *MONITOR failed with " "IPUSER SEVER code = %i\n", rc); rc = -EIO; - goto out_unregister; + goto out_path; } /* * Wait for connection confirmation @@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct file *filp) atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); rc = -EIO; - goto out_unregister; + goto out_path; } P_INFO("open, established connection to *MONITOR service\n\n"); filp->private_data = monpriv; return nonseekable_open(inode, filp); -out_unregister: - iucv_unregister_program(monpriv->iucv_handle); -out_error: - for (i = 0; i < MON_MSGLIM; i++) - kfree(monpriv->msg_array[i]); - kfree(monpriv); +out_path: + kfree(monpriv->path); +out_priv: + mon_free_mem(monpriv); +out_use: clear_bit(MON_IN_USE, &mon_in_use); +out: return rc; } -static int -mon_close(struct inode *inode, struct file *filp) +static int mon_close(struct inode *inode, struct file *filp) { int rc, i; struct mon_private *monpriv = filp->private_data; @@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct file *filp) /* * Close IUCV connection and unregister */ - rc = iucv_sever(monpriv->pathid, user_data_sever); + 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"); - rc = iucv_unregister_program(monpriv->iucv_handle); - if (rc) - P_ERROR("close, iucv_unregister failed with rc = %i\n", rc); - else - P_INFO("close, unregistered with IUCV\n"); - atomic_set(&monpriv->iucv_severed, 0); atomic_set(&monpriv->iucv_connected, 0); atomic_set(&monpriv->read_ready, 0); @@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct file *filp) return 0; } -static ssize_t -mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) +static ssize_t mon_read(struct file *filp, char __user *data, + size_t count, loff_t *ppos) { struct mon_private *monpriv = filp->private_data; struct mon_msg *monmsg; @@ -563,8 +535,7 @@ out_copy: return count; } -static unsigned int -mon_poll(struct file *filp, struct poll_table_struct *p) +static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p) { struct mon_private *monpriv = filp->private_data; @@ -593,8 +564,7 @@ static struct miscdevice mon_dev = { /****************************************************************************** * module init/exit * *****************************************************************************/ -static int __init -mon_init(void) +static int __init mon_init(void) { int rc; @@ -603,22 +573,34 @@ mon_init(void) return -ENODEV; } + /* + * Register with IUCV and connect to *MONITOR service + */ + rc = iucv_register(&monreader_iucv_handler, 1); + if (rc) { + 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) { mon_segment_warn(rc, mon_dcss_name); - return rc; + goto out_iucv; } if (rc != SEG_TYPE_SC) { P_ERROR("segment %s has unsupported type, should be SC\n", mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } rc = segment_load(mon_dcss_name, SEGMENT_SHARED, &mon_dcss_start, &mon_dcss_end); if (rc < 0) { mon_segment_warn(rc, mon_dcss_name); - return -EINVAL; + rc = -EINVAL; + goto out_iucv; } dcss_mkname(mon_dcss_name, &user_data_connect[8]); @@ -634,14 +616,16 @@ mon_init(void) out: segment_unload(mon_dcss_name); +out_iucv: + iucv_unregister(&monreader_iucv_handler, 1); return rc; } -static void __exit -mon_exit(void) +static void __exit mon_exit(void) { segment_unload(mon_dcss_name); WARN_ON(misc_deregister(&mon_dev) != 0); + iucv_unregister(&monreader_iucv_handler, 1); return; } -- cgit v1.2.3 From c9101c5b3f1d018efa36d12cdcde89955642c73d Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 8 Feb 2007 13:40:41 -0800 Subject: [S390]: Adapt vmlogrdr driver to new IUCV API Adapt vmlogrdr character device driver to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller --- drivers/s390/char/vmlogrdr.c | 279 ++++++++++++++++++++----------------------- 1 file changed, 127 insertions(+), 152 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 4f894dc2373b..8432a76b961e 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -3,7 +3,7 @@ * character device driver for reading z/VM system service records * * - * Copyright (C) 2004 IBM Corporation + * Copyright 2004 IBM Corporation * character device driver for reading z/VM system service records, * Version 1.0 * Author(s): Xenia Tkatschow @@ -21,7 +21,7 @@ #include #include #include -#include "../net/iucv.h" +#include #include #include #include @@ -60,12 +60,11 @@ struct vmlogrdr_priv_t { char system_service[8]; char internal_name[8]; char recording_name[8]; - u16 pathid; + struct iucv_path *path; int connection_established; int iucv_path_severed; - iucv_MessagePending local_interrupt_buffer; + struct iucv_message local_interrupt_buffer; atomic_t receive_ready; - iucv_handle_t iucv_handle; int minor_num; char * buffer; char * current_position; @@ -97,37 +96,19 @@ static struct file_operations vmlogrdr_fops = { }; -static u8 iucvMagic[16] = { - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, - 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 -}; +static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]); +static void vmlogrdr_iucv_message_pending(struct iucv_path *, + struct iucv_message *); -static u8 mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +static struct iucv_handler vmlogrdr_iucv_handler = { + .path_complete = vmlogrdr_iucv_path_complete, + .path_severed = vmlogrdr_iucv_path_severed, + .message_pending = vmlogrdr_iucv_message_pending, }; -static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - -static void -vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data); -static void -vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data); -static void -vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data); - - -static iucv_interrupt_ops_t vmlogrdr_iucvops = { - .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete, - .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered, - .MessagePending = vmlogrdr_iucv_MessagePending, -}; - static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); @@ -176,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL; static int recording_class_AB; -static void -vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib, - void * pgm_data) +static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + spin_lock(&logptr->priv_lock); logptr->connection_established = 1; spin_unlock(&logptr->priv_lock); wake_up(&conn_wait_queue); - return; } -static void -vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) +static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) { - u8 reason = (u8) eib->ipuser[8]; - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; + u8 reason = (u8) ipuser[8]; printk (KERN_ERR "vmlogrdr: connection severed with" " reason %i\n", reason); + iucv_path_sever(path, NULL); + kfree(path); + logptr->path = NULL; + spin_lock(&logptr->priv_lock); logptr->connection_established = 0; logptr->iucv_path_severed = 1; @@ -209,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) } -static void -vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) +static void vmlogrdr_iucv_message_pending(struct iucv_path *path, + struct iucv_message *msg) { - struct vmlogrdr_priv_t * logptr = pgm_data; + struct vmlogrdr_priv_t * logptr = path->private; /* * This function is the bottom half so it should be quick. @@ -220,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) * the usage count */ spin_lock(&logptr->priv_lock); - memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib)); + memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg)); atomic_inc(&logptr->receive_ready); spin_unlock(&logptr->priv_lock); wake_up_interruptible(&read_wait_queue); } -static int -vmlogrdr_get_recording_class_AB(void) { +static int vmlogrdr_get_recording_class_AB(void) +{ char cp_command[]="QUERY COMMAND RECORDING "; char cp_response[80]; char *tail; @@ -258,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) { } -static int -vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { +static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, + int action, int purge) +{ char cp_command[80]; char cp_response[160]; @@ -317,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { } -static int -vmlogrdr_open (struct inode *inode, struct file *filp) +static int vmlogrdr_open (struct inode *inode, struct file *filp) { int dev_num = 0; struct vmlogrdr_priv_t * logptr = NULL; @@ -328,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp) dev_num = iminor(inode); if (dev_num > MAXMINOR) return -ENODEV; - logptr = &sys_ser[dev_num]; - if (logptr == NULL) - return -ENODEV; /* * only allow for blocking reads to be open @@ -344,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp) if (logptr->dev_in_use) { spin_unlock_bh(&logptr->priv_lock); return -EBUSY; - } else { - logptr->dev_in_use = 1; - spin_unlock_bh(&logptr->priv_lock); } - + logptr->dev_in_use = 1; + logptr->connection_established = 0; + logptr->iucv_path_severed = 0; atomic_set(&logptr->receive_ready, 0); logptr->buffer_free = 1; + spin_unlock_bh(&logptr->priv_lock); /* set the file options */ filp->private_data = logptr; filp->f_op = &vmlogrdr_fops; /* start recording for this service*/ - ret=0; - if (logptr->autorecording) + if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,1,logptr->autopurge); - if (ret) - printk (KERN_WARNING "vmlogrdr: failed to start " - "recording automatically\n"); - - /* Register with iucv driver */ - logptr->iucv_handle = iucv_register_program(iucvMagic, - logptr->system_service, mask, &vmlogrdr_iucvops, - logptr); - - if (logptr->iucv_handle == NULL) { - printk (KERN_ERR "vmlogrdr: failed to register with" - "iucv driver\n"); - goto not_registered; + if (ret) + printk (KERN_WARNING "vmlogrdr: failed to start " + "recording automatically\n"); } /* create connection to the system service */ - spin_lock_bh(&logptr->priv_lock); - logptr->connection_established = 0; - logptr->iucv_path_severed = 0; - spin_unlock_bh(&logptr->priv_lock); - - connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic, - logptr->system_service, iucv_host, 0, - NULL, NULL, - logptr->iucv_handle, NULL); + logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL); + if (!logptr->path) + goto out_dev; + connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler, + logptr->system_service, NULL, NULL, + logptr); if (connect_rc) { printk (KERN_ERR "vmlogrdr: iucv connection to %s " "failed with rc %i \n", logptr->system_service, connect_rc); - goto not_connected; + goto out_path; } /* We've issued the connect and now we must wait for a @@ -398,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp) */ wait_event(conn_wait_queue, (logptr->connection_established) || (logptr->iucv_path_severed)); - if (logptr->iucv_path_severed) { - goto not_connected; - } - + if (logptr->iucv_path_severed) + goto out_record; return nonseekable_open(inode, filp); -not_connected: - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; -not_registered: +out_record: if (logptr->autorecording) vmlogrdr_recording(logptr,0,logptr->autopurge); +out_path: + kfree(logptr->path); /* kfree(NULL) is ok. */ + logptr->path = NULL; +out_dev: logptr->dev_in_use = 0; return -EIO; - - } -static int -vmlogrdr_release (struct inode *inode, struct file *filp) +static int vmlogrdr_release (struct inode *inode, struct file *filp) { int ret; struct vmlogrdr_priv_t * logptr = filp->private_data; - iucv_unregister_program(logptr->iucv_handle); - logptr->iucv_handle = NULL; - if (logptr->autorecording) { ret = vmlogrdr_recording(logptr,0,logptr->autopurge); if (ret) @@ -439,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp) } -static int -vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) +{ int rc, *temp; /* we need to keep track of two data sizes here: * The number of bytes we need to receive from iucv and @@ -461,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { * We need to return the total length of the record * + size of FENCE in the first 4 bytes of the buffer. */ - iucv_data_count = - priv->local_interrupt_buffer.ln1msg2.ipbfln1f; + iucv_data_count = priv->local_interrupt_buffer.length; user_data_count = sizeof(int); temp = (int*)priv->buffer; *temp= iucv_data_count + sizeof(FENCE); @@ -474,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { */ if (iucv_data_count > NET_BUFFER_SIZE) iucv_data_count = NET_BUFFER_SIZE; - rc = iucv_receive(priv->pathid, - priv->local_interrupt_buffer.ipmsgid, - priv->local_interrupt_buffer.iptrgcls, - buffer, - iucv_data_count, - NULL, - NULL, - &priv->residual_length); + rc = iucv_message_receive(priv->path, + &priv->local_interrupt_buffer, + 0, buffer, iucv_data_count, + &priv->residual_length); spin_unlock_bh(&priv->priv_lock); /* An rc of 5 indicates that the record was bigger then * the buffer, which is OK for us. A 9 indicates that the @@ -513,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { } -static ssize_t -vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) +static ssize_t vmlogrdr_read(struct file *filp, char __user *data, + size_t count, loff_t * ppos) { int rc; struct vmlogrdr_priv_t * priv = filp->private_data; @@ -546,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) return count; } -static ssize_t -vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_autopurge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -565,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con } -static ssize_t -vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autopurge_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autopurge); } @@ -576,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show, vmlogrdr_autopurge_store); -static ssize_t -vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { +static ssize_t vmlogrdr_purge_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ char cp_command[80]; char cp_response[80]; @@ -617,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); -static ssize_t -vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, - size_t count) { +static ssize_t vmlogrdr_autorecording_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret = count; @@ -637,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, } -static ssize_t -vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { +static ssize_t vmlogrdr_autorecording_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; return sprintf(buf, "%u\n", priv->autorecording); } @@ -648,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show, vmlogrdr_autorecording_store); -static ssize_t -vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { - +static ssize_t vmlogrdr_recording_store(struct device * dev, + struct device_attribute *attr, + const char * buf, size_t count) +{ struct vmlogrdr_priv_t *priv = dev->driver_data; ssize_t ret; @@ -675,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); -static ssize_t -vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { +static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver, + char *buf) +{ char cp_command[] = "QUERY RECORDING "; int len; @@ -709,52 +673,63 @@ static struct device_driver vmlogrdr_driver = { }; -static int -vmlogrdr_register_driver(void) { +static int vmlogrdr_register_driver(void) +{ int ret; + /* Register with iucv driver */ + ret = iucv_register(&vmlogrdr_iucv_handler, 1); + if (ret) { + printk (KERN_ERR "vmlogrdr: failed to register with" + "iucv driver\n"); + goto out; + } + ret = driver_register(&vmlogrdr_driver); if (ret) { printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); - return ret; + goto out_iucv; } ret = driver_create_file(&vmlogrdr_driver, &driver_attr_recording_status); if (ret) { printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); - goto unregdriver; + 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 unregattr; + ret = PTR_ERR(vmlogrdr_class); + vmlogrdr_class = NULL; + goto out_attr; } return 0; -unregattr: +out_attr: driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); -unregdriver: +out_driver: driver_unregister(&vmlogrdr_driver); +out_iucv: + iucv_unregister(&vmlogrdr_iucv_handler, 1); +out: return ret; } -static void -vmlogrdr_unregister_driver(void) { +static void vmlogrdr_unregister_driver(void) +{ class_destroy(vmlogrdr_class); vmlogrdr_class = NULL; driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); driver_unregister(&vmlogrdr_driver); - return; + iucv_unregister(&vmlogrdr_iucv_handler, 1); } -static int -vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { +static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) +{ struct device *dev; int ret; @@ -803,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { } -static int -vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { - class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); +static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) +{ + class_device_destroy(vmlogrdr_class, + MKDEV(vmlogrdr_major, priv->minor_num)); if (priv->device != NULL) { sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); device_unregister(priv->device); @@ -815,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { } -static int -vmlogrdr_register_cdev(dev_t dev) { +static int vmlogrdr_register_cdev(dev_t dev) +{ int rc = 0; vmlogrdr_cdev = cdev_alloc(); if (!vmlogrdr_cdev) { @@ -836,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) { } -static void -vmlogrdr_cleanup(void) { +static void vmlogrdr_cleanup(void) +{ int i; + if (vmlogrdr_cdev) { cdev_del(vmlogrdr_cdev); vmlogrdr_cdev=NULL; @@ -855,8 +832,7 @@ vmlogrdr_cleanup(void) { } -static int -vmlogrdr_init(void) +static int vmlogrdr_init(void) { int rc; int i; @@ -906,8 +882,7 @@ cleanup: } -static void -vmlogrdr_exit(void) +static void vmlogrdr_exit(void) { vmlogrdr_cleanup(); printk (KERN_INFO "vmlogrdr: driver unloaded\n"); -- cgit v1.2.3 From eebce38567373e3abbb640ab145d154831cc55df Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 8 Feb 2007 13:50:33 -0800 Subject: [S390]: Adapt netiucv driver to new IUCV API Adapt netiucv network device driver to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller --- drivers/s390/net/netiucv.c | 1314 ++++++++++++++++++++++---------------------- 1 file changed, 652 insertions(+), 662 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 3346088f47e0..6387b483f2bf 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -1,7 +1,7 @@ /* * IUCV network driver * - * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * Sysfs integration and all bugs therein by Cornelia Huck @@ -58,13 +58,94 @@ #include #include -#include "iucv.h" +#include #include "fsm.h" MODULE_AUTHOR ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); +/** + * Debug Facility stuff + */ +#define IUCV_DBF_SETUP_NAME "iucv_setup" +#define IUCV_DBF_SETUP_LEN 32 +#define IUCV_DBF_SETUP_PAGES 2 +#define IUCV_DBF_SETUP_NR_AREAS 1 +#define IUCV_DBF_SETUP_LEVEL 3 + +#define IUCV_DBF_DATA_NAME "iucv_data" +#define IUCV_DBF_DATA_LEN 128 +#define IUCV_DBF_DATA_PAGES 2 +#define IUCV_DBF_DATA_NR_AREAS 1 +#define IUCV_DBF_DATA_LEVEL 2 + +#define IUCV_DBF_TRACE_NAME "iucv_trace" +#define IUCV_DBF_TRACE_LEN 16 +#define IUCV_DBF_TRACE_PAGES 4 +#define IUCV_DBF_TRACE_NR_AREAS 1 +#define IUCV_DBF_TRACE_LEVEL 3 + +#define IUCV_DBF_TEXT(name,level,text) \ + do { \ + debug_text_event(iucv_dbf_##name,level,text); \ + } while (0) + +#define IUCV_DBF_HEX(name,level,addr,len) \ + do { \ + debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ + } while (0) + +DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); + +#define IUCV_DBF_TEXT_(name,level,text...) \ + do { \ + char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ + sprintf(iucv_dbf_txt_buf, text); \ + debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ + put_cpu_var(iucv_dbf_txt_buf); \ + } while (0) + +#define IUCV_DBF_SPRINTF(name,level,text...) \ + do { \ + debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ + debug_sprintf_event(iucv_dbf_trace, level, text ); \ + } while (0) + +/** + * some more debug stuff + */ +#define IUCV_HEXDUMP16(importance,header,ptr) \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ + *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ + *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ + *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ + *(((char*)ptr)+12),*(((char*)ptr)+13), \ + *(((char*)ptr)+14),*(((char*)ptr)+15)); \ +PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ + "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ + *(((char*)ptr)+16),*(((char*)ptr)+17), \ + *(((char*)ptr)+18),*(((char*)ptr)+19), \ + *(((char*)ptr)+20),*(((char*)ptr)+21), \ + *(((char*)ptr)+22),*(((char*)ptr)+23), \ + *(((char*)ptr)+24),*(((char*)ptr)+25), \ + *(((char*)ptr)+26),*(((char*)ptr)+27), \ + *(((char*)ptr)+28),*(((char*)ptr)+29), \ + *(((char*)ptr)+30),*(((char*)ptr)+31)); + +static inline void iucv_hex_dump(unsigned char *buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) { + if (i && !(i % 16)) + printk("\n"); + printk("%02x ", *(buf + i)); + } + printk("\n"); +} #define PRINTK_HEADER " iucv: " /* for debugging */ @@ -73,6 +154,25 @@ static struct device_driver netiucv_driver = { .bus = &iucv_bus, }; +static int netiucv_callback_connreq(struct iucv_path *, + u8 ipvmid[8], u8 ipuser[16]); +static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]); +static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *); +static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler netiucv_handler = { + .path_pending = netiucv_callback_connreq, + .path_complete = netiucv_callback_connack, + .path_severed = netiucv_callback_connrej, + .path_quiesced = netiucv_callback_connsusp, + .path_resumed = netiucv_callback_connres, + .message_pending = netiucv_callback_rx, + .message_complete = netiucv_callback_txdone +}; + /** * Per connection profiling data */ @@ -92,9 +192,8 @@ struct connection_profile { * Representation of one iucv connection */ struct iucv_connection { - struct iucv_connection *next; - iucv_handle_t handle; - __u16 pathid; + struct list_head list; + struct iucv_path *path; struct sk_buff *rx_buff; struct sk_buff *tx_buff; struct sk_buff_head collect_queue; @@ -112,12 +211,9 @@ struct iucv_connection { /** * Linked list of all connection structs. */ -struct iucv_connection_struct { - struct iucv_connection *iucv_connections; - rwlock_t iucv_rwlock; -}; - -static struct iucv_connection_struct iucv_conns; +static struct list_head iucv_connection_list = + LIST_HEAD_INIT(iucv_connection_list); +static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED; /** * Representation of event-data for the @@ -142,11 +238,11 @@ struct netiucv_priv { /** * Link level header for a packet. */ -typedef struct ll_header_t { - __u16 next; -} ll_header; +struct ll_header { + u16 next; +}; -#define NETIUCV_HDRLEN (sizeof(ll_header)) +#define NETIUCV_HDRLEN (sizeof(struct ll_header)) #define NETIUCV_BUFSIZE_MAX 32768 #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) @@ -158,35 +254,25 @@ typedef struct ll_header_t { * Compatibility macros for busy handling * of network devices. */ -static __inline__ void netiucv_clear_busy(struct net_device *dev) +static inline void netiucv_clear_busy(struct net_device *dev) { - clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy)); + struct netiucv_priv *priv = netdev_priv(dev); + clear_bit(0, &priv->tbusy); netif_wake_queue(dev); } -static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) +static inline int netiucv_test_and_set_busy(struct net_device *dev) { + struct netiucv_priv *priv = netdev_priv(dev); netif_stop_queue(dev); - return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy); + return test_and_set_bit(0, &priv->tbusy); } -static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -static __u8 iucvMagic[16] = { +static u8 iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 }; -/** - * This mask means the 16-byte IUCV "magic" and the origin userid must - * match exactly as specified in order to give connection_pending() - * control. - */ -static __u8 netiucv_mask[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - /** * Convert an iucv userId to its printable * form (strip whitespace at end). @@ -195,8 +281,7 @@ static __u8 netiucv_mask[] = { * * @returns The printable string (static data!!) */ -static __inline__ char * -netiucv_printname(char *name) +static inline char *netiucv_printname(char *name) { static char tmp[9]; char *p = tmp; @@ -379,8 +464,7 @@ static debug_info_t *iucv_dbf_trace = NULL; DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); -static void -iucv_unregister_dbf_views(void) +static void iucv_unregister_dbf_views(void) { if (iucv_dbf_setup) debug_unregister(iucv_dbf_setup); @@ -389,8 +473,7 @@ iucv_unregister_dbf_views(void) if (iucv_dbf_trace) debug_unregister(iucv_dbf_trace); } -static int -iucv_register_dbf_views(void) +static int iucv_register_dbf_views(void) { iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, IUCV_DBF_SETUP_PAGES, @@ -422,125 +505,111 @@ iucv_register_dbf_views(void) return 0; } -/** +/* * Callback-wrappers, called from lowlevel iucv layer. - *****************************************************************************/ + */ -static void -netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data) +static void netiucv_callback_rx(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; - + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_RX, &ev); } -static void -netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data) +static void netiucv_callback_txdone(struct iucv_path *path, + struct iucv_message *msg) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; ev.conn = conn; - ev.data = (void *)eib; + ev.data = msg; fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); } -static void -netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data) +static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn); } -static void -netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data) +static int netiucv_callback_connreq(struct iucv_path *path, + u8 ipvmid[8], u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; + struct iucv_connection *conn = path->private; struct iucv_event ev; + int rc; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + if (memcmp(iucvMagic, ipuser, sizeof(ipuser))) + /* ipuser must match iucvMagic. */ + return -EINVAL; + rc = -EINVAL; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(conn, &iucv_connection_list, list) { + if (strncmp(ipvmid, conn->userid, 8)) + continue; + /* Found a matching connection for this path. */ + conn->path = path; + ev.conn = conn; + ev.data = path; + fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); + rc = 0; + } + read_unlock_bh(&iucv_connection_rwlock); + return rc; } -static void -netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data) +static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn); } -static void -netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data) +static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev); + fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn); } -static void -netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data) +static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16]) { - struct iucv_connection *conn = (struct iucv_connection *)pgm_data; - struct iucv_event ev; + struct iucv_connection *conn = path->private; - ev.conn = conn; - ev.data = (void *)eib; - fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev); -} - -static iucv_interrupt_ops_t netiucv_ops = { - .ConnectionPending = netiucv_callback_connreq, - .ConnectionComplete = netiucv_callback_connack, - .ConnectionSevered = netiucv_callback_connrej, - .ConnectionQuiesced = netiucv_callback_connsusp, - .ConnectionResumed = netiucv_callback_connres, - .MessagePending = netiucv_callback_rx, - .MessageComplete = netiucv_callback_txdone -}; + fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn); +} /** * Dummy NOP action for all statemachines */ -static void -fsm_action_nop(fsm_instance *fi, int event, void *arg) +static void fsm_action_nop(fsm_instance *fi, int event, void *arg) { } -/** +/* * Actions of the connection statemachine - *****************************************************************************/ + */ /** - * Helper function for conn_action_rx() - * Unpack a just received skb and hand it over to - * upper layers. + * netiucv_unpack_skb + * @conn: The connection where this skb has been received. + * @pskb: The received skb. * - * @param conn The connection where this skb has been received. - * @param pskb The received skb. + * Unpack a just received skb and hand it over to upper layers. + * Helper function for conn_action_rx. */ -//static __inline__ void -static void -netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) +static void netiucv_unpack_skb(struct iucv_connection *conn, + struct sk_buff *pskb) { struct net_device *dev = conn->netdev; - struct netiucv_priv *privptr = dev->priv; - __u16 offset = 0; + struct netiucv_priv *privptr = netdev_priv(dev); + u16 offset = 0; skb_put(pskb, NETIUCV_HDRLEN); pskb->dev = dev; @@ -549,7 +618,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) while (1) { struct sk_buff *skb; - ll_header *header = (ll_header *)pskb->data; + struct ll_header *header = (struct ll_header *) pskb->data; if (!header->next) break; @@ -595,40 +664,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) } } -static void -conn_action_rx(fsm_instance *fi, int event, void *arg) +static void conn_action_rx(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; - struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv; - - __u32 msglen = eib->ln1msg2.ipbfln1f; + struct iucv_message *msg = ev->data; + struct netiucv_priv *privptr = netdev_priv(conn->netdev); int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); if (!conn->netdev) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + 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"); + "Received data for unlinked connection\n"); return; } - if (msglen > conn->max_buffsize) { - /* FRITZ: How to tell iucv LL to drop the msg? */ + if (msg->length > conn->max_buffsize) { + iucv_message_reject(conn->path, msg); privptr->stats.rx_dropped++; PRINT_WARN("msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", - msglen, conn->max_buffsize); + msg->length, conn->max_buffsize); return; } conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; conn->rx_buff->len = 0; - rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls, - conn->rx_buff->data, msglen, NULL, NULL, NULL); - if (rc || msglen < 5) { + rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data, + 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); @@ -637,26 +703,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg) netiucv_unpack_skb(conn, conn->rx_buff); } -static void -conn_action_txdone(fsm_instance *fi, int event, void *arg) +static void conn_action_txdone(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; + struct iucv_message *msg = ev->data; + struct iucv_message txmsg; struct netiucv_priv *privptr = NULL; - /* Shut up, gcc! skb is always below 2G. */ - __u32 single_flag = eib->ipmsgtag; - __u32 txbytes = 0; - __u32 txpackets = 0; - __u32 stat_maxcq = 0; + u32 single_flag = msg->tag; + u32 txbytes = 0; + u32 txpackets = 0; + u32 stat_maxcq = 0; struct sk_buff *skb; unsigned long saveflags; - ll_header header; + struct ll_header header; + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); - if (conn && conn->netdev && conn->netdev->priv) - privptr = (struct netiucv_priv *)conn->netdev->priv; + if (conn && conn->netdev) + privptr = netdev_priv(conn->netdev); conn->prof.tx_pending--; if (single_flag) { if ((skb = skb_dequeue(&conn->commit_queue))) { @@ -688,56 +754,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg) conn->prof.maxmulti = conn->collect_len; conn->collect_len = 0; spin_unlock_irqrestore(&conn->collect_lock, saveflags); - if (conn->tx_buff->len) { - int rc; - - header.next = 0; - memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, - NETIUCV_HDRLEN); + if (conn->tx_buff->len == 0) { + fsm_newstate(fi, CONN_STATE_IDLE); + return; + } - conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, + header.next = 0; + memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); + conn->prof.send_stamp = xtime; + txmsg.class = 0; + txmsg.tag = 0; + rc = iucv_message_send(conn->path, &txmsg, 0, 0, conn->tx_buff->data, conn->tx_buff->len); - conn->prof.doios_multi++; - conn->prof.txlen += conn->tx_buff->len; - conn->prof.tx_pending++; - if (conn->prof.tx_pending > conn->prof.tx_max_pending) - conn->prof.tx_max_pending = conn->prof.tx_pending; - if (rc) { - conn->prof.tx_pending--; - 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) { - privptr->stats.tx_packets += txpackets; - privptr->stats.tx_bytes += txbytes; - } - if (stat_maxcq > conn->prof.maxcqueue) - conn->prof.maxcqueue = stat_maxcq; - } - } else + conn->prof.doios_multi++; + conn->prof.txlen += conn->tx_buff->len; + conn->prof.tx_pending++; + if (conn->prof.tx_pending > conn->prof.tx_max_pending) + conn->prof.tx_max_pending = conn->prof.tx_pending; + if (rc) { + conn->prof.tx_pending--; 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) { + privptr->stats.tx_packets += txpackets; + privptr->stats.tx_bytes += txbytes; + } + if (stat_maxcq > conn->prof.maxcqueue) + conn->prof.maxcqueue = stat_maxcq; + } } -static void -conn_action_connaccept(fsm_instance *fi, int event, void *arg) +static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; + struct iucv_path *path = ev->data; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); int rc; - __u16 msglimit; - __u8 udata[16]; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, - conn->handle, conn, NULL, &msglimit); + conn->path = path; + path->msglim = NETIUCV_QUEUELEN_DEFAULT; + 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); @@ -745,183 +810,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg) return; } fsm_newstate(fi, CONN_STATE_IDLE); - conn->pathid = eib->ippathid; - netdev->tx_queue_len = msglimit; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_connreject(fsm_instance *fi, int event, void *arg) +static void conn_action_connreject(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - struct net_device *netdev = conn->netdev; - iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; - __u8 udata[16]; + struct iucv_event *ev = arg; + struct iucv_path *path = ev->data; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - - iucv_sever(eib->ippathid, udata); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Pending; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connreject: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - iucv_sever(conn->pathid, udata); - } + iucv_path_sever(path, NULL); } -static void -conn_action_connack(fsm_instance *fi, int event, void *arg) +static void conn_action_connack(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_IDLE); - if (eib->ippathid != conn->pathid) { - PRINT_INFO("%s: IR Connection Complete; " - "pathid %d does not match original pathid %d\n", - netdev->name, eib->ippathid, conn->pathid); - IUCV_DBF_TEXT_(data, 2, - "connack: IR pathid %d, conn. pathid %d\n", - eib->ippathid, conn->pathid); - conn->pathid = eib->ippathid; - } - netdev->tx_queue_len = eib->ipmsglim; + netdev->tx_queue_len = conn->path->msglim; fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); } -static void -conn_action_conntimsev(fsm_instance *fi, int event, void *arg) +static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) { - struct iucv_connection *conn = (struct iucv_connection *)arg; - __u8 udata[16]; + struct iucv_connection *conn = arg; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); fsm_newstate(fi, CONN_STATE_STARTWAIT); } -static void -conn_action_connsever(fsm_instance *fi, int event, void *arg) +static void conn_action_connsever(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; - __u8 udata[16]; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); - iucv_sever(conn->pathid, udata); + iucv_path_sever(conn->path, NULL); PRINT_INFO("%s: Remote dropped connection\n", netdev->name); IUCV_DBF_TEXT(data, 2, - "conn_action_connsever: Remote dropped connection\n"); + "conn_action_connsever: Remote dropped connection\n"); fsm_newstate(fi, CONN_STATE_STARTWAIT); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_start(fsm_instance *fi, int event, void *arg) +static void conn_action_start(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; - __u16 msglimit; + struct iucv_connection *conn = arg; int rc; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (!conn->handle) { - IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n"); - conn->handle = - iucv_register_program(iucvMagic, conn->userid, - netiucv_mask, - &netiucv_ops, conn); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - if (!conn->handle) { - fsm_newstate(fi, CONN_STATE_REGERR); - conn->handle = NULL; - IUCV_DBF_TEXT(setup, 2, - "NULL from iucv_register_program\n"); - return; - } - - PRINT_DEBUG("%s('%s'): registered successfully\n", - conn->netdev->name, conn->userid); - } - + fsm_newstate(fi, CONN_STATE_STARTWAIT); PRINT_DEBUG("%s('%s'): connecting ...\n", - conn->netdev->name, conn->userid); + conn->netdev->name, conn->userid); - /* We must set the state before calling iucv_connect because the callback - * handler could be called at any point after the connection request is - * sent */ + /* + * We must set the state before calling iucv_connect because the + * callback handler could be called at any point after the connection + * request is sent + */ fsm_newstate(fi, CONN_STATE_SETUPWAIT); - rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, - conn->userid, iucv_host, 0, NULL, &msglimit, - conn->handle, conn); + conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); + rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, + NULL, iucvMagic, conn); switch (rc) { - case 0: - conn->netdev->tx_queue_len = msglimit; - fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, - CONN_EVENT_TIMER, conn); - return; - case 11: - PRINT_INFO("%s: User %s is currently not available.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 12: - PRINT_INFO("%s: User %s is currently not ready.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_STARTWAIT); - return; - case 13: - PRINT_WARN("%s: Too many IUCV connections.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 14: - PRINT_WARN( - "%s: User %s has too many IUCV connections.\n", - conn->netdev->name, - netiucv_printname(conn->userid)); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - case 15: - PRINT_WARN( - "%s: No IUCV authorization in CP directory.\n", - conn->netdev->name); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; - default: - PRINT_WARN("%s: iucv_connect returned error %d\n", - conn->netdev->name, rc); - fsm_newstate(fi, CONN_STATE_CONNERR); - break; + case 0: + conn->netdev->tx_queue_len = conn->path->msglim; + fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, + CONN_EVENT_TIMER, conn); + return; + case 11: + PRINT_INFO("%s: User %s is currently not available.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 12: + PRINT_INFO("%s: User %s is currently not ready.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_STARTWAIT); + break; + case 13: + PRINT_WARN("%s: Too many IUCV connections.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 14: + PRINT_WARN("%s: User %s has too many IUCV connections.\n", + conn->netdev->name, + netiucv_printname(conn->userid)); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + case 15: + PRINT_WARN("%s: No IUCV authorization in CP directory.\n", + conn->netdev->name); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; + default: + PRINT_WARN("%s: iucv_connect returned error %d\n", + conn->netdev->name, rc); + fsm_newstate(fi, CONN_STATE_CONNERR); + break; } IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + kfree(conn->path); + conn->path = NULL; } -static void -netiucv_purge_skb_queue(struct sk_buff_head *q) +static void netiucv_purge_skb_queue(struct sk_buff_head *q) { struct sk_buff *skb; @@ -931,36 +939,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q) } } -static void -conn_action_stop(fsm_instance *fi, int event, void *arg) +static void conn_action_stop(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; + struct iucv_event *ev = arg; struct iucv_connection *conn = ev->conn; struct net_device *netdev = conn->netdev; - struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; + struct netiucv_priv *privptr = netdev_priv(netdev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); fsm_deltimer(&conn->timer); fsm_newstate(fi, CONN_STATE_STOPPED); netiucv_purge_skb_queue(&conn->collect_queue); - if (conn->handle) - IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); - iucv_unregister_program(conn->handle); - conn->handle = NULL; + if (conn->path) { + IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; + } netiucv_purge_skb_queue(&conn->commit_queue); fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); } -static void -conn_action_inval(fsm_instance *fi, int event, void *arg) +static void conn_action_inval(fsm_instance *fi, int event, void *arg) { - struct iucv_event *ev = (struct iucv_event *)arg; - struct iucv_connection *conn = ev->conn; + struct iucv_connection *conn = arg; struct net_device *netdev = conn->netdev; - PRINT_WARN("%s: Cannot connect without username\n", - netdev->name); + PRINT_WARN("%s: Cannot connect without username\n", netdev->name); IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); } @@ -999,29 +1005,27 @@ static const fsm_node conn_fsm[] = { static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); -/** +/* * Actions for interface - statemachine. - *****************************************************************************/ + */ /** - * Startup connection by sending CONN_EVENT_START to it. + * dev_action_start + * @fi: An instance of an interface statemachine. + * @event: The event, just happened. + * @arg: Generic pointer, casted from struct net_device * upon call. * - * @param fi An instance of an interface statemachine. - * @param event The event, just happened. - * @param arg Generic pointer, casted from struct net_device * upon call. + * Startup connection by sending CONN_EVENT_START to it. */ -static void -dev_action_start(fsm_instance *fi, int event, void *arg) +static void dev_action_start(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; - struct iucv_event ev; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ev.conn = privptr->conn; fsm_newstate(fi, DEV_STATE_STARTWAIT); - fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); + fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn); } /** @@ -1034,8 +1038,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg) static void dev_action_stop(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); struct iucv_event ev; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1057,8 +1061,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg) static void dev_action_connup(fsm_instance *fi, int event, void *arg) { - struct net_device *dev = (struct net_device *)arg; - struct netiucv_priv *privptr = dev->priv; + struct net_device *dev = arg; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -1131,11 +1135,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node); * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { +static int netiucv_transmit_skb(struct iucv_connection *conn, + struct sk_buff *skb) +{ + struct iucv_message msg; unsigned long saveflags; - ll_header header; - int rc = 0; + struct ll_header header; + int rc; if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { int l = skb->len + NETIUCV_HDRLEN; @@ -1145,11 +1151,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { (conn->max_buffsize - NETIUCV_HDRLEN)) { rc = -EBUSY; IUCV_DBF_TEXT(data, 2, - "EBUSY from netiucv_transmit_skb\n"); + "EBUSY from netiucv_transmit_skb\n"); } else { atomic_inc(&skb->users); skb_queue_tail(&conn->collect_queue, skb); conn->collect_len += l; + rc = 0; } spin_unlock_irqrestore(&conn->collect_lock, saveflags); } else { @@ -1188,9 +1195,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { fsm_newstate(conn->fsm, CONN_STATE_TX); conn->prof.send_stamp = xtime; - rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */, - 0, nskb->data, nskb->len); - /* Shut up, gcc! nskb is always below 2G. */ + msg.tag = 1; + msg.class = 0; + rc = iucv_message_send(conn->path, &msg, 0, 0, + nskb->data, nskb->len); conn->prof.doios_single++; conn->prof.txlen += skb->len; conn->prof.tx_pending++; @@ -1200,7 +1208,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { struct netiucv_priv *privptr; fsm_newstate(conn->fsm, CONN_STATE_IDLE); conn->prof.tx_pending--; - privptr = (struct netiucv_priv *)conn->netdev->priv; + privptr = netdev_priv(conn->netdev); if (privptr) privptr->stats.tx_errors++; if (copied) @@ -1226,9 +1234,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { return rc; } -/** +/* * Interface API for upper network layers - *****************************************************************************/ + */ /** * Open an interface. @@ -1238,9 +1246,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_open(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev); +static int netiucv_open(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_START, dev); return 0; } @@ -1252,9 +1262,11 @@ netiucv_open(struct net_device *dev) { * * @return 0 on success, -ERRNO on failure. (Never fails.) */ -static int -netiucv_close(struct net_device *dev) { - fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev); +static int netiucv_close(struct net_device *dev) +{ + struct netiucv_priv *priv = netdev_priv(dev); + + fsm_event(priv->fsm, DEV_EVENT_STOP, dev); return 0; } @@ -1271,8 +1283,8 @@ netiucv_close(struct net_device *dev) { */ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) { - int rc = 0; - struct netiucv_priv *privptr = dev->priv; + struct netiucv_priv *privptr = netdev_priv(dev); + int rc; IUCV_DBF_TEXT(trace, 4, __FUNCTION__); /** @@ -1312,40 +1324,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) return -EBUSY; } dev->trans_start = jiffies; - if (netiucv_transmit_skb(privptr->conn, skb)) - rc = 1; + rc = netiucv_transmit_skb(privptr->conn, skb) != 0; netiucv_clear_busy(dev); return rc; } /** - * Returns interface statistics of a device. + * netiucv_stats + * @dev: Pointer to interface struct. * - * @param dev Pointer to interface struct. + * Returns interface statistics of a device. * - * @return Pointer to stats struct of this interface. + * Returns pointer to stats struct of this interface. */ -static struct net_device_stats * -netiucv_stats (struct net_device * dev) +static struct net_device_stats *netiucv_stats (struct net_device * dev) { + struct netiucv_priv *priv = netdev_priv(dev); + IUCV_DBF_TEXT(trace, 5, __FUNCTION__); - return &((struct netiucv_priv *)dev->priv)->stats; + return &priv->stats; } /** - * Sets MTU of an interface. + * netiucv_change_mtu + * @dev: Pointer to interface struct. + * @new_mtu: The new MTU to use for this interface. * - * @param dev Pointer to interface struct. - * @param new_mtu The new MTU to use for this interface. + * Sets MTU of an interface. * - * @return 0 on success, -EINVAL if MTU is out of valid range. + * Returns 0 on success, -EINVAL if MTU is out of valid range. * (valid range is 576 .. NETIUCV_MTU_MAX). */ -static int -netiucv_change_mtu (struct net_device * dev, int new_mtu) +static int netiucv_change_mtu(struct net_device * dev, int new_mtu) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) { + if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) { IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); return -EINVAL; } @@ -1353,12 +1366,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu) return 0; } -/** +/* * attributes in sysfs - *****************************************************************************/ + */ -static ssize_t -user_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t user_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1366,8 +1379,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); } -static ssize_t -user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t user_write(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1375,80 +1388,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, char *tmp; char username[9]; int i; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (count>9) { - PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); + 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); + "%d is length of username\n", (int) count); return -EINVAL; } tmp = strsep((char **) &buf, "\n"); - for (i=0, p=tmp; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) + for (i = 0, p = tmp; i < 8 && *p; i++, p++) { + if (isalnum(*p) || (*p == '$')) { username[i]= toupper(*p); - else if (*p == '\n') { + continue; + } + if (*p == '\n') { /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid char %c in username!\n", - *p); - IUCV_DBF_TEXT_(setup, 2, - "username: invalid character %c\n", - *p); - return -EINVAL; } + PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); + IUCV_DBF_TEXT_(setup, 2, + "username: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - if (memcmp(username, priv->conn->userid, 9)) { - /* username changed */ - if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - 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 -EBUSY; + 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 -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); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; } } - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9) || - ((*clist)->netdev != ndev)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; - } + read_unlock_bh(&iucv_connection_rwlock); memcpy(priv->conn->userid, username, 9); - return count; - } static DEVICE_ATTR(user, 0644, user_show, user_write); -static ssize_t -buffer_show (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct netiucv_priv *priv = dev->driver_data; +static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, + char *buf) +{ struct netiucv_priv *priv = dev->driver_data; IUCV_DBF_TEXT(trace, 5, __FUNCTION__); return sprintf(buf, "%d\n", priv->conn->max_buffsize); } -static ssize_t -buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; struct net_device *ndev = priv->conn->netdev; @@ -1502,8 +1505,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); -static ssize_t -dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1513,8 +1516,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); -static ssize_t -conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t conn_fsm_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1524,8 +1527,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); -static ssize_t -maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxmulti_show (struct device *dev, + struct device_attribute *attr, char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1533,8 +1536,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); } -static ssize_t -maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxmulti_write (struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1545,8 +1549,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); -static ssize_t -maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1554,8 +1558,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); } -static ssize_t -maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1566,8 +1570,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); -static ssize_t -sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1575,8 +1579,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); } -static ssize_t -sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1587,8 +1591,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); -static ssize_t -mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1596,8 +1600,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); } -static ssize_t -mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1608,8 +1612,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); -static ssize_t -txlen_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1617,8 +1621,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.txlen); } -static ssize_t -txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1629,8 +1633,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); -static ssize_t -txtime_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1638,8 +1642,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); } -static ssize_t -txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1650,8 +1654,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); -static ssize_t -txpend_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1659,8 +1663,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); } -static ssize_t -txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1671,8 +1675,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); -static ssize_t -txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, + char *buf) { struct netiucv_priv *priv = dev->driver_data; @@ -1680,8 +1684,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); } -static ssize_t -txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct netiucv_priv *priv = dev->driver_data; @@ -1721,8 +1725,7 @@ static struct attribute_group netiucv_stat_attr_group = { .attrs = netiucv_stat_attrs, }; -static inline int -netiucv_add_files(struct device *dev) +static inline int netiucv_add_files(struct device *dev) { int ret; @@ -1736,18 +1739,16 @@ netiucv_add_files(struct device *dev) return ret; } -static inline void -netiucv_remove_files(struct device *dev) +static inline void netiucv_remove_files(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); sysfs_remove_group(&dev->kobj, &netiucv_attr_group); } -static int -netiucv_register_device(struct net_device *ndev) +static int netiucv_register_device(struct net_device *ndev) { - struct netiucv_priv *priv = ndev->priv; + struct netiucv_priv *priv = netdev_priv(ndev); struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); int ret; @@ -1786,8 +1787,7 @@ out_unreg: return ret; } -static void -netiucv_unregister_device(struct device *dev) +static void netiucv_unregister_device(struct device *dev) { IUCV_DBF_TEXT(trace, 3, __FUNCTION__); netiucv_remove_files(dev); @@ -1798,107 +1798,89 @@ netiucv_unregister_device(struct device *dev) * Allocate and initialize a new connection structure. * Add it to the list of netiucv connections; */ -static struct iucv_connection * -netiucv_new_connection(struct net_device *dev, char *username) -{ - unsigned long flags; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - struct iucv_connection *conn = - kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); - - if (conn) { - skb_queue_head_init(&conn->collect_queue); - skb_queue_head_init(&conn->commit_queue); - spin_lock_init(&conn->collect_lock); - conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; - conn->netdev = dev; - - conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->rx_buff) { - kfree(conn); - return NULL; - } - conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, - GFP_KERNEL | GFP_DMA); - if (!conn->tx_buff) { - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - conn->fsm = init_fsm("netiucvconn", conn_state_names, - conn_event_names, NR_CONN_STATES, - NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, - GFP_KERNEL); - if (!conn->fsm) { - kfree_skb(conn->tx_buff); - kfree_skb(conn->rx_buff); - kfree(conn); - return NULL; - } - fsm_settimer(conn->fsm, &conn->timer); - fsm_newstate(conn->fsm, CONN_STATE_INVALID); - - if (username) { - memcpy(conn->userid, username, 9); - fsm_newstate(conn->fsm, CONN_STATE_STOPPED); - } +static struct iucv_connection *netiucv_new_connection(struct net_device *dev, + char *username) +{ + struct iucv_connection *conn; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - conn->next = *clist; - *clist = conn; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + conn = kzalloc(sizeof(*conn), GFP_KERNEL); + if (!conn) + goto out; + skb_queue_head_init(&conn->collect_queue); + skb_queue_head_init(&conn->commit_queue); + spin_lock_init(&conn->collect_lock); + conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; + conn->netdev = dev; + + conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->rx_buff) + goto out_conn; + conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); + if (!conn->tx_buff) + goto out_rx; + conn->fsm = init_fsm("netiucvconn", conn_state_names, + conn_event_names, NR_CONN_STATES, + NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, + GFP_KERNEL); + if (!conn->fsm) + goto out_tx; + + fsm_settimer(conn->fsm, &conn->timer); + fsm_newstate(conn->fsm, CONN_STATE_INVALID); + + if (username) { + memcpy(conn->userid, username, 9); + fsm_newstate(conn->fsm, CONN_STATE_STOPPED); } + + write_lock_bh(&iucv_connection_rwlock); + list_add_tail(&conn->list, &iucv_connection_list); + write_unlock_bh(&iucv_connection_rwlock); return conn; + +out_tx: + kfree_skb(conn->tx_buff); +out_rx: + kfree_skb(conn->rx_buff); +out_conn: + kfree(conn); +out: + return NULL; } /** * Release a connection structure and remove it from the * list of netiucv connections. */ -static void -netiucv_remove_connection(struct iucv_connection *conn) +static void netiucv_remove_connection(struct iucv_connection *conn) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; - IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - if (conn == NULL) - return; - write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (*clist == conn) { - *clist = conn->next; - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (conn->handle) { - iucv_unregister_program(conn->handle); - conn->handle = NULL; - } - fsm_deltimer(&conn->timer); - kfree_fsm(conn->fsm); - kfree_skb(conn->rx_buff); - kfree_skb(conn->tx_buff); - return; - } - clist = &((*clist)->next); + write_lock_bh(&iucv_connection_rwlock); + list_del_init(&conn->list); + write_unlock_bh(&iucv_connection_rwlock); + if (conn->path) { + iucv_path_sever(conn->path, iucvMagic); + kfree(conn->path); + conn->path = NULL; } - write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + fsm_deltimer(&conn->timer); + kfree_fsm(conn->fsm); + kfree_skb(conn->rx_buff); + kfree_skb(conn->tx_buff); } /** * Release everything of a net device. */ -static void -netiucv_free_netdevice(struct net_device *dev) +static void netiucv_free_netdevice(struct net_device *dev) { - struct netiucv_priv *privptr; + struct netiucv_priv *privptr = netdev_priv(dev); IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (!dev) return; - privptr = (struct netiucv_priv *)dev->priv; if (privptr) { if (privptr->conn) netiucv_remove_connection(privptr->conn); @@ -1913,11 +1895,8 @@ netiucv_free_netdevice(struct net_device *dev) /** * Initialize a net device. (Called from kernel in alloc_netdev()) */ -static void -netiucv_setup_netdevice(struct net_device *dev) +static void netiucv_setup_netdevice(struct net_device *dev) { - memset(dev->priv, 0, sizeof(struct netiucv_priv)); - dev->mtu = NETIUCV_MTU_DEFAULT; dev->hard_start_xmit = netiucv_tx; dev->open = netiucv_open; @@ -1936,8 +1915,7 @@ netiucv_setup_netdevice(struct net_device *dev) /** * Allocate and initialize everything of a net device. */ -static struct net_device * -netiucv_init_netdevice(char *username) +static struct net_device *netiucv_init_netdevice(char *username) { struct netiucv_priv *privptr; struct net_device *dev; @@ -1946,40 +1924,40 @@ netiucv_init_netdevice(char *username) netiucv_setup_netdevice); if (!dev) return NULL; - if (dev_alloc_name(dev, dev->name) < 0) { - free_netdev(dev); - return NULL; - } + if (dev_alloc_name(dev, dev->name) < 0) + goto out_netdev; - privptr = (struct netiucv_priv *)dev->priv; + privptr = netdev_priv(dev); privptr->fsm = init_fsm("netiucvdev", dev_state_names, dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, dev_fsm, DEV_FSM_LEN, GFP_KERNEL); - if (!privptr->fsm) { - free_netdev(dev); - return NULL; - } + if (!privptr->fsm) + goto out_netdev; + privptr->conn = netiucv_new_connection(dev, username); if (!privptr->conn) { - kfree_fsm(privptr->fsm); - free_netdev(dev); IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); - return NULL; + goto out_fsm; } fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); - return dev; + +out_fsm: + kfree_fsm(privptr->fsm); +out_netdev: + free_netdev(dev); + return NULL; } -static ssize_t -conn_write(struct device_driver *drv, const char *buf, size_t count) +static ssize_t conn_write(struct device_driver *drv, + const char *buf, size_t count) { - char *p; + const char *p; char username[9]; - int i, ret; + int i, rc; struct net_device *dev; - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct netiucv_priv *priv; + struct iucv_connection *cp; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); if (count>9) { @@ -1988,83 +1966,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) return -EINVAL; } - for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { - if (isalnum(*p) || (*p == '$')) - username[i]= toupper(*p); - else if (*p == '\n') { + for (i = 0, p = buf; i < 8 && *p; i++, p++) { + if (isalnum(*p) || *p == '$') { + username[i] = toupper(*p); + continue; + } + if (*p == '\n') /* trailing lf, grr */ break; - } else { - PRINT_WARN("netiucv: Invalid character in username!\n"); - IUCV_DBF_TEXT_(setup, 2, - "conn_write: invalid character %c\n", *p); - return -EINVAL; - } + PRINT_WARN("netiucv: Invalid character in username!\n"); + IUCV_DBF_TEXT_(setup, 2, + "conn_write: invalid character %c\n", *p); + return -EINVAL; } - while (i<8) + while (i < 8) username[i++] = ' '; username[8] = '\0'; - read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); - while (*clist) { - if (!strncmp(username, (*clist)->userid, 9)) - break; - clist = &((*clist)->next); - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); - if (*clist) { - PRINT_WARN("netiucv: Connection to %s already exists\n", - username); - return -EEXIST; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + if (!strncmp(username, cp->userid, 9)) { + read_unlock_bh(&iucv_connection_rwlock); + PRINT_WARN("netiucv: Connection to %s already " + "exists\n", username); + return -EEXIST; + } } + read_unlock_bh(&iucv_connection_rwlock); + dev = netiucv_init_netdevice(username); if (!dev) { - PRINT_WARN( - "netiucv: Could not allocate network device structure " - "for user '%s'\n", netiucv_printname(username)); + 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; } - if ((ret = netiucv_register_device(dev))) { + rc = netiucv_register_device(dev); + if (rc) { IUCV_DBF_TEXT_(setup, 2, - "ret %d from netiucv_register_device\n", ret); + "ret %d from netiucv_register_device\n", rc); goto out_free_ndev; } /* sysfs magic */ - SET_NETDEV_DEV(dev, - (struct device*)((struct netiucv_priv*)dev->priv)->dev); + priv = netdev_priv(dev); + SET_NETDEV_DEV(dev, priv->dev); - if ((ret = register_netdev(dev))) { - netiucv_unregister_device((struct device*) - ((struct netiucv_priv*)dev->priv)->dev); - goto out_free_ndev; - } + rc = register_netdev(dev); + 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 ret; + return rc; } static DRIVER_ATTR(connection, 0200, NULL, conn_write); -static ssize_t -remove_write (struct device_driver *drv, const char *buf, size_t count) +static ssize_t remove_write (struct device_driver *drv, + const char *buf, size_t count) { - struct iucv_connection **clist = &iucv_conns.iucv_connections; - unsigned long flags; + struct iucv_connection *cp; struct net_device *ndev; struct netiucv_priv *priv; struct device *dev; char name[IFNAMSIZ]; - char *p; + const char *p; int i; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); @@ -2072,33 +2049,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) if (count >= IFNAMSIZ) count = IFNAMSIZ - 1;; - for (i=0, p=(char *)buf; inetdev; - priv = (struct netiucv_priv*)ndev->priv; + read_lock_bh(&iucv_connection_rwlock); + list_for_each_entry(cp, &iucv_connection_list, list) { + ndev = cp->netdev; + priv = netdev_priv(ndev); dev = priv->dev; - - if (strncmp(name, ndev->name, count)) { - clist = &((*clist)->next); - continue; - } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + if (strncmp(name, ndev->name, count)) + continue; + read_unlock_bh(&iucv_connection_rwlock); if (ndev->flags & (IFF_UP | IFF_RUNNING)) { - PRINT_WARN( - "netiucv: net device %s active with peer %s\n", - ndev->name, priv->conn->userid); + PRINT_WARN("netiucv: net device %s active with peer " + "%s\n", ndev->name, priv->conn->userid); PRINT_WARN("netiucv: %s cannot be removed\n", - ndev->name); + ndev->name); IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); return -EBUSY; } @@ -2106,7 +2077,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) netiucv_unregister_device(dev); return count; } - read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); + 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; @@ -2114,67 +2085,86 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) static DRIVER_ATTR(remove, 0200, NULL, remove_write); -static void -netiucv_banner(void) +static struct attribute * netiucv_drv_attrs[] = { + &driver_attr_connection.attr, + &driver_attr_remove.attr, + NULL, +}; + +static struct attribute_group netiucv_drv_attr_group = { + .attrs = netiucv_drv_attrs, +}; + +static void netiucv_banner(void) { PRINT_INFO("NETIUCV driver initialized\n"); } -static void __exit -netiucv_exit(void) +static void __exit netiucv_exit(void) { + struct iucv_connection *cp; + struct net_device *ndev; + struct netiucv_priv *priv; + struct device *dev; + IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - while (iucv_conns.iucv_connections) { - struct net_device *ndev = iucv_conns.iucv_connections->netdev; - struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; - struct device *dev = priv->dev; + while (!list_empty(&iucv_connection_list)) { + cp = list_entry(iucv_connection_list.next, + struct iucv_connection, list); + list_del(&cp->list); + ndev = cp->netdev; + priv = netdev_priv(ndev); + dev = priv->dev; unregister_netdev(ndev); netiucv_unregister_device(dev); } - driver_remove_file(&netiucv_driver, &driver_attr_connection); - driver_remove_file(&netiucv_driver, &driver_attr_remove); + sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); driver_unregister(&netiucv_driver); + iucv_unregister(&netiucv_handler, 1); iucv_unregister_dbf_views(); PRINT_INFO("NETIUCV driver unloaded\n"); return; } -static int __init -netiucv_init(void) +static int __init netiucv_init(void) { - int ret; + int rc; - ret = iucv_register_dbf_views(); - if (ret) { - PRINT_WARN("netiucv_init failed, " - "iucv_register_dbf_views rc = %d\n", ret); - return ret; - } + rc = iucv_register_dbf_views(); + if (rc) + goto out; + rc = iucv_register(&netiucv_handler, 1); + if (rc) + goto out_dbf; IUCV_DBF_TEXT(trace, 3, __FUNCTION__); - ret = driver_register(&netiucv_driver); - if (ret) { + 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", ret); - iucv_unregister_dbf_views(); - return ret; + IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); + goto out_iucv; } - /* Add entry for specifying connections. */ - ret = driver_create_file(&netiucv_driver, &driver_attr_connection); - if (!ret) { - ret = driver_create_file(&netiucv_driver, &driver_attr_remove); - netiucv_banner(); - rwlock_init(&iucv_conns.iucv_rwlock); - } else { - PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); - IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); - driver_unregister(&netiucv_driver); - iucv_unregister_dbf_views(); + rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); + if (rc) { + PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); + IUCV_DBF_TEXT_(setup, 2, + "ret %d - netiucv_drv_attr_group\n", rc); + goto out_driver; } - return ret; + netiucv_banner(); + return rc; + +out_driver: + driver_unregister(&netiucv_driver); +out_iucv: + iucv_unregister(&netiucv_handler, 1); +out_dbf: + iucv_unregister_dbf_views(); +out: + return rc; } module_init(netiucv_init); -- cgit v1.2.3 From 5da5e658debb7deddbfe5c133c76db3be0a3e12c Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Thu, 8 Feb 2007 13:51:11 -0800 Subject: [S390]: Adapt special message interface to new IUCV API Adapt special message interface to new IUCV API Signed-off-by: Frank Pavlic Signed-off-by: Martin Schwidefsky Signed-off-by: David S. Miller --- drivers/s390/net/smsgiucv.c | 147 ++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 73 deletions(-) (limited to 'drivers/s390') diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index b8179c27ceb6..3ccca5871fdf 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c @@ -1,7 +1,7 @@ /* * IUCV special message driver * - * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -23,10 +23,10 @@ #include #include #include +#include #include #include - -#include "iucv.h" +#include "smsgiucv.h" struct smsg_callback { struct list_head list; @@ -39,38 +39,46 @@ MODULE_AUTHOR ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)"); MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); -static iucv_handle_t smsg_handle; -static unsigned short smsg_pathid; +static struct iucv_path *smsg_path; + static DEFINE_SPINLOCK(smsg_list_lock); static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list); -static void -smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data) +static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); +static void smsg_message_pending(struct iucv_path *, struct iucv_message *); + +static struct iucv_handler smsg_handler = { + .path_pending = smsg_path_pending, + .message_pending = smsg_message_pending, +}; + +static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8], + u8 ipuser[16]) { + if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0) + return -EINVAL; + /* Path pending from *MSG. */ + return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL); } - -static void -smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) +static void smsg_message_pending(struct iucv_path *path, + struct iucv_message *msg) { struct smsg_callback *cb; - unsigned char *msg; + unsigned char *buffer; unsigned char sender[9]; - unsigned short len; int rc, i; - len = eib->ln1msg2.ipbfln1f; - msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA); - if (!msg) { - iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls); + buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA); + if (!buffer) { + iucv_message_reject(path, msg); return; } - rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls, - msg, len, NULL, NULL, NULL); + rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL); if (rc == 0) { - msg[len] = 0; - EBCASC(msg, len); - memcpy(sender, msg, 8); + buffer[msg->length] = 0; + EBCASC(buffer, msg->length); + memcpy(sender, buffer, 8); sender[8] = 0; /* Remove trailing whitespace from the sender name. */ for (i = 7; i >= 0; i--) { @@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) } spin_lock(&smsg_list_lock); list_for_each_entry(cb, &smsg_list, list) - if (strncmp(msg + 8, cb->prefix, cb->len) == 0) { - cb->callback(sender, msg + 8); + if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) { + cb->callback(sender, buffer + 8); break; } spin_unlock(&smsg_list_lock); } - kfree(msg); + kfree(buffer); } -static iucv_interrupt_ops_t smsg_ops = { - .ConnectionComplete = smsg_connection_complete, - .MessagePending = smsg_message_pending, -}; - -static struct device_driver smsg_driver = { - .name = "SMSGIUCV", - .bus = &iucv_bus, -}; - -int -smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) +int smsg_register_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb; @@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) cb->prefix = prefix; cb->len = strlen(prefix); cb->callback = callback; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); list_add_tail(&cb->list, &smsg_list); - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); return 0; } -void -smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) +void smsg_unregister_callback(char *prefix, + void (*callback)(char *from, char *str)) { struct smsg_callback *cb, *tmp; - spin_lock(&smsg_list_lock); + spin_lock_bh(&smsg_list_lock); cb = NULL; list_for_each_entry(tmp, &smsg_list, list) if (tmp->callback == callback && @@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) list_del(&cb->list); break; } - spin_unlock(&smsg_list_lock); + spin_unlock_bh(&smsg_list_lock); kfree(cb); } -static void __exit -smsg_exit(void) +static struct device_driver smsg_driver = { + .name = "SMSGIUCV", + .bus = &iucv_bus, +}; + +static void __exit smsg_exit(void) { - if (smsg_handle > 0) { - cpcmd("SET SMSG OFF", NULL, 0, NULL); - iucv_sever(smsg_pathid, NULL); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - } - return; + cpcmd("SET SMSG IUCV", NULL, 0, NULL); + iucv_unregister(&smsg_handler, 1); + driver_unregister(&smsg_driver); } -static int __init -smsg_init(void) +static int __init smsg_init(void) { - static unsigned char pgmmask[24] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - }; int rc; rc = driver_register(&smsg_driver); - if (rc != 0) { - printk(KERN_ERR "SMSGIUCV: failed to register driver.\n"); - return rc; - } - smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ", - pgmmask, &smsg_ops, NULL); - if (!smsg_handle) { + if (rc != 0) + goto out; + rc = iucv_register(&smsg_handler, 1); + if (rc) { printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); - driver_unregister(&smsg_driver); - return -EIO; /* better errno ? */ + rc = -EIO; /* better errno ? */ + goto out_driver; + } + smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL); + if (!smsg_path) { + rc = -ENOMEM; + goto out_register; } - rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0, - NULL, NULL, smsg_handle, NULL); + rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", + NULL, NULL, NULL); if (rc) { printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); - iucv_unregister_program(smsg_handle); - driver_unregister(&smsg_driver); - smsg_handle = NULL; - return -EIO; + rc = -EIO; /* better errno ? */ + goto out_free; } cpcmd("SET SMSG IUCV", NULL, 0, NULL); return 0; + +out_free: + iucv_path_free(smsg_path); +out_register: + iucv_unregister(&smsg_handler, 1); +out_driver: + driver_unregister(&smsg_driver); +out: + return rc; } module_init(smsg_init); -- cgit v1.2.3