diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-01-26 08:10:43 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-01-26 08:10:59 -0500 |
commit | cd6b4f27b9bb2a6a5ec82b96b87c85421257be6c (patch) | |
tree | bf5ac3d351242de6438ab1453a7f1b007f24c29f | |
parent | bc698bcf8897363732226dc9ecba044771679996 (diff) |
[S390] cio: Introduce subchannel->private.
Introduce a private pointer in struct subchannel to store
per-subchannel type data (cannot use dev->priv since this
is already used for something else).
Create a new header io_sch.h for I/O subchannel specific structures
and instructions.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | drivers/s390/cio/cio.c | 43 | ||||
-rw-r--r-- | drivers/s390/cio/cio.h | 84 | ||||
-rw-r--r-- | drivers/s390/cio/css.c | 2 | ||||
-rw-r--r-- | drivers/s390/cio/css.h | 58 | ||||
-rw-r--r-- | drivers/s390/cio/device.c | 16 | ||||
-rw-r--r-- | drivers/s390/cio/device.h | 2 | ||||
-rw-r--r-- | drivers/s390/cio/device_fsm.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/device_id.c | 9 | ||||
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 6 | ||||
-rw-r--r-- | drivers/s390/cio/device_status.c | 13 | ||||
-rw-r--r-- | drivers/s390/cio/io_sch.h | 161 | ||||
-rw-r--r-- | drivers/s390/cio/ioasm.h | 66 |
12 files changed, 261 insertions, 212 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index cd5475b82420..d0bcebde3fa2 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "css.h" | 28 | #include "css.h" |
29 | #include "chsc.h" | 29 | #include "chsc.h" |
30 | #include "ioasm.h" | 30 | #include "ioasm.h" |
31 | #include "io_sch.h" | ||
31 | #include "blacklist.h" | 32 | #include "blacklist.h" |
32 | #include "cio_debug.h" | 33 | #include "cio_debug.h" |
33 | #include "chp.h" | 34 | #include "chp.h" |
@@ -182,33 +183,35 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */ | |||
182 | { | 183 | { |
183 | char dbf_txt[15]; | 184 | char dbf_txt[15]; |
184 | int ccode; | 185 | int ccode; |
186 | struct orb *orb; | ||
185 | 187 | ||
186 | CIO_TRACE_EVENT (4, "stIO"); | 188 | CIO_TRACE_EVENT(4, "stIO"); |
187 | CIO_TRACE_EVENT (4, sch->dev.bus_id); | 189 | CIO_TRACE_EVENT(4, sch->dev.bus_id); |
188 | 190 | ||
191 | orb = &to_io_private(sch)->orb; | ||
189 | /* sch is always under 2G. */ | 192 | /* sch is always under 2G. */ |
190 | sch->orb.intparm = (__u32)(unsigned long)sch; | 193 | orb->intparm = (u32)(addr_t)sch; |
191 | sch->orb.fmt = 1; | 194 | orb->fmt = 1; |
192 | 195 | ||
193 | sch->orb.pfch = sch->options.prefetch == 0; | 196 | orb->pfch = sch->options.prefetch == 0; |
194 | sch->orb.spnd = sch->options.suspend; | 197 | orb->spnd = sch->options.suspend; |
195 | sch->orb.ssic = sch->options.suspend && sch->options.inter; | 198 | orb->ssic = sch->options.suspend && sch->options.inter; |
196 | sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm; | 199 | orb->lpm = (lpm != 0) ? lpm : sch->lpm; |
197 | #ifdef CONFIG_64BIT | 200 | #ifdef CONFIG_64BIT |
198 | /* | 201 | /* |
199 | * for 64 bit we always support 64 bit IDAWs with 4k page size only | 202 | * for 64 bit we always support 64 bit IDAWs with 4k page size only |
200 | */ | 203 | */ |
201 | sch->orb.c64 = 1; | 204 | orb->c64 = 1; |
202 | sch->orb.i2k = 0; | 205 | orb->i2k = 0; |
203 | #endif | 206 | #endif |
204 | sch->orb.key = key >> 4; | 207 | orb->key = key >> 4; |
205 | /* issue "Start Subchannel" */ | 208 | /* issue "Start Subchannel" */ |
206 | sch->orb.cpa = (__u32) __pa (cpa); | 209 | orb->cpa = (__u32) __pa(cpa); |
207 | ccode = ssch (sch->schid, &sch->orb); | 210 | ccode = ssch(sch->schid, orb); |
208 | 211 | ||
209 | /* process condition code */ | 212 | /* process condition code */ |
210 | sprintf (dbf_txt, "ccode:%d", ccode); | 213 | sprintf(dbf_txt, "ccode:%d", ccode); |
211 | CIO_TRACE_EVENT (4, dbf_txt); | 214 | CIO_TRACE_EVENT(4, dbf_txt); |
212 | 215 | ||
213 | switch (ccode) { | 216 | switch (ccode) { |
214 | case 0: | 217 | case 0: |
@@ -423,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc) | |||
423 | for (retry = 5, ret = 0; retry > 0; retry--) { | 426 | for (retry = 5, ret = 0; retry > 0; retry--) { |
424 | sch->schib.pmcw.ena = 1; | 427 | sch->schib.pmcw.ena = 1; |
425 | sch->schib.pmcw.isc = isc; | 428 | sch->schib.pmcw.isc = isc; |
426 | sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; | 429 | sch->schib.pmcw.intparm = (u32)(addr_t)sch; |
427 | ret = cio_modify(sch); | 430 | ret = cio_modify(sch); |
428 | if (ret == -ENODEV) | 431 | if (ret == -ENODEV) |
429 | break; | 432 | break; |
@@ -696,8 +699,14 @@ do_IRQ (struct pt_regs *regs) | |||
696 | 699 | ||
697 | #ifdef CONFIG_CCW_CONSOLE | 700 | #ifdef CONFIG_CCW_CONSOLE |
698 | static struct subchannel console_subchannel; | 701 | static struct subchannel console_subchannel; |
702 | static struct io_subchannel_private console_priv; | ||
699 | static int console_subchannel_in_use; | 703 | static int console_subchannel_in_use; |
700 | 704 | ||
705 | void *cio_get_console_priv(void) | ||
706 | { | ||
707 | return &console_priv; | ||
708 | } | ||
709 | |||
701 | /* | 710 | /* |
702 | * busy wait for the next interrupt on the console | 711 | * busy wait for the next interrupt on the console |
703 | */ | 712 | */ |
@@ -802,7 +811,7 @@ cio_probe_console(void) | |||
802 | ctl_set_bit(6, 24); | 811 | ctl_set_bit(6, 24); |
803 | console_subchannel.schib.pmcw.isc = 7; | 812 | console_subchannel.schib.pmcw.isc = 7; |
804 | console_subchannel.schib.pmcw.intparm = | 813 | console_subchannel.schib.pmcw.intparm = |
805 | (__u32)(unsigned long)&console_subchannel; | 814 | (u32)(addr_t)&console_subchannel; |
806 | ret = cio_modify(&console_subchannel); | 815 | ret = cio_modify(&console_subchannel); |
807 | if (ret) { | 816 | if (ret) { |
808 | console_subchannel_in_use = 0; | 817 | console_subchannel_in_use = 0; |
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h index 7446c39951a7..a6ef218defbe 100644 --- a/drivers/s390/cio/cio.h +++ b/drivers/s390/cio/cio.h | |||
@@ -11,32 +11,32 @@ | |||
11 | * path management control word | 11 | * path management control word |
12 | */ | 12 | */ |
13 | struct pmcw { | 13 | struct pmcw { |
14 | __u32 intparm; /* interruption parameter */ | 14 | u32 intparm; /* interruption parameter */ |
15 | __u32 qf : 1; /* qdio facility */ | 15 | u32 qf : 1; /* qdio facility */ |
16 | __u32 res0 : 1; /* reserved zeros */ | 16 | u32 res0 : 1; /* reserved zeros */ |
17 | __u32 isc : 3; /* interruption sublass */ | 17 | u32 isc : 3; /* interruption sublass */ |
18 | __u32 res5 : 3; /* reserved zeros */ | 18 | u32 res5 : 3; /* reserved zeros */ |
19 | __u32 ena : 1; /* enabled */ | 19 | u32 ena : 1; /* enabled */ |
20 | __u32 lm : 2; /* limit mode */ | 20 | u32 lm : 2; /* limit mode */ |
21 | __u32 mme : 2; /* measurement-mode enable */ | 21 | u32 mme : 2; /* measurement-mode enable */ |
22 | __u32 mp : 1; /* multipath mode */ | 22 | u32 mp : 1; /* multipath mode */ |
23 | __u32 tf : 1; /* timing facility */ | 23 | u32 tf : 1; /* timing facility */ |
24 | __u32 dnv : 1; /* device number valid */ | 24 | u32 dnv : 1; /* device number valid */ |
25 | __u32 dev : 16; /* device number */ | 25 | u32 dev : 16; /* device number */ |
26 | __u8 lpm; /* logical path mask */ | 26 | u8 lpm; /* logical path mask */ |
27 | __u8 pnom; /* path not operational mask */ | 27 | u8 pnom; /* path not operational mask */ |
28 | __u8 lpum; /* last path used mask */ | 28 | u8 lpum; /* last path used mask */ |
29 | __u8 pim; /* path installed mask */ | 29 | u8 pim; /* path installed mask */ |
30 | __u16 mbi; /* measurement-block index */ | 30 | u16 mbi; /* measurement-block index */ |
31 | __u8 pom; /* path operational mask */ | 31 | u8 pom; /* path operational mask */ |
32 | __u8 pam; /* path available mask */ | 32 | u8 pam; /* path available mask */ |
33 | __u8 chpid[8]; /* CHPID 0-7 (if available) */ | 33 | u8 chpid[8]; /* CHPID 0-7 (if available) */ |
34 | __u32 unused1 : 8; /* reserved zeros */ | 34 | u32 unused1 : 8; /* reserved zeros */ |
35 | __u32 st : 3; /* subchannel type */ | 35 | u32 st : 3; /* subchannel type */ |
36 | __u32 unused2 : 18; /* reserved zeros */ | 36 | u32 unused2 : 18; /* reserved zeros */ |
37 | __u32 mbfc : 1; /* measurement block format control */ | 37 | u32 mbfc : 1; /* measurement block format control */ |
38 | __u32 xmwme : 1; /* extended measurement word mode enable */ | 38 | u32 xmwme : 1; /* extended measurement word mode enable */ |
39 | __u32 csense : 1; /* concurrent sense; can be enabled ...*/ | 39 | u32 csense : 1; /* concurrent sense; can be enabled ...*/ |
40 | /* ... per MSCH, however, if facility */ | 40 | /* ... per MSCH, however, if facility */ |
41 | /* ... is not installed, this results */ | 41 | /* ... is not installed, this results */ |
42 | /* ... in an operand exception. */ | 42 | /* ... in an operand exception. */ |
@@ -52,31 +52,6 @@ struct schib { | |||
52 | __u8 mda[4]; /* model dependent area */ | 52 | __u8 mda[4]; /* model dependent area */ |
53 | } __attribute__ ((packed,aligned(4))); | 53 | } __attribute__ ((packed,aligned(4))); |
54 | 54 | ||
55 | /* | ||
56 | * operation request block | ||
57 | */ | ||
58 | struct orb { | ||
59 | __u32 intparm; /* interruption parameter */ | ||
60 | __u32 key : 4; /* flags, like key, suspend control, etc. */ | ||
61 | __u32 spnd : 1; /* suspend control */ | ||
62 | __u32 res1 : 1; /* reserved */ | ||
63 | __u32 mod : 1; /* modification control */ | ||
64 | __u32 sync : 1; /* synchronize control */ | ||
65 | __u32 fmt : 1; /* format control */ | ||
66 | __u32 pfch : 1; /* prefetch control */ | ||
67 | __u32 isic : 1; /* initial-status-interruption control */ | ||
68 | __u32 alcc : 1; /* address-limit-checking control */ | ||
69 | __u32 ssic : 1; /* suppress-suspended-interr. control */ | ||
70 | __u32 res2 : 1; /* reserved */ | ||
71 | __u32 c64 : 1; /* IDAW/QDIO 64 bit control */ | ||
72 | __u32 i2k : 1; /* IDAW 2/4kB block size control */ | ||
73 | __u32 lpm : 8; /* logical path mask */ | ||
74 | __u32 ils : 1; /* incorrect length */ | ||
75 | __u32 zero : 6; /* reserved zeros */ | ||
76 | __u32 orbx : 1; /* ORB extension control */ | ||
77 | __u32 cpa; /* channel program address */ | ||
78 | } __attribute__ ((packed,aligned(4))); | ||
79 | |||
80 | /* subchannel data structure used by I/O subroutines */ | 55 | /* subchannel data structure used by I/O subroutines */ |
81 | struct subchannel { | 56 | struct subchannel { |
82 | struct subchannel_id schid; | 57 | struct subchannel_id schid; |
@@ -99,11 +74,10 @@ struct subchannel { | |||
99 | __u8 lpm; /* logical path mask */ | 74 | __u8 lpm; /* logical path mask */ |
100 | __u8 opm; /* operational path mask */ | 75 | __u8 opm; /* operational path mask */ |
101 | struct schib schib; /* subchannel information block */ | 76 | struct schib schib; /* subchannel information block */ |
102 | struct orb orb; /* operation request block */ | ||
103 | struct ccw1 sense_ccw; /* static ccw for sense command */ | ||
104 | struct chsc_ssd_info ssd_info; /* subchannel description */ | 77 | struct chsc_ssd_info ssd_info; /* subchannel description */ |
105 | struct device dev; /* entry in device tree */ | 78 | struct device dev; /* entry in device tree */ |
106 | struct css_driver *driver; | 79 | struct css_driver *driver; |
80 | void *private; /* private per subchannel type data */ | ||
107 | } __attribute__ ((aligned(8))); | 81 | } __attribute__ ((aligned(8))); |
108 | 82 | ||
109 | #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ | 83 | #define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ |
@@ -133,10 +107,12 @@ extern void cio_release_console(void); | |||
133 | extern int cio_is_console(struct subchannel_id); | 107 | extern int cio_is_console(struct subchannel_id); |
134 | extern struct subchannel *cio_get_console_subchannel(void); | 108 | extern struct subchannel *cio_get_console_subchannel(void); |
135 | extern spinlock_t * cio_get_console_lock(void); | 109 | extern spinlock_t * cio_get_console_lock(void); |
110 | extern void *cio_get_console_priv(void); | ||
136 | #else | 111 | #else |
137 | #define cio_is_console(schid) 0 | 112 | #define cio_is_console(schid) 0 |
138 | #define cio_get_console_subchannel() NULL | 113 | #define cio_get_console_subchannel() NULL |
139 | #define cio_get_console_lock() NULL; | 114 | #define cio_get_console_lock() NULL |
115 | #define cio_get_console_priv() NULL | ||
140 | #endif | 116 | #endif |
141 | 117 | ||
142 | extern int cio_show_msg; | 118 | extern int cio_show_msg; |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 7d887f88bb73..2520a44fb93d 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -77,7 +77,7 @@ css_alloc_subchannel(struct subchannel_id schid) | |||
77 | * This is fine even on 64bit since the subchannel is always located | 77 | * This is fine even on 64bit since the subchannel is always located |
78 | * under 2G. | 78 | * under 2G. |
79 | */ | 79 | */ |
80 | sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; | 80 | sch->schib.pmcw.intparm = (u32)(addr_t)sch; |
81 | ret = cio_modify(sch); | 81 | ret = cio_modify(sch); |
82 | if (ret) { | 82 | if (ret) { |
83 | kfree(sch->lock); | 83 | kfree(sch->lock); |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index c9fd600411c4..b2b4a30c285e 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -58,64 +58,6 @@ struct pgid { | |||
58 | __u32 tod_high; /* high word TOD clock */ | 58 | __u32 tod_high; /* high word TOD clock */ |
59 | } __attribute__ ((packed)); | 59 | } __attribute__ ((packed)); |
60 | 60 | ||
61 | #define MAX_CIWS 8 | ||
62 | |||
63 | /* | ||
64 | * sense-id response buffer layout | ||
65 | */ | ||
66 | struct senseid { | ||
67 | /* common part */ | ||
68 | __u8 reserved; /* always 0x'FF' */ | ||
69 | __u16 cu_type; /* control unit type */ | ||
70 | __u8 cu_model; /* control unit model */ | ||
71 | __u16 dev_type; /* device type */ | ||
72 | __u8 dev_model; /* device model */ | ||
73 | __u8 unused; /* padding byte */ | ||
74 | /* extended part */ | ||
75 | struct ciw ciw[MAX_CIWS]; /* variable # of CIWs */ | ||
76 | } __attribute__ ((packed,aligned(4))); | ||
77 | |||
78 | struct ccw_device_private { | ||
79 | struct ccw_device *cdev; | ||
80 | struct subchannel *sch; | ||
81 | int state; /* device state */ | ||
82 | atomic_t onoff; | ||
83 | unsigned long registered; | ||
84 | struct ccw_dev_id dev_id; /* device id */ | ||
85 | struct subchannel_id schid; /* subchannel number */ | ||
86 | __u8 imask; /* lpm mask for SNID/SID/SPGID */ | ||
87 | int iretry; /* retry counter SNID/SID/SPGID */ | ||
88 | struct { | ||
89 | unsigned int fast:1; /* post with "channel end" */ | ||
90 | unsigned int repall:1; /* report every interrupt status */ | ||
91 | unsigned int pgroup:1; /* do path grouping */ | ||
92 | unsigned int force:1; /* allow forced online */ | ||
93 | } __attribute__ ((packed)) options; | ||
94 | struct { | ||
95 | unsigned int pgid_single:1; /* use single path for Set PGID */ | ||
96 | unsigned int esid:1; /* Ext. SenseID supported by HW */ | ||
97 | unsigned int dosense:1; /* delayed SENSE required */ | ||
98 | unsigned int doverify:1; /* delayed path verification */ | ||
99 | unsigned int donotify:1; /* call notify function */ | ||
100 | unsigned int recog_done:1; /* dev. recog. complete */ | ||
101 | unsigned int fake_irb:1; /* deliver faked irb */ | ||
102 | unsigned int intretry:1; /* retry internal operation */ | ||
103 | } __attribute__((packed)) flags; | ||
104 | unsigned long intparm; /* user interruption parameter */ | ||
105 | struct qdio_irq *qdio_data; | ||
106 | struct irb irb; /* device status */ | ||
107 | struct senseid senseid; /* SenseID info */ | ||
108 | struct pgid pgid[8]; /* path group IDs per chpid*/ | ||
109 | struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ | ||
110 | struct work_struct kick_work; | ||
111 | wait_queue_head_t wait_q; | ||
112 | struct timer_list timer; | ||
113 | void *cmb; /* measurement information */ | ||
114 | struct list_head cmb_list; /* list of measured devices */ | ||
115 | u64 cmb_start_time; /* clock value of cmb reset */ | ||
116 | void *cmb_wait; /* deferred cmb enable/disable */ | ||
117 | }; | ||
118 | |||
119 | /* | 61 | /* |
120 | * A css driver handles all subchannels of one type. | 62 | * A css driver handles all subchannels of one type. |
121 | * Currently, we only care about I/O subchannels (type 0), these | 63 | * Currently, we only care about I/O subchannels (type 0), these |
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 7bccca9684e5..30fe59cc28c9 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include "css.h" | 28 | #include "css.h" |
29 | #include "device.h" | 29 | #include "device.h" |
30 | #include "ioasm.h" | 30 | #include "ioasm.h" |
31 | #include "io_sch.h" | ||
31 | 32 | ||
32 | /******************* bus type handling ***********************/ | 33 | /******************* bus type handling ***********************/ |
33 | 34 | ||
@@ -1143,6 +1144,11 @@ io_subchannel_probe (struct subchannel *sch) | |||
1143 | */ | 1144 | */ |
1144 | dev_id.devno = sch->schib.pmcw.dev; | 1145 | dev_id.devno = sch->schib.pmcw.dev; |
1145 | dev_id.ssid = sch->schid.ssid; | 1146 | dev_id.ssid = sch->schid.ssid; |
1147 | /* Allocate I/O subchannel private data. */ | ||
1148 | sch->private = kzalloc(sizeof(struct io_subchannel_private), | ||
1149 | GFP_KERNEL | GFP_DMA); | ||
1150 | if (!sch->private) | ||
1151 | return -ENOMEM; | ||
1146 | cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); | 1152 | cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL); |
1147 | if (!cdev) | 1153 | if (!cdev) |
1148 | cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), | 1154 | cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent), |
@@ -1160,9 +1166,10 @@ io_subchannel_probe (struct subchannel *sch) | |||
1160 | return 0; | 1166 | return 0; |
1161 | } | 1167 | } |
1162 | cdev = io_subchannel_create_ccwdev(sch); | 1168 | cdev = io_subchannel_create_ccwdev(sch); |
1163 | if (IS_ERR(cdev)) | 1169 | if (IS_ERR(cdev)) { |
1170 | kfree(sch->private); | ||
1164 | return PTR_ERR(cdev); | 1171 | return PTR_ERR(cdev); |
1165 | 1172 | } | |
1166 | rc = io_subchannel_recog(cdev, sch); | 1173 | rc = io_subchannel_recog(cdev, sch); |
1167 | if (rc) { | 1174 | if (rc) { |
1168 | spin_lock_irqsave(sch->lock, flags); | 1175 | spin_lock_irqsave(sch->lock, flags); |
@@ -1170,6 +1177,7 @@ io_subchannel_probe (struct subchannel *sch) | |||
1170 | spin_unlock_irqrestore(sch->lock, flags); | 1177 | spin_unlock_irqrestore(sch->lock, flags); |
1171 | if (cdev->dev.release) | 1178 | if (cdev->dev.release) |
1172 | cdev->dev.release(&cdev->dev); | 1179 | cdev->dev.release(&cdev->dev); |
1180 | kfree(sch->private); | ||
1173 | } | 1181 | } |
1174 | 1182 | ||
1175 | return rc; | 1183 | return rc; |
@@ -1191,6 +1199,7 @@ io_subchannel_remove (struct subchannel *sch) | |||
1191 | spin_unlock_irqrestore(cdev->ccwlock, flags); | 1199 | spin_unlock_irqrestore(cdev->ccwlock, flags); |
1192 | ccw_device_unregister(cdev); | 1200 | ccw_device_unregister(cdev); |
1193 | put_device(&cdev->dev); | 1201 | put_device(&cdev->dev); |
1202 | kfree(sch->private); | ||
1194 | return 0; | 1203 | return 0; |
1195 | } | 1204 | } |
1196 | 1205 | ||
@@ -1279,6 +1288,9 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch) | |||
1279 | { | 1288 | { |
1280 | int rc; | 1289 | int rc; |
1281 | 1290 | ||
1291 | /* Attach subchannel private data. */ | ||
1292 | sch->private = cio_get_console_priv(); | ||
1293 | memset(sch->private, 0, sizeof(struct io_subchannel_private)); | ||
1282 | /* Initialize the ccw_device structure. */ | 1294 | /* Initialize the ccw_device structure. */ |
1283 | cdev->dev.parent= &sch->dev; | 1295 | cdev->dev.parent= &sch->dev; |
1284 | rc = io_subchannel_recog(cdev, sch); | 1296 | rc = io_subchannel_recog(cdev, sch); |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 6183731fb9a2..87576fe2c7c4 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -5,6 +5,8 @@ | |||
5 | #include <asm/atomic.h> | 5 | #include <asm/atomic.h> |
6 | #include <linux/wait.h> | 6 | #include <linux/wait.h> |
7 | 7 | ||
8 | #include "io_sch.h" | ||
9 | |||
8 | /* | 10 | /* |
9 | * states of the device statemachine | 11 | * states of the device statemachine |
10 | */ | 12 | */ |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index 8b6be2142c81..44ce7a3d3857 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -96,29 +96,32 @@ static void ccw_timeout_log(struct ccw_device *cdev) | |||
96 | { | 96 | { |
97 | struct schib schib; | 97 | struct schib schib; |
98 | struct subchannel *sch; | 98 | struct subchannel *sch; |
99 | struct io_subchannel_private *private; | ||
99 | int cc; | 100 | int cc; |
100 | 101 | ||
101 | sch = to_subchannel(cdev->dev.parent); | 102 | sch = to_subchannel(cdev->dev.parent); |
103 | private = to_io_private(sch); | ||
102 | cc = stsch(sch->schid, &schib); | 104 | cc = stsch(sch->schid, &schib); |
103 | 105 | ||
104 | printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " | 106 | printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " |
105 | "device information:\n", get_clock()); | 107 | "device information:\n", get_clock()); |
106 | printk(KERN_WARNING "cio: orb:\n"); | 108 | printk(KERN_WARNING "cio: orb:\n"); |
107 | print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, | 109 | print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, |
108 | &sch->orb, sizeof(sch->orb), 0); | 110 | &private->orb, sizeof(private->orb), 0); |
109 | printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id); | 111 | printk(KERN_WARNING "cio: ccw device bus id: %s\n", cdev->dev.bus_id); |
110 | printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id); | 112 | printk(KERN_WARNING "cio: subchannel bus id: %s\n", sch->dev.bus_id); |
111 | printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " | 113 | printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " |
112 | "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); | 114 | "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); |
113 | 115 | ||
114 | if ((void *)(addr_t)sch->orb.cpa == &sch->sense_ccw || | 116 | if ((void *)(addr_t)private->orb.cpa == &private->sense_ccw || |
115 | (void *)(addr_t)sch->orb.cpa == cdev->private->iccws) | 117 | (void *)(addr_t)private->orb.cpa == cdev->private->iccws) |
116 | printk(KERN_WARNING "cio: last channel program (intern):\n"); | 118 | printk(KERN_WARNING "cio: last channel program (intern):\n"); |
117 | else | 119 | else |
118 | printk(KERN_WARNING "cio: last channel program:\n"); | 120 | printk(KERN_WARNING "cio: last channel program:\n"); |
119 | 121 | ||
120 | print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, | 122 | print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, |
121 | (void *)(addr_t)sch->orb.cpa, sizeof(struct ccw1), 0); | 123 | (void *)(addr_t)private->orb.cpa, |
124 | sizeof(struct ccw1), 0); | ||
122 | printk(KERN_WARNING "cio: ccw device state: %d\n", | 125 | printk(KERN_WARNING "cio: ccw device state: %d\n", |
123 | cdev->private->state); | 126 | cdev->private->state); |
124 | printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc); | 127 | printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc); |
@@ -1078,7 +1081,7 @@ device_trigger_reprobe(struct subchannel *sch) | |||
1078 | sch->schib.pmcw.ena = 0; | 1081 | sch->schib.pmcw.ena = 0; |
1079 | if ((sch->lpm & (sch->lpm - 1)) != 0) | 1082 | if ((sch->lpm & (sch->lpm - 1)) != 0) |
1080 | sch->schib.pmcw.mp = 1; | 1083 | sch->schib.pmcw.mp = 1; |
1081 | sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; | 1084 | sch->schib.pmcw.intparm = (u32)(addr_t)sch; |
1082 | /* We should also udate ssd info, but this has to wait. */ | 1085 | /* We should also udate ssd info, but this has to wait. */ |
1083 | /* Check if this is another device which appeared on the same sch. */ | 1086 | /* Check if this is another device which appeared on the same sch. */ |
1084 | if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { | 1087 | if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { |
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c index 156f3f9786b5..918b8b89cf9a 100644 --- a/drivers/s390/cio/device_id.c +++ b/drivers/s390/cio/device_id.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "css.h" | 24 | #include "css.h" |
25 | #include "device.h" | 25 | #include "device.h" |
26 | #include "ioasm.h" | 26 | #include "ioasm.h" |
27 | #include "io_sch.h" | ||
27 | 28 | ||
28 | /* | 29 | /* |
29 | * Input : | 30 | * Input : |
@@ -219,11 +220,13 @@ ccw_device_check_sense_id(struct ccw_device *cdev) | |||
219 | return -EAGAIN; | 220 | return -EAGAIN; |
220 | } | 221 | } |
221 | if (irb->scsw.cc == 3) { | 222 | if (irb->scsw.cc == 3) { |
222 | if ((sch->orb.lpm & | 223 | u8 lpm; |
223 | sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) | 224 | |
225 | lpm = to_io_private(sch)->orb.lpm; | ||
226 | if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0) | ||
224 | CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x " | 227 | CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x " |
225 | "on subchannel 0.%x.%04x is " | 228 | "on subchannel 0.%x.%04x is " |
226 | "'not operational'\n", sch->orb.lpm, | 229 | "'not operational'\n", lpm, |
227 | cdev->private->dev_id.devno, | 230 | cdev->private->dev_id.devno, |
228 | sch->schid.ssid, sch->schid.sch_no); | 231 | sch->schid.ssid, sch->schid.sch_no); |
229 | return -EACCES; | 232 | return -EACCES; |
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index cb1879a96818..c52449a1f9fc 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "css.h" | 22 | #include "css.h" |
23 | #include "device.h" | 23 | #include "device.h" |
24 | #include "ioasm.h" | 24 | #include "ioasm.h" |
25 | #include "io_sch.h" | ||
25 | 26 | ||
26 | /* | 27 | /* |
27 | * Helper function called from interrupt context to decide whether an | 28 | * Helper function called from interrupt context to decide whether an |
@@ -155,10 +156,13 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev) | |||
155 | return -EAGAIN; | 156 | return -EAGAIN; |
156 | } | 157 | } |
157 | if (irb->scsw.cc == 3) { | 158 | if (irb->scsw.cc == 3) { |
159 | u8 lpm; | ||
160 | |||
161 | lpm = to_io_private(sch)->orb.lpm; | ||
158 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," | 162 | CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x," |
159 | " lpm %02X, became 'not operational'\n", | 163 | " lpm %02X, became 'not operational'\n", |
160 | cdev->private->dev_id.devno, sch->schid.ssid, | 164 | cdev->private->dev_id.devno, sch->schid.ssid, |
161 | sch->schid.sch_no, sch->orb.lpm); | 165 | sch->schid.sch_no, lpm); |
162 | return -EACCES; | 166 | return -EACCES; |
163 | } | 167 | } |
164 | i = 8 - ffs(cdev->private->imask); | 168 | i = 8 - ffs(cdev->private->imask); |
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c index aa96e6752592..ebe0848cfe33 100644 --- a/drivers/s390/cio/device_status.c +++ b/drivers/s390/cio/device_status.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "css.h" | 20 | #include "css.h" |
21 | #include "device.h" | 21 | #include "device.h" |
22 | #include "ioasm.h" | 22 | #include "ioasm.h" |
23 | #include "io_sch.h" | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * Check for any kind of channel or interface control check but don't | 26 | * Check for any kind of channel or interface control check but don't |
@@ -310,6 +311,7 @@ int | |||
310 | ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) | 311 | ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) |
311 | { | 312 | { |
312 | struct subchannel *sch; | 313 | struct subchannel *sch; |
314 | struct ccw1 *sense_ccw; | ||
313 | 315 | ||
314 | sch = to_subchannel(cdev->dev.parent); | 316 | sch = to_subchannel(cdev->dev.parent); |
315 | 317 | ||
@@ -326,15 +328,16 @@ ccw_device_do_sense(struct ccw_device *cdev, struct irb *irb) | |||
326 | /* | 328 | /* |
327 | * We have ending status but no sense information. Do a basic sense. | 329 | * We have ending status but no sense information. Do a basic sense. |
328 | */ | 330 | */ |
329 | sch->sense_ccw.cmd_code = CCW_CMD_BASIC_SENSE; | 331 | sense_ccw = &to_io_private(sch)->sense_ccw; |
330 | sch->sense_ccw.cda = (__u32) __pa(cdev->private->irb.ecw); | 332 | sense_ccw->cmd_code = CCW_CMD_BASIC_SENSE; |
331 | sch->sense_ccw.count = SENSE_MAX_COUNT; | 333 | sense_ccw->cda = (__u32) __pa(cdev->private->irb.ecw); |
332 | sch->sense_ccw.flags = CCW_FLAG_SLI; | 334 | sense_ccw->count = SENSE_MAX_COUNT; |
335 | sense_ccw->flags = CCW_FLAG_SLI; | ||
333 | 336 | ||
334 | /* Reset internal retry indication. */ | 337 | /* Reset internal retry indication. */ |
335 | cdev->private->flags.intretry = 0; | 338 | cdev->private->flags.intretry = 0; |
336 | 339 | ||
337 | return cio_start (sch, &sch->sense_ccw, 0xff); | 340 | return cio_start(sch, sense_ccw, 0xff); |
338 | } | 341 | } |
339 | 342 | ||
340 | /* | 343 | /* |
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h new file mode 100644 index 000000000000..d49e5a77a6bf --- /dev/null +++ b/drivers/s390/cio/io_sch.h | |||
@@ -0,0 +1,161 @@ | |||
1 | #ifndef S390_IO_SCH_H | ||
2 | #define S390_IO_SCH_H | ||
3 | |||
4 | #include "schid.h" | ||
5 | |||
6 | /* | ||
7 | * operation request block | ||
8 | */ | ||
9 | struct orb { | ||
10 | u32 intparm; /* interruption parameter */ | ||
11 | u32 key : 4; /* flags, like key, suspend control, etc. */ | ||
12 | u32 spnd : 1; /* suspend control */ | ||
13 | u32 res1 : 1; /* reserved */ | ||
14 | u32 mod : 1; /* modification control */ | ||
15 | u32 sync : 1; /* synchronize control */ | ||
16 | u32 fmt : 1; /* format control */ | ||
17 | u32 pfch : 1; /* prefetch control */ | ||
18 | u32 isic : 1; /* initial-status-interruption control */ | ||
19 | u32 alcc : 1; /* address-limit-checking control */ | ||
20 | u32 ssic : 1; /* suppress-suspended-interr. control */ | ||
21 | u32 res2 : 1; /* reserved */ | ||
22 | u32 c64 : 1; /* IDAW/QDIO 64 bit control */ | ||
23 | u32 i2k : 1; /* IDAW 2/4kB block size control */ | ||
24 | u32 lpm : 8; /* logical path mask */ | ||
25 | u32 ils : 1; /* incorrect length */ | ||
26 | u32 zero : 6; /* reserved zeros */ | ||
27 | u32 orbx : 1; /* ORB extension control */ | ||
28 | u32 cpa; /* channel program address */ | ||
29 | } __attribute__ ((packed, aligned(4))); | ||
30 | |||
31 | struct io_subchannel_private { | ||
32 | struct orb orb; /* operation request block */ | ||
33 | struct ccw1 sense_ccw; /* static ccw for sense command */ | ||
34 | } __attribute__ ((aligned(8))); | ||
35 | |||
36 | #define to_io_private(n) ((struct io_subchannel_private *)n->private) | ||
37 | |||
38 | #define MAX_CIWS 8 | ||
39 | |||
40 | /* | ||
41 | * sense-id response buffer layout | ||
42 | */ | ||
43 | struct senseid { | ||
44 | /* common part */ | ||
45 | u8 reserved; /* always 0x'FF' */ | ||
46 | u16 cu_type; /* control unit type */ | ||
47 | u8 cu_model; /* control unit model */ | ||
48 | u16 dev_type; /* device type */ | ||
49 | u8 dev_model; /* device model */ | ||
50 | u8 unused; /* padding byte */ | ||
51 | /* extended part */ | ||
52 | struct ciw ciw[MAX_CIWS]; /* variable # of CIWs */ | ||
53 | } __attribute__ ((packed, aligned(4))); | ||
54 | |||
55 | struct ccw_device_private { | ||
56 | struct ccw_device *cdev; | ||
57 | struct subchannel *sch; | ||
58 | int state; /* device state */ | ||
59 | atomic_t onoff; | ||
60 | unsigned long registered; | ||
61 | struct ccw_dev_id dev_id; /* device id */ | ||
62 | struct subchannel_id schid; /* subchannel number */ | ||
63 | u8 imask; /* lpm mask for SNID/SID/SPGID */ | ||
64 | int iretry; /* retry counter SNID/SID/SPGID */ | ||
65 | struct { | ||
66 | unsigned int fast:1; /* post with "channel end" */ | ||
67 | unsigned int repall:1; /* report every interrupt status */ | ||
68 | unsigned int pgroup:1; /* do path grouping */ | ||
69 | unsigned int force:1; /* allow forced online */ | ||
70 | } __attribute__ ((packed)) options; | ||
71 | struct { | ||
72 | unsigned int pgid_single:1; /* use single path for Set PGID */ | ||
73 | unsigned int esid:1; /* Ext. SenseID supported by HW */ | ||
74 | unsigned int dosense:1; /* delayed SENSE required */ | ||
75 | unsigned int doverify:1; /* delayed path verification */ | ||
76 | unsigned int donotify:1; /* call notify function */ | ||
77 | unsigned int recog_done:1; /* dev. recog. complete */ | ||
78 | unsigned int fake_irb:1; /* deliver faked irb */ | ||
79 | unsigned int intretry:1; /* retry internal operation */ | ||
80 | } __attribute__((packed)) flags; | ||
81 | unsigned long intparm; /* user interruption parameter */ | ||
82 | struct qdio_irq *qdio_data; | ||
83 | struct irb irb; /* device status */ | ||
84 | struct senseid senseid; /* SenseID info */ | ||
85 | struct pgid pgid[8]; /* path group IDs per chpid*/ | ||
86 | struct ccw1 iccws[2]; /* ccws for SNID/SID/SPGID commands */ | ||
87 | struct work_struct kick_work; | ||
88 | wait_queue_head_t wait_q; | ||
89 | struct timer_list timer; | ||
90 | void *cmb; /* measurement information */ | ||
91 | struct list_head cmb_list; /* list of measured devices */ | ||
92 | u64 cmb_start_time; /* clock value of cmb reset */ | ||
93 | void *cmb_wait; /* deferred cmb enable/disable */ | ||
94 | }; | ||
95 | |||
96 | static inline int ssch(struct subchannel_id schid, volatile struct orb *addr) | ||
97 | { | ||
98 | register struct subchannel_id reg1 asm("1") = schid; | ||
99 | int ccode; | ||
100 | |||
101 | asm volatile( | ||
102 | " ssch 0(%2)\n" | ||
103 | " ipm %0\n" | ||
104 | " srl %0,28" | ||
105 | : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); | ||
106 | return ccode; | ||
107 | } | ||
108 | |||
109 | static inline int rsch(struct subchannel_id schid) | ||
110 | { | ||
111 | register struct subchannel_id reg1 asm("1") = schid; | ||
112 | int ccode; | ||
113 | |||
114 | asm volatile( | ||
115 | " rsch\n" | ||
116 | " ipm %0\n" | ||
117 | " srl %0,28" | ||
118 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
119 | return ccode; | ||
120 | } | ||
121 | |||
122 | static inline int csch(struct subchannel_id schid) | ||
123 | { | ||
124 | register struct subchannel_id reg1 asm("1") = schid; | ||
125 | int ccode; | ||
126 | |||
127 | asm volatile( | ||
128 | " csch\n" | ||
129 | " ipm %0\n" | ||
130 | " srl %0,28" | ||
131 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
132 | return ccode; | ||
133 | } | ||
134 | |||
135 | static inline int hsch(struct subchannel_id schid) | ||
136 | { | ||
137 | register struct subchannel_id reg1 asm("1") = schid; | ||
138 | int ccode; | ||
139 | |||
140 | asm volatile( | ||
141 | " hsch\n" | ||
142 | " ipm %0\n" | ||
143 | " srl %0,28" | ||
144 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
145 | return ccode; | ||
146 | } | ||
147 | |||
148 | static inline int xsch(struct subchannel_id schid) | ||
149 | { | ||
150 | register struct subchannel_id reg1 asm("1") = schid; | ||
151 | int ccode; | ||
152 | |||
153 | asm volatile( | ||
154 | " .insn rre,0xb2760000,%1,0\n" | ||
155 | " ipm %0\n" | ||
156 | " srl %0,28" | ||
157 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
158 | return ccode; | ||
159 | } | ||
160 | |||
161 | #endif | ||
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h index 7153dd959082..652ea3625f9d 100644 --- a/drivers/s390/cio/ioasm.h +++ b/drivers/s390/cio/ioasm.h | |||
@@ -109,72 +109,6 @@ static inline int tpi( volatile struct tpi_info *addr) | |||
109 | return ccode; | 109 | return ccode; |
110 | } | 110 | } |
111 | 111 | ||
112 | static inline int ssch(struct subchannel_id schid, | ||
113 | volatile struct orb *addr) | ||
114 | { | ||
115 | register struct subchannel_id reg1 asm ("1") = schid; | ||
116 | int ccode; | ||
117 | |||
118 | asm volatile( | ||
119 | " ssch 0(%2)\n" | ||
120 | " ipm %0\n" | ||
121 | " srl %0,28" | ||
122 | : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc"); | ||
123 | return ccode; | ||
124 | } | ||
125 | |||
126 | static inline int rsch(struct subchannel_id schid) | ||
127 | { | ||
128 | register struct subchannel_id reg1 asm ("1") = schid; | ||
129 | int ccode; | ||
130 | |||
131 | asm volatile( | ||
132 | " rsch\n" | ||
133 | " ipm %0\n" | ||
134 | " srl %0,28" | ||
135 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
136 | return ccode; | ||
137 | } | ||
138 | |||
139 | static inline int csch(struct subchannel_id schid) | ||
140 | { | ||
141 | register struct subchannel_id reg1 asm ("1") = schid; | ||
142 | int ccode; | ||
143 | |||
144 | asm volatile( | ||
145 | " csch\n" | ||
146 | " ipm %0\n" | ||
147 | " srl %0,28" | ||
148 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
149 | return ccode; | ||
150 | } | ||
151 | |||
152 | static inline int hsch(struct subchannel_id schid) | ||
153 | { | ||
154 | register struct subchannel_id reg1 asm ("1") = schid; | ||
155 | int ccode; | ||
156 | |||
157 | asm volatile( | ||
158 | " hsch\n" | ||
159 | " ipm %0\n" | ||
160 | " srl %0,28" | ||
161 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
162 | return ccode; | ||
163 | } | ||
164 | |||
165 | static inline int xsch(struct subchannel_id schid) | ||
166 | { | ||
167 | register struct subchannel_id reg1 asm ("1") = schid; | ||
168 | int ccode; | ||
169 | |||
170 | asm volatile( | ||
171 | " .insn rre,0xb2760000,%1,0\n" | ||
172 | " ipm %0\n" | ||
173 | " srl %0,28" | ||
174 | : "=d" (ccode) : "d" (reg1) : "cc"); | ||
175 | return ccode; | ||
176 | } | ||
177 | |||
178 | static inline int chsc(void *chsc_area) | 112 | static inline int chsc(void *chsc_area) |
179 | { | 113 | { |
180 | typedef struct { char _[4096]; } addr_type; | 114 | typedef struct { char _[4096]; } addr_type; |