1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53#include <linux/device.h>
54#include <linux/init.h>
55#include <linux/interrupt.h>
56#include <linux/kernel.h>
57#include <linux/kref.h>
58#include <linux/kthread.h>
59#include <linux/list.h>
60#include <linux/major.h>
61#include <linux/module.h>
62#include <linux/moduleparam.h>
63#include <linux/sched.h>
64#include <linux/slab.h>
65#include <linux/spinlock.h>
66#include <linux/stat.h>
67#include <linux/tty.h>
68#include <linux/tty_flip.h>
69#include <asm/hvconsole.h>
70#include <asm/hvcserver.h>
71#include <linux/uaccess.h>
72#include <asm/vio.h>
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115#define HVCS_DRIVER_VERSION "1.3.3"
116
117MODULE_AUTHOR("Ryan S. Arnold <rsa@us.ibm.com>");
118MODULE_DESCRIPTION("IBM hvcs (Hypervisor Virtual Console Server) Driver");
119MODULE_LICENSE("GPL");
120MODULE_VERSION(HVCS_DRIVER_VERSION);
121
122
123
124
125
126#define HVCS_CLOSE_WAIT (HZ/100)
127
128
129
130
131
132
133
134
135
136#define HVCS_DEFAULT_SERVER_ADAPTERS 64
137
138
139
140
141
142
143#define HVCS_MAX_SERVER_ADAPTERS 1024
144
145
146
147
148
149
150
151#define HVCS_MINOR_START 0
152
153
154
155
156
157
158
159
160#define __ALIGNED__ __attribute__((__aligned__(8)))
161
162
163
164
165
166#define HVCS_BUFF_LEN 16
167
168
169
170
171
172#define HVCS_MAX_FROM_USER 4096
173
174
175
176
177
178
179static const struct ktermios hvcs_tty_termios = {
180 .c_iflag = IGNBRK | IGNPAR,
181 .c_oflag = OPOST,
182 .c_cflag = B38400 | CS8 | CREAD | HUPCL,
183 .c_cc = INIT_C_CC,
184 .c_ispeed = 38400,
185 .c_ospeed = 38400
186};
187
188
189
190
191
192
193
194static int hvcs_parm_num_devs = -1;
195module_param(hvcs_parm_num_devs, int, 0);
196
197static const char hvcs_driver_name[] = "hvcs";
198static const char hvcs_device_node[] = "hvcs";
199static const char hvcs_driver_string[]
200 = "IBM hvcs (Hypervisor Virtual Console Server) Driver";
201
202
203static int hvcs_rescan_status;
204
205static struct tty_driver *hvcs_tty_driver;
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220static int *hvcs_index_list;
221
222
223
224
225
226static int hvcs_index_count;
227
228
229
230
231
232static int hvcs_kicked;
233
234
235
236
237
238static struct task_struct *hvcs_task;
239
240
241
242
243
244static unsigned long *hvcs_pi_buff;
245
246
247static DEFINE_SPINLOCK(hvcs_pi_lock);
248
249
250struct hvcs_struct {
251 struct tty_port port;
252 spinlock_t lock;
253
254
255
256
257
258 unsigned int index;
259
260
261
262
263
264 int todo_mask;
265
266
267
268
269
270
271
272
273
274 char buffer[HVCS_BUFF_LEN];
275 int chars_in_buffer;
276
277
278
279
280
281
282
283 int connected;
284 uint32_t p_unit_address;
285 uint32_t p_partition_ID;
286 char p_location_code[HVCS_CLC_LENGTH + 1];
287 struct list_head next;
288 struct vio_dev *vdev;
289};
290
291static LIST_HEAD(hvcs_structs);
292static DEFINE_SPINLOCK(hvcs_structs_lock);
293static DEFINE_MUTEX(hvcs_init_mutex);
294
295static void hvcs_unthrottle(struct tty_struct *tty);
296static void hvcs_throttle(struct tty_struct *tty);
297static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance);
298
299static int hvcs_write(struct tty_struct *tty,
300 const unsigned char *buf, int count);
301static int hvcs_write_room(struct tty_struct *tty);
302static int hvcs_chars_in_buffer(struct tty_struct *tty);
303
304static int hvcs_has_pi(struct hvcs_struct *hvcsd);
305static void hvcs_set_pi(struct hvcs_partner_info *pi,
306 struct hvcs_struct *hvcsd);
307static int hvcs_get_pi(struct hvcs_struct *hvcsd);
308static int hvcs_rescan_devices_list(void);
309
310static int hvcs_partner_connect(struct hvcs_struct *hvcsd);
311static void hvcs_partner_free(struct hvcs_struct *hvcsd);
312
313static int hvcs_enable_device(struct hvcs_struct *hvcsd,
314 uint32_t unit_address, unsigned int irq, struct vio_dev *dev);
315
316static int hvcs_open(struct tty_struct *tty, struct file *filp);
317static void hvcs_close(struct tty_struct *tty, struct file *filp);
318static void hvcs_hangup(struct tty_struct * tty);
319
320static int hvcs_probe(struct vio_dev *dev,
321 const struct vio_device_id *id);
322static int __init hvcs_module_init(void);
323static void __exit hvcs_module_exit(void);
324static int hvcs_initialize(void);
325
326#define HVCS_SCHED_READ 0x00000001
327#define HVCS_QUICK_READ 0x00000002
328#define HVCS_TRY_WRITE 0x00000004
329#define HVCS_READ_MASK (HVCS_SCHED_READ | HVCS_QUICK_READ)
330
331static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
332{
333 return dev_get_drvdata(&viod->dev);
334}
335
336
337static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf)
338{
339 struct vio_dev *viod = to_vio_dev(dev);
340 struct hvcs_struct *hvcsd = from_vio_dev(viod);
341 unsigned long flags;
342 int retval;
343
344 spin_lock_irqsave(&hvcsd->lock, flags);
345 retval = sprintf(buf, "%X\n", hvcsd->p_unit_address);
346 spin_unlock_irqrestore(&hvcsd->lock, flags);
347 return retval;
348}
349static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL);
350
351static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf)
352{
353 struct vio_dev *viod = to_vio_dev(dev);
354 struct hvcs_struct *hvcsd = from_vio_dev(viod);
355 unsigned long flags;
356 int retval;
357
358 spin_lock_irqsave(&hvcsd->lock, flags);
359 retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
360 spin_unlock_irqrestore(&hvcsd->lock, flags);
361 return retval;
362}
363static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL);
364
365static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf,
366 size_t count)
367{
368
369
370
371
372 printk(KERN_INFO "HVCS: Denied current_vty change: -EPERM.\n");
373 return -EPERM;
374}
375
376static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf)
377{
378 struct vio_dev *viod = to_vio_dev(dev);
379 struct hvcs_struct *hvcsd = from_vio_dev(viod);
380 unsigned long flags;
381 int retval;
382
383 spin_lock_irqsave(&hvcsd->lock, flags);
384 retval = sprintf(buf, "%s\n", &hvcsd->p_location_code[0]);
385 spin_unlock_irqrestore(&hvcsd->lock, flags);
386 return retval;
387}
388
389static DEVICE_ATTR(current_vty,
390 S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store);
391
392static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf,
393 size_t count)
394{
395 struct vio_dev *viod = to_vio_dev(dev);
396 struct hvcs_struct *hvcsd = from_vio_dev(viod);
397 unsigned long flags;
398
399
400 if (simple_strtol(buf, NULL, 0) != 0)
401 return -EINVAL;
402
403 spin_lock_irqsave(&hvcsd->lock, flags);
404
405 if (hvcsd->port.count > 0) {
406 spin_unlock_irqrestore(&hvcsd->lock, flags);
407 printk(KERN_INFO "HVCS: vterm state unchanged. "
408 "The hvcs device node is still in use.\n");
409 return -EPERM;
410 }
411
412 if (hvcsd->connected == 0) {
413 spin_unlock_irqrestore(&hvcsd->lock, flags);
414 printk(KERN_INFO "HVCS: vterm state unchanged. The"
415 " vty-server is not connected to a vty.\n");
416 return -EPERM;
417 }
418
419 hvcs_partner_free(hvcsd);
420 printk(KERN_INFO "HVCS: Closed vty-server@%X and"
421 " partner vty@%X:%d connection.\n",
422 hvcsd->vdev->unit_address,
423 hvcsd->p_unit_address,
424 (uint32_t)hvcsd->p_partition_ID);
425
426 spin_unlock_irqrestore(&hvcsd->lock, flags);
427 return count;
428}
429
430static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf)
431{
432 struct vio_dev *viod = to_vio_dev(dev);
433 struct hvcs_struct *hvcsd = from_vio_dev(viod);
434 unsigned long flags;
435 int retval;
436
437 spin_lock_irqsave(&hvcsd->lock, flags);
438 retval = sprintf(buf, "%d\n", hvcsd->connected);
439 spin_unlock_irqrestore(&hvcsd->lock, flags);
440 return retval;
441}
442static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR,
443 hvcs_vterm_state_show, hvcs_vterm_state_store);
444
445static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf)
446{
447 struct vio_dev *viod = to_vio_dev(dev);
448 struct hvcs_struct *hvcsd = from_vio_dev(viod);
449 unsigned long flags;
450 int retval;
451
452 spin_lock_irqsave(&hvcsd->lock, flags);
453 retval = sprintf(buf, "%d\n", hvcsd->index);
454 spin_unlock_irqrestore(&hvcsd->lock, flags);
455 return retval;
456}
457
458static DEVICE_ATTR(index, S_IRUGO, hvcs_index_show, NULL);
459
460static struct attribute *hvcs_attrs[] = {
461 &dev_attr_partner_vtys.attr,
462 &dev_attr_partner_clcs.attr,
463 &dev_attr_current_vty.attr,
464 &dev_attr_vterm_state.attr,
465 &dev_attr_index.attr,
466 NULL,
467};
468
469static struct attribute_group hvcs_attr_group = {
470 .attrs = hvcs_attrs,
471};
472
473static ssize_t rescan_show(struct device_driver *ddp, char *buf)
474{
475
476 return snprintf(buf, PAGE_SIZE, "%d\n", hvcs_rescan_status);
477}
478
479static ssize_t rescan_store(struct device_driver *ddp, const char * buf,
480 size_t count)
481{
482 if ((simple_strtol(buf, NULL, 0) != 1)
483 && (hvcs_rescan_status != 0))
484 return -EINVAL;
485
486 hvcs_rescan_status = 1;
487 printk(KERN_INFO "HVCS: rescanning partner info for all"
488 " vty-servers.\n");
489 hvcs_rescan_devices_list();
490 hvcs_rescan_status = 0;
491 return count;
492}
493
494static DRIVER_ATTR_RW(rescan);
495
496static void hvcs_kick(void)
497{
498 hvcs_kicked = 1;
499 wmb();
500 wake_up_process(hvcs_task);
501}
502
503static void hvcs_unthrottle(struct tty_struct *tty)
504{
505 struct hvcs_struct *hvcsd = tty->driver_data;
506 unsigned long flags;
507
508 spin_lock_irqsave(&hvcsd->lock, flags);
509 hvcsd->todo_mask |= HVCS_SCHED_READ;
510 spin_unlock_irqrestore(&hvcsd->lock, flags);
511 hvcs_kick();
512}
513
514static void hvcs_throttle(struct tty_struct *tty)
515{
516 struct hvcs_struct *hvcsd = tty->driver_data;
517 unsigned long flags;
518
519 spin_lock_irqsave(&hvcsd->lock, flags);
520 vio_disable_interrupts(hvcsd->vdev);
521 spin_unlock_irqrestore(&hvcsd->lock, flags);
522}
523
524
525
526
527
528
529static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
530{
531 struct hvcs_struct *hvcsd = dev_instance;
532
533 spin_lock(&hvcsd->lock);
534 vio_disable_interrupts(hvcsd->vdev);
535 hvcsd->todo_mask |= HVCS_SCHED_READ;
536 spin_unlock(&hvcsd->lock);
537 hvcs_kick();
538
539 return IRQ_HANDLED;
540}
541
542
543static void hvcs_try_write(struct hvcs_struct *hvcsd)
544{
545 uint32_t unit_address = hvcsd->vdev->unit_address;
546 struct tty_struct *tty = hvcsd->port.tty;
547 int sent;
548
549 if (hvcsd->todo_mask & HVCS_TRY_WRITE) {
550
551 sent = hvc_put_chars(unit_address,
552 &hvcsd->buffer[0],
553 hvcsd->chars_in_buffer );
554 if (sent > 0) {
555 hvcsd->chars_in_buffer = 0;
556
557 hvcsd->todo_mask &= ~(HVCS_TRY_WRITE);
558
559
560
561
562
563
564
565
566 if (tty) {
567 tty_wakeup(tty);
568 }
569 }
570 }
571}
572
573static int hvcs_io(struct hvcs_struct *hvcsd)
574{
575 uint32_t unit_address;
576 struct tty_struct *tty;
577 char buf[HVCS_BUFF_LEN] __ALIGNED__;
578 unsigned long flags;
579 int got = 0;
580
581 spin_lock_irqsave(&hvcsd->lock, flags);
582
583 unit_address = hvcsd->vdev->unit_address;
584 tty = hvcsd->port.tty;
585
586 hvcs_try_write(hvcsd);
587
588 if (!tty || tty_throttled(tty)) {
589 hvcsd->todo_mask &= ~(HVCS_READ_MASK);
590 goto bail;
591 } else if (!(hvcsd->todo_mask & (HVCS_READ_MASK)))
592 goto bail;
593
594
595 hvcsd->todo_mask &= ~(HVCS_READ_MASK);
596
597 if (tty_buffer_request_room(&hvcsd->port, HVCS_BUFF_LEN) >= HVCS_BUFF_LEN) {
598 got = hvc_get_chars(unit_address,
599 &buf[0],
600 HVCS_BUFF_LEN);
601 tty_insert_flip_string(&hvcsd->port, buf, got);
602 }
603
604
605 if (got)
606 hvcsd->todo_mask |= HVCS_QUICK_READ;
607
608 spin_unlock_irqrestore(&hvcsd->lock, flags);
609
610 if(got)
611 tty_flip_buffer_push(&hvcsd->port);
612
613 if (!got) {
614
615 spin_lock_irqsave(&hvcsd->lock, flags);
616 vio_enable_interrupts(hvcsd->vdev);
617 spin_unlock_irqrestore(&hvcsd->lock, flags);
618 }
619
620 return hvcsd->todo_mask;
621
622 bail:
623 spin_unlock_irqrestore(&hvcsd->lock, flags);
624 return hvcsd->todo_mask;
625}
626
627static int khvcsd(void *unused)
628{
629 struct hvcs_struct *hvcsd;
630 int hvcs_todo_mask;
631
632 __set_current_state(TASK_RUNNING);
633
634 do {
635 hvcs_todo_mask = 0;
636 hvcs_kicked = 0;
637 wmb();
638
639 spin_lock(&hvcs_structs_lock);
640 list_for_each_entry(hvcsd, &hvcs_structs, next) {
641 hvcs_todo_mask |= hvcs_io(hvcsd);
642 }
643 spin_unlock(&hvcs_structs_lock);
644
645
646
647
648
649
650 if (hvcs_todo_mask & (HVCS_TRY_WRITE | HVCS_QUICK_READ)) {
651 yield();
652 continue;
653 }
654
655 set_current_state(TASK_INTERRUPTIBLE);
656 if (!hvcs_kicked)
657 schedule();
658 __set_current_state(TASK_RUNNING);
659 } while (!kthread_should_stop());
660
661 return 0;
662}
663
664static const struct vio_device_id hvcs_driver_table[] = {
665 {"serial-server", "hvterm2"},
666 { "", "" }
667};
668MODULE_DEVICE_TABLE(vio, hvcs_driver_table);
669
670static void hvcs_return_index(int index)
671{
672
673 if (!hvcs_index_list)
674 return;
675 if (index < 0 || index >= hvcs_index_count)
676 return;
677 if (hvcs_index_list[index] == -1)
678 return;
679 else
680 hvcs_index_list[index] = -1;
681}
682
683static void hvcs_destruct_port(struct tty_port *p)
684{
685 struct hvcs_struct *hvcsd = container_of(p, struct hvcs_struct, port);
686 struct vio_dev *vdev;
687 unsigned long flags;
688
689 spin_lock(&hvcs_structs_lock);
690 spin_lock_irqsave(&hvcsd->lock, flags);
691
692
693 list_del(&(hvcsd->next));
694
695 if (hvcsd->connected == 1) {
696 hvcs_partner_free(hvcsd);
697 printk(KERN_INFO "HVCS: Closed vty-server@%X and"
698 " partner vty@%X:%d connection.\n",
699 hvcsd->vdev->unit_address,
700 hvcsd->p_unit_address,
701 (uint32_t)hvcsd->p_partition_ID);
702 }
703 printk(KERN_INFO "HVCS: Destroyed hvcs_struct for vty-server@%X.\n",
704 hvcsd->vdev->unit_address);
705
706 vdev = hvcsd->vdev;
707 hvcsd->vdev = NULL;
708
709 hvcsd->p_unit_address = 0;
710 hvcsd->p_partition_ID = 0;
711 hvcs_return_index(hvcsd->index);
712 memset(&hvcsd->p_location_code[0], 0x00, HVCS_CLC_LENGTH + 1);
713
714 spin_unlock_irqrestore(&hvcsd->lock, flags);
715 spin_unlock(&hvcs_structs_lock);
716
717 sysfs_remove_group(&vdev->dev.kobj, &hvcs_attr_group);
718
719 kfree(hvcsd);
720}
721
722static const struct tty_port_operations hvcs_port_ops = {
723 .destruct = hvcs_destruct_port,
724};
725
726static int hvcs_get_index(void)
727{
728 int i;
729
730 if (!hvcs_index_list) {
731 printk(KERN_ERR "HVCS: hvcs_index_list NOT valid!.\n");
732 return -EFAULT;
733 }
734
735 for(i = 0; i < hvcs_index_count; i++) {
736 if (hvcs_index_list[i] == -1) {
737 hvcs_index_list[i] = 0;
738 return i;
739 }
740 }
741 return -1;
742}
743
744static int hvcs_probe(
745 struct vio_dev *dev,
746 const struct vio_device_id *id)
747{
748 struct hvcs_struct *hvcsd;
749 int index, rc;
750 int retval;
751
752 if (!dev || !id) {
753 printk(KERN_ERR "HVCS: probed with invalid parameter.\n");
754 return -EPERM;
755 }
756
757
758 rc = hvcs_initialize();
759 if (rc) {
760 pr_err("HVCS: Failed to initialize core driver.\n");
761 return rc;
762 }
763
764
765 index = hvcs_get_index();
766 if (index < 0) {
767 return -EFAULT;
768 }
769
770 hvcsd = kzalloc(sizeof(*hvcsd), GFP_KERNEL);
771 if (!hvcsd)
772 return -ENODEV;
773
774 tty_port_init(&hvcsd->port);
775 hvcsd->port.ops = &hvcs_port_ops;
776 spin_lock_init(&hvcsd->lock);
777
778 hvcsd->vdev = dev;
779 dev_set_drvdata(&dev->dev, hvcsd);
780
781 hvcsd->index = index;
782
783
784 hvcsd->chars_in_buffer = 0;
785 hvcsd->todo_mask = 0;
786 hvcsd->connected = 0;
787
788
789
790
791
792 if (hvcs_get_pi(hvcsd)) {
793 printk(KERN_ERR "HVCS: Failed to fetch partner"
794 " info for vty-server@%X on device probe.\n",
795 hvcsd->vdev->unit_address);
796 }
797
798
799
800
801
802
803 spin_lock(&hvcs_structs_lock);
804 list_add_tail(&(hvcsd->next), &hvcs_structs);
805 spin_unlock(&hvcs_structs_lock);
806
807 retval = sysfs_create_group(&dev->dev.kobj, &hvcs_attr_group);
808 if (retval) {
809 printk(KERN_ERR "HVCS: Can't create sysfs attrs for vty-server@%X\n",
810 hvcsd->vdev->unit_address);
811 return retval;
812 }
813
814 printk(KERN_INFO "HVCS: vty-server@%X added to the vio bus.\n", dev->unit_address);
815
816
817
818
819
820 return 0;
821}
822
823static void hvcs_remove(struct vio_dev *dev)
824{
825 struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
826 unsigned long flags;
827 struct tty_struct *tty;
828
829
830
831 spin_lock_irqsave(&hvcsd->lock, flags);
832
833 tty = hvcsd->port.tty;
834
835 spin_unlock_irqrestore(&hvcsd->lock, flags);
836
837
838
839
840
841 tty_port_put(&hvcsd->port);
842
843
844
845
846
847
848 if (tty)
849 tty_hangup(tty);
850
851 printk(KERN_INFO "HVCS: vty-server@%X removed from the"
852 " vio bus.\n", dev->unit_address);
853};
854
855static struct vio_driver hvcs_vio_driver = {
856 .id_table = hvcs_driver_table,
857 .probe = hvcs_probe,
858 .remove = hvcs_remove,
859 .name = hvcs_driver_name,
860};
861
862
863static void hvcs_set_pi(struct hvcs_partner_info *pi, struct hvcs_struct *hvcsd)
864{
865 hvcsd->p_unit_address = pi->unit_address;
866 hvcsd->p_partition_ID = pi->partition_ID;
867
868
869 strlcpy(&hvcsd->p_location_code[0],
870 &pi->location_code[0], sizeof(hvcsd->p_location_code));
871}
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886static int hvcs_get_pi(struct hvcs_struct *hvcsd)
887{
888 struct hvcs_partner_info *pi;
889 uint32_t unit_address = hvcsd->vdev->unit_address;
890 struct list_head head;
891 int retval;
892
893 spin_lock(&hvcs_pi_lock);
894 if (!hvcs_pi_buff) {
895 spin_unlock(&hvcs_pi_lock);
896 return -EFAULT;
897 }
898 retval = hvcs_get_partner_info(unit_address, &head, hvcs_pi_buff);
899 spin_unlock(&hvcs_pi_lock);
900 if (retval) {
901 printk(KERN_ERR "HVCS: Failed to fetch partner"
902 " info for vty-server@%x.\n", unit_address);
903 return retval;
904 }
905
906
907 hvcsd->p_unit_address = 0;
908 hvcsd->p_partition_ID = 0;
909
910 list_for_each_entry(pi, &head, node)
911 hvcs_set_pi(pi, hvcsd);
912
913 hvcs_free_partner_info(&head);
914 return 0;
915}
916
917
918
919
920
921static int hvcs_rescan_devices_list(void)
922{
923 struct hvcs_struct *hvcsd;
924 unsigned long flags;
925
926 spin_lock(&hvcs_structs_lock);
927
928 list_for_each_entry(hvcsd, &hvcs_structs, next) {
929 spin_lock_irqsave(&hvcsd->lock, flags);
930 hvcs_get_pi(hvcsd);
931 spin_unlock_irqrestore(&hvcsd->lock, flags);
932 }
933
934 spin_unlock(&hvcs_structs_lock);
935
936 return 0;
937}
938
939
940
941
942
943
944static int hvcs_has_pi(struct hvcs_struct *hvcsd)
945{
946 if ((!hvcsd->p_unit_address) || (!hvcsd->p_partition_ID))
947 return 0;
948 return 1;
949}
950
951
952
953
954
955
956
957static int hvcs_partner_connect(struct hvcs_struct *hvcsd)
958{
959 int retval;
960 unsigned int unit_address = hvcsd->vdev->unit_address;
961
962
963
964
965
966
967
968
969 retval = hvcs_register_connection(unit_address,
970 hvcsd->p_partition_ID,
971 hvcsd->p_unit_address);
972 if (!retval) {
973 hvcsd->connected = 1;
974 return 0;
975 } else if (retval != -EINVAL)
976 return retval;
977
978
979
980
981
982 if (hvcs_get_pi(hvcsd))
983 return -ENOMEM;
984
985 if (!hvcs_has_pi(hvcsd))
986 return -ENODEV;
987
988 retval = hvcs_register_connection(unit_address,
989 hvcsd->p_partition_ID,
990 hvcsd->p_unit_address);
991 if (retval != -EINVAL) {
992 hvcsd->connected = 1;
993 return retval;
994 }
995
996
997
998
999
1000
1001
1002 printk(KERN_INFO "HVCS: vty-server or partner"
1003 " vty is busy. Try again later.\n");
1004 return -EBUSY;
1005}
1006
1007
1008static void hvcs_partner_free(struct hvcs_struct *hvcsd)
1009{
1010 int retval;
1011 do {
1012 retval = hvcs_free_connection(hvcsd->vdev->unit_address);
1013 } while (retval == -EBUSY);
1014 hvcsd->connected = 0;
1015}
1016
1017
1018static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address,
1019 unsigned int irq, struct vio_dev *vdev)
1020{
1021 unsigned long flags;
1022 int rc;
1023
1024
1025
1026
1027
1028 rc = request_irq(irq, &hvcs_handle_interrupt, 0, "ibmhvcs", hvcsd);
1029 if (!rc) {
1030
1031
1032
1033
1034 if (vio_enable_interrupts(vdev) == H_SUCCESS)
1035 return 0;
1036 else {
1037 printk(KERN_ERR "HVCS: int enable failed for"
1038 " vty-server@%X.\n", unit_address);
1039 free_irq(irq, hvcsd);
1040 }
1041 } else
1042 printk(KERN_ERR "HVCS: irq req failed for"
1043 " vty-server@%X.\n", unit_address);
1044
1045 spin_lock_irqsave(&hvcsd->lock, flags);
1046 hvcs_partner_free(hvcsd);
1047 spin_unlock_irqrestore(&hvcsd->lock, flags);
1048
1049 return rc;
1050
1051}
1052
1053
1054
1055
1056
1057
1058
1059
1060static struct hvcs_struct *hvcs_get_by_index(int index)
1061{
1062 struct hvcs_struct *hvcsd;
1063 unsigned long flags;
1064
1065 spin_lock(&hvcs_structs_lock);
1066 list_for_each_entry(hvcsd, &hvcs_structs, next) {
1067 spin_lock_irqsave(&hvcsd->lock, flags);
1068 if (hvcsd->index == index) {
1069 tty_port_get(&hvcsd->port);
1070 spin_unlock_irqrestore(&hvcsd->lock, flags);
1071 spin_unlock(&hvcs_structs_lock);
1072 return hvcsd;
1073 }
1074 spin_unlock_irqrestore(&hvcsd->lock, flags);
1075 }
1076 spin_unlock(&hvcs_structs_lock);
1077
1078 return NULL;
1079}
1080
1081static int hvcs_install(struct tty_driver *driver, struct tty_struct *tty)
1082{
1083 struct hvcs_struct *hvcsd;
1084 struct vio_dev *vdev;
1085 unsigned long unit_address, flags;
1086 unsigned int irq;
1087 int retval;
1088
1089
1090
1091
1092
1093 hvcsd = hvcs_get_by_index(tty->index);
1094 if (!hvcsd) {
1095 printk(KERN_WARNING "HVCS: open failed, no device associated"
1096 " with tty->index %d.\n", tty->index);
1097 return -ENODEV;
1098 }
1099
1100 spin_lock_irqsave(&hvcsd->lock, flags);
1101
1102 if (hvcsd->connected == 0) {
1103 retval = hvcs_partner_connect(hvcsd);
1104 if (retval) {
1105 spin_unlock_irqrestore(&hvcsd->lock, flags);
1106 printk(KERN_WARNING "HVCS: partner connect failed.\n");
1107 goto err_put;
1108 }
1109 }
1110
1111 hvcsd->port.count = 0;
1112 hvcsd->port.tty = tty;
1113 tty->driver_data = hvcsd;
1114
1115 memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
1116
1117
1118
1119
1120
1121 irq = hvcsd->vdev->irq;
1122 vdev = hvcsd->vdev;
1123 unit_address = hvcsd->vdev->unit_address;
1124
1125 hvcsd->todo_mask |= HVCS_SCHED_READ;
1126 spin_unlock_irqrestore(&hvcsd->lock, flags);
1127
1128
1129
1130
1131
1132 retval = hvcs_enable_device(hvcsd, unit_address, irq, vdev);
1133 if (retval) {
1134 printk(KERN_WARNING "HVCS: enable device failed.\n");
1135 goto err_put;
1136 }
1137
1138 retval = tty_port_install(&hvcsd->port, driver, tty);
1139 if (retval)
1140 goto err_irq;
1141
1142 return 0;
1143err_irq:
1144 spin_lock_irqsave(&hvcsd->lock, flags);
1145 vio_disable_interrupts(hvcsd->vdev);
1146 spin_unlock_irqrestore(&hvcsd->lock, flags);
1147 free_irq(irq, hvcsd);
1148err_put:
1149 tty_port_put(&hvcsd->port);
1150
1151 return retval;
1152}
1153
1154
1155
1156
1157
1158static int hvcs_open(struct tty_struct *tty, struct file *filp)
1159{
1160 struct hvcs_struct *hvcsd = tty->driver_data;
1161 unsigned long flags;
1162
1163 spin_lock_irqsave(&hvcsd->lock, flags);
1164 hvcsd->port.count++;
1165 hvcsd->todo_mask |= HVCS_SCHED_READ;
1166 spin_unlock_irqrestore(&hvcsd->lock, flags);
1167
1168 hvcs_kick();
1169
1170 printk(KERN_INFO "HVCS: vty-server@%X connection opened.\n",
1171 hvcsd->vdev->unit_address );
1172
1173 return 0;
1174}
1175
1176static void hvcs_close(struct tty_struct *tty, struct file *filp)
1177{
1178 struct hvcs_struct *hvcsd;
1179 unsigned long flags;
1180 int irq;
1181
1182
1183
1184
1185
1186 if (tty_hung_up_p(filp))
1187 return;
1188
1189
1190
1191
1192
1193
1194 if (!tty->driver_data)
1195 return;
1196
1197 hvcsd = tty->driver_data;
1198
1199 spin_lock_irqsave(&hvcsd->lock, flags);
1200 if (--hvcsd->port.count == 0) {
1201
1202 vio_disable_interrupts(hvcsd->vdev);
1203
1204
1205
1206
1207
1208
1209 hvcsd->port.tty = NULL;
1210
1211 irq = hvcsd->vdev->irq;
1212 spin_unlock_irqrestore(&hvcsd->lock, flags);
1213
1214 tty_wait_until_sent(tty, HVCS_CLOSE_WAIT);
1215
1216
1217
1218
1219
1220
1221 tty->driver_data = NULL;
1222
1223 free_irq(irq, hvcsd);
1224 return;
1225 } else if (hvcsd->port.count < 0) {
1226 printk(KERN_ERR "HVCS: vty-server@%X open_count: %d is mismanaged.\n",
1227 hvcsd->vdev->unit_address, hvcsd->port.count);
1228 }
1229
1230 spin_unlock_irqrestore(&hvcsd->lock, flags);
1231}
1232
1233static void hvcs_cleanup(struct tty_struct * tty)
1234{
1235 struct hvcs_struct *hvcsd = tty->driver_data;
1236
1237 tty_port_put(&hvcsd->port);
1238}
1239
1240static void hvcs_hangup(struct tty_struct * tty)
1241{
1242 struct hvcs_struct *hvcsd = tty->driver_data;
1243 unsigned long flags;
1244 int temp_open_count;
1245 int irq;
1246
1247 spin_lock_irqsave(&hvcsd->lock, flags);
1248
1249 temp_open_count = hvcsd->port.count;
1250
1251
1252
1253
1254
1255
1256 vio_disable_interrupts(hvcsd->vdev);
1257
1258 hvcsd->todo_mask = 0;
1259
1260
1261 tty->driver_data = NULL;
1262 hvcsd->port.tty = NULL;
1263
1264 hvcsd->port.count = 0;
1265
1266
1267
1268 memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
1269 hvcsd->chars_in_buffer = 0;
1270
1271 irq = hvcsd->vdev->irq;
1272
1273 spin_unlock_irqrestore(&hvcsd->lock, flags);
1274
1275 free_irq(irq, hvcsd);
1276
1277
1278
1279
1280
1281
1282 while(temp_open_count) {
1283 --temp_open_count;
1284
1285
1286
1287
1288
1289 tty_port_put(&hvcsd->port);
1290 }
1291}
1292
1293
1294
1295
1296
1297
1298
1299
1300static int hvcs_write(struct tty_struct *tty,
1301 const unsigned char *buf, int count)
1302{
1303 struct hvcs_struct *hvcsd = tty->driver_data;
1304 unsigned int unit_address;
1305 const unsigned char *charbuf;
1306 unsigned long flags;
1307 int total_sent = 0;
1308 int tosend = 0;
1309 int result = 0;
1310
1311
1312
1313
1314
1315 if (!hvcsd)
1316 return -ENODEV;
1317
1318
1319 if (count > HVCS_MAX_FROM_USER) {
1320 printk(KERN_WARNING "HVCS write: count being truncated to"
1321 " HVCS_MAX_FROM_USER.\n");
1322 count = HVCS_MAX_FROM_USER;
1323 }
1324
1325 charbuf = buf;
1326
1327 spin_lock_irqsave(&hvcsd->lock, flags);
1328
1329
1330
1331
1332
1333
1334
1335 if (hvcsd->port.count <= 0) {
1336 spin_unlock_irqrestore(&hvcsd->lock, flags);
1337 return -ENODEV;
1338 }
1339
1340 unit_address = hvcsd->vdev->unit_address;
1341
1342 while (count > 0) {
1343 tosend = min(count, (HVCS_BUFF_LEN - hvcsd->chars_in_buffer));
1344
1345
1346
1347
1348 if (!tosend)
1349 break;
1350
1351 memcpy(&hvcsd->buffer[hvcsd->chars_in_buffer],
1352 &charbuf[total_sent],
1353 tosend);
1354
1355 hvcsd->chars_in_buffer += tosend;
1356
1357 result = 0;
1358
1359
1360
1361
1362
1363
1364 if (!(hvcsd->todo_mask & HVCS_TRY_WRITE))
1365
1366 result = hvc_put_chars(unit_address,
1367 &hvcsd->buffer[0],
1368 hvcsd->chars_in_buffer);
1369
1370
1371
1372
1373
1374
1375 total_sent+=tosend;
1376 count-=tosend;
1377 if (result == 0) {
1378 hvcsd->todo_mask |= HVCS_TRY_WRITE;
1379 hvcs_kick();
1380 break;
1381 }
1382
1383 hvcsd->chars_in_buffer = 0;
1384
1385
1386
1387
1388 if (result < 0)
1389 break;
1390 }
1391
1392 spin_unlock_irqrestore(&hvcsd->lock, flags);
1393
1394 if (result == -1)
1395 return -EIO;
1396 else
1397 return total_sent;
1398}
1399
1400
1401
1402
1403
1404
1405static int hvcs_write_room(struct tty_struct *tty)
1406{
1407 struct hvcs_struct *hvcsd = tty->driver_data;
1408
1409 if (!hvcsd || hvcsd->port.count <= 0)
1410 return 0;
1411
1412 return HVCS_BUFF_LEN - hvcsd->chars_in_buffer;
1413}
1414
1415static int hvcs_chars_in_buffer(struct tty_struct *tty)
1416{
1417 struct hvcs_struct *hvcsd = tty->driver_data;
1418
1419 return hvcsd->chars_in_buffer;
1420}
1421
1422static const struct tty_operations hvcs_ops = {
1423 .install = hvcs_install,
1424 .open = hvcs_open,
1425 .close = hvcs_close,
1426 .cleanup = hvcs_cleanup,
1427 .hangup = hvcs_hangup,
1428 .write = hvcs_write,
1429 .write_room = hvcs_write_room,
1430 .chars_in_buffer = hvcs_chars_in_buffer,
1431 .unthrottle = hvcs_unthrottle,
1432 .throttle = hvcs_throttle,
1433};
1434
1435static int hvcs_alloc_index_list(int n)
1436{
1437 int i;
1438
1439 hvcs_index_list = kmalloc_array(n, sizeof(hvcs_index_count),
1440 GFP_KERNEL);
1441 if (!hvcs_index_list)
1442 return -ENOMEM;
1443 hvcs_index_count = n;
1444 for (i = 0; i < hvcs_index_count; i++)
1445 hvcs_index_list[i] = -1;
1446 return 0;
1447}
1448
1449static void hvcs_free_index_list(void)
1450{
1451
1452 kfree(hvcs_index_list);
1453 hvcs_index_list = NULL;
1454 hvcs_index_count = 0;
1455}
1456
1457static int hvcs_initialize(void)
1458{
1459 int rc, num_ttys_to_alloc;
1460
1461 mutex_lock(&hvcs_init_mutex);
1462 if (hvcs_task) {
1463 mutex_unlock(&hvcs_init_mutex);
1464 return 0;
1465 }
1466
1467
1468 if (hvcs_parm_num_devs <= 0 ||
1469 (hvcs_parm_num_devs > HVCS_MAX_SERVER_ADAPTERS)) {
1470 num_ttys_to_alloc = HVCS_DEFAULT_SERVER_ADAPTERS;
1471 } else
1472 num_ttys_to_alloc = hvcs_parm_num_devs;
1473
1474 hvcs_tty_driver = alloc_tty_driver(num_ttys_to_alloc);
1475 if (!hvcs_tty_driver) {
1476 mutex_unlock(&hvcs_init_mutex);
1477 return -ENOMEM;
1478 }
1479
1480 if (hvcs_alloc_index_list(num_ttys_to_alloc)) {
1481 rc = -ENOMEM;
1482 goto index_fail;
1483 }
1484
1485 hvcs_tty_driver->driver_name = hvcs_driver_name;
1486 hvcs_tty_driver->name = hvcs_device_node;
1487
1488
1489
1490
1491
1492
1493 hvcs_tty_driver->minor_start = HVCS_MINOR_START;
1494 hvcs_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
1495
1496
1497
1498
1499
1500
1501 hvcs_tty_driver->init_termios = hvcs_tty_termios;
1502 hvcs_tty_driver->flags = TTY_DRIVER_REAL_RAW;
1503
1504 tty_set_operations(hvcs_tty_driver, &hvcs_ops);
1505
1506
1507
1508
1509
1510 if (tty_register_driver(hvcs_tty_driver)) {
1511 printk(KERN_ERR "HVCS: registration as a tty driver failed.\n");
1512 rc = -EIO;
1513 goto register_fail;
1514 }
1515
1516 hvcs_pi_buff = (unsigned long *) __get_free_page(GFP_KERNEL);
1517 if (!hvcs_pi_buff) {
1518 rc = -ENOMEM;
1519 goto buff_alloc_fail;
1520 }
1521
1522 hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
1523 if (IS_ERR(hvcs_task)) {
1524 printk(KERN_ERR "HVCS: khvcsd creation failed.\n");
1525 rc = -EIO;
1526 goto kthread_fail;
1527 }
1528 mutex_unlock(&hvcs_init_mutex);
1529 return 0;
1530
1531kthread_fail:
1532 free_page((unsigned long)hvcs_pi_buff);
1533buff_alloc_fail:
1534 tty_unregister_driver(hvcs_tty_driver);
1535register_fail:
1536 hvcs_free_index_list();
1537index_fail:
1538 put_tty_driver(hvcs_tty_driver);
1539 hvcs_tty_driver = NULL;
1540 mutex_unlock(&hvcs_init_mutex);
1541 return rc;
1542}
1543
1544static int __init hvcs_module_init(void)
1545{
1546 int rc = vio_register_driver(&hvcs_vio_driver);
1547 if (rc) {
1548 printk(KERN_ERR "HVCS: can't register vio driver\n");
1549 return rc;
1550 }
1551
1552 pr_info("HVCS: Driver registered.\n");
1553
1554
1555
1556
1557 rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
1558 if (rc)
1559 pr_warn("HVCS: Failed to create rescan file (err %d)\n", rc);
1560
1561 return 0;
1562}
1563
1564static void __exit hvcs_module_exit(void)
1565{
1566
1567
1568
1569
1570 vio_unregister_driver(&hvcs_vio_driver);
1571 if (!hvcs_task)
1572 return;
1573
1574
1575
1576
1577
1578 kthread_stop(hvcs_task);
1579
1580 spin_lock(&hvcs_pi_lock);
1581 free_page((unsigned long)hvcs_pi_buff);
1582 hvcs_pi_buff = NULL;
1583 spin_unlock(&hvcs_pi_lock);
1584
1585 driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
1586
1587 tty_unregister_driver(hvcs_tty_driver);
1588
1589 hvcs_free_index_list();
1590
1591 put_tty_driver(hvcs_tty_driver);
1592
1593 printk(KERN_INFO "HVCS: driver module removed.\n");
1594}
1595
1596module_init(hvcs_module_init);
1597module_exit(hvcs_module_exit);
1598