diff options
author | Jiri Kosina <jkosina@suse.cz> | 2008-05-06 10:57:55 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2008-05-06 10:57:55 -0400 |
commit | 7022b15e2a9f878fd5184586064c63352c3dd225 (patch) | |
tree | 5365c2f5bc82ae1946636ee8d5cd5d3b7e804f1b /drivers/s390 | |
parent | aaad2b0c757f3e6e02552cb0bdcd91a5ec0d6305 (diff) | |
parent | a15306365a16380f3bafee9e181ba01231d4acd7 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'drivers/s390')
33 files changed, 835 insertions, 281 deletions
diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index 5a888704a8d0..4f4e7cf105d4 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w | 5 | CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w |
6 | 6 | ||
7 | obj-y += s390mach.o sysinfo.o s390_rdev.o | 7 | obj-y += s390mach.o sysinfo.o s390_rdev.o |
8 | obj-y += cio/ block/ char/ crypto/ net/ scsi/ | 8 | obj-y += cio/ block/ char/ crypto/ net/ scsi/ kvm/ |
9 | 9 | ||
10 | drivers-y += drivers/s390/built-in.o | 10 | drivers-y += drivers/s390/built-in.o |
11 | 11 | ||
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index 556063e8f7a9..03c0e40a92ff 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c | |||
@@ -157,6 +157,7 @@ static int dasd_devices_open(struct inode *inode, struct file *file) | |||
157 | } | 157 | } |
158 | 158 | ||
159 | static const struct file_operations dasd_devices_file_ops = { | 159 | static const struct file_operations dasd_devices_file_ops = { |
160 | .owner = THIS_MODULE, | ||
160 | .open = dasd_devices_open, | 161 | .open = dasd_devices_open, |
161 | .read = seq_read, | 162 | .read = seq_read, |
162 | .llseek = seq_lseek, | 163 | .llseek = seq_lseek, |
@@ -311,17 +312,16 @@ out_error: | |||
311 | int | 312 | int |
312 | dasd_proc_init(void) | 313 | dasd_proc_init(void) |
313 | { | 314 | { |
314 | dasd_proc_root_entry = proc_mkdir("dasd", &proc_root); | 315 | dasd_proc_root_entry = proc_mkdir("dasd", NULL); |
315 | if (!dasd_proc_root_entry) | 316 | if (!dasd_proc_root_entry) |
316 | goto out_nodasd; | 317 | goto out_nodasd; |
317 | dasd_proc_root_entry->owner = THIS_MODULE; | 318 | dasd_proc_root_entry->owner = THIS_MODULE; |
318 | dasd_devices_entry = create_proc_entry("devices", | 319 | dasd_devices_entry = proc_create("devices", |
319 | S_IFREG | S_IRUGO | S_IWUSR, | 320 | S_IFREG | S_IRUGO | S_IWUSR, |
320 | dasd_proc_root_entry); | 321 | dasd_proc_root_entry, |
322 | &dasd_devices_file_ops); | ||
321 | if (!dasd_devices_entry) | 323 | if (!dasd_devices_entry) |
322 | goto out_nodevices; | 324 | goto out_nodevices; |
323 | dasd_devices_entry->proc_fops = &dasd_devices_file_ops; | ||
324 | dasd_devices_entry->owner = THIS_MODULE; | ||
325 | dasd_statistics_entry = create_proc_entry("statistics", | 325 | dasd_statistics_entry = create_proc_entry("statistics", |
326 | S_IFREG | S_IRUGO | S_IWUSR, | 326 | S_IFREG | S_IRUGO | S_IWUSR, |
327 | dasd_proc_root_entry); | 327 | dasd_proc_root_entry); |
@@ -335,7 +335,7 @@ dasd_proc_init(void) | |||
335 | out_nostatistics: | 335 | out_nostatistics: |
336 | remove_proc_entry("devices", dasd_proc_root_entry); | 336 | remove_proc_entry("devices", dasd_proc_root_entry); |
337 | out_nodevices: | 337 | out_nodevices: |
338 | remove_proc_entry("dasd", &proc_root); | 338 | remove_proc_entry("dasd", NULL); |
339 | out_nodasd: | 339 | out_nodasd: |
340 | return -ENOENT; | 340 | return -ENOENT; |
341 | } | 341 | } |
@@ -345,5 +345,5 @@ dasd_proc_exit(void) | |||
345 | { | 345 | { |
346 | remove_proc_entry("devices", dasd_proc_root_entry); | 346 | remove_proc_entry("devices", dasd_proc_root_entry); |
347 | remove_proc_entry("statistics", dasd_proc_root_entry); | 347 | remove_proc_entry("statistics", dasd_proc_root_entry); |
348 | remove_proc_entry("dasd", &proc_root); | 348 | remove_proc_entry("dasd", NULL); |
349 | } | 349 | } |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 04787eab1016..bb52d2fbac18 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -36,7 +36,7 @@ static int dcssblk_open(struct inode *inode, struct file *filp); | |||
36 | static int dcssblk_release(struct inode *inode, struct file *filp); | 36 | static int dcssblk_release(struct inode *inode, struct file *filp); |
37 | static int dcssblk_make_request(struct request_queue *q, struct bio *bio); | 37 | static int dcssblk_make_request(struct request_queue *q, struct bio *bio); |
38 | static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, | 38 | static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum, |
39 | unsigned long *data); | 39 | void **kaddr, unsigned long *pfn); |
40 | 40 | ||
41 | static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; | 41 | static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; |
42 | 42 | ||
@@ -636,7 +636,7 @@ fail: | |||
636 | 636 | ||
637 | static int | 637 | static int |
638 | dcssblk_direct_access (struct block_device *bdev, sector_t secnum, | 638 | dcssblk_direct_access (struct block_device *bdev, sector_t secnum, |
639 | unsigned long *data) | 639 | void **kaddr, unsigned long *pfn) |
640 | { | 640 | { |
641 | struct dcssblk_dev_info *dev_info; | 641 | struct dcssblk_dev_info *dev_info; |
642 | unsigned long pgoff; | 642 | unsigned long pgoff; |
@@ -649,7 +649,9 @@ dcssblk_direct_access (struct block_device *bdev, sector_t secnum, | |||
649 | pgoff = secnum / (PAGE_SIZE / 512); | 649 | pgoff = secnum / (PAGE_SIZE / 512); |
650 | if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) | 650 | if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start) |
651 | return -ERANGE; | 651 | return -ERANGE; |
652 | *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE); | 652 | *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE); |
653 | *pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT; | ||
654 | |||
653 | return 0; | 655 | return 0; |
654 | } | 656 | } |
655 | 657 | ||
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 0e1f35c9ed9d..3e5653c92f4b 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -982,15 +982,16 @@ tty3215_write(struct tty_struct * tty, | |||
982 | /* | 982 | /* |
983 | * Put character routine for 3215 ttys | 983 | * Put character routine for 3215 ttys |
984 | */ | 984 | */ |
985 | static void | 985 | static int |
986 | tty3215_put_char(struct tty_struct *tty, unsigned char ch) | 986 | tty3215_put_char(struct tty_struct *tty, unsigned char ch) |
987 | { | 987 | { |
988 | struct raw3215_info *raw; | 988 | struct raw3215_info *raw; |
989 | 989 | ||
990 | if (!tty) | 990 | if (!tty) |
991 | return; | 991 | return 0; |
992 | raw = (struct raw3215_info *) tty->driver_data; | 992 | raw = (struct raw3215_info *) tty->driver_data; |
993 | raw3215_putchar(raw, ch); | 993 | raw3215_putchar(raw, ch); |
994 | return 1; | ||
994 | } | 995 | } |
995 | 996 | ||
996 | static void | 997 | static void |
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index b8f35bc52b7b..9e784d5f7f57 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/cpu.h> | 10 | #include <linux/cpu.h> |
11 | #include <linux/sysdev.h> | 11 | #include <linux/sysdev.h> |
12 | #include <linux/workqueue.h> | 12 | #include <linux/workqueue.h> |
13 | #include <asm/smp.h> | ||
13 | #include "sclp.h" | 14 | #include "sclp.h" |
14 | 15 | ||
15 | #define TAG "sclp_config: " | 16 | #define TAG "sclp_config: " |
@@ -19,9 +20,11 @@ struct conf_mgm_data { | |||
19 | u8 ev_qualifier; | 20 | u8 ev_qualifier; |
20 | } __attribute__((packed)); | 21 | } __attribute__((packed)); |
21 | 22 | ||
23 | #define EV_QUAL_CPU_CHANGE 1 | ||
22 | #define EV_QUAL_CAP_CHANGE 3 | 24 | #define EV_QUAL_CAP_CHANGE 3 |
23 | 25 | ||
24 | static struct work_struct sclp_cpu_capability_work; | 26 | static struct work_struct sclp_cpu_capability_work; |
27 | static struct work_struct sclp_cpu_change_work; | ||
25 | 28 | ||
26 | static void sclp_cpu_capability_notify(struct work_struct *work) | 29 | static void sclp_cpu_capability_notify(struct work_struct *work) |
27 | { | 30 | { |
@@ -37,13 +40,24 @@ static void sclp_cpu_capability_notify(struct work_struct *work) | |||
37 | put_online_cpus(); | 40 | put_online_cpus(); |
38 | } | 41 | } |
39 | 42 | ||
43 | static void sclp_cpu_change_notify(struct work_struct *work) | ||
44 | { | ||
45 | smp_rescan_cpus(); | ||
46 | } | ||
47 | |||
40 | static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) | 48 | static void sclp_conf_receiver_fn(struct evbuf_header *evbuf) |
41 | { | 49 | { |
42 | struct conf_mgm_data *cdata; | 50 | struct conf_mgm_data *cdata; |
43 | 51 | ||
44 | cdata = (struct conf_mgm_data *)(evbuf + 1); | 52 | cdata = (struct conf_mgm_data *)(evbuf + 1); |
45 | if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE) | 53 | switch (cdata->ev_qualifier) { |
54 | case EV_QUAL_CPU_CHANGE: | ||
55 | schedule_work(&sclp_cpu_change_work); | ||
56 | break; | ||
57 | case EV_QUAL_CAP_CHANGE: | ||
46 | schedule_work(&sclp_cpu_capability_work); | 58 | schedule_work(&sclp_cpu_capability_work); |
59 | break; | ||
60 | } | ||
47 | } | 61 | } |
48 | 62 | ||
49 | static struct sclp_register sclp_conf_register = | 63 | static struct sclp_register sclp_conf_register = |
@@ -57,6 +71,7 @@ static int __init sclp_conf_init(void) | |||
57 | int rc; | 71 | int rc; |
58 | 72 | ||
59 | INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); | 73 | INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify); |
74 | INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify); | ||
60 | 75 | ||
61 | rc = sclp_register(&sclp_conf_register); | 76 | rc = sclp_register(&sclp_conf_register); |
62 | if (rc) { | 77 | if (rc) { |
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index e3b3d390b4a3..40b11521cd20 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c | |||
@@ -412,14 +412,14 @@ sclp_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) | |||
412 | * - including previous characters from sclp_tty_put_char() and strings from | 412 | * - including previous characters from sclp_tty_put_char() and strings from |
413 | * sclp_write() without final '\n' - will be written. | 413 | * sclp_write() without final '\n' - will be written. |
414 | */ | 414 | */ |
415 | static void | 415 | static int |
416 | sclp_tty_put_char(struct tty_struct *tty, unsigned char ch) | 416 | sclp_tty_put_char(struct tty_struct *tty, unsigned char ch) |
417 | { | 417 | { |
418 | sclp_tty_chars[sclp_tty_chars_count++] = ch; | 418 | sclp_tty_chars[sclp_tty_chars_count++] = ch; |
419 | if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) { | 419 | if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) { |
420 | sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); | 420 | sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count); |
421 | sclp_tty_chars_count = 0; | 421 | sclp_tty_chars_count = 0; |
422 | } | 422 | } return 1; |
423 | } | 423 | } |
424 | 424 | ||
425 | /* | 425 | /* |
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index ed507594e62b..35707c04e613 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
@@ -524,11 +524,15 @@ sclp_vt220_close(struct tty_struct *tty, struct file *filp) | |||
524 | * NOTE: include/linux/tty_driver.h specifies that a character should be | 524 | * NOTE: include/linux/tty_driver.h specifies that a character should be |
525 | * ignored if there is no room in the queue. This driver implements a different | 525 | * ignored if there is no room in the queue. This driver implements a different |
526 | * semantic in that it will block when there is no more room left. | 526 | * semantic in that it will block when there is no more room left. |
527 | * | ||
528 | * FIXME: putchar can currently be called from BH and other non blocking | ||
529 | * handlers so this semantic isn't a good idea. | ||
527 | */ | 530 | */ |
528 | static void | 531 | static int |
529 | sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) | 532 | sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) |
530 | { | 533 | { |
531 | __sclp_vt220_write(&ch, 1, 0, 0, 1); | 534 | __sclp_vt220_write(&ch, 1, 0, 0, 1); |
535 | return 1; | ||
532 | } | 536 | } |
533 | 537 | ||
534 | /* | 538 | /* |
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c index c9b96d51b28f..e7c888c14e71 100644 --- a/drivers/s390/char/tape_proc.c +++ b/drivers/s390/char/tape_proc.c | |||
@@ -111,6 +111,7 @@ static int tape_proc_open(struct inode *inode, struct file *file) | |||
111 | 111 | ||
112 | static const struct file_operations tape_proc_ops = | 112 | static const struct file_operations tape_proc_ops = |
113 | { | 113 | { |
114 | .owner = THIS_MODULE, | ||
114 | .open = tape_proc_open, | 115 | .open = tape_proc_open, |
115 | .read = seq_read, | 116 | .read = seq_read, |
116 | .llseek = seq_lseek, | 117 | .llseek = seq_lseek, |
@@ -124,14 +125,12 @@ void | |||
124 | tape_proc_init(void) | 125 | tape_proc_init(void) |
125 | { | 126 | { |
126 | tape_proc_devices = | 127 | tape_proc_devices = |
127 | create_proc_entry ("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, | 128 | proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL, |
128 | &proc_root); | 129 | &tape_proc_ops); |
129 | if (tape_proc_devices == NULL) { | 130 | if (tape_proc_devices == NULL) { |
130 | PRINT_WARN("tape: Cannot register procfs entry tapedevices\n"); | 131 | PRINT_WARN("tape: Cannot register procfs entry tapedevices\n"); |
131 | return; | 132 | return; |
132 | } | 133 | } |
133 | tape_proc_devices->proc_fops = &tape_proc_ops; | ||
134 | tape_proc_devices->owner = THIS_MODULE; | ||
135 | } | 134 | } |
136 | 135 | ||
137 | /* | 136 | /* |
@@ -141,5 +140,5 @@ void | |||
141 | tape_proc_cleanup(void) | 140 | tape_proc_cleanup(void) |
142 | { | 141 | { |
143 | if (tape_proc_devices != NULL) | 142 | if (tape_proc_devices != NULL) |
144 | remove_proc_entry ("tapedevices", &proc_root); | 143 | remove_proc_entry ("tapedevices", NULL); |
145 | } | 144 | } |
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 70b1980a08b6..c1f2adefad41 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c | |||
@@ -965,7 +965,7 @@ tty3270_write_room(struct tty_struct *tty) | |||
965 | * Insert character into the screen at the current position with the | 965 | * Insert character into the screen at the current position with the |
966 | * current color and highlight. This function does NOT do cursor movement. | 966 | * current color and highlight. This function does NOT do cursor movement. |
967 | */ | 967 | */ |
968 | static void | 968 | static int |
969 | tty3270_put_character(struct tty3270 *tp, char ch) | 969 | tty3270_put_character(struct tty3270 *tp, char ch) |
970 | { | 970 | { |
971 | struct tty3270_line *line; | 971 | struct tty3270_line *line; |
@@ -986,6 +986,7 @@ tty3270_put_character(struct tty3270 *tp, char ch) | |||
986 | cell->character = tp->view.ascebc[(unsigned int) ch]; | 986 | cell->character = tp->view.ascebc[(unsigned int) ch]; |
987 | cell->highlight = tp->highlight; | 987 | cell->highlight = tp->highlight; |
988 | cell->f_color = tp->f_color; | 988 | cell->f_color = tp->f_color; |
989 | return 1; | ||
989 | } | 990 | } |
990 | 991 | ||
991 | /* | 992 | /* |
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index e8597ec92247..40ef948fcb3a 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c | |||
@@ -374,13 +374,10 @@ cio_ignore_proc_init (void) | |||
374 | { | 374 | { |
375 | struct proc_dir_entry *entry; | 375 | struct proc_dir_entry *entry; |
376 | 376 | ||
377 | entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, | 377 | entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL, |
378 | &proc_root); | 378 | &cio_ignore_proc_fops); |
379 | if (!entry) | 379 | if (!entry) |
380 | return -ENOENT; | 380 | return -ENOENT; |
381 | |||
382 | entry->proc_fops = &cio_ignore_proc_fops; | ||
383 | |||
384 | return 0; | 381 | return 0; |
385 | } | 382 | } |
386 | 383 | ||
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index fe1ad1722158..26a930e832bd 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -152,44 +152,89 @@ __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) | |||
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | static int __get_next_bus_id(const char **buf, char *bus_id) | ||
156 | { | ||
157 | int rc, len; | ||
158 | char *start, *end; | ||
159 | |||
160 | start = (char *)*buf; | ||
161 | end = strchr(start, ','); | ||
162 | if (!end) { | ||
163 | /* Last entry. Strip trailing newline, if applicable. */ | ||
164 | end = strchr(start, '\n'); | ||
165 | if (end) | ||
166 | *end = '\0'; | ||
167 | len = strlen(start) + 1; | ||
168 | } else { | ||
169 | len = end - start + 1; | ||
170 | end++; | ||
171 | } | ||
172 | if (len < BUS_ID_SIZE) { | ||
173 | strlcpy(bus_id, start, len); | ||
174 | rc = 0; | ||
175 | } else | ||
176 | rc = -EINVAL; | ||
177 | *buf = end; | ||
178 | return rc; | ||
179 | } | ||
180 | |||
181 | static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE]) | ||
182 | { | ||
183 | int cssid, ssid, devno; | ||
184 | |||
185 | /* Must be of form %x.%x.%04x */ | ||
186 | if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) | ||
187 | return 0; | ||
188 | return 1; | ||
189 | } | ||
190 | |||
155 | /** | 191 | /** |
156 | * ccwgroup_create() - create and register a ccw group device | 192 | * ccwgroup_create_from_string() - create and register a ccw group device |
157 | * @root: parent device for the new device | 193 | * @root: parent device for the new device |
158 | * @creator_id: identifier of creating driver | 194 | * @creator_id: identifier of creating driver |
159 | * @cdrv: ccw driver of slave devices | 195 | * @cdrv: ccw driver of slave devices |
160 | * @argc: number of slave devices | 196 | * @num_devices: number of slave devices |
161 | * @argv: bus ids of slave devices | 197 | * @buf: buffer containing comma separated bus ids of slave devices |
162 | * | 198 | * |
163 | * Create and register a new ccw group device as a child of @root. Slave | 199 | * Create and register a new ccw group device as a child of @root. Slave |
164 | * devices are obtained from the list of bus ids given in @argv[] and must all | 200 | * devices are obtained from the list of bus ids given in @buf and must all |
165 | * belong to @cdrv. | 201 | * belong to @cdrv. |
166 | * Returns: | 202 | * Returns: |
167 | * %0 on success and an error code on failure. | 203 | * %0 on success and an error code on failure. |
168 | * Context: | 204 | * Context: |
169 | * non-atomic | 205 | * non-atomic |
170 | */ | 206 | */ |
171 | int ccwgroup_create(struct device *root, unsigned int creator_id, | 207 | int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, |
172 | struct ccw_driver *cdrv, int argc, char *argv[]) | 208 | struct ccw_driver *cdrv, int num_devices, |
209 | const char *buf) | ||
173 | { | 210 | { |
174 | struct ccwgroup_device *gdev; | 211 | struct ccwgroup_device *gdev; |
175 | int i; | 212 | int rc, i; |
176 | int rc; | 213 | char tmp_bus_id[BUS_ID_SIZE]; |
214 | const char *curr_buf; | ||
177 | 215 | ||
178 | if (argc > 256) /* disallow dumb users */ | 216 | gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), |
179 | return -EINVAL; | 217 | GFP_KERNEL); |
180 | |||
181 | gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL); | ||
182 | if (!gdev) | 218 | if (!gdev) |
183 | return -ENOMEM; | 219 | return -ENOMEM; |
184 | 220 | ||
185 | atomic_set(&gdev->onoff, 0); | 221 | atomic_set(&gdev->onoff, 0); |
186 | mutex_init(&gdev->reg_mutex); | 222 | mutex_init(&gdev->reg_mutex); |
187 | mutex_lock(&gdev->reg_mutex); | 223 | mutex_lock(&gdev->reg_mutex); |
188 | for (i = 0; i < argc; i++) { | 224 | curr_buf = buf; |
189 | gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]); | 225 | for (i = 0; i < num_devices && curr_buf; i++) { |
190 | 226 | rc = __get_next_bus_id(&curr_buf, tmp_bus_id); | |
191 | /* all devices have to be of the same type in | 227 | if (rc != 0) |
192 | * order to be grouped */ | 228 | goto error; |
229 | if (!__is_valid_bus_id(tmp_bus_id)) { | ||
230 | rc = -EINVAL; | ||
231 | goto error; | ||
232 | } | ||
233 | gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id); | ||
234 | /* | ||
235 | * All devices have to be of the same type in | ||
236 | * order to be grouped. | ||
237 | */ | ||
193 | if (!gdev->cdev[i] | 238 | if (!gdev->cdev[i] |
194 | || gdev->cdev[i]->id.driver_info != | 239 | || gdev->cdev[i]->id.driver_info != |
195 | gdev->cdev[0]->id.driver_info) { | 240 | gdev->cdev[0]->id.driver_info) { |
@@ -203,9 +248,18 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, | |||
203 | } | 248 | } |
204 | dev_set_drvdata(&gdev->cdev[i]->dev, gdev); | 249 | dev_set_drvdata(&gdev->cdev[i]->dev, gdev); |
205 | } | 250 | } |
206 | 251 | /* Check for sufficient number of bus ids. */ | |
252 | if (i < num_devices && !curr_buf) { | ||
253 | rc = -EINVAL; | ||
254 | goto error; | ||
255 | } | ||
256 | /* Check for trailing stuff. */ | ||
257 | if (i == num_devices && strlen(curr_buf) > 0) { | ||
258 | rc = -EINVAL; | ||
259 | goto error; | ||
260 | } | ||
207 | gdev->creator_id = creator_id; | 261 | gdev->creator_id = creator_id; |
208 | gdev->count = argc; | 262 | gdev->count = num_devices; |
209 | gdev->dev.bus = &ccwgroup_bus_type; | 263 | gdev->dev.bus = &ccwgroup_bus_type; |
210 | gdev->dev.parent = root; | 264 | gdev->dev.parent = root; |
211 | gdev->dev.release = ccwgroup_release; | 265 | gdev->dev.release = ccwgroup_release; |
@@ -233,7 +287,7 @@ int ccwgroup_create(struct device *root, unsigned int creator_id, | |||
233 | device_remove_file(&gdev->dev, &dev_attr_ungroup); | 287 | device_remove_file(&gdev->dev, &dev_attr_ungroup); |
234 | device_unregister(&gdev->dev); | 288 | device_unregister(&gdev->dev); |
235 | error: | 289 | error: |
236 | for (i = 0; i < argc; i++) | 290 | for (i = 0; i < num_devices; i++) |
237 | if (gdev->cdev[i]) { | 291 | if (gdev->cdev[i]) { |
238 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) | 292 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) |
239 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); | 293 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); |
@@ -243,6 +297,7 @@ error: | |||
243 | put_device(&gdev->dev); | 297 | put_device(&gdev->dev); |
244 | return rc; | 298 | return rc; |
245 | } | 299 | } |
300 | EXPORT_SYMBOL(ccwgroup_create_from_string); | ||
246 | 301 | ||
247 | static int __init | 302 | static int __init |
248 | init_ccwgroup (void) | 303 | init_ccwgroup (void) |
@@ -318,7 +373,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
318 | { | 373 | { |
319 | struct ccwgroup_device *gdev; | 374 | struct ccwgroup_device *gdev; |
320 | struct ccwgroup_driver *gdrv; | 375 | struct ccwgroup_driver *gdrv; |
321 | unsigned int value; | 376 | unsigned long value; |
322 | int ret; | 377 | int ret; |
323 | 378 | ||
324 | gdev = to_ccwgroupdev(dev); | 379 | gdev = to_ccwgroupdev(dev); |
@@ -329,7 +384,9 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
329 | if (!try_module_get(gdrv->owner)) | 384 | if (!try_module_get(gdrv->owner)) |
330 | return -EINVAL; | 385 | return -EINVAL; |
331 | 386 | ||
332 | value = simple_strtoul(buf, NULL, 0); | 387 | ret = strict_strtoul(buf, 0, &value); |
388 | if (ret) | ||
389 | goto out; | ||
333 | ret = count; | 390 | ret = count; |
334 | if (value == 1) | 391 | if (value == 1) |
335 | ccwgroup_set_online(gdev); | 392 | ccwgroup_set_online(gdev); |
@@ -337,6 +394,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
337 | ccwgroup_set_offline(gdev); | 394 | ccwgroup_set_offline(gdev); |
338 | else | 395 | else |
339 | ret = -EINVAL; | 396 | ret = -EINVAL; |
397 | out: | ||
340 | module_put(gdrv->owner); | 398 | module_put(gdrv->owner); |
341 | return ret; | 399 | return ret; |
342 | } | 400 | } |
@@ -518,6 +576,5 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev) | |||
518 | MODULE_LICENSE("GPL"); | 576 | MODULE_LICENSE("GPL"); |
519 | EXPORT_SYMBOL(ccwgroup_driver_register); | 577 | EXPORT_SYMBOL(ccwgroup_driver_register); |
520 | EXPORT_SYMBOL(ccwgroup_driver_unregister); | 578 | EXPORT_SYMBOL(ccwgroup_driver_unregister); |
521 | EXPORT_SYMBOL(ccwgroup_create); | ||
522 | EXPORT_SYMBOL(ccwgroup_probe_ccwdev); | 579 | EXPORT_SYMBOL(ccwgroup_probe_ccwdev); |
523 | EXPORT_SYMBOL(ccwgroup_remove_ccwdev); | 580 | EXPORT_SYMBOL(ccwgroup_remove_ccwdev); |
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 23ffcc4768a7..08a578161306 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -407,8 +407,7 @@ cio_modify (struct subchannel *sch) | |||
407 | /* | 407 | /* |
408 | * Enable subchannel. | 408 | * Enable subchannel. |
409 | */ | 409 | */ |
410 | int cio_enable_subchannel(struct subchannel *sch, unsigned int isc, | 410 | int cio_enable_subchannel(struct subchannel *sch, u32 intparm) |
411 | u32 intparm) | ||
412 | { | 411 | { |
413 | char dbf_txt[15]; | 412 | char dbf_txt[15]; |
414 | int ccode; | 413 | int ccode; |
@@ -426,7 +425,7 @@ int cio_enable_subchannel(struct subchannel *sch, unsigned int isc, | |||
426 | 425 | ||
427 | for (retry = 5, ret = 0; retry > 0; retry--) { | 426 | for (retry = 5, ret = 0; retry > 0; retry--) { |
428 | sch->schib.pmcw.ena = 1; | 427 | sch->schib.pmcw.ena = 1; |
429 | sch->schib.pmcw.isc = isc; | 428 | sch->schib.pmcw.isc = sch->isc; |
430 | sch->schib.pmcw.intparm = intparm; | 429 | sch->schib.pmcw.intparm = intparm; |
431 | ret = cio_modify(sch); | 430 | ret = cio_modify(sch); |
432 | if (ret == -ENODEV) | 431 | if (ret == -ENODEV) |
@@ -600,6 +599,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
600 | else | 599 | else |
601 | sch->opm = chp_get_sch_opm(sch); | 600 | sch->opm = chp_get_sch_opm(sch); |
602 | sch->lpm = sch->schib.pmcw.pam & sch->opm; | 601 | sch->lpm = sch->schib.pmcw.pam & sch->opm; |
602 | sch->isc = 3; | ||
603 | 603 | ||
604 | CIO_DEBUG(KERN_INFO, 0, | 604 | CIO_DEBUG(KERN_INFO, 0, |
605 | "Detected device %04x on subchannel 0.%x.%04X" | 605 | "Detected device %04x on subchannel 0.%x.%04X" |
@@ -610,13 +610,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid) | |||
610 | 610 | ||
611 | /* | 611 | /* |
612 | * We now have to initially ... | 612 | * We now have to initially ... |
613 | * ... set "interruption subclass" | ||
614 | * ... enable "concurrent sense" | 613 | * ... enable "concurrent sense" |
615 | * ... enable "multipath mode" if more than one | 614 | * ... enable "multipath mode" if more than one |
616 | * CHPID is available. This is done regardless | 615 | * CHPID is available. This is done regardless |
617 | * whether multiple paths are available for us. | 616 | * whether multiple paths are available for us. |
618 | */ | 617 | */ |
619 | sch->schib.pmcw.isc = 3; /* could be smth. else */ | ||
620 | sch->schib.pmcw.csense = 1; /* concurrent sense */ | 618 | sch->schib.pmcw.csense = 1; /* concurrent sense */ |
621 | sch->schib.pmcw.ena = 0; | 619 | sch->schib.pmcw.ena = 0; |
622 | if ((sch->lpm & (sch->lpm - 1)) != 0) | 620 | if ((sch->lpm & (sch->lpm - 1)) != 0) |
@@ -812,6 +810,7 @@ cio_probe_console(void) | |||
812 | * enable console I/O-interrupt subclass 7 | 810 | * enable console I/O-interrupt subclass 7 |
813 | */ | 811 | */ |
814 | ctl_set_bit(6, 24); | 812 | ctl_set_bit(6, 24); |
813 | console_subchannel.isc = 7; | ||
815 | console_subchannel.schib.pmcw.isc = 7; | 814 | console_subchannel.schib.pmcw.isc = 7; |
816 | console_subchannel.schib.pmcw.intparm = | 815 | console_subchannel.schib.pmcw.intparm = |
817 | (u32)(addr_t)&console_subchannel; | 816 | (u32)(addr_t)&console_subchannel; |
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 08f2235c5a6f..3c75412904dc 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h | |||
@@ -74,6 +74,7 @@ struct subchannel { | |||
74 | __u8 lpm; /* logical path mask */ | 74 | __u8 lpm; /* logical path mask */ |
75 | __u8 opm; /* operational path mask */ | 75 | __u8 opm; /* operational path mask */ |
76 | struct schib schib; /* subchannel information block */ | 76 | struct schib schib; /* subchannel information block */ |
77 | int isc; /* desired interruption subclass */ | ||
77 | struct chsc_ssd_info ssd_info; /* subchannel description */ | 78 | struct chsc_ssd_info ssd_info; /* subchannel description */ |
78 | struct device dev; /* entry in device tree */ | 79 | struct device dev; /* entry in device tree */ |
79 | struct css_driver *driver; | 80 | struct css_driver *driver; |
@@ -85,7 +86,7 @@ struct subchannel { | |||
85 | #define to_subchannel(n) container_of(n, struct subchannel, dev) | 86 | #define to_subchannel(n) container_of(n, struct subchannel, dev) |
86 | 87 | ||
87 | extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id); | 88 | extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id); |
88 | extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32); | 89 | extern int cio_enable_subchannel(struct subchannel *, u32); |
89 | extern int cio_disable_subchannel (struct subchannel *); | 90 | extern int cio_disable_subchannel (struct subchannel *); |
90 | extern int cio_cancel (struct subchannel *); | 91 | extern int cio_cancel (struct subchannel *); |
91 | extern int cio_clear (struct subchannel *); | 92 | extern int cio_clear (struct subchannel *); |
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index f4c132ab39ed..2808b6833b9e 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c | |||
@@ -1219,16 +1219,21 @@ static ssize_t cmb_enable_store(struct device *dev, | |||
1219 | { | 1219 | { |
1220 | struct ccw_device *cdev; | 1220 | struct ccw_device *cdev; |
1221 | int ret; | 1221 | int ret; |
1222 | unsigned long val; | ||
1223 | |||
1224 | ret = strict_strtoul(buf, 16, &val); | ||
1225 | if (ret) | ||
1226 | return ret; | ||
1222 | 1227 | ||
1223 | cdev = to_ccwdev(dev); | 1228 | cdev = to_ccwdev(dev); |
1224 | 1229 | ||
1225 | switch (buf[0]) { | 1230 | switch (val) { |
1226 | case '0': | 1231 | case 0: |
1227 | ret = disable_cmf(cdev); | 1232 | ret = disable_cmf(cdev); |
1228 | if (ret) | 1233 | if (ret) |
1229 | dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret); | 1234 | dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret); |
1230 | break; | 1235 | break; |
1231 | case '1': | 1236 | case 1: |
1232 | ret = enable_cmf(cdev); | 1237 | ret = enable_cmf(cdev); |
1233 | if (ret && ret != -EBUSY) | 1238 | if (ret && ret != -EBUSY) |
1234 | dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret); | 1239 | dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret); |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index c1afab5f72d6..595e327d2f76 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -705,13 +705,17 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr, | |||
705 | { | 705 | { |
706 | struct channel_subsystem *css = to_css(dev); | 706 | struct channel_subsystem *css = to_css(dev); |
707 | int ret; | 707 | int ret; |
708 | unsigned long val; | ||
708 | 709 | ||
710 | ret = strict_strtoul(buf, 16, &val); | ||
711 | if (ret) | ||
712 | return ret; | ||
709 | mutex_lock(&css->mutex); | 713 | mutex_lock(&css->mutex); |
710 | switch (buf[0]) { | 714 | switch (val) { |
711 | case '0': | 715 | case 0: |
712 | ret = css->cm_enabled ? chsc_secm(css, 0) : 0; | 716 | ret = css->cm_enabled ? chsc_secm(css, 0) : 0; |
713 | break; | 717 | break; |
714 | case '1': | 718 | case 1: |
715 | ret = css->cm_enabled ? 0 : chsc_secm(css, 1); | 719 | ret = css->cm_enabled ? 0 : chsc_secm(css, 1); |
716 | break; | 720 | break; |
717 | default: | 721 | default: |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index e0c7adb8958e..abfd601d237a 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -512,8 +512,8 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, | |||
512 | const char *buf, size_t count) | 512 | const char *buf, size_t count) |
513 | { | 513 | { |
514 | struct ccw_device *cdev = to_ccwdev(dev); | 514 | struct ccw_device *cdev = to_ccwdev(dev); |
515 | int i, force; | 515 | int force, ret; |
516 | char *tmp; | 516 | unsigned long i; |
517 | 517 | ||
518 | if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) | 518 | if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0) |
519 | return -EAGAIN; | 519 | return -EAGAIN; |
@@ -525,25 +525,30 @@ static ssize_t online_store (struct device *dev, struct device_attribute *attr, | |||
525 | if (!strncmp(buf, "force\n", count)) { | 525 | if (!strncmp(buf, "force\n", count)) { |
526 | force = 1; | 526 | force = 1; |
527 | i = 1; | 527 | i = 1; |
528 | ret = 0; | ||
528 | } else { | 529 | } else { |
529 | force = 0; | 530 | force = 0; |
530 | i = simple_strtoul(buf, &tmp, 16); | 531 | ret = strict_strtoul(buf, 16, &i); |
531 | } | 532 | } |
532 | 533 | if (ret) | |
534 | goto out; | ||
533 | switch (i) { | 535 | switch (i) { |
534 | case 0: | 536 | case 0: |
535 | online_store_handle_offline(cdev); | 537 | online_store_handle_offline(cdev); |
538 | ret = count; | ||
536 | break; | 539 | break; |
537 | case 1: | 540 | case 1: |
538 | online_store_handle_online(cdev, force); | 541 | online_store_handle_online(cdev, force); |
542 | ret = count; | ||
539 | break; | 543 | break; |
540 | default: | 544 | default: |
541 | count = -EINVAL; | 545 | ret = -EINVAL; |
542 | } | 546 | } |
547 | out: | ||
543 | if (cdev->drv) | 548 | if (cdev->drv) |
544 | module_put(cdev->drv->owner); | 549 | module_put(cdev->drv->owner); |
545 | atomic_set(&cdev->private->onoff, 0); | 550 | atomic_set(&cdev->private->onoff, 0); |
546 | return count; | 551 | return ret; |
547 | } | 552 | } |
548 | 553 | ||
549 | static ssize_t | 554 | static ssize_t |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 4b92c84fb438..99403b0a97a7 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -555,8 +555,7 @@ ccw_device_recognition(struct ccw_device *cdev) | |||
555 | (cdev->private->state != DEV_STATE_BOXED)) | 555 | (cdev->private->state != DEV_STATE_BOXED)) |
556 | return -EINVAL; | 556 | return -EINVAL; |
557 | sch = to_subchannel(cdev->dev.parent); | 557 | sch = to_subchannel(cdev->dev.parent); |
558 | ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc, | 558 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); |
559 | (u32)(addr_t)sch); | ||
560 | if (ret != 0) | 559 | if (ret != 0) |
561 | /* Couldn't enable the subchannel for i/o. Sick device. */ | 560 | /* Couldn't enable the subchannel for i/o. Sick device. */ |
562 | return ret; | 561 | return ret; |
@@ -667,8 +666,7 @@ ccw_device_online(struct ccw_device *cdev) | |||
667 | sch = to_subchannel(cdev->dev.parent); | 666 | sch = to_subchannel(cdev->dev.parent); |
668 | if (css_init_done && !get_device(&cdev->dev)) | 667 | if (css_init_done && !get_device(&cdev->dev)) |
669 | return -ENODEV; | 668 | return -ENODEV; |
670 | ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc, | 669 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); |
671 | (u32)(addr_t)sch); | ||
672 | if (ret != 0) { | 670 | if (ret != 0) { |
673 | /* Couldn't enable the subchannel for i/o. Sick device. */ | 671 | /* Couldn't enable the subchannel for i/o. Sick device. */ |
674 | if (ret == -ENODEV) | 672 | if (ret == -ENODEV) |
@@ -1048,8 +1046,7 @@ ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) | |||
1048 | struct subchannel *sch; | 1046 | struct subchannel *sch; |
1049 | 1047 | ||
1050 | sch = to_subchannel(cdev->dev.parent); | 1048 | sch = to_subchannel(cdev->dev.parent); |
1051 | if (cio_enable_subchannel(sch, sch->schib.pmcw.isc, | 1049 | if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0) |
1052 | (u32)(addr_t)sch) != 0) | ||
1053 | /* Couldn't enable the subchannel for i/o. Sick device. */ | 1050 | /* Couldn't enable the subchannel for i/o. Sick device. */ |
1054 | return; | 1051 | return; |
1055 | 1052 | ||
@@ -1082,7 +1079,6 @@ device_trigger_reprobe(struct subchannel *sch) | |||
1082 | */ | 1079 | */ |
1083 | sch->lpm = sch->schib.pmcw.pam & sch->opm; | 1080 | sch->lpm = sch->schib.pmcw.pam & sch->opm; |
1084 | /* Re-set some bits in the pmcw that were lost. */ | 1081 | /* Re-set some bits in the pmcw that were lost. */ |
1085 | sch->schib.pmcw.isc = 3; | ||
1086 | sch->schib.pmcw.csense = 1; | 1082 | sch->schib.pmcw.csense = 1; |
1087 | sch->schib.pmcw.ena = 0; | 1083 | sch->schib.pmcw.ena = 0; |
1088 | if ((sch->lpm & (sch->lpm - 1)) != 0) | 1084 | if ((sch->lpm & (sch->lpm - 1)) != 0) |
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index a1718a0aa539..f308ad55a6d5 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c | |||
@@ -508,7 +508,7 @@ ccw_device_stlck(struct ccw_device *cdev) | |||
508 | return -ENOMEM; | 508 | return -ENOMEM; |
509 | } | 509 | } |
510 | spin_lock_irqsave(sch->lock, flags); | 510 | spin_lock_irqsave(sch->lock, flags); |
511 | ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch); | 511 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); |
512 | if (ret) | 512 | if (ret) |
513 | goto out_unlock; | 513 | goto out_unlock; |
514 | /* | 514 | /* |
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c index 10aa1e780801..445cf364e461 100644 --- a/drivers/s390/cio/qdio.c +++ b/drivers/s390/cio/qdio.c | |||
@@ -3632,7 +3632,7 @@ qdio_add_procfs_entry(void) | |||
3632 | { | 3632 | { |
3633 | proc_perf_file_registration=0; | 3633 | proc_perf_file_registration=0; |
3634 | qdio_perf_proc_file=create_proc_entry(QDIO_PERF, | 3634 | qdio_perf_proc_file=create_proc_entry(QDIO_PERF, |
3635 | S_IFREG|0444,&proc_root); | 3635 | S_IFREG|0444,NULL); |
3636 | if (qdio_perf_proc_file) { | 3636 | if (qdio_perf_proc_file) { |
3637 | qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read; | 3637 | qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read; |
3638 | } else proc_perf_file_registration=-1; | 3638 | } else proc_perf_file_registration=-1; |
@@ -3647,7 +3647,7 @@ static void | |||
3647 | qdio_remove_procfs_entry(void) | 3647 | qdio_remove_procfs_entry(void) |
3648 | { | 3648 | { |
3649 | if (!proc_perf_file_registration) /* means if it went ok earlier */ | 3649 | if (!proc_perf_file_registration) /* means if it went ok earlier */ |
3650 | remove_proc_entry(QDIO_PERF,&proc_root); | 3650 | remove_proc_entry(QDIO_PERF,NULL); |
3651 | } | 3651 | } |
3652 | 3652 | ||
3653 | /** | 3653 | /** |
@@ -3663,11 +3663,11 @@ qdio_performance_stats_show(struct bus_type *bus, char *buf) | |||
3663 | static ssize_t | 3663 | static ssize_t |
3664 | qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count) | 3664 | qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count) |
3665 | { | 3665 | { |
3666 | char *tmp; | 3666 | unsigned long i; |
3667 | int i; | 3667 | int ret; |
3668 | 3668 | ||
3669 | i = simple_strtoul(buf, &tmp, 16); | 3669 | ret = strict_strtoul(buf, 16, &i); |
3670 | if ((i == 0) || (i == 1)) { | 3670 | if (!ret && ((i == 0) || (i == 1))) { |
3671 | if (i == qdio_performance_stats) | 3671 | if (i == qdio_performance_stats) |
3672 | return count; | 3672 | return count; |
3673 | qdio_performance_stats = i; | 3673 | qdio_performance_stats = i; |
diff --git a/drivers/s390/kvm/Makefile b/drivers/s390/kvm/Makefile new file mode 100644 index 000000000000..4a5ec39f9ca6 --- /dev/null +++ b/drivers/s390/kvm/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # Makefile for kvm guest drivers on s390 | ||
2 | # | ||
3 | # Copyright IBM Corp. 2008 | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License (version 2 only) | ||
7 | # as published by the Free Software Foundation. | ||
8 | |||
9 | obj-$(CONFIG_VIRTIO) += kvm_virtio.o | ||
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c new file mode 100644 index 000000000000..47a7e6200b26 --- /dev/null +++ b/drivers/s390/kvm/kvm_virtio.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* | ||
2 | * kvm_virtio.c - virtio for kvm on s390 | ||
3 | * | ||
4 | * Copyright IBM Corp. 2008 | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License (version 2 only) | ||
8 | * as published by the Free Software Foundation. | ||
9 | * | ||
10 | * Author(s): Christian Borntraeger <borntraeger@de.ibm.com> | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/bootmem.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/virtio.h> | ||
17 | #include <linux/virtio_config.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/virtio_ring.h> | ||
20 | #include <linux/pfn.h> | ||
21 | #include <asm/io.h> | ||
22 | #include <asm/kvm_para.h> | ||
23 | #include <asm/kvm_virtio.h> | ||
24 | #include <asm/setup.h> | ||
25 | #include <asm/s390_ext.h> | ||
26 | |||
27 | #define VIRTIO_SUBCODE_64 0x0D00 | ||
28 | |||
29 | /* | ||
30 | * The pointer to our (page) of device descriptions. | ||
31 | */ | ||
32 | static void *kvm_devices; | ||
33 | |||
34 | /* | ||
35 | * Unique numbering for kvm devices. | ||
36 | */ | ||
37 | static unsigned int dev_index; | ||
38 | |||
39 | struct kvm_device { | ||
40 | struct virtio_device vdev; | ||
41 | struct kvm_device_desc *desc; | ||
42 | }; | ||
43 | |||
44 | #define to_kvmdev(vd) container_of(vd, struct kvm_device, vdev) | ||
45 | |||
46 | /* | ||
47 | * memory layout: | ||
48 | * - kvm_device_descriptor | ||
49 | * struct kvm_device_desc | ||
50 | * - configuration | ||
51 | * struct kvm_vqconfig | ||
52 | * - feature bits | ||
53 | * - config space | ||
54 | */ | ||
55 | static struct kvm_vqconfig *kvm_vq_config(const struct kvm_device_desc *desc) | ||
56 | { | ||
57 | return (struct kvm_vqconfig *)(desc + 1); | ||
58 | } | ||
59 | |||
60 | static u8 *kvm_vq_features(const struct kvm_device_desc *desc) | ||
61 | { | ||
62 | return (u8 *)(kvm_vq_config(desc) + desc->num_vq); | ||
63 | } | ||
64 | |||
65 | static u8 *kvm_vq_configspace(const struct kvm_device_desc *desc) | ||
66 | { | ||
67 | return kvm_vq_features(desc) + desc->feature_len * 2; | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | * The total size of the config page used by this device (incl. desc) | ||
72 | */ | ||
73 | static unsigned desc_size(const struct kvm_device_desc *desc) | ||
74 | { | ||
75 | return sizeof(*desc) | ||
76 | + desc->num_vq * sizeof(struct kvm_vqconfig) | ||
77 | + desc->feature_len * 2 | ||
78 | + desc->config_len; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * This tests (and acknowleges) a feature bit. | ||
83 | */ | ||
84 | static bool kvm_feature(struct virtio_device *vdev, unsigned fbit) | ||
85 | { | ||
86 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | ||
87 | u8 *features; | ||
88 | |||
89 | if (fbit / 8 > desc->feature_len) | ||
90 | return false; | ||
91 | |||
92 | features = kvm_vq_features(desc); | ||
93 | if (!(features[fbit / 8] & (1 << (fbit % 8)))) | ||
94 | return false; | ||
95 | |||
96 | /* | ||
97 | * We set the matching bit in the other half of the bitmap to tell the | ||
98 | * Host we want to use this feature. | ||
99 | */ | ||
100 | features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8)); | ||
101 | return true; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Reading and writing elements in config space | ||
106 | */ | ||
107 | static void kvm_get(struct virtio_device *vdev, unsigned int offset, | ||
108 | void *buf, unsigned len) | ||
109 | { | ||
110 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | ||
111 | |||
112 | BUG_ON(offset + len > desc->config_len); | ||
113 | memcpy(buf, kvm_vq_configspace(desc) + offset, len); | ||
114 | } | ||
115 | |||
116 | static void kvm_set(struct virtio_device *vdev, unsigned int offset, | ||
117 | const void *buf, unsigned len) | ||
118 | { | ||
119 | struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; | ||
120 | |||
121 | BUG_ON(offset + len > desc->config_len); | ||
122 | memcpy(kvm_vq_configspace(desc) + offset, buf, len); | ||
123 | } | ||
124 | |||
125 | /* | ||
126 | * The operations to get and set the status word just access | ||
127 | * the status field of the device descriptor. set_status will also | ||
128 | * make a hypercall to the host, to tell about status changes | ||
129 | */ | ||
130 | static u8 kvm_get_status(struct virtio_device *vdev) | ||
131 | { | ||
132 | return to_kvmdev(vdev)->desc->status; | ||
133 | } | ||
134 | |||
135 | static void kvm_set_status(struct virtio_device *vdev, u8 status) | ||
136 | { | ||
137 | BUG_ON(!status); | ||
138 | to_kvmdev(vdev)->desc->status = status; | ||
139 | kvm_hypercall1(KVM_S390_VIRTIO_SET_STATUS, | ||
140 | (unsigned long) to_kvmdev(vdev)->desc); | ||
141 | } | ||
142 | |||
143 | /* | ||
144 | * To reset the device, we use the KVM_VIRTIO_RESET hypercall, using the | ||
145 | * descriptor address. The Host will zero the status and all the | ||
146 | * features. | ||
147 | */ | ||
148 | static void kvm_reset(struct virtio_device *vdev) | ||
149 | { | ||
150 | kvm_hypercall1(KVM_S390_VIRTIO_RESET, | ||
151 | (unsigned long) to_kvmdev(vdev)->desc); | ||
152 | } | ||
153 | |||
154 | /* | ||
155 | * When the virtio_ring code wants to notify the Host, it calls us here and we | ||
156 | * make a hypercall. We hand the address of the virtqueue so the Host | ||
157 | * knows which virtqueue we're talking about. | ||
158 | */ | ||
159 | static void kvm_notify(struct virtqueue *vq) | ||
160 | { | ||
161 | struct kvm_vqconfig *config = vq->priv; | ||
162 | |||
163 | kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, config->address); | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * This routine finds the first virtqueue described in the configuration of | ||
168 | * this device and sets it up. | ||
169 | */ | ||
170 | static struct virtqueue *kvm_find_vq(struct virtio_device *vdev, | ||
171 | unsigned index, | ||
172 | void (*callback)(struct virtqueue *vq)) | ||
173 | { | ||
174 | struct kvm_device *kdev = to_kvmdev(vdev); | ||
175 | struct kvm_vqconfig *config; | ||
176 | struct virtqueue *vq; | ||
177 | int err; | ||
178 | |||
179 | if (index >= kdev->desc->num_vq) | ||
180 | return ERR_PTR(-ENOENT); | ||
181 | |||
182 | config = kvm_vq_config(kdev->desc)+index; | ||
183 | |||
184 | err = vmem_add_mapping(config->address, | ||
185 | vring_size(config->num, PAGE_SIZE)); | ||
186 | if (err) | ||
187 | goto out; | ||
188 | |||
189 | vq = vring_new_virtqueue(config->num, vdev, (void *) config->address, | ||
190 | kvm_notify, callback); | ||
191 | if (!vq) { | ||
192 | err = -ENOMEM; | ||
193 | goto unmap; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * register a callback token | ||
198 | * The host will sent this via the external interrupt parameter | ||
199 | */ | ||
200 | config->token = (u64) vq; | ||
201 | |||
202 | vq->priv = config; | ||
203 | return vq; | ||
204 | unmap: | ||
205 | vmem_remove_mapping(config->address, | ||
206 | vring_size(config->num, PAGE_SIZE)); | ||
207 | out: | ||
208 | return ERR_PTR(err); | ||
209 | } | ||
210 | |||
211 | static void kvm_del_vq(struct virtqueue *vq) | ||
212 | { | ||
213 | struct kvm_vqconfig *config = vq->priv; | ||
214 | |||
215 | vring_del_virtqueue(vq); | ||
216 | vmem_remove_mapping(config->address, | ||
217 | vring_size(config->num, PAGE_SIZE)); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * The config ops structure as defined by virtio config | ||
222 | */ | ||
223 | static struct virtio_config_ops kvm_vq_configspace_ops = { | ||
224 | .feature = kvm_feature, | ||
225 | .get = kvm_get, | ||
226 | .set = kvm_set, | ||
227 | .get_status = kvm_get_status, | ||
228 | .set_status = kvm_set_status, | ||
229 | .reset = kvm_reset, | ||
230 | .find_vq = kvm_find_vq, | ||
231 | .del_vq = kvm_del_vq, | ||
232 | }; | ||
233 | |||
234 | /* | ||
235 | * The root device for the kvm virtio devices. | ||
236 | * This makes them appear as /sys/devices/kvm_s390/0,1,2 not /sys/devices/0,1,2. | ||
237 | */ | ||
238 | static struct device kvm_root = { | ||
239 | .parent = NULL, | ||
240 | .bus_id = "kvm_s390", | ||
241 | }; | ||
242 | |||
243 | /* | ||
244 | * adds a new device and register it with virtio | ||
245 | * appropriate drivers are loaded by the device model | ||
246 | */ | ||
247 | static void add_kvm_device(struct kvm_device_desc *d) | ||
248 | { | ||
249 | struct kvm_device *kdev; | ||
250 | |||
251 | kdev = kzalloc(sizeof(*kdev), GFP_KERNEL); | ||
252 | if (!kdev) { | ||
253 | printk(KERN_EMERG "Cannot allocate kvm dev %u\n", | ||
254 | dev_index++); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | kdev->vdev.dev.parent = &kvm_root; | ||
259 | kdev->vdev.index = dev_index++; | ||
260 | kdev->vdev.id.device = d->type; | ||
261 | kdev->vdev.config = &kvm_vq_configspace_ops; | ||
262 | kdev->desc = d; | ||
263 | |||
264 | if (register_virtio_device(&kdev->vdev) != 0) { | ||
265 | printk(KERN_ERR "Failed to register kvm device %u\n", | ||
266 | kdev->vdev.index); | ||
267 | kfree(kdev); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* | ||
272 | * scan_devices() simply iterates through the device page. | ||
273 | * The type 0 is reserved to mean "end of devices". | ||
274 | */ | ||
275 | static void scan_devices(void) | ||
276 | { | ||
277 | unsigned int i; | ||
278 | struct kvm_device_desc *d; | ||
279 | |||
280 | for (i = 0; i < PAGE_SIZE; i += desc_size(d)) { | ||
281 | d = kvm_devices + i; | ||
282 | |||
283 | if (d->type == 0) | ||
284 | break; | ||
285 | |||
286 | add_kvm_device(d); | ||
287 | } | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * we emulate the request_irq behaviour on top of s390 extints | ||
292 | */ | ||
293 | static void kvm_extint_handler(u16 code) | ||
294 | { | ||
295 | void *data = (void *) *(long *) __LC_PFAULT_INTPARM; | ||
296 | u16 subcode = S390_lowcore.cpu_addr; | ||
297 | |||
298 | if ((subcode & 0xff00) != VIRTIO_SUBCODE_64) | ||
299 | return; | ||
300 | |||
301 | vring_interrupt(0, data); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Init function for virtio | ||
306 | * devices are in a single page above top of "normal" mem | ||
307 | */ | ||
308 | static int __init kvm_devices_init(void) | ||
309 | { | ||
310 | int rc; | ||
311 | |||
312 | if (!MACHINE_IS_KVM) | ||
313 | return -ENODEV; | ||
314 | |||
315 | rc = device_register(&kvm_root); | ||
316 | if (rc) { | ||
317 | printk(KERN_ERR "Could not register kvm_s390 root device"); | ||
318 | return rc; | ||
319 | } | ||
320 | |||
321 | rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE); | ||
322 | if (rc) { | ||
323 | device_unregister(&kvm_root); | ||
324 | return rc; | ||
325 | } | ||
326 | |||
327 | kvm_devices = (void *) PFN_PHYS(max_pfn); | ||
328 | |||
329 | ctl_set_bit(0, 9); | ||
330 | register_external_interrupt(0x2603, kvm_extint_handler); | ||
331 | |||
332 | scan_devices(); | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | /* | ||
337 | * We do this after core stuff, but before the drivers. | ||
338 | */ | ||
339 | postcore_initcall(kvm_devices_init); | ||
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c index 76728ae4b843..8e7697305a4c 100644 --- a/drivers/s390/net/cu3088.c +++ b/drivers/s390/net/cu3088.c | |||
@@ -62,30 +62,14 @@ static struct device *cu3088_root_dev; | |||
62 | static ssize_t | 62 | static ssize_t |
63 | group_write(struct device_driver *drv, const char *buf, size_t count) | 63 | group_write(struct device_driver *drv, const char *buf, size_t count) |
64 | { | 64 | { |
65 | const char *start, *end; | ||
66 | char bus_ids[2][BUS_ID_SIZE], *argv[2]; | ||
67 | int i; | ||
68 | int ret; | 65 | int ret; |
69 | struct ccwgroup_driver *cdrv; | 66 | struct ccwgroup_driver *cdrv; |
70 | 67 | ||
71 | cdrv = to_ccwgroupdrv(drv); | 68 | cdrv = to_ccwgroupdrv(drv); |
72 | if (!cdrv) | 69 | if (!cdrv) |
73 | return -EINVAL; | 70 | return -EINVAL; |
74 | start = buf; | 71 | ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id, |
75 | for (i=0; i<2; i++) { | 72 | &cu3088_driver, 2, buf); |
76 | static const char delim[] = {',', '\n'}; | ||
77 | int len; | ||
78 | |||
79 | if (!(end = strchr(start, delim[i]))) | ||
80 | return -EINVAL; | ||
81 | len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1); | ||
82 | strlcpy (bus_ids[i], start, len); | ||
83 | argv[i] = bus_ids[i]; | ||
84 | start = end + 1; | ||
85 | } | ||
86 | |||
87 | ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id, | ||
88 | &cu3088_driver, 2, argv); | ||
89 | 73 | ||
90 | return (ret == 0) ? count : ret; | 74 | return (ret == 0) ? count : ret; |
91 | } | 75 | } |
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index f51ed9972587..dd22f4b37037 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -1793,7 +1793,8 @@ lcs_get_skb(struct lcs_card *card, char *skb_data, unsigned int skb_len) | |||
1793 | skb->protocol = card->lan_type_trans(skb, card->dev); | 1793 | skb->protocol = card->lan_type_trans(skb, card->dev); |
1794 | card->stats.rx_bytes += skb_len; | 1794 | card->stats.rx_bytes += skb_len; |
1795 | card->stats.rx_packets++; | 1795 | card->stats.rx_packets++; |
1796 | *((__u32 *)skb->cb) = ++card->pkt_seq; | 1796 | if (skb->protocol == htons(ETH_P_802_2)) |
1797 | *((__u32 *)skb->cb) = ++card->pkt_seq; | ||
1797 | netif_rx(skb); | 1798 | netif_rx(skb); |
1798 | } | 1799 | } |
1799 | 1800 | ||
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 8f876f6ab367..e4ba6a0372ac 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -1313,8 +1313,6 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) | |||
1313 | * and throw away packet. | 1313 | * and throw away packet. |
1314 | */ | 1314 | */ |
1315 | if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) { | 1315 | if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) { |
1316 | if (!in_atomic()) | ||
1317 | fsm_event(privptr->fsm, DEV_EVENT_START, dev); | ||
1318 | dev_kfree_skb(skb); | 1316 | dev_kfree_skb(skb); |
1319 | privptr->stats.tx_dropped++; | 1317 | privptr->stats.tx_dropped++; |
1320 | privptr->stats.tx_errors++; | 1318 | privptr->stats.tx_errors++; |
@@ -2147,6 +2145,7 @@ static int __init netiucv_init(void) | |||
2147 | if (rc) | 2145 | if (rc) |
2148 | goto out_dbf; | 2146 | goto out_dbf; |
2149 | IUCV_DBF_TEXT(trace, 3, __func__); | 2147 | IUCV_DBF_TEXT(trace, 3, __func__); |
2148 | netiucv_driver.groups = netiucv_drv_attr_groups; | ||
2150 | rc = driver_register(&netiucv_driver); | 2149 | rc = driver_register(&netiucv_driver); |
2151 | if (rc) { | 2150 | if (rc) { |
2152 | PRINT_ERR("NETIUCV: failed to register driver.\n"); | 2151 | PRINT_ERR("NETIUCV: failed to register driver.\n"); |
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index 66f4f12503c9..699ac11debd8 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h | |||
@@ -72,22 +72,7 @@ struct qeth_dbf_info { | |||
72 | debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text) | 72 | debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text) |
73 | 73 | ||
74 | #define QETH_DBF_TEXT_(name, level, text...) \ | 74 | #define QETH_DBF_TEXT_(name, level, text...) \ |
75 | do { \ | 75 | qeth_dbf_longtext(QETH_DBF_##name, level, text) |
76 | if (qeth_dbf_passes(qeth_dbf[QETH_DBF_##name].id, level)) { \ | ||
77 | char *dbf_txt_buf = \ | ||
78 | get_cpu_var(QETH_DBF_TXT_BUF); \ | ||
79 | sprintf(dbf_txt_buf, text); \ | ||
80 | debug_text_event(qeth_dbf[QETH_DBF_##name].id, \ | ||
81 | level, dbf_txt_buf); \ | ||
82 | put_cpu_var(QETH_DBF_TXT_BUF); \ | ||
83 | } \ | ||
84 | } while (0) | ||
85 | |||
86 | /* Allow to sort out low debug levels early to avoid wasted sprints */ | ||
87 | static inline int qeth_dbf_passes(debug_info_t *dbf_grp, int level) | ||
88 | { | ||
89 | return (level <= dbf_grp->level); | ||
90 | } | ||
91 | 76 | ||
92 | /** | 77 | /** |
93 | * some more debug stuff | 78 | * some more debug stuff |
@@ -773,27 +758,6 @@ static inline int qeth_get_micros(void) | |||
773 | return (int) (get_clock() >> 12); | 758 | return (int) (get_clock() >> 12); |
774 | } | 759 | } |
775 | 760 | ||
776 | static inline void *qeth_push_skb(struct qeth_card *card, struct sk_buff *skb, | ||
777 | int size) | ||
778 | { | ||
779 | void *hdr; | ||
780 | |||
781 | hdr = (void *) skb_push(skb, size); | ||
782 | /* | ||
783 | * sanity check, the Linux memory allocation scheme should | ||
784 | * never present us cases like this one (the qdio header size plus | ||
785 | * the first 40 bytes of the paket cross a 4k boundary) | ||
786 | */ | ||
787 | if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) != | ||
788 | (((unsigned long) hdr + size + | ||
789 | QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) { | ||
790 | PRINT_ERR("Misaligned packet on interface %s. Discarded.", | ||
791 | QETH_CARD_IFNAME(card)); | ||
792 | return NULL; | ||
793 | } | ||
794 | return hdr; | ||
795 | } | ||
796 | |||
797 | static inline int qeth_get_ip_version(struct sk_buff *skb) | 761 | static inline int qeth_get_ip_version(struct sk_buff *skb) |
798 | { | 762 | { |
799 | switch (skb->protocol) { | 763 | switch (skb->protocol) { |
@@ -806,6 +770,12 @@ static inline int qeth_get_ip_version(struct sk_buff *skb) | |||
806 | } | 770 | } |
807 | } | 771 | } |
808 | 772 | ||
773 | static inline void qeth_put_buffer_pool_entry(struct qeth_card *card, | ||
774 | struct qeth_buffer_pool_entry *entry) | ||
775 | { | ||
776 | list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list); | ||
777 | } | ||
778 | |||
809 | struct qeth_eddp_context; | 779 | struct qeth_eddp_context; |
810 | extern struct ccwgroup_driver qeth_l2_ccwgroup_driver; | 780 | extern struct ccwgroup_driver qeth_l2_ccwgroup_driver; |
811 | extern struct ccwgroup_driver qeth_l3_ccwgroup_driver; | 781 | extern struct ccwgroup_driver qeth_l3_ccwgroup_driver; |
@@ -843,8 +813,6 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *, | |||
843 | int qeth_query_setadapterparms(struct qeth_card *); | 813 | int qeth_query_setadapterparms(struct qeth_card *); |
844 | int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, | 814 | int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, |
845 | unsigned int, const char *); | 815 | unsigned int, const char *); |
846 | void qeth_put_buffer_pool_entry(struct qeth_card *, | ||
847 | struct qeth_buffer_pool_entry *); | ||
848 | void qeth_queue_input_buffer(struct qeth_card *, int); | 816 | void qeth_queue_input_buffer(struct qeth_card *, int); |
849 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, | 817 | struct sk_buff *qeth_core_get_next_skb(struct qeth_card *, |
850 | struct qdio_buffer *, struct qdio_buffer_element **, int *, | 818 | struct qdio_buffer *, struct qdio_buffer_element **, int *, |
@@ -880,8 +848,6 @@ int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, | |||
880 | void *reply_param); | 848 | void *reply_param); |
881 | int qeth_get_cast_type(struct qeth_card *, struct sk_buff *); | 849 | int qeth_get_cast_type(struct qeth_card *, struct sk_buff *); |
882 | int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); | 850 | int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); |
883 | struct sk_buff *qeth_prepare_skb(struct qeth_card *, struct sk_buff *, | ||
884 | struct qeth_hdr **); | ||
885 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); | 851 | int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int); |
886 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, | 852 | int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *, |
887 | struct sk_buff *, struct qeth_hdr *, int, | 853 | struct sk_buff *, struct qeth_hdr *, int, |
@@ -894,6 +860,8 @@ void qeth_core_get_ethtool_stats(struct net_device *, | |||
894 | struct ethtool_stats *, u64 *); | 860 | struct ethtool_stats *, u64 *); |
895 | void qeth_core_get_strings(struct net_device *, u32, u8 *); | 861 | void qeth_core_get_strings(struct net_device *, u32, u8 *); |
896 | void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); | 862 | void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *); |
863 | void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...); | ||
864 | int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *); | ||
897 | 865 | ||
898 | /* exports for OSN */ | 866 | /* exports for OSN */ |
899 | int qeth_osn_assist(struct net_device *, void *, int); | 867 | int qeth_osn_assist(struct net_device *, void *, int); |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 055f5c3e7b56..436bf1f6d4a6 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -26,9 +26,6 @@ | |||
26 | #include "qeth_core.h" | 26 | #include "qeth_core.h" |
27 | #include "qeth_core_offl.h" | 27 | #include "qeth_core_offl.h" |
28 | 28 | ||
29 | static DEFINE_PER_CPU(char[256], qeth_core_dbf_txt_buf); | ||
30 | #define QETH_DBF_TXT_BUF qeth_core_dbf_txt_buf | ||
31 | |||
32 | struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = { | 29 | struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = { |
33 | /* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */ | 30 | /* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */ |
34 | /* N P A M L V H */ | 31 | /* N P A M L V H */ |
@@ -2255,14 +2252,6 @@ void qeth_print_status_message(struct qeth_card *card) | |||
2255 | } | 2252 | } |
2256 | EXPORT_SYMBOL_GPL(qeth_print_status_message); | 2253 | EXPORT_SYMBOL_GPL(qeth_print_status_message); |
2257 | 2254 | ||
2258 | void qeth_put_buffer_pool_entry(struct qeth_card *card, | ||
2259 | struct qeth_buffer_pool_entry *entry) | ||
2260 | { | ||
2261 | QETH_DBF_TEXT(TRACE, 6, "ptbfplen"); | ||
2262 | list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list); | ||
2263 | } | ||
2264 | EXPORT_SYMBOL_GPL(qeth_put_buffer_pool_entry); | ||
2265 | |||
2266 | static void qeth_initialize_working_pool_list(struct qeth_card *card) | 2255 | static void qeth_initialize_working_pool_list(struct qeth_card *card) |
2267 | { | 2256 | { |
2268 | struct qeth_buffer_pool_entry *entry; | 2257 | struct qeth_buffer_pool_entry *entry; |
@@ -2603,7 +2592,6 @@ void qeth_queue_input_buffer(struct qeth_card *card, int index) | |||
2603 | int rc; | 2592 | int rc; |
2604 | int newcount = 0; | 2593 | int newcount = 0; |
2605 | 2594 | ||
2606 | QETH_DBF_TEXT(TRACE, 6, "queinbuf"); | ||
2607 | count = (index < queue->next_buf_to_init)? | 2595 | count = (index < queue->next_buf_to_init)? |
2608 | card->qdio.in_buf_pool.buf_count - | 2596 | card->qdio.in_buf_pool.buf_count - |
2609 | (queue->next_buf_to_init - index) : | 2597 | (queue->next_buf_to_init - index) : |
@@ -2792,8 +2780,6 @@ static void qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int, | |||
2792 | int i; | 2780 | int i; |
2793 | unsigned int qdio_flags; | 2781 | unsigned int qdio_flags; |
2794 | 2782 | ||
2795 | QETH_DBF_TEXT(TRACE, 6, "flushbuf"); | ||
2796 | |||
2797 | for (i = index; i < index + count; ++i) { | 2783 | for (i = index; i < index + count; ++i) { |
2798 | buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; | 2784 | buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q]; |
2799 | buf->buffer->element[buf->next_element_to_fill - 1].flags |= | 2785 | buf->buffer->element[buf->next_element_to_fill - 1].flags |= |
@@ -3037,49 +3023,6 @@ int qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb, | |||
3037 | } | 3023 | } |
3038 | EXPORT_SYMBOL_GPL(qeth_get_priority_queue); | 3024 | EXPORT_SYMBOL_GPL(qeth_get_priority_queue); |
3039 | 3025 | ||
3040 | static void __qeth_free_new_skb(struct sk_buff *orig_skb, | ||
3041 | struct sk_buff *new_skb) | ||
3042 | { | ||
3043 | if (orig_skb != new_skb) | ||
3044 | dev_kfree_skb_any(new_skb); | ||
3045 | } | ||
3046 | |||
3047 | static inline struct sk_buff *qeth_realloc_headroom(struct qeth_card *card, | ||
3048 | struct sk_buff *skb, int size) | ||
3049 | { | ||
3050 | struct sk_buff *new_skb = skb; | ||
3051 | |||
3052 | if (skb_headroom(skb) >= size) | ||
3053 | return skb; | ||
3054 | new_skb = skb_realloc_headroom(skb, size); | ||
3055 | if (!new_skb) | ||
3056 | PRINT_ERR("Could not realloc headroom for qeth_hdr " | ||
3057 | "on interface %s", QETH_CARD_IFNAME(card)); | ||
3058 | return new_skb; | ||
3059 | } | ||
3060 | |||
3061 | struct sk_buff *qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, | ||
3062 | struct qeth_hdr **hdr) | ||
3063 | { | ||
3064 | struct sk_buff *new_skb; | ||
3065 | |||
3066 | QETH_DBF_TEXT(TRACE, 6, "prepskb"); | ||
3067 | |||
3068 | new_skb = qeth_realloc_headroom(card, skb, | ||
3069 | sizeof(struct qeth_hdr)); | ||
3070 | if (!new_skb) | ||
3071 | return NULL; | ||
3072 | |||
3073 | *hdr = ((struct qeth_hdr *)qeth_push_skb(card, new_skb, | ||
3074 | sizeof(struct qeth_hdr))); | ||
3075 | if (*hdr == NULL) { | ||
3076 | __qeth_free_new_skb(skb, new_skb); | ||
3077 | return NULL; | ||
3078 | } | ||
3079 | return new_skb; | ||
3080 | } | ||
3081 | EXPORT_SYMBOL_GPL(qeth_prepare_skb); | ||
3082 | |||
3083 | int qeth_get_elements_no(struct qeth_card *card, void *hdr, | 3026 | int qeth_get_elements_no(struct qeth_card *card, void *hdr, |
3084 | struct sk_buff *skb, int elems) | 3027 | struct sk_buff *skb, int elems) |
3085 | { | 3028 | { |
@@ -3100,8 +3043,8 @@ int qeth_get_elements_no(struct qeth_card *card, void *hdr, | |||
3100 | } | 3043 | } |
3101 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); | 3044 | EXPORT_SYMBOL_GPL(qeth_get_elements_no); |
3102 | 3045 | ||
3103 | static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, | 3046 | static inline void __qeth_fill_buffer(struct sk_buff *skb, |
3104 | int is_tso, int *next_element_to_fill) | 3047 | struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill) |
3105 | { | 3048 | { |
3106 | int length = skb->len; | 3049 | int length = skb->len; |
3107 | int length_here; | 3050 | int length_here; |
@@ -3143,15 +3086,13 @@ static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer, | |||
3143 | *next_element_to_fill = element; | 3086 | *next_element_to_fill = element; |
3144 | } | 3087 | } |
3145 | 3088 | ||
3146 | static int qeth_fill_buffer(struct qeth_qdio_out_q *queue, | 3089 | static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue, |
3147 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) | 3090 | struct qeth_qdio_out_buffer *buf, struct sk_buff *skb) |
3148 | { | 3091 | { |
3149 | struct qdio_buffer *buffer; | 3092 | struct qdio_buffer *buffer; |
3150 | struct qeth_hdr_tso *hdr; | 3093 | struct qeth_hdr_tso *hdr; |
3151 | int flush_cnt = 0, hdr_len, large_send = 0; | 3094 | int flush_cnt = 0, hdr_len, large_send = 0; |
3152 | 3095 | ||
3153 | QETH_DBF_TEXT(TRACE, 6, "qdfillbf"); | ||
3154 | |||
3155 | buffer = buf->buffer; | 3096 | buffer = buf->buffer; |
3156 | atomic_inc(&skb->users); | 3097 | atomic_inc(&skb->users); |
3157 | skb_queue_tail(&buf->skb_list, skb); | 3098 | skb_queue_tail(&buf->skb_list, skb); |
@@ -3210,8 +3151,6 @@ int qeth_do_send_packet_fast(struct qeth_card *card, | |||
3210 | int flush_cnt = 0; | 3151 | int flush_cnt = 0; |
3211 | int index; | 3152 | int index; |
3212 | 3153 | ||
3213 | QETH_DBF_TEXT(TRACE, 6, "dosndpfa"); | ||
3214 | |||
3215 | /* spin until we get the queue ... */ | 3154 | /* spin until we get the queue ... */ |
3216 | while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED, | 3155 | while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED, |
3217 | QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED); | 3156 | QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED); |
@@ -3263,8 +3202,6 @@ int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, | |||
3263 | int tmp; | 3202 | int tmp; |
3264 | int rc = 0; | 3203 | int rc = 0; |
3265 | 3204 | ||
3266 | QETH_DBF_TEXT(TRACE, 6, "dosndpkt"); | ||
3267 | |||
3268 | /* spin until we get the queue ... */ | 3205 | /* spin until we get the queue ... */ |
3269 | while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED, | 3206 | while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED, |
3270 | QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED); | 3207 | QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED); |
@@ -3827,27 +3764,8 @@ static struct ccw_driver qeth_ccw_driver = { | |||
3827 | static int qeth_core_driver_group(const char *buf, struct device *root_dev, | 3764 | static int qeth_core_driver_group(const char *buf, struct device *root_dev, |
3828 | unsigned long driver_id) | 3765 | unsigned long driver_id) |
3829 | { | 3766 | { |
3830 | const char *start, *end; | 3767 | return ccwgroup_create_from_string(root_dev, driver_id, |
3831 | char bus_ids[3][BUS_ID_SIZE], *argv[3]; | 3768 | &qeth_ccw_driver, 3, buf); |
3832 | int i; | ||
3833 | |||
3834 | start = buf; | ||
3835 | for (i = 0; i < 3; i++) { | ||
3836 | static const char delim[] = { ',', ',', '\n' }; | ||
3837 | int len; | ||
3838 | |||
3839 | end = strchr(start, delim[i]); | ||
3840 | if (!end) | ||
3841 | return -EINVAL; | ||
3842 | len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start); | ||
3843 | strncpy(bus_ids[i], start, len); | ||
3844 | bus_ids[i][len] = '\0'; | ||
3845 | start = end + 1; | ||
3846 | argv[i] = bus_ids[i]; | ||
3847 | } | ||
3848 | |||
3849 | return (ccwgroup_create(root_dev, driver_id, | ||
3850 | &qeth_ccw_driver, 3, argv)); | ||
3851 | } | 3769 | } |
3852 | 3770 | ||
3853 | int qeth_core_hardsetup_card(struct qeth_card *card) | 3771 | int qeth_core_hardsetup_card(struct qeth_card *card) |
@@ -3885,8 +3803,9 @@ retry: | |||
3885 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); | 3803 | QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc); |
3886 | return rc; | 3804 | return rc; |
3887 | } | 3805 | } |
3888 | 3806 | mpno = qdio_get_ssqd_pct(CARD_DDEV(card)); | |
3889 | mpno = QETH_MAX_PORTNO; | 3807 | if (mpno) |
3808 | mpno = min(mpno - 1, QETH_MAX_PORTNO); | ||
3890 | if (card->info.portno > mpno) { | 3809 | if (card->info.portno > mpno) { |
3891 | PRINT_ERR("Device %s does not offer port number %d \n.", | 3810 | PRINT_ERR("Device %s does not offer port number %d \n.", |
3892 | CARD_BUS_ID(card), card->info.portno); | 3811 | CARD_BUS_ID(card), card->info.portno); |
@@ -3980,7 +3899,6 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card, | |||
3980 | int use_rx_sg = 0; | 3899 | int use_rx_sg = 0; |
3981 | int frag = 0; | 3900 | int frag = 0; |
3982 | 3901 | ||
3983 | QETH_DBF_TEXT(TRACE, 6, "nextskb"); | ||
3984 | /* qeth_hdr must not cross element boundaries */ | 3902 | /* qeth_hdr must not cross element boundaries */ |
3985 | if (element->length < offset + sizeof(struct qeth_hdr)) { | 3903 | if (element->length < offset + sizeof(struct qeth_hdr)) { |
3986 | if (qeth_is_last_sbale(element)) | 3904 | if (qeth_is_last_sbale(element)) |
@@ -4086,6 +4004,18 @@ static void qeth_unregister_dbf_views(void) | |||
4086 | } | 4004 | } |
4087 | } | 4005 | } |
4088 | 4006 | ||
4007 | void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...) | ||
4008 | { | ||
4009 | char dbf_txt_buf[32]; | ||
4010 | |||
4011 | if (level > (qeth_dbf[dbf_nix].id)->level) | ||
4012 | return; | ||
4013 | snprintf(dbf_txt_buf, sizeof(dbf_txt_buf), text); | ||
4014 | debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf); | ||
4015 | |||
4016 | } | ||
4017 | EXPORT_SYMBOL_GPL(qeth_dbf_longtext); | ||
4018 | |||
4089 | static int qeth_register_dbf_views(void) | 4019 | static int qeth_register_dbf_views(void) |
4090 | { | 4020 | { |
4091 | int ret; | 4021 | int ret; |
@@ -4433,6 +4363,96 @@ void qeth_core_get_drvinfo(struct net_device *dev, | |||
4433 | } | 4363 | } |
4434 | EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo); | 4364 | EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo); |
4435 | 4365 | ||
4366 | int qeth_core_ethtool_get_settings(struct net_device *netdev, | ||
4367 | struct ethtool_cmd *ecmd) | ||
4368 | { | ||
4369 | struct qeth_card *card = netdev_priv(netdev); | ||
4370 | enum qeth_link_types link_type; | ||
4371 | |||
4372 | if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan)) | ||
4373 | link_type = QETH_LINK_TYPE_10GBIT_ETH; | ||
4374 | else | ||
4375 | link_type = card->info.link_type; | ||
4376 | |||
4377 | ecmd->transceiver = XCVR_INTERNAL; | ||
4378 | ecmd->supported = SUPPORTED_Autoneg; | ||
4379 | ecmd->advertising = ADVERTISED_Autoneg; | ||
4380 | ecmd->duplex = DUPLEX_FULL; | ||
4381 | ecmd->autoneg = AUTONEG_ENABLE; | ||
4382 | |||
4383 | switch (link_type) { | ||
4384 | case QETH_LINK_TYPE_FAST_ETH: | ||
4385 | case QETH_LINK_TYPE_LANE_ETH100: | ||
4386 | ecmd->supported |= SUPPORTED_10baseT_Half | | ||
4387 | SUPPORTED_10baseT_Full | | ||
4388 | SUPPORTED_100baseT_Half | | ||
4389 | SUPPORTED_100baseT_Full | | ||
4390 | SUPPORTED_TP; | ||
4391 | ecmd->advertising |= ADVERTISED_10baseT_Half | | ||
4392 | ADVERTISED_10baseT_Full | | ||
4393 | ADVERTISED_100baseT_Half | | ||
4394 | ADVERTISED_100baseT_Full | | ||
4395 | ADVERTISED_TP; | ||
4396 | ecmd->speed = SPEED_100; | ||
4397 | ecmd->port = PORT_TP; | ||
4398 | break; | ||
4399 | |||
4400 | case QETH_LINK_TYPE_GBIT_ETH: | ||
4401 | case QETH_LINK_TYPE_LANE_ETH1000: | ||
4402 | ecmd->supported |= SUPPORTED_10baseT_Half | | ||
4403 | SUPPORTED_10baseT_Full | | ||
4404 | SUPPORTED_100baseT_Half | | ||
4405 | SUPPORTED_100baseT_Full | | ||
4406 | SUPPORTED_1000baseT_Half | | ||
4407 | SUPPORTED_1000baseT_Full | | ||
4408 | SUPPORTED_FIBRE; | ||
4409 | ecmd->advertising |= ADVERTISED_10baseT_Half | | ||
4410 | ADVERTISED_10baseT_Full | | ||
4411 | ADVERTISED_100baseT_Half | | ||
4412 | ADVERTISED_100baseT_Full | | ||
4413 | ADVERTISED_1000baseT_Half | | ||
4414 | ADVERTISED_1000baseT_Full | | ||
4415 | ADVERTISED_FIBRE; | ||
4416 | ecmd->speed = SPEED_1000; | ||
4417 | ecmd->port = PORT_FIBRE; | ||
4418 | break; | ||
4419 | |||
4420 | case QETH_LINK_TYPE_10GBIT_ETH: | ||
4421 | ecmd->supported |= SUPPORTED_10baseT_Half | | ||
4422 | SUPPORTED_10baseT_Full | | ||
4423 | SUPPORTED_100baseT_Half | | ||
4424 | SUPPORTED_100baseT_Full | | ||
4425 | SUPPORTED_1000baseT_Half | | ||
4426 | SUPPORTED_1000baseT_Full | | ||
4427 | SUPPORTED_10000baseT_Full | | ||
4428 | SUPPORTED_FIBRE; | ||
4429 | ecmd->advertising |= ADVERTISED_10baseT_Half | | ||
4430 | ADVERTISED_10baseT_Full | | ||
4431 | ADVERTISED_100baseT_Half | | ||
4432 | ADVERTISED_100baseT_Full | | ||
4433 | ADVERTISED_1000baseT_Half | | ||
4434 | ADVERTISED_1000baseT_Full | | ||
4435 | ADVERTISED_10000baseT_Full | | ||
4436 | ADVERTISED_FIBRE; | ||
4437 | ecmd->speed = SPEED_10000; | ||
4438 | ecmd->port = PORT_FIBRE; | ||
4439 | break; | ||
4440 | |||
4441 | default: | ||
4442 | ecmd->supported |= SUPPORTED_10baseT_Half | | ||
4443 | SUPPORTED_10baseT_Full | | ||
4444 | SUPPORTED_TP; | ||
4445 | ecmd->advertising |= ADVERTISED_10baseT_Half | | ||
4446 | ADVERTISED_10baseT_Full | | ||
4447 | ADVERTISED_TP; | ||
4448 | ecmd->speed = SPEED_10; | ||
4449 | ecmd->port = PORT_TP; | ||
4450 | } | ||
4451 | |||
4452 | return 0; | ||
4453 | } | ||
4454 | EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings); | ||
4455 | |||
4436 | static int __init qeth_core_init(void) | 4456 | static int __init qeth_core_init(void) |
4437 | { | 4457 | { |
4438 | int rc; | 4458 | int rc; |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 3921d1631a78..86ec50ddae13 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -22,9 +22,6 @@ | |||
22 | #include "qeth_core.h" | 22 | #include "qeth_core.h" |
23 | #include "qeth_core_offl.h" | 23 | #include "qeth_core_offl.h" |
24 | 24 | ||
25 | #define QETH_DBF_TXT_BUF qeth_l2_dbf_txt_buf | ||
26 | static DEFINE_PER_CPU(char[256], qeth_l2_dbf_txt_buf); | ||
27 | |||
28 | static int qeth_l2_set_offline(struct ccwgroup_device *); | 25 | static int qeth_l2_set_offline(struct ccwgroup_device *); |
29 | static int qeth_l2_stop(struct net_device *); | 26 | static int qeth_l2_stop(struct net_device *); |
30 | static int qeth_l2_send_delmac(struct qeth_card *, __u8 *); | 27 | static int qeth_l2_send_delmac(struct qeth_card *, __u8 *); |
@@ -635,8 +632,6 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
635 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 632 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
636 | struct qeth_eddp_context *ctx = NULL; | 633 | struct qeth_eddp_context *ctx = NULL; |
637 | 634 | ||
638 | QETH_DBF_TEXT(TRACE, 6, "l2xmit"); | ||
639 | |||
640 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { | 635 | if ((card->state != CARD_STATE_UP) || !card->lan_online) { |
641 | card->stats.tx_carrier_errors++; | 636 | card->stats.tx_carrier_errors++; |
642 | goto tx_drop; | 637 | goto tx_drop; |
@@ -658,9 +653,12 @@ static int qeth_l2_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
658 | if (card->info.type == QETH_CARD_TYPE_OSN) | 653 | if (card->info.type == QETH_CARD_TYPE_OSN) |
659 | hdr = (struct qeth_hdr *)skb->data; | 654 | hdr = (struct qeth_hdr *)skb->data; |
660 | else { | 655 | else { |
661 | new_skb = qeth_prepare_skb(card, skb, &hdr); | 656 | /* create a clone with writeable headroom */ |
657 | new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr)); | ||
662 | if (!new_skb) | 658 | if (!new_skb) |
663 | goto tx_drop; | 659 | goto tx_drop; |
660 | hdr = (struct qeth_hdr *)skb_push(new_skb, | ||
661 | sizeof(struct qeth_hdr)); | ||
664 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); | 662 | qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type); |
665 | } | 663 | } |
666 | 664 | ||
@@ -747,7 +745,6 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev, | |||
747 | int index; | 745 | int index; |
748 | int i; | 746 | int i; |
749 | 747 | ||
750 | QETH_DBF_TEXT(TRACE, 6, "qdinput"); | ||
751 | card = (struct qeth_card *) card_ptr; | 748 | card = (struct qeth_card *) card_ptr; |
752 | net_dev = card->dev; | 749 | net_dev = card->dev; |
753 | if (card->options.performance_stats) { | 750 | if (card->options.performance_stats) { |
@@ -852,6 +849,22 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) | |||
852 | return; | 849 | return; |
853 | } | 850 | } |
854 | 851 | ||
852 | static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data) | ||
853 | { | ||
854 | struct qeth_card *card = netdev_priv(dev); | ||
855 | |||
856 | if (data) { | ||
857 | if (card->options.large_send == QETH_LARGE_SEND_NO) { | ||
858 | card->options.large_send = QETH_LARGE_SEND_EDDP; | ||
859 | dev->features |= NETIF_F_TSO; | ||
860 | } | ||
861 | } else { | ||
862 | dev->features &= ~NETIF_F_TSO; | ||
863 | card->options.large_send = QETH_LARGE_SEND_NO; | ||
864 | } | ||
865 | return 0; | ||
866 | } | ||
867 | |||
855 | static struct ethtool_ops qeth_l2_ethtool_ops = { | 868 | static struct ethtool_ops qeth_l2_ethtool_ops = { |
856 | .get_link = ethtool_op_get_link, | 869 | .get_link = ethtool_op_get_link, |
857 | .get_tx_csum = ethtool_op_get_tx_csum, | 870 | .get_tx_csum = ethtool_op_get_tx_csum, |
@@ -859,11 +872,12 @@ static struct ethtool_ops qeth_l2_ethtool_ops = { | |||
859 | .get_sg = ethtool_op_get_sg, | 872 | .get_sg = ethtool_op_get_sg, |
860 | .set_sg = ethtool_op_set_sg, | 873 | .set_sg = ethtool_op_set_sg, |
861 | .get_tso = ethtool_op_get_tso, | 874 | .get_tso = ethtool_op_get_tso, |
862 | .set_tso = ethtool_op_set_tso, | 875 | .set_tso = qeth_l2_ethtool_set_tso, |
863 | .get_strings = qeth_core_get_strings, | 876 | .get_strings = qeth_core_get_strings, |
864 | .get_ethtool_stats = qeth_core_get_ethtool_stats, | 877 | .get_ethtool_stats = qeth_core_get_ethtool_stats, |
865 | .get_stats_count = qeth_core_get_stats_count, | 878 | .get_stats_count = qeth_core_get_stats_count, |
866 | .get_drvinfo = qeth_core_get_drvinfo, | 879 | .get_drvinfo = qeth_core_get_drvinfo, |
880 | .get_settings = qeth_core_ethtool_get_settings, | ||
867 | }; | 881 | }; |
868 | 882 | ||
869 | static struct ethtool_ops qeth_l2_osn_ops = { | 883 | static struct ethtool_ops qeth_l2_osn_ops = { |
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h index 1be353593a59..9f143c83bba3 100644 --- a/drivers/s390/net/qeth_l3.h +++ b/drivers/s390/net/qeth_l3.h | |||
@@ -13,9 +13,6 @@ | |||
13 | 13 | ||
14 | #include "qeth_core.h" | 14 | #include "qeth_core.h" |
15 | 15 | ||
16 | #define QETH_DBF_TXT_BUF qeth_l3_dbf_txt_buf | ||
17 | DECLARE_PER_CPU(char[256], qeth_l3_dbf_txt_buf); | ||
18 | |||
19 | struct qeth_ipaddr { | 16 | struct qeth_ipaddr { |
20 | struct list_head entry; | 17 | struct list_head entry; |
21 | enum qeth_ip_types type; | 18 | enum qeth_ip_types type; |
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index e1bfe56087d6..94a8ead64ed4 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -28,8 +28,6 @@ | |||
28 | #include "qeth_l3.h" | 28 | #include "qeth_l3.h" |
29 | #include "qeth_core_offl.h" | 29 | #include "qeth_core_offl.h" |
30 | 30 | ||
31 | DEFINE_PER_CPU(char[256], qeth_l3_dbf_txt_buf); | ||
32 | |||
33 | static int qeth_l3_set_offline(struct ccwgroup_device *); | 31 | static int qeth_l3_set_offline(struct ccwgroup_device *); |
34 | static int qeth_l3_recover(void *); | 32 | static int qeth_l3_recover(void *); |
35 | static int qeth_l3_stop(struct net_device *); | 33 | static int qeth_l3_stop(struct net_device *); |
@@ -2093,6 +2091,11 @@ static int qeth_l3_stop_card(struct qeth_card *card, int recovery_mode) | |||
2093 | (card->state == CARD_STATE_UP)) { | 2091 | (card->state == CARD_STATE_UP)) { |
2094 | if (recovery_mode) | 2092 | if (recovery_mode) |
2095 | qeth_l3_stop(card->dev); | 2093 | qeth_l3_stop(card->dev); |
2094 | else { | ||
2095 | rtnl_lock(); | ||
2096 | dev_close(card->dev); | ||
2097 | rtnl_unlock(); | ||
2098 | } | ||
2096 | if (!card->use_hard_stop) { | 2099 | if (!card->use_hard_stop) { |
2097 | rc = qeth_send_stoplan(card); | 2100 | rc = qeth_send_stoplan(card); |
2098 | if (rc) | 2101 | if (rc) |
@@ -2559,8 +2562,6 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
2559 | static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | 2562 | static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, |
2560 | struct sk_buff *skb, int ipv, int cast_type) | 2563 | struct sk_buff *skb, int ipv, int cast_type) |
2561 | { | 2564 | { |
2562 | QETH_DBF_TEXT(TRACE, 6, "fillhdr"); | ||
2563 | |||
2564 | memset(hdr, 0, sizeof(struct qeth_hdr)); | 2565 | memset(hdr, 0, sizeof(struct qeth_hdr)); |
2565 | hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; | 2566 | hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3; |
2566 | hdr->hdr.l3.ext_flags = 0; | 2567 | hdr->hdr.l3.ext_flags = 0; |
@@ -2570,9 +2571,10 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, | |||
2570 | * v6 uses passthrough, v4 sets the tag in the QDIO header. | 2571 | * v6 uses passthrough, v4 sets the tag in the QDIO header. |
2571 | */ | 2572 | */ |
2572 | if (card->vlangrp && vlan_tx_tag_present(skb)) { | 2573 | if (card->vlangrp && vlan_tx_tag_present(skb)) { |
2573 | hdr->hdr.l3.ext_flags = (ipv == 4) ? | 2574 | if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD)) |
2574 | QETH_HDR_EXT_VLAN_FRAME : | 2575 | hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME; |
2575 | QETH_HDR_EXT_INCLUDE_VLAN_TAG; | 2576 | else |
2577 | hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG; | ||
2576 | hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb); | 2578 | hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb); |
2577 | } | 2579 | } |
2578 | 2580 | ||
@@ -2638,8 +2640,6 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
2638 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; | 2640 | enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO; |
2639 | struct qeth_eddp_context *ctx = NULL; | 2641 | struct qeth_eddp_context *ctx = NULL; |
2640 | 2642 | ||
2641 | QETH_DBF_TEXT(TRACE, 6, "l3xmit"); | ||
2642 | |||
2643 | if ((card->info.type == QETH_CARD_TYPE_IQD) && | 2643 | if ((card->info.type == QETH_CARD_TYPE_IQD) && |
2644 | (skb->protocol != htons(ETH_P_IPV6)) && | 2644 | (skb->protocol != htons(ETH_P_IPV6)) && |
2645 | (skb->protocol != htons(ETH_P_IP))) | 2645 | (skb->protocol != htons(ETH_P_IP))) |
@@ -2890,6 +2890,7 @@ static struct ethtool_ops qeth_l3_ethtool_ops = { | |||
2890 | .get_ethtool_stats = qeth_core_get_ethtool_stats, | 2890 | .get_ethtool_stats = qeth_core_get_ethtool_stats, |
2891 | .get_stats_count = qeth_core_get_stats_count, | 2891 | .get_stats_count = qeth_core_get_stats_count, |
2892 | .get_drvinfo = qeth_core_get_drvinfo, | 2892 | .get_drvinfo = qeth_core_get_drvinfo, |
2893 | .get_settings = qeth_core_ethtool_get_settings, | ||
2893 | }; | 2894 | }; |
2894 | 2895 | ||
2895 | /* | 2896 | /* |
@@ -2982,7 +2983,6 @@ static void qeth_l3_qdio_input_handler(struct ccw_device *ccwdev, | |||
2982 | int index; | 2983 | int index; |
2983 | int i; | 2984 | int i; |
2984 | 2985 | ||
2985 | QETH_DBF_TEXT(TRACE, 6, "qdinput"); | ||
2986 | card = (struct qeth_card *) card_ptr; | 2986 | card = (struct qeth_card *) card_ptr; |
2987 | net_dev = card->dev; | 2987 | net_dev = card->dev; |
2988 | if (card->options.performance_stats) { | 2988 | if (card->options.performance_stats) { |
@@ -3140,9 +3140,15 @@ static int __qeth_l3_set_online(struct ccwgroup_device *gdev, int recovery_mode) | |||
3140 | netif_carrier_on(card->dev); | 3140 | netif_carrier_on(card->dev); |
3141 | 3141 | ||
3142 | qeth_set_allowed_threads(card, 0xffffffff, 0); | 3142 | qeth_set_allowed_threads(card, 0xffffffff, 0); |
3143 | if ((recover_flag == CARD_STATE_RECOVER) && recovery_mode) { | 3143 | if (recover_flag == CARD_STATE_RECOVER) { |
3144 | if (recovery_mode) | ||
3144 | qeth_l3_open(card->dev); | 3145 | qeth_l3_open(card->dev); |
3145 | qeth_l3_set_multicast_list(card->dev); | 3146 | else { |
3147 | rtnl_lock(); | ||
3148 | dev_open(card->dev); | ||
3149 | rtnl_unlock(); | ||
3150 | } | ||
3151 | qeth_l3_set_multicast_list(card->dev); | ||
3146 | } | 3152 | } |
3147 | /* let user_space know that device is online */ | 3153 | /* let user_space know that device is online */ |
3148 | kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); | 3154 | kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE); |
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 37b85c67b11d..c8bad675dbd1 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c | |||
@@ -1055,7 +1055,7 @@ static void zfcp_scsi_dbf_event(const char *tag, const char *tag2, int level, | |||
1055 | rec->scsi_result = scsi_cmnd->result; | 1055 | rec->scsi_result = scsi_cmnd->result; |
1056 | rec->scsi_cmnd = (unsigned long)scsi_cmnd; | 1056 | rec->scsi_cmnd = (unsigned long)scsi_cmnd; |
1057 | rec->scsi_serial = scsi_cmnd->serial_number; | 1057 | rec->scsi_serial = scsi_cmnd->serial_number; |
1058 | memcpy(rec->scsi_opcode, &scsi_cmnd->cmnd, | 1058 | memcpy(rec->scsi_opcode, scsi_cmnd->cmnd, |
1059 | min((int)scsi_cmnd->cmd_len, | 1059 | min((int)scsi_cmnd->cmd_len, |
1060 | ZFCP_DBF_SCSI_OPCODE)); | 1060 | ZFCP_DBF_SCSI_OPCODE)); |
1061 | rec->scsi_retries = scsi_cmnd->retries; | 1061 | rec->scsi_retries = scsi_cmnd->retries; |
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 7c3f02816e95..b2ea4ea051f5 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c | |||
@@ -1927,7 +1927,8 @@ zfcp_fsf_exchange_config_data_sync(struct zfcp_adapter *adapter, | |||
1927 | 1927 | ||
1928 | /* setup new FSF request */ | 1928 | /* setup new FSF request */ |
1929 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, | 1929 | retval = zfcp_fsf_req_create(adapter, FSF_QTCB_EXCHANGE_CONFIG_DATA, |
1930 | 0, NULL, &lock_flags, &fsf_req); | 1930 | ZFCP_WAIT_FOR_SBAL, NULL, &lock_flags, |
1931 | &fsf_req); | ||
1931 | if (retval) { | 1932 | if (retval) { |
1932 | ZFCP_LOG_INFO("error: Could not create exchange configuration " | 1933 | ZFCP_LOG_INFO("error: Could not create exchange configuration " |
1933 | "data request for adapter %s.\n", | 1934 | "data request for adapter %s.\n", |
@@ -2035,21 +2036,21 @@ zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *fsf_req, int xchg_ok) | |||
2035 | min(FC_SERIAL_NUMBER_SIZE, 17)); | 2036 | min(FC_SERIAL_NUMBER_SIZE, 17)); |
2036 | } | 2037 | } |
2037 | 2038 | ||
2038 | ZFCP_LOG_NORMAL("The adapter %s reported the following " | 2039 | if (fsf_req->erp_action) |
2039 | "characteristics:\n" | 2040 | ZFCP_LOG_NORMAL("The adapter %s reported the following " |
2040 | "WWNN 0x%016Lx, " | 2041 | "characteristics:\n" |
2041 | "WWPN 0x%016Lx, " | 2042 | "WWNN 0x%016Lx, WWPN 0x%016Lx, " |
2042 | "S_ID 0x%06x,\n" | 2043 | "S_ID 0x%06x,\n" |
2043 | "adapter version 0x%x, " | 2044 | "adapter version 0x%x, " |
2044 | "LIC version 0x%x, " | 2045 | "LIC version 0x%x, " |
2045 | "FC link speed %d Gb/s\n", | 2046 | "FC link speed %d Gb/s\n", |
2046 | zfcp_get_busid_by_adapter(adapter), | 2047 | zfcp_get_busid_by_adapter(adapter), |
2047 | (wwn_t) fc_host_node_name(shost), | 2048 | (wwn_t) fc_host_node_name(shost), |
2048 | (wwn_t) fc_host_port_name(shost), | 2049 | (wwn_t) fc_host_port_name(shost), |
2049 | fc_host_port_id(shost), | 2050 | fc_host_port_id(shost), |
2050 | adapter->hydra_version, | 2051 | adapter->hydra_version, |
2051 | adapter->fsf_lic_version, | 2052 | adapter->fsf_lic_version, |
2052 | fc_host_speed(shost)); | 2053 | fc_host_speed(shost)); |
2053 | if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { | 2054 | if (ZFCP_QTCB_VERSION < bottom->low_qtcb_version) { |
2054 | ZFCP_LOG_NORMAL("error: the adapter %s " | 2055 | ZFCP_LOG_NORMAL("error: the adapter %s " |
2055 | "only supports newer control block " | 2056 | "only supports newer control block " |
@@ -2114,8 +2115,10 @@ zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *fsf_req) | |||
2114 | zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req); | 2115 | zfcp_erp_adapter_shutdown(adapter, 0, 127, fsf_req); |
2115 | return -EIO; | 2116 | return -EIO; |
2116 | case FC_PORTTYPE_NPORT: | 2117 | case FC_PORTTYPE_NPORT: |
2117 | ZFCP_LOG_NORMAL("Switched fabric fibrechannel " | 2118 | if (fsf_req->erp_action) |
2118 | "network detected at adapter %s.\n", | 2119 | ZFCP_LOG_NORMAL("Switched fabric fibrechannel " |
2120 | "network detected at adapter " | ||
2121 | "%s.\n", | ||
2119 | zfcp_get_busid_by_adapter(adapter)); | 2122 | zfcp_get_busid_by_adapter(adapter)); |
2120 | break; | 2123 | break; |
2121 | default: | 2124 | default: |
@@ -4011,7 +4014,7 @@ zfcp_fsf_send_fcp_command_task_handler(struct zfcp_fsf_req *fsf_req) | |||
4011 | ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n", | 4014 | ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n", |
4012 | scpnt->result); | 4015 | scpnt->result); |
4013 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, | 4016 | ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE, |
4014 | (void *) &scpnt->cmnd, scpnt->cmd_len); | 4017 | scpnt->cmnd, scpnt->cmd_len); |
4015 | 4018 | ||
4016 | ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n", | 4019 | ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n", |
4017 | fcp_rsp_iu->fcp_sns_len); | 4020 | fcp_rsp_iu->fcp_sns_len); |
diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 8cce5cc11d50..099970b27001 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h | |||
@@ -213,6 +213,7 @@ | |||
213 | #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 | 213 | #define FSF_FEATURE_HBAAPI_MANAGEMENT 0x00000010 |
214 | #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 | 214 | #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 |
215 | #define FSF_FEATURE_UPDATE_ALERT 0x00000100 | 215 | #define FSF_FEATURE_UPDATE_ALERT 0x00000100 |
216 | #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 | ||
216 | 217 | ||
217 | /* host connection features */ | 218 | /* host connection features */ |
218 | #define FSF_FEATURE_NPIV_MODE 0x00000001 | 219 | #define FSF_FEATURE_NPIV_MODE 0x00000001 |
@@ -340,6 +341,15 @@ struct fsf_qtcb_prefix { | |||
340 | u8 res1[20]; | 341 | u8 res1[20]; |
341 | } __attribute__ ((packed)); | 342 | } __attribute__ ((packed)); |
342 | 343 | ||
344 | struct fsf_statistics_info { | ||
345 | u64 input_req; | ||
346 | u64 output_req; | ||
347 | u64 control_req; | ||
348 | u64 input_mb; | ||
349 | u64 output_mb; | ||
350 | u64 seconds_act; | ||
351 | } __attribute__ ((packed)); | ||
352 | |||
343 | union fsf_status_qual { | 353 | union fsf_status_qual { |
344 | u8 byte[FSF_STATUS_QUALIFIER_SIZE]; | 354 | u8 byte[FSF_STATUS_QUALIFIER_SIZE]; |
345 | u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)]; | 355 | u16 halfword[FSF_STATUS_QUALIFIER_SIZE / sizeof (u16)]; |
@@ -436,7 +446,8 @@ struct fsf_qtcb_bottom_config { | |||
436 | u32 hardware_version; | 446 | u32 hardware_version; |
437 | u8 serial_number[32]; | 447 | u8 serial_number[32]; |
438 | struct fsf_nport_serv_param plogi_payload; | 448 | struct fsf_nport_serv_param plogi_payload; |
439 | u8 res4[160]; | 449 | struct fsf_statistics_info stat_info; |
450 | u8 res4[112]; | ||
440 | } __attribute__ ((packed)); | 451 | } __attribute__ ((packed)); |
441 | 452 | ||
442 | struct fsf_qtcb_bottom_port { | 453 | struct fsf_qtcb_bottom_port { |
@@ -469,7 +480,10 @@ struct fsf_qtcb_bottom_port { | |||
469 | u64 control_requests; | 480 | u64 control_requests; |
470 | u64 input_mb; /* where 1 MByte == 1.000.000 Bytes */ | 481 | u64 input_mb; /* where 1 MByte == 1.000.000 Bytes */ |
471 | u64 output_mb; /* where 1 MByte == 1.000.000 Bytes */ | 482 | u64 output_mb; /* where 1 MByte == 1.000.000 Bytes */ |
472 | u8 res2[256]; | 483 | u8 cp_util; |
484 | u8 cb_util; | ||
485 | u8 a_util; | ||
486 | u8 res2[253]; | ||
473 | } __attribute__ ((packed)); | 487 | } __attribute__ ((packed)); |
474 | 488 | ||
475 | union fsf_qtcb_bottom { | 489 | union fsf_qtcb_bottom { |
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index f81850624eed..01687559dc06 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c | |||
@@ -40,6 +40,7 @@ static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, | |||
40 | unsigned int, unsigned int); | 40 | unsigned int, unsigned int); |
41 | 41 | ||
42 | static struct device_attribute *zfcp_sysfs_sdev_attrs[]; | 42 | static struct device_attribute *zfcp_sysfs_sdev_attrs[]; |
43 | static struct device_attribute *zfcp_a_stats_attrs[]; | ||
43 | 44 | ||
44 | struct zfcp_data zfcp_data = { | 45 | struct zfcp_data zfcp_data = { |
45 | .scsi_host_template = { | 46 | .scsi_host_template = { |
@@ -61,6 +62,7 @@ struct zfcp_data zfcp_data = { | |||
61 | .use_clustering = 1, | 62 | .use_clustering = 1, |
62 | .sdev_attrs = zfcp_sysfs_sdev_attrs, | 63 | .sdev_attrs = zfcp_sysfs_sdev_attrs, |
63 | .max_sectors = ZFCP_MAX_SECTORS, | 64 | .max_sectors = ZFCP_MAX_SECTORS, |
65 | .shost_attrs = zfcp_a_stats_attrs, | ||
64 | }, | 66 | }, |
65 | .driver_version = ZFCP_VERSION, | 67 | .driver_version = ZFCP_VERSION, |
66 | }; | 68 | }; |
@@ -809,4 +811,116 @@ static struct device_attribute *zfcp_sysfs_sdev_attrs[] = { | |||
809 | NULL | 811 | NULL |
810 | }; | 812 | }; |
811 | 813 | ||
814 | static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, | ||
815 | struct device_attribute *attr, | ||
816 | char *buf) | ||
817 | { | ||
818 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
819 | struct fsf_qtcb_bottom_port *qtcb_port; | ||
820 | int retval; | ||
821 | struct zfcp_adapter *adapter; | ||
822 | |||
823 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
824 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
825 | return -EOPNOTSUPP; | ||
826 | |||
827 | qtcb_port = kzalloc(sizeof(struct fsf_qtcb_bottom_port), GFP_KERNEL); | ||
828 | if (!qtcb_port) | ||
829 | return -ENOMEM; | ||
830 | |||
831 | retval = zfcp_fsf_exchange_port_data_sync(adapter, qtcb_port); | ||
832 | if (!retval) | ||
833 | retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, | ||
834 | qtcb_port->cb_util, qtcb_port->a_util); | ||
835 | kfree(qtcb_port); | ||
836 | return retval; | ||
837 | } | ||
838 | |||
839 | static int zfcp_sysfs_adapter_ex_config(struct device *dev, | ||
840 | struct fsf_statistics_info *stat_inf) | ||
841 | { | ||
842 | int retval; | ||
843 | struct fsf_qtcb_bottom_config *qtcb_config; | ||
844 | struct Scsi_Host *scsi_host = dev_to_shost(dev); | ||
845 | struct zfcp_adapter *adapter; | ||
846 | |||
847 | adapter = (struct zfcp_adapter *) scsi_host->hostdata[0]; | ||
848 | if (!(adapter->adapter_features & FSF_FEATURE_MEASUREMENT_DATA)) | ||
849 | return -EOPNOTSUPP; | ||
850 | |||
851 | qtcb_config = kzalloc(sizeof(struct fsf_qtcb_bottom_config), | ||
852 | GFP_KERNEL); | ||
853 | if (!qtcb_config) | ||
854 | return -ENOMEM; | ||
855 | |||
856 | retval = zfcp_fsf_exchange_config_data_sync(adapter, qtcb_config); | ||
857 | if (!retval) | ||
858 | *stat_inf = qtcb_config->stat_info; | ||
859 | |||
860 | kfree(qtcb_config); | ||
861 | return retval; | ||
862 | } | ||
863 | |||
864 | static ssize_t zfcp_sysfs_adapter_request_show(struct device *dev, | ||
865 | struct device_attribute *attr, | ||
866 | char *buf) | ||
867 | { | ||
868 | struct fsf_statistics_info stat_info; | ||
869 | int retval; | ||
870 | |||
871 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
872 | if (retval) | ||
873 | return retval; | ||
874 | |||
875 | return sprintf(buf, "%llu %llu %llu\n", | ||
876 | (unsigned long long) stat_info.input_req, | ||
877 | (unsigned long long) stat_info.output_req, | ||
878 | (unsigned long long) stat_info.control_req); | ||
879 | } | ||
880 | |||
881 | static ssize_t zfcp_sysfs_adapter_mb_show(struct device *dev, | ||
882 | struct device_attribute *attr, | ||
883 | char *buf) | ||
884 | { | ||
885 | struct fsf_statistics_info stat_info; | ||
886 | int retval; | ||
887 | |||
888 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
889 | if (retval) | ||
890 | return retval; | ||
891 | |||
892 | return sprintf(buf, "%llu %llu\n", | ||
893 | (unsigned long long) stat_info.input_mb, | ||
894 | (unsigned long long) stat_info.output_mb); | ||
895 | } | ||
896 | |||
897 | static ssize_t zfcp_sysfs_adapter_sec_active_show(struct device *dev, | ||
898 | struct device_attribute *attr, | ||
899 | char *buf) | ||
900 | { | ||
901 | struct fsf_statistics_info stat_info; | ||
902 | int retval; | ||
903 | |||
904 | retval = zfcp_sysfs_adapter_ex_config(dev, &stat_info); | ||
905 | if (retval) | ||
906 | return retval; | ||
907 | |||
908 | return sprintf(buf, "%llu\n", | ||
909 | (unsigned long long) stat_info.seconds_act); | ||
910 | } | ||
911 | |||
912 | static DEVICE_ATTR(utilization, S_IRUGO, zfcp_sysfs_adapter_util_show, NULL); | ||
913 | static DEVICE_ATTR(requests, S_IRUGO, zfcp_sysfs_adapter_request_show, NULL); | ||
914 | static DEVICE_ATTR(megabytes, S_IRUGO, zfcp_sysfs_adapter_mb_show, NULL); | ||
915 | static DEVICE_ATTR(seconds_active, S_IRUGO, | ||
916 | zfcp_sysfs_adapter_sec_active_show, NULL); | ||
917 | |||
918 | static struct device_attribute *zfcp_a_stats_attrs[] = { | ||
919 | &dev_attr_utilization, | ||
920 | &dev_attr_requests, | ||
921 | &dev_attr_megabytes, | ||
922 | &dev_attr_seconds_active, | ||
923 | NULL | ||
924 | }; | ||
925 | |||
812 | #undef ZFCP_LOG_AREA | 926 | #undef ZFCP_LOG_AREA |