diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-09 11:01:37 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-09 11:01:37 -0500 |
commit | f049274b012fd3b50113f194bfbbcbc3143d0da3 (patch) | |
tree | 15ef947c1959da3196d8dbc524b435972f6d37f7 /drivers | |
parent | b37df85960a34dd96d0a4695c650f7972ef56c30 (diff) | |
parent | 1539b98b561754252dd520b98fa03a688a4f81b5 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (79 commits)
[IPX]: Fix NULL pointer dereference on ipx unload
[ATM]: atmarp.h needs to always include linux/types.h
[NET]: Fix net/socket.c warnings.
[NET]: cleanup sock_from_file()
[NET]: change layout of ehash table
[S390]: Add AF_IUCV socket support
[S390]: Adapt special message interface to new IUCV API
[S390]: Adapt netiucv driver to new IUCV API
[S390]: Adapt vmlogrdr driver to new IUCV API
[S390]: Adapt monreader driver to new IUCV API
[S390]: Rewrite of the IUCV base code, part 2
[S390]: Rewrite of the IUCV base code, part 1
[X.25]: Adds /proc/net/x25/forward to view active forwarded calls.
[X.25]: Adds /proc/sys/net/x25/x25_forward to control forwarding.
[X.25]: Add call forwarding
[XFRM]: xfrm_migrate() needs exporting to modules.
[PFKEYV2]: CONFIG_NET_KEY_MIGRATE option
[PFKEYV2]: Extension for dynamic update of endpoint address(es)
[XFRM]: CONFIG_XFRM_MIGRATE option
[XFRM]: User interface for handling XFRM_MSG_MIGRATE
...
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/crypto/geode-aes.c | 2 | ||||
-rw-r--r-- | drivers/net/bonding/bond_alb.c | 4 | ||||
-rw-r--r-- | drivers/net/bonding/bond_main.c | 4 | ||||
-rw-r--r-- | drivers/net/slip.c | 5 | ||||
-rw-r--r-- | drivers/net/tg3.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/monreader.c | 218 | ||||
-rw-r--r-- | drivers/s390/char/vmlogrdr.c | 279 | ||||
-rw-r--r-- | drivers/s390/net/Kconfig | 7 | ||||
-rw-r--r-- | drivers/s390/net/Makefile | 1 | ||||
-rw-r--r-- | drivers/s390/net/iucv.c | 2540 | ||||
-rw-r--r-- | drivers/s390/net/iucv.h | 849 | ||||
-rw-r--r-- | drivers/s390/net/netiucv.c | 1314 | ||||
-rw-r--r-- | drivers/s390/net/smsgiucv.c | 147 |
13 files changed, 959 insertions, 4413 deletions
diff --git a/drivers/crypto/geode-aes.c b/drivers/crypto/geode-aes.c index 43a68398656f..31ea405f2eeb 100644 --- a/drivers/crypto/geode-aes.c +++ b/drivers/crypto/geode-aes.c | |||
@@ -457,7 +457,7 @@ static struct pci_driver geode_aes_driver = { | |||
457 | static int __init | 457 | static int __init |
458 | geode_aes_init(void) | 458 | geode_aes_init(void) |
459 | { | 459 | { |
460 | return pci_module_init(&geode_aes_driver); | 460 | return pci_register_driver(&geode_aes_driver); |
461 | } | 461 | } |
462 | 462 | ||
463 | static void __exit | 463 | static void __exit |
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 32923162179e..217a2eedee0a 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c | |||
@@ -184,7 +184,7 @@ static int tlb_initialize(struct bonding *bond) | |||
184 | 184 | ||
185 | spin_lock_init(&(bond_info->tx_hashtbl_lock)); | 185 | spin_lock_init(&(bond_info->tx_hashtbl_lock)); |
186 | 186 | ||
187 | new_hashtbl = kmalloc(size, GFP_KERNEL); | 187 | new_hashtbl = kzalloc(size, GFP_KERNEL); |
188 | if (!new_hashtbl) { | 188 | if (!new_hashtbl) { |
189 | printk(KERN_ERR DRV_NAME | 189 | printk(KERN_ERR DRV_NAME |
190 | ": %s: Error: Failed to allocate TLB hash table\n", | 190 | ": %s: Error: Failed to allocate TLB hash table\n", |
@@ -195,8 +195,6 @@ static int tlb_initialize(struct bonding *bond) | |||
195 | 195 | ||
196 | bond_info->tx_hashtbl = new_hashtbl; | 196 | bond_info->tx_hashtbl = new_hashtbl; |
197 | 197 | ||
198 | memset(bond_info->tx_hashtbl, 0, size); | ||
199 | |||
200 | for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { | 198 | for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { |
201 | tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); | 199 | tlb_init_table_entry(&bond_info->tx_hashtbl[i], 1); |
202 | } | 200 | } |
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index d3801a00d3d5..8ce8fec615ba 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c | |||
@@ -1343,14 +1343,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) | |||
1343 | "inaccurate.\n", bond_dev->name, slave_dev->name); | 1343 | "inaccurate.\n", bond_dev->name, slave_dev->name); |
1344 | } | 1344 | } |
1345 | 1345 | ||
1346 | new_slave = kmalloc(sizeof(struct slave), GFP_KERNEL); | 1346 | new_slave = kzalloc(sizeof(struct slave), GFP_KERNEL); |
1347 | if (!new_slave) { | 1347 | if (!new_slave) { |
1348 | res = -ENOMEM; | 1348 | res = -ENOMEM; |
1349 | goto err_undo_flags; | 1349 | goto err_undo_flags; |
1350 | } | 1350 | } |
1351 | 1351 | ||
1352 | memset(new_slave, 0, sizeof(struct slave)); | ||
1353 | |||
1354 | /* save slave's original flags before calling | 1352 | /* save slave's original flags before calling |
1355 | * netdev_set_master and dev_open | 1353 | * netdev_set_master and dev_open |
1356 | */ | 1354 | */ |
diff --git a/drivers/net/slip.c b/drivers/net/slip.c index a0806d262fc6..2f4b1de7a2b4 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c | |||
@@ -1343,15 +1343,12 @@ static int __init slip_init(void) | |||
1343 | printk(KERN_INFO "SLIP linefill/keepalive option.\n"); | 1343 | printk(KERN_INFO "SLIP linefill/keepalive option.\n"); |
1344 | #endif | 1344 | #endif |
1345 | 1345 | ||
1346 | slip_devs = kmalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); | 1346 | slip_devs = kzalloc(sizeof(struct net_device *)*slip_maxdev, GFP_KERNEL); |
1347 | if (!slip_devs) { | 1347 | if (!slip_devs) { |
1348 | printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n"); | 1348 | printk(KERN_ERR "SLIP: Can't allocate slip devices array! Uaargh! (-> No SLIP available)\n"); |
1349 | return -ENOMEM; | 1349 | return -ENOMEM; |
1350 | } | 1350 | } |
1351 | 1351 | ||
1352 | /* Clear the pointer array, we allocate devices when we need them */ | ||
1353 | memset(slip_devs, 0, sizeof(struct net_device *)*slip_maxdev); | ||
1354 | |||
1355 | /* Fill in our line protocol discipline, and register it */ | 1352 | /* Fill in our line protocol discipline, and register it */ |
1356 | if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { | 1353 | if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { |
1357 | printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); | 1354 | printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); |
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 135c0987deae..e136bae61970 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c | |||
@@ -3380,7 +3380,7 @@ next_pkt: | |||
3380 | } | 3380 | } |
3381 | next_pkt_nopost: | 3381 | next_pkt_nopost: |
3382 | sw_idx++; | 3382 | sw_idx++; |
3383 | sw_idx %= TG3_RX_RCB_RING_SIZE(tp); | 3383 | sw_idx &= (TG3_RX_RCB_RING_SIZE(tp) - 1); |
3384 | 3384 | ||
3385 | /* Refresh hw_idx to see if there is new work */ | 3385 | /* Refresh hw_idx to see if there is new work */ |
3386 | if (sw_idx == hw_idx) { | 3386 | if (sw_idx == hw_idx) { |
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index a138b1510093..3a1a958fb5f2 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Character device driver for reading z/VM *MONITOR service records. | 4 | * Character device driver for reading z/VM *MONITOR service records. |
5 | * | 5 | * |
6 | * Copyright (C) 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. | 6 | * Copyright 2004 IBM Corporation, IBM Deutschland Entwicklung GmbH. |
7 | * | 7 | * |
8 | * Author: Gerald Schaefer <geraldsc@de.ibm.com> | 8 | * Author: Gerald Schaefer <geraldsc@de.ibm.com> |
9 | */ | 9 | */ |
@@ -22,7 +22,7 @@ | |||
22 | #include <asm/ebcdic.h> | 22 | #include <asm/ebcdic.h> |
23 | #include <asm/extmem.h> | 23 | #include <asm/extmem.h> |
24 | #include <linux/poll.h> | 24 | #include <linux/poll.h> |
25 | #include "../net/iucv.h" | 25 | #include <net/iucv/iucv.h> |
26 | 26 | ||
27 | 27 | ||
28 | //#define MON_DEBUG /* Debug messages on/off */ | 28 | //#define MON_DEBUG /* Debug messages on/off */ |
@@ -50,14 +50,13 @@ static char mon_dcss_name[9] = "MONDCSS\0"; | |||
50 | struct mon_msg { | 50 | struct mon_msg { |
51 | u32 pos; | 51 | u32 pos; |
52 | u32 mca_offset; | 52 | u32 mca_offset; |
53 | iucv_MessagePending local_eib; | 53 | struct iucv_message msg; |
54 | char msglim_reached; | 54 | char msglim_reached; |
55 | char replied_msglim; | 55 | char replied_msglim; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct mon_private { | 58 | struct mon_private { |
59 | u16 pathid; | 59 | struct iucv_path *path; |
60 | iucv_handle_t iucv_handle; | ||
61 | struct mon_msg *msg_array[MON_MSGLIM]; | 60 | struct mon_msg *msg_array[MON_MSGLIM]; |
62 | unsigned int write_index; | 61 | unsigned int write_index; |
63 | unsigned int read_index; | 62 | unsigned int read_index; |
@@ -75,8 +74,6 @@ static unsigned long mon_dcss_end; | |||
75 | static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue); | 74 | static DECLARE_WAIT_QUEUE_HEAD(mon_read_wait_queue); |
76 | static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue); | 75 | static DECLARE_WAIT_QUEUE_HEAD(mon_conn_wait_queue); |
77 | 76 | ||
78 | static u8 iucv_host[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
79 | |||
80 | static u8 user_data_connect[16] = { | 77 | static u8 user_data_connect[16] = { |
81 | /* Version code, must be 0x01 for shared mode */ | 78 | /* Version code, must be 0x01 for shared mode */ |
82 | 0x01, | 79 | 0x01, |
@@ -100,8 +97,7 @@ static u8 user_data_sever[16] = { | |||
100 | * Create the 8 bytes EBCDIC DCSS segment name from | 97 | * Create the 8 bytes EBCDIC DCSS segment name from |
101 | * an ASCII name, incl. padding | 98 | * an ASCII name, incl. padding |
102 | */ | 99 | */ |
103 | static inline void | 100 | static inline void dcss_mkname(char *ascii_name, char *ebcdic_name) |
104 | dcss_mkname(char *ascii_name, char *ebcdic_name) | ||
105 | { | 101 | { |
106 | int i; | 102 | int i; |
107 | 103 | ||
@@ -119,8 +115,7 @@ dcss_mkname(char *ascii_name, char *ebcdic_name) | |||
119 | * print appropriate error message for segment_load()/segment_type() | 115 | * print appropriate error message for segment_load()/segment_type() |
120 | * return code | 116 | * return code |
121 | */ | 117 | */ |
122 | static void | 118 | static void mon_segment_warn(int rc, char* seg_name) |
123 | mon_segment_warn(int rc, char* seg_name) | ||
124 | { | 119 | { |
125 | switch (rc) { | 120 | switch (rc) { |
126 | case -ENOENT: | 121 | case -ENOENT: |
@@ -166,44 +161,37 @@ mon_segment_warn(int rc, char* seg_name) | |||
166 | } | 161 | } |
167 | } | 162 | } |
168 | 163 | ||
169 | static inline unsigned long | 164 | static inline unsigned long mon_mca_start(struct mon_msg *monmsg) |
170 | mon_mca_start(struct mon_msg *monmsg) | ||
171 | { | 165 | { |
172 | return monmsg->local_eib.ln1msg1.iprmmsg1_u32; | 166 | return *(u32 *) &monmsg->msg.rmmsg; |
173 | } | 167 | } |
174 | 168 | ||
175 | static inline unsigned long | 169 | static inline unsigned long mon_mca_end(struct mon_msg *monmsg) |
176 | mon_mca_end(struct mon_msg *monmsg) | ||
177 | { | 170 | { |
178 | return monmsg->local_eib.ln1msg2.ipbfln1f; | 171 | return *(u32 *) &monmsg->msg.rmmsg[4]; |
179 | } | 172 | } |
180 | 173 | ||
181 | static inline u8 | 174 | static inline u8 mon_mca_type(struct mon_msg *monmsg, u8 index) |
182 | mon_mca_type(struct mon_msg *monmsg, u8 index) | ||
183 | { | 175 | { |
184 | return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index); | 176 | return *((u8 *) mon_mca_start(monmsg) + monmsg->mca_offset + index); |
185 | } | 177 | } |
186 | 178 | ||
187 | static inline u32 | 179 | static inline u32 mon_mca_size(struct mon_msg *monmsg) |
188 | mon_mca_size(struct mon_msg *monmsg) | ||
189 | { | 180 | { |
190 | return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1; | 181 | return mon_mca_end(monmsg) - mon_mca_start(monmsg) + 1; |
191 | } | 182 | } |
192 | 183 | ||
193 | static inline u32 | 184 | static inline u32 mon_rec_start(struct mon_msg *monmsg) |
194 | mon_rec_start(struct mon_msg *monmsg) | ||
195 | { | 185 | { |
196 | return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4)); | 186 | return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 4)); |
197 | } | 187 | } |
198 | 188 | ||
199 | static inline u32 | 189 | static inline u32 mon_rec_end(struct mon_msg *monmsg) |
200 | mon_rec_end(struct mon_msg *monmsg) | ||
201 | { | 190 | { |
202 | return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8)); | 191 | return *((u32 *) (mon_mca_start(monmsg) + monmsg->mca_offset + 8)); |
203 | } | 192 | } |
204 | 193 | ||
205 | static inline int | 194 | static inline int mon_check_mca(struct mon_msg *monmsg) |
206 | mon_check_mca(struct mon_msg *monmsg) | ||
207 | { | 195 | { |
208 | if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || | 196 | if ((mon_rec_end(monmsg) <= mon_rec_start(monmsg)) || |
209 | (mon_rec_start(monmsg) < mon_dcss_start) || | 197 | (mon_rec_start(monmsg) < mon_dcss_start) || |
@@ -221,20 +209,17 @@ mon_check_mca(struct mon_msg *monmsg) | |||
221 | return 0; | 209 | return 0; |
222 | } | 210 | } |
223 | 211 | ||
224 | static inline int | 212 | static inline int mon_send_reply(struct mon_msg *monmsg, |
225 | mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) | 213 | struct mon_private *monpriv) |
226 | { | 214 | { |
227 | u8 prmmsg[8]; | ||
228 | int rc; | 215 | int rc; |
229 | 216 | ||
230 | P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " | 217 | P_DEBUG("read, REPLY: pathid = 0x%04X, msgid = 0x%08X, trgcls = " |
231 | "0x%08X\n\n", | 218 | "0x%08X\n\n", |
232 | monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, | 219 | monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); |
233 | monmsg->local_eib.iptrgcls); | 220 | |
234 | rc = iucv_reply_prmmsg(monmsg->local_eib.ippathid, | 221 | rc = iucv_message_reply(monpriv->path, &monmsg->msg, |
235 | monmsg->local_eib.ipmsgid, | 222 | IUCV_IPRMDATA, NULL, 0); |
236 | monmsg->local_eib.iptrgcls, | ||
237 | 0, prmmsg); | ||
238 | atomic_dec(&monpriv->msglim_count); | 223 | atomic_dec(&monpriv->msglim_count); |
239 | if (likely(!monmsg->msglim_reached)) { | 224 | if (likely(!monmsg->msglim_reached)) { |
240 | monmsg->pos = 0; | 225 | monmsg->pos = 0; |
@@ -251,10 +236,19 @@ mon_send_reply(struct mon_msg *monmsg, struct mon_private *monpriv) | |||
251 | return 0; | 236 | return 0; |
252 | } | 237 | } |
253 | 238 | ||
254 | static inline struct mon_private * | 239 | static inline void mon_free_mem(struct mon_private *monpriv) |
255 | mon_alloc_mem(void) | 240 | { |
241 | int i; | ||
242 | |||
243 | for (i = 0; i < MON_MSGLIM; i++) | ||
244 | if (monpriv->msg_array[i]) | ||
245 | kfree(monpriv->msg_array[i]); | ||
246 | kfree(monpriv); | ||
247 | } | ||
248 | |||
249 | static inline struct mon_private *mon_alloc_mem(void) | ||
256 | { | 250 | { |
257 | int i,j; | 251 | int i; |
258 | struct mon_private *monpriv; | 252 | struct mon_private *monpriv; |
259 | 253 | ||
260 | monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); | 254 | monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); |
@@ -267,16 +261,15 @@ mon_alloc_mem(void) | |||
267 | GFP_KERNEL); | 261 | GFP_KERNEL); |
268 | if (!monpriv->msg_array[i]) { | 262 | if (!monpriv->msg_array[i]) { |
269 | P_ERROR("open, no memory for msg_array\n"); | 263 | P_ERROR("open, no memory for msg_array\n"); |
270 | for (j = 0; j < i; j++) | 264 | mon_free_mem(monpriv); |
271 | kfree(monpriv->msg_array[j]); | ||
272 | return NULL; | 265 | return NULL; |
273 | } | 266 | } |
274 | } | 267 | } |
275 | return monpriv; | 268 | return monpriv; |
276 | } | 269 | } |
277 | 270 | ||
278 | static inline void | 271 | static inline void mon_read_debug(struct mon_msg *monmsg, |
279 | mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) | 272 | struct mon_private *monpriv) |
280 | { | 273 | { |
281 | #ifdef MON_DEBUG | 274 | #ifdef MON_DEBUG |
282 | u8 msg_type[2], mca_type; | 275 | u8 msg_type[2], mca_type; |
@@ -284,7 +277,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) | |||
284 | 277 | ||
285 | records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; | 278 | records_len = mon_rec_end(monmsg) - mon_rec_start(monmsg) + 1; |
286 | 279 | ||
287 | memcpy(msg_type, &monmsg->local_eib.iptrgcls, 2); | 280 | memcpy(msg_type, &monmsg->msg.class, 2); |
288 | EBCASC(msg_type, 2); | 281 | EBCASC(msg_type, 2); |
289 | mca_type = mon_mca_type(monmsg, 0); | 282 | mca_type = mon_mca_type(monmsg, 0); |
290 | EBCASC(&mca_type, 1); | 283 | EBCASC(&mca_type, 1); |
@@ -292,8 +285,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) | |||
292 | P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", | 285 | P_DEBUG("read, mon_read_index = %i, mon_write_index = %i\n", |
293 | monpriv->read_index, monpriv->write_index); | 286 | monpriv->read_index, monpriv->write_index); |
294 | P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", | 287 | P_DEBUG("read, pathid = 0x%04X, msgid = 0x%08X, trgcls = 0x%08X\n", |
295 | monmsg->local_eib.ippathid, monmsg->local_eib.ipmsgid, | 288 | monpriv->path->pathid, monmsg->msg.id, monmsg->msg.class); |
296 | monmsg->local_eib.iptrgcls); | ||
297 | P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", | 289 | P_DEBUG("read, msg_type = '%c%c', mca_type = '%c' / 0x%X / 0x%X\n", |
298 | msg_type[0], msg_type[1], mca_type ? mca_type : 'X', | 290 | msg_type[0], msg_type[1], mca_type ? mca_type : 'X', |
299 | mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); | 291 | mon_mca_type(monmsg, 1), mon_mca_type(monmsg, 2)); |
@@ -306,8 +298,7 @@ mon_read_debug(struct mon_msg *monmsg, struct mon_private *monpriv) | |||
306 | #endif | 298 | #endif |
307 | } | 299 | } |
308 | 300 | ||
309 | static inline void | 301 | static inline void mon_next_mca(struct mon_msg *monmsg) |
310 | mon_next_mca(struct mon_msg *monmsg) | ||
311 | { | 302 | { |
312 | if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) | 303 | if (likely((mon_mca_size(monmsg) - monmsg->mca_offset) == 12)) |
313 | return; | 304 | return; |
@@ -316,8 +307,7 @@ mon_next_mca(struct mon_msg *monmsg) | |||
316 | monmsg->pos = 0; | 307 | monmsg->pos = 0; |
317 | } | 308 | } |
318 | 309 | ||
319 | static inline struct mon_msg * | 310 | static inline struct mon_msg *mon_next_message(struct mon_private *monpriv) |
320 | mon_next_message(struct mon_private *monpriv) | ||
321 | { | 311 | { |
322 | struct mon_msg *monmsg; | 312 | struct mon_msg *monmsg; |
323 | 313 | ||
@@ -342,39 +332,37 @@ mon_next_message(struct mon_private *monpriv) | |||
342 | /****************************************************************************** | 332 | /****************************************************************************** |
343 | * IUCV handler * | 333 | * IUCV handler * |
344 | *****************************************************************************/ | 334 | *****************************************************************************/ |
345 | static void | 335 | static void mon_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) |
346 | mon_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data) | ||
347 | { | 336 | { |
348 | struct mon_private *monpriv = (struct mon_private *) pgm_data; | 337 | struct mon_private *monpriv = path->private; |
349 | 338 | ||
350 | P_DEBUG("IUCV connection completed\n"); | 339 | P_DEBUG("IUCV connection completed\n"); |
351 | P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " | 340 | P_DEBUG("IUCV ACCEPT (from *MONITOR): Version = 0x%02X, Event = " |
352 | "0x%02X, Sample = 0x%02X\n", | 341 | "0x%02X, Sample = 0x%02X\n", |
353 | eib->ipuser[0], eib->ipuser[1], eib->ipuser[2]); | 342 | ipuser[0], ipuser[1], ipuser[2]); |
354 | atomic_set(&monpriv->iucv_connected, 1); | 343 | atomic_set(&monpriv->iucv_connected, 1); |
355 | wake_up(&mon_conn_wait_queue); | 344 | wake_up(&mon_conn_wait_queue); |
356 | } | 345 | } |
357 | 346 | ||
358 | static void | 347 | static void mon_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) |
359 | mon_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data) | ||
360 | { | 348 | { |
361 | struct mon_private *monpriv = (struct mon_private *) pgm_data; | 349 | struct mon_private *monpriv = path->private; |
362 | 350 | ||
363 | P_ERROR("IUCV connection severed with rc = 0x%X\n", | 351 | P_ERROR("IUCV connection severed with rc = 0x%X\n", ipuser[0]); |
364 | (u8) eib->ipuser[0]); | 352 | iucv_path_sever(path, NULL); |
365 | atomic_set(&monpriv->iucv_severed, 1); | 353 | atomic_set(&monpriv->iucv_severed, 1); |
366 | wake_up(&mon_conn_wait_queue); | 354 | wake_up(&mon_conn_wait_queue); |
367 | wake_up_interruptible(&mon_read_wait_queue); | 355 | wake_up_interruptible(&mon_read_wait_queue); |
368 | } | 356 | } |
369 | 357 | ||
370 | static void | 358 | static void mon_iucv_message_pending(struct iucv_path *path, |
371 | mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) | 359 | struct iucv_message *msg) |
372 | { | 360 | { |
373 | struct mon_private *monpriv = (struct mon_private *) pgm_data; | 361 | struct mon_private *monpriv = path->private; |
374 | 362 | ||
375 | P_DEBUG("IUCV message pending\n"); | 363 | P_DEBUG("IUCV message pending\n"); |
376 | memcpy(&monpriv->msg_array[monpriv->write_index]->local_eib, eib, | 364 | memcpy(&monpriv->msg_array[monpriv->write_index]->msg, |
377 | sizeof(iucv_MessagePending)); | 365 | msg, sizeof(*msg)); |
378 | if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { | 366 | if (atomic_inc_return(&monpriv->msglim_count) == MON_MSGLIM) { |
379 | P_WARNING("IUCV message pending, message limit (%i) reached\n", | 367 | P_WARNING("IUCV message pending, message limit (%i) reached\n", |
380 | MON_MSGLIM); | 368 | MON_MSGLIM); |
@@ -385,54 +373,45 @@ mon_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data) | |||
385 | wake_up_interruptible(&mon_read_wait_queue); | 373 | wake_up_interruptible(&mon_read_wait_queue); |
386 | } | 374 | } |
387 | 375 | ||
388 | static iucv_interrupt_ops_t mon_iucvops = { | 376 | static struct iucv_handler monreader_iucv_handler = { |
389 | .ConnectionComplete = mon_iucv_ConnectionComplete, | 377 | .path_complete = mon_iucv_path_complete, |
390 | .ConnectionSevered = mon_iucv_ConnectionSevered, | 378 | .path_severed = mon_iucv_path_severed, |
391 | .MessagePending = mon_iucv_MessagePending, | 379 | .message_pending = mon_iucv_message_pending, |
392 | }; | 380 | }; |
393 | 381 | ||
394 | /****************************************************************************** | 382 | /****************************************************************************** |
395 | * file operations * | 383 | * file operations * |
396 | *****************************************************************************/ | 384 | *****************************************************************************/ |
397 | static int | 385 | static int mon_open(struct inode *inode, struct file *filp) |
398 | mon_open(struct inode *inode, struct file *filp) | ||
399 | { | 386 | { |
400 | int rc, i; | ||
401 | struct mon_private *monpriv; | 387 | struct mon_private *monpriv; |
388 | int rc; | ||
402 | 389 | ||
403 | /* | 390 | /* |
404 | * only one user allowed | 391 | * only one user allowed |
405 | */ | 392 | */ |
393 | rc = -EBUSY; | ||
406 | if (test_and_set_bit(MON_IN_USE, &mon_in_use)) | 394 | if (test_and_set_bit(MON_IN_USE, &mon_in_use)) |
407 | return -EBUSY; | 395 | goto out; |
408 | 396 | ||
397 | rc = -ENOMEM; | ||
409 | monpriv = mon_alloc_mem(); | 398 | monpriv = mon_alloc_mem(); |
410 | if (!monpriv) | 399 | if (!monpriv) |
411 | return -ENOMEM; | 400 | goto out_use; |
412 | 401 | ||
413 | /* | 402 | /* |
414 | * Register with IUCV and connect to *MONITOR service | 403 | * Connect to *MONITOR service |
415 | */ | 404 | */ |
416 | monpriv->iucv_handle = iucv_register_program("my_monreader ", | 405 | monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); |
417 | MON_SERVICE, | 406 | if (!monpriv->path) |
418 | NULL, | 407 | goto out_priv; |
419 | &mon_iucvops, | 408 | rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, |
420 | monpriv); | 409 | MON_SERVICE, NULL, user_data_connect, monpriv); |
421 | if (!monpriv->iucv_handle) { | ||
422 | P_ERROR("failed to register with iucv driver\n"); | ||
423 | rc = -EIO; | ||
424 | goto out_error; | ||
425 | } | ||
426 | P_INFO("open, registered with IUCV\n"); | ||
427 | |||
428 | rc = iucv_connect(&monpriv->pathid, MON_MSGLIM, user_data_connect, | ||
429 | MON_SERVICE, iucv_host, IPRMDATA, NULL, NULL, | ||
430 | monpriv->iucv_handle, NULL); | ||
431 | if (rc) { | 410 | if (rc) { |
432 | P_ERROR("iucv connection to *MONITOR failed with " | 411 | P_ERROR("iucv connection to *MONITOR failed with " |
433 | "IPUSER SEVER code = %i\n", rc); | 412 | "IPUSER SEVER code = %i\n", rc); |
434 | rc = -EIO; | 413 | rc = -EIO; |
435 | goto out_unregister; | 414 | goto out_path; |
436 | } | 415 | } |
437 | /* | 416 | /* |
438 | * Wait for connection confirmation | 417 | * Wait for connection confirmation |
@@ -444,24 +423,23 @@ mon_open(struct inode *inode, struct file *filp) | |||
444 | atomic_set(&monpriv->iucv_severed, 0); | 423 | atomic_set(&monpriv->iucv_severed, 0); |
445 | atomic_set(&monpriv->iucv_connected, 0); | 424 | atomic_set(&monpriv->iucv_connected, 0); |
446 | rc = -EIO; | 425 | rc = -EIO; |
447 | goto out_unregister; | 426 | goto out_path; |
448 | } | 427 | } |
449 | P_INFO("open, established connection to *MONITOR service\n\n"); | 428 | P_INFO("open, established connection to *MONITOR service\n\n"); |
450 | filp->private_data = monpriv; | 429 | filp->private_data = monpriv; |
451 | return nonseekable_open(inode, filp); | 430 | return nonseekable_open(inode, filp); |
452 | 431 | ||
453 | out_unregister: | 432 | out_path: |
454 | iucv_unregister_program(monpriv->iucv_handle); | 433 | kfree(monpriv->path); |
455 | out_error: | 434 | out_priv: |
456 | for (i = 0; i < MON_MSGLIM; i++) | 435 | mon_free_mem(monpriv); |
457 | kfree(monpriv->msg_array[i]); | 436 | out_use: |
458 | kfree(monpriv); | ||
459 | clear_bit(MON_IN_USE, &mon_in_use); | 437 | clear_bit(MON_IN_USE, &mon_in_use); |
438 | out: | ||
460 | return rc; | 439 | return rc; |
461 | } | 440 | } |
462 | 441 | ||
463 | static int | 442 | static int mon_close(struct inode *inode, struct file *filp) |
464 | mon_close(struct inode *inode, struct file *filp) | ||
465 | { | 443 | { |
466 | int rc, i; | 444 | int rc, i; |
467 | struct mon_private *monpriv = filp->private_data; | 445 | struct mon_private *monpriv = filp->private_data; |
@@ -469,18 +447,12 @@ mon_close(struct inode *inode, struct file *filp) | |||
469 | /* | 447 | /* |
470 | * Close IUCV connection and unregister | 448 | * Close IUCV connection and unregister |
471 | */ | 449 | */ |
472 | rc = iucv_sever(monpriv->pathid, user_data_sever); | 450 | rc = iucv_path_sever(monpriv->path, user_data_sever); |
473 | if (rc) | 451 | if (rc) |
474 | P_ERROR("close, iucv_sever failed with rc = %i\n", rc); | 452 | P_ERROR("close, iucv_sever failed with rc = %i\n", rc); |
475 | else | 453 | else |
476 | P_INFO("close, terminated connection to *MONITOR service\n"); | 454 | P_INFO("close, terminated connection to *MONITOR service\n"); |
477 | 455 | ||
478 | rc = iucv_unregister_program(monpriv->iucv_handle); | ||
479 | if (rc) | ||
480 | P_ERROR("close, iucv_unregister failed with rc = %i\n", rc); | ||
481 | else | ||
482 | P_INFO("close, unregistered with IUCV\n"); | ||
483 | |||
484 | atomic_set(&monpriv->iucv_severed, 0); | 456 | atomic_set(&monpriv->iucv_severed, 0); |
485 | atomic_set(&monpriv->iucv_connected, 0); | 457 | atomic_set(&monpriv->iucv_connected, 0); |
486 | atomic_set(&monpriv->read_ready, 0); | 458 | atomic_set(&monpriv->read_ready, 0); |
@@ -495,8 +467,8 @@ mon_close(struct inode *inode, struct file *filp) | |||
495 | return 0; | 467 | return 0; |
496 | } | 468 | } |
497 | 469 | ||
498 | static ssize_t | 470 | static ssize_t mon_read(struct file *filp, char __user *data, |
499 | mon_read(struct file *filp, char __user *data, size_t count, loff_t *ppos) | 471 | size_t count, loff_t *ppos) |
500 | { | 472 | { |
501 | struct mon_private *monpriv = filp->private_data; | 473 | struct mon_private *monpriv = filp->private_data; |
502 | struct mon_msg *monmsg; | 474 | struct mon_msg *monmsg; |
@@ -563,8 +535,7 @@ out_copy: | |||
563 | return count; | 535 | return count; |
564 | } | 536 | } |
565 | 537 | ||
566 | static unsigned int | 538 | static unsigned int mon_poll(struct file *filp, struct poll_table_struct *p) |
567 | mon_poll(struct file *filp, struct poll_table_struct *p) | ||
568 | { | 539 | { |
569 | struct mon_private *monpriv = filp->private_data; | 540 | struct mon_private *monpriv = filp->private_data; |
570 | 541 | ||
@@ -593,8 +564,7 @@ static struct miscdevice mon_dev = { | |||
593 | /****************************************************************************** | 564 | /****************************************************************************** |
594 | * module init/exit * | 565 | * module init/exit * |
595 | *****************************************************************************/ | 566 | *****************************************************************************/ |
596 | static int __init | 567 | static int __init mon_init(void) |
597 | mon_init(void) | ||
598 | { | 568 | { |
599 | int rc; | 569 | int rc; |
600 | 570 | ||
@@ -603,22 +573,34 @@ mon_init(void) | |||
603 | return -ENODEV; | 573 | return -ENODEV; |
604 | } | 574 | } |
605 | 575 | ||
576 | /* | ||
577 | * Register with IUCV and connect to *MONITOR service | ||
578 | */ | ||
579 | rc = iucv_register(&monreader_iucv_handler, 1); | ||
580 | if (rc) { | ||
581 | P_ERROR("failed to register with iucv driver\n"); | ||
582 | return rc; | ||
583 | } | ||
584 | P_INFO("open, registered with IUCV\n"); | ||
585 | |||
606 | rc = segment_type(mon_dcss_name); | 586 | rc = segment_type(mon_dcss_name); |
607 | if (rc < 0) { | 587 | if (rc < 0) { |
608 | mon_segment_warn(rc, mon_dcss_name); | 588 | mon_segment_warn(rc, mon_dcss_name); |
609 | return rc; | 589 | goto out_iucv; |
610 | } | 590 | } |
611 | if (rc != SEG_TYPE_SC) { | 591 | if (rc != SEG_TYPE_SC) { |
612 | P_ERROR("segment %s has unsupported type, should be SC\n", | 592 | P_ERROR("segment %s has unsupported type, should be SC\n", |
613 | mon_dcss_name); | 593 | mon_dcss_name); |
614 | return -EINVAL; | 594 | rc = -EINVAL; |
595 | goto out_iucv; | ||
615 | } | 596 | } |
616 | 597 | ||
617 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, | 598 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, |
618 | &mon_dcss_start, &mon_dcss_end); | 599 | &mon_dcss_start, &mon_dcss_end); |
619 | if (rc < 0) { | 600 | if (rc < 0) { |
620 | mon_segment_warn(rc, mon_dcss_name); | 601 | mon_segment_warn(rc, mon_dcss_name); |
621 | return -EINVAL; | 602 | rc = -EINVAL; |
603 | goto out_iucv; | ||
622 | } | 604 | } |
623 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); | 605 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); |
624 | 606 | ||
@@ -634,14 +616,16 @@ mon_init(void) | |||
634 | 616 | ||
635 | out: | 617 | out: |
636 | segment_unload(mon_dcss_name); | 618 | segment_unload(mon_dcss_name); |
619 | out_iucv: | ||
620 | iucv_unregister(&monreader_iucv_handler, 1); | ||
637 | return rc; | 621 | return rc; |
638 | } | 622 | } |
639 | 623 | ||
640 | static void __exit | 624 | static void __exit mon_exit(void) |
641 | mon_exit(void) | ||
642 | { | 625 | { |
643 | segment_unload(mon_dcss_name); | 626 | segment_unload(mon_dcss_name); |
644 | WARN_ON(misc_deregister(&mon_dev) != 0); | 627 | WARN_ON(misc_deregister(&mon_dev) != 0); |
628 | iucv_unregister(&monreader_iucv_handler, 1); | ||
645 | return; | 629 | return; |
646 | } | 630 | } |
647 | 631 | ||
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 4f894dc2373b..8432a76b961e 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * character device driver for reading z/VM system service records | 3 | * character device driver for reading z/VM system service records |
4 | * | 4 | * |
5 | * | 5 | * |
6 | * Copyright (C) 2004 IBM Corporation | 6 | * Copyright 2004 IBM Corporation |
7 | * character device driver for reading z/VM system service records, | 7 | * character device driver for reading z/VM system service records, |
8 | * Version 1.0 | 8 | * Version 1.0 |
9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> | 9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> |
@@ -21,7 +21,7 @@ | |||
21 | #include <asm/cpcmd.h> | 21 | #include <asm/cpcmd.h> |
22 | #include <asm/debug.h> | 22 | #include <asm/debug.h> |
23 | #include <asm/ebcdic.h> | 23 | #include <asm/ebcdic.h> |
24 | #include "../net/iucv.h" | 24 | #include <net/iucv/iucv.h> |
25 | #include <linux/kmod.h> | 25 | #include <linux/kmod.h> |
26 | #include <linux/cdev.h> | 26 | #include <linux/cdev.h> |
27 | #include <linux/device.h> | 27 | #include <linux/device.h> |
@@ -60,12 +60,11 @@ struct vmlogrdr_priv_t { | |||
60 | char system_service[8]; | 60 | char system_service[8]; |
61 | char internal_name[8]; | 61 | char internal_name[8]; |
62 | char recording_name[8]; | 62 | char recording_name[8]; |
63 | u16 pathid; | 63 | struct iucv_path *path; |
64 | int connection_established; | 64 | int connection_established; |
65 | int iucv_path_severed; | 65 | int iucv_path_severed; |
66 | iucv_MessagePending local_interrupt_buffer; | 66 | struct iucv_message local_interrupt_buffer; |
67 | atomic_t receive_ready; | 67 | atomic_t receive_ready; |
68 | iucv_handle_t iucv_handle; | ||
69 | int minor_num; | 68 | int minor_num; |
70 | char * buffer; | 69 | char * buffer; |
71 | char * current_position; | 70 | char * current_position; |
@@ -97,37 +96,19 @@ static struct file_operations vmlogrdr_fops = { | |||
97 | }; | 96 | }; |
98 | 97 | ||
99 | 98 | ||
100 | static u8 iucvMagic[16] = { | 99 | static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 ipuser[16]); |
101 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | 100 | static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 ipuser[16]); |
102 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 | 101 | static void vmlogrdr_iucv_message_pending(struct iucv_path *, |
103 | }; | 102 | struct iucv_message *); |
104 | 103 | ||
105 | 104 | ||
106 | static u8 mask[] = { | 105 | static struct iucv_handler vmlogrdr_iucv_handler = { |
107 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 106 | .path_complete = vmlogrdr_iucv_path_complete, |
108 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 107 | .path_severed = vmlogrdr_iucv_path_severed, |
109 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 108 | .message_pending = vmlogrdr_iucv_message_pending, |
110 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
111 | }; | 109 | }; |
112 | 110 | ||
113 | 111 | ||
114 | static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
115 | |||
116 | |||
117 | static void | ||
118 | vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data); | ||
119 | static void | ||
120 | vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data); | ||
121 | static void | ||
122 | vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data); | ||
123 | |||
124 | |||
125 | static iucv_interrupt_ops_t vmlogrdr_iucvops = { | ||
126 | .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete, | ||
127 | .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered, | ||
128 | .MessagePending = vmlogrdr_iucv_MessagePending, | ||
129 | }; | ||
130 | |||
131 | static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); | 112 | static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue); |
132 | static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); | 113 | static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue); |
133 | 114 | ||
@@ -176,28 +157,29 @@ static struct cdev *vmlogrdr_cdev = NULL; | |||
176 | static int recording_class_AB; | 157 | static int recording_class_AB; |
177 | 158 | ||
178 | 159 | ||
179 | static void | 160 | static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 ipuser[16]) |
180 | vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib, | ||
181 | void * pgm_data) | ||
182 | { | 161 | { |
183 | struct vmlogrdr_priv_t * logptr = pgm_data; | 162 | struct vmlogrdr_priv_t * logptr = path->private; |
163 | |||
184 | spin_lock(&logptr->priv_lock); | 164 | spin_lock(&logptr->priv_lock); |
185 | logptr->connection_established = 1; | 165 | logptr->connection_established = 1; |
186 | spin_unlock(&logptr->priv_lock); | 166 | spin_unlock(&logptr->priv_lock); |
187 | wake_up(&conn_wait_queue); | 167 | wake_up(&conn_wait_queue); |
188 | return; | ||
189 | } | 168 | } |
190 | 169 | ||
191 | 170 | ||
192 | static void | 171 | static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) |
193 | vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) | ||
194 | { | 172 | { |
195 | u8 reason = (u8) eib->ipuser[8]; | 173 | struct vmlogrdr_priv_t * logptr = path->private; |
196 | struct vmlogrdr_priv_t * logptr = pgm_data; | 174 | u8 reason = (u8) ipuser[8]; |
197 | 175 | ||
198 | printk (KERN_ERR "vmlogrdr: connection severed with" | 176 | printk (KERN_ERR "vmlogrdr: connection severed with" |
199 | " reason %i\n", reason); | 177 | " reason %i\n", reason); |
200 | 178 | ||
179 | iucv_path_sever(path, NULL); | ||
180 | kfree(path); | ||
181 | logptr->path = NULL; | ||
182 | |||
201 | spin_lock(&logptr->priv_lock); | 183 | spin_lock(&logptr->priv_lock); |
202 | logptr->connection_established = 0; | 184 | logptr->connection_established = 0; |
203 | logptr->iucv_path_severed = 1; | 185 | logptr->iucv_path_severed = 1; |
@@ -209,10 +191,10 @@ vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data) | |||
209 | } | 191 | } |
210 | 192 | ||
211 | 193 | ||
212 | static void | 194 | static void vmlogrdr_iucv_message_pending(struct iucv_path *path, |
213 | vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) | 195 | struct iucv_message *msg) |
214 | { | 196 | { |
215 | struct vmlogrdr_priv_t * logptr = pgm_data; | 197 | struct vmlogrdr_priv_t * logptr = path->private; |
216 | 198 | ||
217 | /* | 199 | /* |
218 | * This function is the bottom half so it should be quick. | 200 | * This function is the bottom half so it should be quick. |
@@ -220,15 +202,15 @@ vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data) | |||
220 | * the usage count | 202 | * the usage count |
221 | */ | 203 | */ |
222 | spin_lock(&logptr->priv_lock); | 204 | spin_lock(&logptr->priv_lock); |
223 | memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib)); | 205 | memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg)); |
224 | atomic_inc(&logptr->receive_ready); | 206 | atomic_inc(&logptr->receive_ready); |
225 | spin_unlock(&logptr->priv_lock); | 207 | spin_unlock(&logptr->priv_lock); |
226 | wake_up_interruptible(&read_wait_queue); | 208 | wake_up_interruptible(&read_wait_queue); |
227 | } | 209 | } |
228 | 210 | ||
229 | 211 | ||
230 | static int | 212 | static int vmlogrdr_get_recording_class_AB(void) |
231 | vmlogrdr_get_recording_class_AB(void) { | 213 | { |
232 | char cp_command[]="QUERY COMMAND RECORDING "; | 214 | char cp_command[]="QUERY COMMAND RECORDING "; |
233 | char cp_response[80]; | 215 | char cp_response[80]; |
234 | char *tail; | 216 | char *tail; |
@@ -258,8 +240,9 @@ vmlogrdr_get_recording_class_AB(void) { | |||
258 | } | 240 | } |
259 | 241 | ||
260 | 242 | ||
261 | static int | 243 | static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, |
262 | vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { | 244 | int action, int purge) |
245 | { | ||
263 | 246 | ||
264 | char cp_command[80]; | 247 | char cp_command[80]; |
265 | char cp_response[160]; | 248 | char cp_response[160]; |
@@ -317,8 +300,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) { | |||
317 | } | 300 | } |
318 | 301 | ||
319 | 302 | ||
320 | static int | 303 | static int vmlogrdr_open (struct inode *inode, struct file *filp) |
321 | vmlogrdr_open (struct inode *inode, struct file *filp) | ||
322 | { | 304 | { |
323 | int dev_num = 0; | 305 | int dev_num = 0; |
324 | struct vmlogrdr_priv_t * logptr = NULL; | 306 | struct vmlogrdr_priv_t * logptr = NULL; |
@@ -328,10 +310,7 @@ vmlogrdr_open (struct inode *inode, struct file *filp) | |||
328 | dev_num = iminor(inode); | 310 | dev_num = iminor(inode); |
329 | if (dev_num > MAXMINOR) | 311 | if (dev_num > MAXMINOR) |
330 | return -ENODEV; | 312 | return -ENODEV; |
331 | |||
332 | logptr = &sys_ser[dev_num]; | 313 | logptr = &sys_ser[dev_num]; |
333 | if (logptr == NULL) | ||
334 | return -ENODEV; | ||
335 | 314 | ||
336 | /* | 315 | /* |
337 | * only allow for blocking reads to be open | 316 | * only allow for blocking reads to be open |
@@ -344,52 +323,38 @@ vmlogrdr_open (struct inode *inode, struct file *filp) | |||
344 | if (logptr->dev_in_use) { | 323 | if (logptr->dev_in_use) { |
345 | spin_unlock_bh(&logptr->priv_lock); | 324 | spin_unlock_bh(&logptr->priv_lock); |
346 | return -EBUSY; | 325 | return -EBUSY; |
347 | } else { | ||
348 | logptr->dev_in_use = 1; | ||
349 | spin_unlock_bh(&logptr->priv_lock); | ||
350 | } | 326 | } |
351 | 327 | logptr->dev_in_use = 1; | |
328 | logptr->connection_established = 0; | ||
329 | logptr->iucv_path_severed = 0; | ||
352 | atomic_set(&logptr->receive_ready, 0); | 330 | atomic_set(&logptr->receive_ready, 0); |
353 | logptr->buffer_free = 1; | 331 | logptr->buffer_free = 1; |
332 | spin_unlock_bh(&logptr->priv_lock); | ||
354 | 333 | ||
355 | /* set the file options */ | 334 | /* set the file options */ |
356 | filp->private_data = logptr; | 335 | filp->private_data = logptr; |
357 | filp->f_op = &vmlogrdr_fops; | 336 | filp->f_op = &vmlogrdr_fops; |
358 | 337 | ||
359 | /* start recording for this service*/ | 338 | /* start recording for this service*/ |
360 | ret=0; | 339 | if (logptr->autorecording) { |
361 | if (logptr->autorecording) | ||
362 | ret = vmlogrdr_recording(logptr,1,logptr->autopurge); | 340 | ret = vmlogrdr_recording(logptr,1,logptr->autopurge); |
363 | if (ret) | 341 | if (ret) |
364 | printk (KERN_WARNING "vmlogrdr: failed to start " | 342 | printk (KERN_WARNING "vmlogrdr: failed to start " |
365 | "recording automatically\n"); | 343 | "recording automatically\n"); |
366 | |||
367 | /* Register with iucv driver */ | ||
368 | logptr->iucv_handle = iucv_register_program(iucvMagic, | ||
369 | logptr->system_service, mask, &vmlogrdr_iucvops, | ||
370 | logptr); | ||
371 | |||
372 | if (logptr->iucv_handle == NULL) { | ||
373 | printk (KERN_ERR "vmlogrdr: failed to register with" | ||
374 | "iucv driver\n"); | ||
375 | goto not_registered; | ||
376 | } | 344 | } |
377 | 345 | ||
378 | /* create connection to the system service */ | 346 | /* create connection to the system service */ |
379 | spin_lock_bh(&logptr->priv_lock); | 347 | logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL); |
380 | logptr->connection_established = 0; | 348 | if (!logptr->path) |
381 | logptr->iucv_path_severed = 0; | 349 | goto out_dev; |
382 | spin_unlock_bh(&logptr->priv_lock); | 350 | connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler, |
383 | 351 | logptr->system_service, NULL, NULL, | |
384 | connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic, | 352 | logptr); |
385 | logptr->system_service, iucv_host, 0, | ||
386 | NULL, NULL, | ||
387 | logptr->iucv_handle, NULL); | ||
388 | if (connect_rc) { | 353 | if (connect_rc) { |
389 | printk (KERN_ERR "vmlogrdr: iucv connection to %s " | 354 | printk (KERN_ERR "vmlogrdr: iucv connection to %s " |
390 | "failed with rc %i \n", logptr->system_service, | 355 | "failed with rc %i \n", logptr->system_service, |
391 | connect_rc); | 356 | connect_rc); |
392 | goto not_connected; | 357 | goto out_path; |
393 | } | 358 | } |
394 | 359 | ||
395 | /* We've issued the connect and now we must wait for a | 360 | /* We've issued the connect and now we must wait for a |
@@ -398,35 +363,28 @@ vmlogrdr_open (struct inode *inode, struct file *filp) | |||
398 | */ | 363 | */ |
399 | wait_event(conn_wait_queue, (logptr->connection_established) | 364 | wait_event(conn_wait_queue, (logptr->connection_established) |
400 | || (logptr->iucv_path_severed)); | 365 | || (logptr->iucv_path_severed)); |
401 | if (logptr->iucv_path_severed) { | 366 | if (logptr->iucv_path_severed) |
402 | goto not_connected; | 367 | goto out_record; |
403 | } | ||
404 | |||
405 | return nonseekable_open(inode, filp); | 368 | return nonseekable_open(inode, filp); |
406 | 369 | ||
407 | not_connected: | 370 | out_record: |
408 | iucv_unregister_program(logptr->iucv_handle); | ||
409 | logptr->iucv_handle = NULL; | ||
410 | not_registered: | ||
411 | if (logptr->autorecording) | 371 | if (logptr->autorecording) |
412 | vmlogrdr_recording(logptr,0,logptr->autopurge); | 372 | vmlogrdr_recording(logptr,0,logptr->autopurge); |
373 | out_path: | ||
374 | kfree(logptr->path); /* kfree(NULL) is ok. */ | ||
375 | logptr->path = NULL; | ||
376 | out_dev: | ||
413 | logptr->dev_in_use = 0; | 377 | logptr->dev_in_use = 0; |
414 | return -EIO; | 378 | return -EIO; |
415 | |||
416 | |||
417 | } | 379 | } |
418 | 380 | ||
419 | 381 | ||
420 | static int | 382 | static int vmlogrdr_release (struct inode *inode, struct file *filp) |
421 | vmlogrdr_release (struct inode *inode, struct file *filp) | ||
422 | { | 383 | { |
423 | int ret; | 384 | int ret; |
424 | 385 | ||
425 | struct vmlogrdr_priv_t * logptr = filp->private_data; | 386 | struct vmlogrdr_priv_t * logptr = filp->private_data; |
426 | 387 | ||
427 | iucv_unregister_program(logptr->iucv_handle); | ||
428 | logptr->iucv_handle = NULL; | ||
429 | |||
430 | if (logptr->autorecording) { | 388 | if (logptr->autorecording) { |
431 | ret = vmlogrdr_recording(logptr,0,logptr->autopurge); | 389 | ret = vmlogrdr_recording(logptr,0,logptr->autopurge); |
432 | if (ret) | 390 | if (ret) |
@@ -439,8 +397,8 @@ vmlogrdr_release (struct inode *inode, struct file *filp) | |||
439 | } | 397 | } |
440 | 398 | ||
441 | 399 | ||
442 | static int | 400 | static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) |
443 | vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | 401 | { |
444 | int rc, *temp; | 402 | int rc, *temp; |
445 | /* we need to keep track of two data sizes here: | 403 | /* we need to keep track of two data sizes here: |
446 | * The number of bytes we need to receive from iucv and | 404 | * The number of bytes we need to receive from iucv and |
@@ -461,8 +419,7 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | |||
461 | * We need to return the total length of the record | 419 | * We need to return the total length of the record |
462 | * + size of FENCE in the first 4 bytes of the buffer. | 420 | * + size of FENCE in the first 4 bytes of the buffer. |
463 | */ | 421 | */ |
464 | iucv_data_count = | 422 | iucv_data_count = priv->local_interrupt_buffer.length; |
465 | priv->local_interrupt_buffer.ln1msg2.ipbfln1f; | ||
466 | user_data_count = sizeof(int); | 423 | user_data_count = sizeof(int); |
467 | temp = (int*)priv->buffer; | 424 | temp = (int*)priv->buffer; |
468 | *temp= iucv_data_count + sizeof(FENCE); | 425 | *temp= iucv_data_count + sizeof(FENCE); |
@@ -474,14 +431,10 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | |||
474 | */ | 431 | */ |
475 | if (iucv_data_count > NET_BUFFER_SIZE) | 432 | if (iucv_data_count > NET_BUFFER_SIZE) |
476 | iucv_data_count = NET_BUFFER_SIZE; | 433 | iucv_data_count = NET_BUFFER_SIZE; |
477 | rc = iucv_receive(priv->pathid, | 434 | rc = iucv_message_receive(priv->path, |
478 | priv->local_interrupt_buffer.ipmsgid, | 435 | &priv->local_interrupt_buffer, |
479 | priv->local_interrupt_buffer.iptrgcls, | 436 | 0, buffer, iucv_data_count, |
480 | buffer, | 437 | &priv->residual_length); |
481 | iucv_data_count, | ||
482 | NULL, | ||
483 | NULL, | ||
484 | &priv->residual_length); | ||
485 | spin_unlock_bh(&priv->priv_lock); | 438 | spin_unlock_bh(&priv->priv_lock); |
486 | /* An rc of 5 indicates that the record was bigger then | 439 | /* An rc of 5 indicates that the record was bigger then |
487 | * the buffer, which is OK for us. A 9 indicates that the | 440 | * the buffer, which is OK for us. A 9 indicates that the |
@@ -513,8 +466,8 @@ vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) { | |||
513 | } | 466 | } |
514 | 467 | ||
515 | 468 | ||
516 | static ssize_t | 469 | static ssize_t vmlogrdr_read(struct file *filp, char __user *data, |
517 | vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) | 470 | size_t count, loff_t * ppos) |
518 | { | 471 | { |
519 | int rc; | 472 | int rc; |
520 | struct vmlogrdr_priv_t * priv = filp->private_data; | 473 | struct vmlogrdr_priv_t * priv = filp->private_data; |
@@ -546,8 +499,10 @@ vmlogrdr_read(struct file *filp, char __user *data, size_t count, loff_t * ppos) | |||
546 | return count; | 499 | return count; |
547 | } | 500 | } |
548 | 501 | ||
549 | static ssize_t | 502 | static ssize_t vmlogrdr_autopurge_store(struct device * dev, |
550 | vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { | 503 | struct device_attribute *attr, |
504 | const char * buf, size_t count) | ||
505 | { | ||
551 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 506 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
552 | ssize_t ret = count; | 507 | ssize_t ret = count; |
553 | 508 | ||
@@ -565,8 +520,10 @@ vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, con | |||
565 | } | 520 | } |
566 | 521 | ||
567 | 522 | ||
568 | static ssize_t | 523 | static ssize_t vmlogrdr_autopurge_show(struct device *dev, |
569 | vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) { | 524 | struct device_attribute *attr, |
525 | char *buf) | ||
526 | { | ||
570 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 527 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
571 | return sprintf(buf, "%u\n", priv->autopurge); | 528 | return sprintf(buf, "%u\n", priv->autopurge); |
572 | } | 529 | } |
@@ -576,8 +533,10 @@ static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show, | |||
576 | vmlogrdr_autopurge_store); | 533 | vmlogrdr_autopurge_store); |
577 | 534 | ||
578 | 535 | ||
579 | static ssize_t | 536 | static ssize_t vmlogrdr_purge_store(struct device * dev, |
580 | vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { | 537 | struct device_attribute *attr, |
538 | const char * buf, size_t count) | ||
539 | { | ||
581 | 540 | ||
582 | char cp_command[80]; | 541 | char cp_command[80]; |
583 | char cp_response[80]; | 542 | char cp_response[80]; |
@@ -617,9 +576,10 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c | |||
617 | static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); | 576 | static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store); |
618 | 577 | ||
619 | 578 | ||
620 | static ssize_t | 579 | static ssize_t vmlogrdr_autorecording_store(struct device *dev, |
621 | vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf, | 580 | struct device_attribute *attr, |
622 | size_t count) { | 581 | const char *buf, size_t count) |
582 | { | ||
623 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 583 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
624 | ssize_t ret = count; | 584 | ssize_t ret = count; |
625 | 585 | ||
@@ -637,8 +597,10 @@ vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, | |||
637 | } | 597 | } |
638 | 598 | ||
639 | 599 | ||
640 | static ssize_t | 600 | static ssize_t vmlogrdr_autorecording_show(struct device *dev, |
641 | vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) { | 601 | struct device_attribute *attr, |
602 | char *buf) | ||
603 | { | ||
642 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 604 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
643 | return sprintf(buf, "%u\n", priv->autorecording); | 605 | return sprintf(buf, "%u\n", priv->autorecording); |
644 | } | 606 | } |
@@ -648,9 +610,10 @@ static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show, | |||
648 | vmlogrdr_autorecording_store); | 610 | vmlogrdr_autorecording_store); |
649 | 611 | ||
650 | 612 | ||
651 | static ssize_t | 613 | static ssize_t vmlogrdr_recording_store(struct device * dev, |
652 | vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) { | 614 | struct device_attribute *attr, |
653 | 615 | const char * buf, size_t count) | |
616 | { | ||
654 | struct vmlogrdr_priv_t *priv = dev->driver_data; | 617 | struct vmlogrdr_priv_t *priv = dev->driver_data; |
655 | ssize_t ret; | 618 | ssize_t ret; |
656 | 619 | ||
@@ -675,8 +638,9 @@ vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, con | |||
675 | static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); | 638 | static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store); |
676 | 639 | ||
677 | 640 | ||
678 | static ssize_t | 641 | static ssize_t vmlogrdr_recording_status_show(struct device_driver *driver, |
679 | vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) { | 642 | char *buf) |
643 | { | ||
680 | 644 | ||
681 | char cp_command[] = "QUERY RECORDING "; | 645 | char cp_command[] = "QUERY RECORDING "; |
682 | int len; | 646 | int len; |
@@ -709,52 +673,63 @@ static struct device_driver vmlogrdr_driver = { | |||
709 | }; | 673 | }; |
710 | 674 | ||
711 | 675 | ||
712 | static int | 676 | static int vmlogrdr_register_driver(void) |
713 | vmlogrdr_register_driver(void) { | 677 | { |
714 | int ret; | 678 | int ret; |
715 | 679 | ||
680 | /* Register with iucv driver */ | ||
681 | ret = iucv_register(&vmlogrdr_iucv_handler, 1); | ||
682 | if (ret) { | ||
683 | printk (KERN_ERR "vmlogrdr: failed to register with" | ||
684 | "iucv driver\n"); | ||
685 | goto out; | ||
686 | } | ||
687 | |||
716 | ret = driver_register(&vmlogrdr_driver); | 688 | ret = driver_register(&vmlogrdr_driver); |
717 | if (ret) { | 689 | if (ret) { |
718 | printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); | 690 | printk(KERN_ERR "vmlogrdr: failed to register driver.\n"); |
719 | return ret; | 691 | goto out_iucv; |
720 | } | 692 | } |
721 | 693 | ||
722 | ret = driver_create_file(&vmlogrdr_driver, | 694 | ret = driver_create_file(&vmlogrdr_driver, |
723 | &driver_attr_recording_status); | 695 | &driver_attr_recording_status); |
724 | if (ret) { | 696 | if (ret) { |
725 | printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); | 697 | printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n"); |
726 | goto unregdriver; | 698 | goto out_driver; |
727 | } | 699 | } |
728 | 700 | ||
729 | vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); | 701 | vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr"); |
730 | if (IS_ERR(vmlogrdr_class)) { | 702 | if (IS_ERR(vmlogrdr_class)) { |
731 | printk(KERN_ERR "vmlogrdr: failed to create class.\n"); | 703 | printk(KERN_ERR "vmlogrdr: failed to create class.\n"); |
732 | ret=PTR_ERR(vmlogrdr_class); | 704 | ret = PTR_ERR(vmlogrdr_class); |
733 | vmlogrdr_class=NULL; | 705 | vmlogrdr_class = NULL; |
734 | goto unregattr; | 706 | goto out_attr; |
735 | } | 707 | } |
736 | return 0; | 708 | return 0; |
737 | 709 | ||
738 | unregattr: | 710 | out_attr: |
739 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); | 711 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); |
740 | unregdriver: | 712 | out_driver: |
741 | driver_unregister(&vmlogrdr_driver); | 713 | driver_unregister(&vmlogrdr_driver); |
714 | out_iucv: | ||
715 | iucv_unregister(&vmlogrdr_iucv_handler, 1); | ||
716 | out: | ||
742 | return ret; | 717 | return ret; |
743 | } | 718 | } |
744 | 719 | ||
745 | 720 | ||
746 | static void | 721 | static void vmlogrdr_unregister_driver(void) |
747 | vmlogrdr_unregister_driver(void) { | 722 | { |
748 | class_destroy(vmlogrdr_class); | 723 | class_destroy(vmlogrdr_class); |
749 | vmlogrdr_class = NULL; | 724 | vmlogrdr_class = NULL; |
750 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); | 725 | driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status); |
751 | driver_unregister(&vmlogrdr_driver); | 726 | driver_unregister(&vmlogrdr_driver); |
752 | return; | 727 | iucv_unregister(&vmlogrdr_iucv_handler, 1); |
753 | } | 728 | } |
754 | 729 | ||
755 | 730 | ||
756 | static int | 731 | static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) |
757 | vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { | 732 | { |
758 | struct device *dev; | 733 | struct device *dev; |
759 | int ret; | 734 | int ret; |
760 | 735 | ||
@@ -803,9 +778,10 @@ vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) { | |||
803 | } | 778 | } |
804 | 779 | ||
805 | 780 | ||
806 | static int | 781 | static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv) |
807 | vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { | 782 | { |
808 | class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num)); | 783 | class_device_destroy(vmlogrdr_class, |
784 | MKDEV(vmlogrdr_major, priv->minor_num)); | ||
809 | if (priv->device != NULL) { | 785 | if (priv->device != NULL) { |
810 | sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); | 786 | sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group); |
811 | device_unregister(priv->device); | 787 | device_unregister(priv->device); |
@@ -815,8 +791,8 @@ vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) { | |||
815 | } | 791 | } |
816 | 792 | ||
817 | 793 | ||
818 | static int | 794 | static int vmlogrdr_register_cdev(dev_t dev) |
819 | vmlogrdr_register_cdev(dev_t dev) { | 795 | { |
820 | int rc = 0; | 796 | int rc = 0; |
821 | vmlogrdr_cdev = cdev_alloc(); | 797 | vmlogrdr_cdev = cdev_alloc(); |
822 | if (!vmlogrdr_cdev) { | 798 | if (!vmlogrdr_cdev) { |
@@ -836,9 +812,10 @@ vmlogrdr_register_cdev(dev_t dev) { | |||
836 | } | 812 | } |
837 | 813 | ||
838 | 814 | ||
839 | static void | 815 | static void vmlogrdr_cleanup(void) |
840 | vmlogrdr_cleanup(void) { | 816 | { |
841 | int i; | 817 | int i; |
818 | |||
842 | if (vmlogrdr_cdev) { | 819 | if (vmlogrdr_cdev) { |
843 | cdev_del(vmlogrdr_cdev); | 820 | cdev_del(vmlogrdr_cdev); |
844 | vmlogrdr_cdev=NULL; | 821 | vmlogrdr_cdev=NULL; |
@@ -855,8 +832,7 @@ vmlogrdr_cleanup(void) { | |||
855 | } | 832 | } |
856 | 833 | ||
857 | 834 | ||
858 | static int | 835 | static int vmlogrdr_init(void) |
859 | vmlogrdr_init(void) | ||
860 | { | 836 | { |
861 | int rc; | 837 | int rc; |
862 | int i; | 838 | int i; |
@@ -906,8 +882,7 @@ cleanup: | |||
906 | } | 882 | } |
907 | 883 | ||
908 | 884 | ||
909 | static void | 885 | static void vmlogrdr_exit(void) |
910 | vmlogrdr_exit(void) | ||
911 | { | 886 | { |
912 | vmlogrdr_cleanup(); | 887 | vmlogrdr_cleanup(); |
913 | printk (KERN_INFO "vmlogrdr: driver unloaded\n"); | 888 | printk (KERN_INFO "vmlogrdr: driver unloaded\n"); |
diff --git a/drivers/s390/net/Kconfig b/drivers/s390/net/Kconfig index 52625153a4f0..f98fa465df0a 100644 --- a/drivers/s390/net/Kconfig +++ b/drivers/s390/net/Kconfig | |||
@@ -22,13 +22,6 @@ config CTC | |||
22 | available. This option is also available as a module which will be | 22 | available. This option is also available as a module which will be |
23 | called ctc.ko. If you do not know what it is, it's safe to say "Y". | 23 | called ctc.ko. If you do not know what it is, it's safe to say "Y". |
24 | 24 | ||
25 | config IUCV | ||
26 | tristate "IUCV support (VM only)" | ||
27 | help | ||
28 | Select this option if you want to use inter-user communication | ||
29 | under VM or VIF. If unsure, say "Y" to enable a fast communication | ||
30 | link between VM guests. | ||
31 | |||
32 | config NETIUCV | 25 | config NETIUCV |
33 | tristate "IUCV network device support (VM only)" | 26 | tristate "IUCV network device support (VM only)" |
34 | depends on IUCV && NETDEVICES | 27 | depends on IUCV && NETDEVICES |
diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 4777e36a922f..bbe3ab2e93d9 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile | |||
@@ -4,7 +4,6 @@ | |||
4 | 4 | ||
5 | ctc-objs := ctcmain.o ctcdbug.o | 5 | ctc-objs := ctcmain.o ctcdbug.o |
6 | 6 | ||
7 | obj-$(CONFIG_IUCV) += iucv.o | ||
8 | obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o | 7 | obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o |
9 | obj-$(CONFIG_SMSGIUCV) += smsgiucv.o | 8 | obj-$(CONFIG_SMSGIUCV) += smsgiucv.o |
10 | obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o | 9 | obj-$(CONFIG_CTC) += ctc.o fsm.o cu3088.o |
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c deleted file mode 100644 index 229aeb5fc399..000000000000 --- a/drivers/s390/net/iucv.c +++ /dev/null | |||
@@ -1,2540 +0,0 @@ | |||
1 | /* | ||
2 | * IUCV network driver | ||
3 | * | ||
4 | * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation | ||
5 | * Author(s): | ||
6 | * Original source: | ||
7 | * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 | ||
8 | * Xenia Tkatschow (xenia@us.ibm.com) | ||
9 | * 2Gb awareness and general cleanup: | ||
10 | * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | ||
11 | * | ||
12 | * Documentation used: | ||
13 | * The original source | ||
14 | * CP Programming Service, IBM document # SC24-5760 | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2, or (at your option) | ||
19 | * any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | /* #define DEBUG */ | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | #include <linux/moduleparam.h> | ||
36 | |||
37 | #include <linux/spinlock.h> | ||
38 | #include <linux/kernel.h> | ||
39 | #include <linux/slab.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/list.h> | ||
43 | #include <linux/errno.h> | ||
44 | #include <linux/err.h> | ||
45 | #include <linux/device.h> | ||
46 | #include <asm/atomic.h> | ||
47 | #include "iucv.h" | ||
48 | #include <asm/io.h> | ||
49 | #include <asm/s390_ext.h> | ||
50 | #include <asm/ebcdic.h> | ||
51 | #include <asm/smp.h> | ||
52 | #include <asm/s390_rdev.h> | ||
53 | |||
54 | /* FLAGS: | ||
55 | * All flags are defined in the field IPFLAGS1 of each function | ||
56 | * and can be found in CP Programming Services. | ||
57 | * IPSRCCLS - Indicates you have specified a source class | ||
58 | * IPFGMCL - Indicates you have specified a target class | ||
59 | * IPFGPID - Indicates you have specified a pathid | ||
60 | * IPFGMID - Indicates you have specified a message ID | ||
61 | * IPANSLST - Indicates that you are using an address list for | ||
62 | * reply data | ||
63 | * IPBUFLST - Indicates that you are using an address list for | ||
64 | * message data | ||
65 | */ | ||
66 | |||
67 | #define IPSRCCLS 0x01 | ||
68 | #define IPFGMCL 0x01 | ||
69 | #define IPFGPID 0x02 | ||
70 | #define IPFGMID 0x04 | ||
71 | #define IPANSLST 0x08 | ||
72 | #define IPBUFLST 0x40 | ||
73 | |||
74 | static int | ||
75 | iucv_bus_match (struct device *dev, struct device_driver *drv) | ||
76 | { | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | struct bus_type iucv_bus = { | ||
81 | .name = "iucv", | ||
82 | .match = iucv_bus_match, | ||
83 | }; | ||
84 | |||
85 | struct device *iucv_root; | ||
86 | |||
87 | /* General IUCV interrupt structure */ | ||
88 | typedef struct { | ||
89 | __u16 ippathid; | ||
90 | __u8 res1; | ||
91 | __u8 iptype; | ||
92 | __u32 res2; | ||
93 | __u8 ipvmid[8]; | ||
94 | __u8 res3[24]; | ||
95 | } iucv_GeneralInterrupt; | ||
96 | |||
97 | static iucv_GeneralInterrupt *iucv_external_int_buffer = NULL; | ||
98 | |||
99 | /* Spin Lock declaration */ | ||
100 | |||
101 | static DEFINE_SPINLOCK(iucv_lock); | ||
102 | |||
103 | static int messagesDisabled = 0; | ||
104 | |||
105 | /***************INTERRUPT HANDLING ***************/ | ||
106 | |||
107 | typedef struct { | ||
108 | struct list_head queue; | ||
109 | iucv_GeneralInterrupt data; | ||
110 | } iucv_irqdata; | ||
111 | |||
112 | static struct list_head iucv_irq_queue; | ||
113 | static DEFINE_SPINLOCK(iucv_irq_queue_lock); | ||
114 | |||
115 | /* | ||
116 | *Internal function prototypes | ||
117 | */ | ||
118 | static void iucv_tasklet_handler(unsigned long); | ||
119 | static void iucv_irq_handler(__u16); | ||
120 | |||
121 | static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0); | ||
122 | |||
123 | /************ FUNCTION ID'S ****************************/ | ||
124 | |||
125 | #define ACCEPT 10 | ||
126 | #define CONNECT 11 | ||
127 | #define DECLARE_BUFFER 12 | ||
128 | #define PURGE 9 | ||
129 | #define QUERY 0 | ||
130 | #define QUIESCE 13 | ||
131 | #define RECEIVE 5 | ||
132 | #define REJECT 8 | ||
133 | #define REPLY 6 | ||
134 | #define RESUME 14 | ||
135 | #define RETRIEVE_BUFFER 2 | ||
136 | #define SEND 4 | ||
137 | #define SETMASK 16 | ||
138 | #define SEVER 15 | ||
139 | |||
140 | /** | ||
141 | * Structure: handler | ||
142 | * members: list - list management. | ||
143 | * structure: id | ||
144 | * userid - 8 char array of machine identification | ||
145 | * user_data - 16 char array for user identification | ||
146 | * mask - 24 char array used to compare the 2 previous | ||
147 | * interrupt_table - vector of interrupt functions. | ||
148 | * pgm_data - ulong, application data that is passed | ||
149 | * to the interrupt handlers | ||
150 | */ | ||
151 | typedef struct handler_t { | ||
152 | struct list_head list; | ||
153 | struct { | ||
154 | __u8 userid[8]; | ||
155 | __u8 user_data[16]; | ||
156 | __u8 mask[24]; | ||
157 | } id; | ||
158 | iucv_interrupt_ops_t *interrupt_table; | ||
159 | void *pgm_data; | ||
160 | } handler; | ||
161 | |||
162 | /** | ||
163 | * iucv_handler_table: List of registered handlers. | ||
164 | */ | ||
165 | static struct list_head iucv_handler_table; | ||
166 | |||
167 | /** | ||
168 | * iucv_pathid_table: an array of *handler pointing into | ||
169 | * iucv_handler_table for fast indexing by pathid; | ||
170 | */ | ||
171 | static handler **iucv_pathid_table; | ||
172 | |||
173 | static unsigned long max_connections; | ||
174 | |||
175 | /** | ||
176 | * iucv_cpuid: contains the logical cpu number of the cpu which | ||
177 | * has declared the iucv buffer by issuing DECLARE_BUFFER. | ||
178 | * If no cpu has done the initialization iucv_cpuid contains -1. | ||
179 | */ | ||
180 | static int iucv_cpuid = -1; | ||
181 | /** | ||
182 | * register_flag: is 0 when external interrupt has not been registered | ||
183 | */ | ||
184 | static int register_flag; | ||
185 | |||
186 | /****************FIVE 40-BYTE PARAMETER STRUCTURES******************/ | ||
187 | /* Data struct 1: iparml_control | ||
188 | * Used for iucv_accept | ||
189 | * iucv_connect | ||
190 | * iucv_quiesce | ||
191 | * iucv_resume | ||
192 | * iucv_sever | ||
193 | * iucv_retrieve_buffer | ||
194 | * Data struct 2: iparml_dpl (data in parameter list) | ||
195 | * Used for iucv_send_prmmsg | ||
196 | * iucv_send2way_prmmsg | ||
197 | * iucv_send2way_prmmsg_array | ||
198 | * iucv_reply_prmmsg | ||
199 | * Data struct 3: iparml_db (data in a buffer) | ||
200 | * Used for iucv_receive | ||
201 | * iucv_receive_array | ||
202 | * iucv_reject | ||
203 | * iucv_reply | ||
204 | * iucv_reply_array | ||
205 | * iucv_send | ||
206 | * iucv_send_array | ||
207 | * iucv_send2way | ||
208 | * iucv_send2way_array | ||
209 | * iucv_declare_buffer | ||
210 | * Data struct 4: iparml_purge | ||
211 | * Used for iucv_purge | ||
212 | * iucv_query | ||
213 | * Data struct 5: iparml_set_mask | ||
214 | * Used for iucv_set_mask | ||
215 | */ | ||
216 | |||
217 | typedef struct { | ||
218 | __u16 ippathid; | ||
219 | __u8 ipflags1; | ||
220 | __u8 iprcode; | ||
221 | __u16 ipmsglim; | ||
222 | __u16 res1; | ||
223 | __u8 ipvmid[8]; | ||
224 | __u8 ipuser[16]; | ||
225 | __u8 iptarget[8]; | ||
226 | } iparml_control; | ||
227 | |||
228 | typedef struct { | ||
229 | __u16 ippathid; | ||
230 | __u8 ipflags1; | ||
231 | __u8 iprcode; | ||
232 | __u32 ipmsgid; | ||
233 | __u32 iptrgcls; | ||
234 | __u8 iprmmsg[8]; | ||
235 | __u32 ipsrccls; | ||
236 | __u32 ipmsgtag; | ||
237 | __u32 ipbfadr2; | ||
238 | __u32 ipbfln2f; | ||
239 | __u32 res; | ||
240 | } iparml_dpl; | ||
241 | |||
242 | typedef struct { | ||
243 | __u16 ippathid; | ||
244 | __u8 ipflags1; | ||
245 | __u8 iprcode; | ||
246 | __u32 ipmsgid; | ||
247 | __u32 iptrgcls; | ||
248 | __u32 ipbfadr1; | ||
249 | __u32 ipbfln1f; | ||
250 | __u32 ipsrccls; | ||
251 | __u32 ipmsgtag; | ||
252 | __u32 ipbfadr2; | ||
253 | __u32 ipbfln2f; | ||
254 | __u32 res; | ||
255 | } iparml_db; | ||
256 | |||
257 | typedef struct { | ||
258 | __u16 ippathid; | ||
259 | __u8 ipflags1; | ||
260 | __u8 iprcode; | ||
261 | __u32 ipmsgid; | ||
262 | __u8 ipaudit[3]; | ||
263 | __u8 res1[5]; | ||
264 | __u32 res2; | ||
265 | __u32 ipsrccls; | ||
266 | __u32 ipmsgtag; | ||
267 | __u32 res3[3]; | ||
268 | } iparml_purge; | ||
269 | |||
270 | typedef struct { | ||
271 | __u8 ipmask; | ||
272 | __u8 res1[2]; | ||
273 | __u8 iprcode; | ||
274 | __u32 res2[9]; | ||
275 | } iparml_set_mask; | ||
276 | |||
277 | typedef struct { | ||
278 | union { | ||
279 | iparml_control p_ctrl; | ||
280 | iparml_dpl p_dpl; | ||
281 | iparml_db p_db; | ||
282 | iparml_purge p_purge; | ||
283 | iparml_set_mask p_set_mask; | ||
284 | } param; | ||
285 | atomic_t in_use; | ||
286 | __u32 res; | ||
287 | } __attribute__ ((aligned(8))) iucv_param; | ||
288 | #define PARAM_POOL_SIZE (PAGE_SIZE / sizeof(iucv_param)) | ||
289 | |||
290 | static iucv_param * iucv_param_pool; | ||
291 | |||
292 | MODULE_AUTHOR("(C) 2001 IBM Corp. by Fritz Elfert (felfert@millenux.com)"); | ||
293 | MODULE_DESCRIPTION("Linux for S/390 IUCV lowlevel driver"); | ||
294 | MODULE_LICENSE("GPL"); | ||
295 | |||
296 | /* | ||
297 | * Debugging stuff | ||
298 | *******************************************************************************/ | ||
299 | |||
300 | |||
301 | #ifdef DEBUG | ||
302 | static int debuglevel = 0; | ||
303 | |||
304 | module_param(debuglevel, int, 0); | ||
305 | MODULE_PARM_DESC(debuglevel, | ||
306 | "Specifies the debug level (0=off ... 3=all)"); | ||
307 | |||
308 | static void | ||
309 | iucv_dumpit(char *title, void *buf, int len) | ||
310 | { | ||
311 | int i; | ||
312 | __u8 *p = (__u8 *)buf; | ||
313 | |||
314 | if (debuglevel < 3) | ||
315 | return; | ||
316 | |||
317 | printk(KERN_DEBUG "%s\n", title); | ||
318 | printk(" "); | ||
319 | for (i = 0; i < len; i++) { | ||
320 | if (!(i % 16) && i != 0) | ||
321 | printk ("\n "); | ||
322 | else if (!(i % 4) && i != 0) | ||
323 | printk(" "); | ||
324 | printk("%02X", *p++); | ||
325 | } | ||
326 | if (len % 16) | ||
327 | printk ("\n"); | ||
328 | return; | ||
329 | } | ||
330 | #define iucv_debug(lvl, fmt, args...) \ | ||
331 | do { \ | ||
332 | if (debuglevel >= lvl) \ | ||
333 | printk(KERN_DEBUG "%s: " fmt "\n", __FUNCTION__ , ## args); \ | ||
334 | } while (0) | ||
335 | |||
336 | #else | ||
337 | |||
338 | #define iucv_debug(lvl, fmt, args...) do { } while (0) | ||
339 | #define iucv_dumpit(title, buf, len) do { } while (0) | ||
340 | |||
341 | #endif | ||
342 | |||
343 | /* | ||
344 | * Internal functions | ||
345 | *******************************************************************************/ | ||
346 | |||
347 | /** | ||
348 | * print start banner | ||
349 | */ | ||
350 | static void | ||
351 | iucv_banner(void) | ||
352 | { | ||
353 | printk(KERN_INFO "IUCV lowlevel driver initialized\n"); | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * iucv_init - Initialization | ||
358 | * | ||
359 | * Allocates and initializes various data structures. | ||
360 | */ | ||
361 | static int | ||
362 | iucv_init(void) | ||
363 | { | ||
364 | int ret; | ||
365 | |||
366 | if (iucv_external_int_buffer) | ||
367 | return 0; | ||
368 | |||
369 | if (!MACHINE_IS_VM) { | ||
370 | printk(KERN_ERR "IUCV: IUCV connection needs VM as base\n"); | ||
371 | return -EPROTONOSUPPORT; | ||
372 | } | ||
373 | |||
374 | ret = bus_register(&iucv_bus); | ||
375 | if (ret) { | ||
376 | printk(KERN_ERR "IUCV: failed to register bus.\n"); | ||
377 | return ret; | ||
378 | } | ||
379 | |||
380 | iucv_root = s390_root_dev_register("iucv"); | ||
381 | if (IS_ERR(iucv_root)) { | ||
382 | printk(KERN_ERR "IUCV: failed to register iucv root.\n"); | ||
383 | bus_unregister(&iucv_bus); | ||
384 | return PTR_ERR(iucv_root); | ||
385 | } | ||
386 | |||
387 | /* Note: GFP_DMA used used to get memory below 2G */ | ||
388 | iucv_external_int_buffer = kzalloc(sizeof(iucv_GeneralInterrupt), | ||
389 | GFP_KERNEL|GFP_DMA); | ||
390 | if (!iucv_external_int_buffer) { | ||
391 | printk(KERN_WARNING | ||
392 | "%s: Could not allocate external interrupt buffer\n", | ||
393 | __FUNCTION__); | ||
394 | s390_root_dev_unregister(iucv_root); | ||
395 | bus_unregister(&iucv_bus); | ||
396 | return -ENOMEM; | ||
397 | } | ||
398 | |||
399 | /* Initialize parameter pool */ | ||
400 | iucv_param_pool = kzalloc(sizeof(iucv_param) * PARAM_POOL_SIZE, | ||
401 | GFP_KERNEL|GFP_DMA); | ||
402 | if (!iucv_param_pool) { | ||
403 | printk(KERN_WARNING "%s: Could not allocate param pool\n", | ||
404 | __FUNCTION__); | ||
405 | kfree(iucv_external_int_buffer); | ||
406 | iucv_external_int_buffer = NULL; | ||
407 | s390_root_dev_unregister(iucv_root); | ||
408 | bus_unregister(&iucv_bus); | ||
409 | return -ENOMEM; | ||
410 | } | ||
411 | |||
412 | /* Initialize irq queue */ | ||
413 | INIT_LIST_HEAD(&iucv_irq_queue); | ||
414 | |||
415 | /* Initialize handler table */ | ||
416 | INIT_LIST_HEAD(&iucv_handler_table); | ||
417 | |||
418 | iucv_banner(); | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | /** | ||
423 | * iucv_exit - De-Initialization | ||
424 | * | ||
425 | * Frees everything allocated from iucv_init. | ||
426 | */ | ||
427 | static int iucv_retrieve_buffer (void); | ||
428 | |||
429 | static void | ||
430 | iucv_exit(void) | ||
431 | { | ||
432 | iucv_retrieve_buffer(); | ||
433 | kfree(iucv_external_int_buffer); | ||
434 | iucv_external_int_buffer = NULL; | ||
435 | kfree(iucv_param_pool); | ||
436 | iucv_param_pool = NULL; | ||
437 | s390_root_dev_unregister(iucv_root); | ||
438 | bus_unregister(&iucv_bus); | ||
439 | printk(KERN_INFO "IUCV lowlevel driver unloaded\n"); | ||
440 | } | ||
441 | |||
442 | /** | ||
443 | * grab_param: - Get a parameter buffer from the pre-allocated pool. | ||
444 | * | ||
445 | * This function searches for an unused element in the pre-allocated pool | ||
446 | * of parameter buffers. If one is found, it marks it "in use" and returns | ||
447 | * a pointer to it. The calling function is responsible for releasing it | ||
448 | * when it has finished its usage. | ||
449 | * | ||
450 | * Returns: A pointer to iucv_param. | ||
451 | */ | ||
452 | static __inline__ iucv_param * | ||
453 | grab_param(void) | ||
454 | { | ||
455 | iucv_param *ptr; | ||
456 | static int hint = 0; | ||
457 | |||
458 | ptr = iucv_param_pool + hint; | ||
459 | do { | ||
460 | ptr++; | ||
461 | if (ptr >= iucv_param_pool + PARAM_POOL_SIZE) | ||
462 | ptr = iucv_param_pool; | ||
463 | } while (atomic_cmpxchg(&ptr->in_use, 0, 1) != 0); | ||
464 | hint = ptr - iucv_param_pool; | ||
465 | |||
466 | memset(&ptr->param, 0, sizeof(ptr->param)); | ||
467 | return ptr; | ||
468 | } | ||
469 | |||
470 | /** | ||
471 | * release_param - Release a parameter buffer. | ||
472 | * @p: A pointer to a struct iucv_param, previously obtained by calling | ||
473 | * grab_param(). | ||
474 | * | ||
475 | * This function marks the specified parameter buffer "unused". | ||
476 | */ | ||
477 | static __inline__ void | ||
478 | release_param(void *p) | ||
479 | { | ||
480 | atomic_set(&((iucv_param *)p)->in_use, 0); | ||
481 | } | ||
482 | |||
483 | /** | ||
484 | * iucv_add_handler: - Add a new handler | ||
485 | * @new_handler: handle that is being entered into chain. | ||
486 | * | ||
487 | * Places new handle on iucv_handler_table, if identical handler is not | ||
488 | * found. | ||
489 | * | ||
490 | * Returns: 0 on success, !0 on failure (handler already in chain). | ||
491 | */ | ||
492 | static int | ||
493 | iucv_add_handler (handler *new) | ||
494 | { | ||
495 | ulong flags; | ||
496 | |||
497 | iucv_debug(1, "entering"); | ||
498 | iucv_dumpit("handler:", new, sizeof(handler)); | ||
499 | |||
500 | spin_lock_irqsave (&iucv_lock, flags); | ||
501 | if (!list_empty(&iucv_handler_table)) { | ||
502 | struct list_head *lh; | ||
503 | |||
504 | /** | ||
505 | * Search list for handler with identical id. If one | ||
506 | * is found, the new handler is _not_ added. | ||
507 | */ | ||
508 | list_for_each(lh, &iucv_handler_table) { | ||
509 | handler *h = list_entry(lh, handler, list); | ||
510 | if (!memcmp(&new->id, &h->id, sizeof(h->id))) { | ||
511 | iucv_debug(1, "ret 1"); | ||
512 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
513 | return 1; | ||
514 | } | ||
515 | } | ||
516 | } | ||
517 | /** | ||
518 | * If we get here, no handler was found. | ||
519 | */ | ||
520 | INIT_LIST_HEAD(&new->list); | ||
521 | list_add(&new->list, &iucv_handler_table); | ||
522 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
523 | |||
524 | iucv_debug(1, "exiting"); | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | /** | ||
529 | * b2f0: | ||
530 | * @code: identifier of IUCV call to CP. | ||
531 | * @parm: pointer to 40 byte iparml area passed to CP | ||
532 | * | ||
533 | * Calls CP to execute IUCV commands. | ||
534 | * | ||
535 | * Returns: return code from CP's IUCV call | ||
536 | */ | ||
537 | static inline ulong b2f0(__u32 code, void *parm) | ||
538 | { | ||
539 | register unsigned long reg0 asm ("0"); | ||
540 | register unsigned long reg1 asm ("1"); | ||
541 | iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param)); | ||
542 | |||
543 | reg0 = code; | ||
544 | reg1 = virt_to_phys(parm); | ||
545 | asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1)); | ||
546 | |||
547 | iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param)); | ||
548 | |||
549 | return (unsigned long)*((__u8 *)(parm + 3)); | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * Name: iucv_add_pathid | ||
554 | * Purpose: Adds a path id to the system. | ||
555 | * Input: pathid - pathid that is going to be entered into system | ||
556 | * handle - address of handler that the pathid will be associated | ||
557 | * with. | ||
558 | * pgm_data - token passed in by application. | ||
559 | * Output: 0: successful addition of pathid | ||
560 | * - EINVAL - pathid entry is being used by another application | ||
561 | * - ENOMEM - storage allocation for a new pathid table failed | ||
562 | */ | ||
563 | static int | ||
564 | __iucv_add_pathid(__u16 pathid, handler *handler) | ||
565 | { | ||
566 | |||
567 | iucv_debug(1, "entering"); | ||
568 | |||
569 | iucv_debug(1, "handler is pointing to %p", handler); | ||
570 | |||
571 | if (pathid > (max_connections - 1)) | ||
572 | return -EINVAL; | ||
573 | |||
574 | if (iucv_pathid_table[pathid]) { | ||
575 | iucv_debug(1, "pathid entry is %p", iucv_pathid_table[pathid]); | ||
576 | printk(KERN_WARNING | ||
577 | "%s: Pathid being used, error.\n", __FUNCTION__); | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | iucv_pathid_table[pathid] = handler; | ||
581 | |||
582 | iucv_debug(1, "exiting"); | ||
583 | return 0; | ||
584 | } /* end of add_pathid function */ | ||
585 | |||
586 | static int | ||
587 | iucv_add_pathid(__u16 pathid, handler *handler) | ||
588 | { | ||
589 | ulong flags; | ||
590 | int rc; | ||
591 | |||
592 | spin_lock_irqsave (&iucv_lock, flags); | ||
593 | rc = __iucv_add_pathid(pathid, handler); | ||
594 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
595 | return rc; | ||
596 | } | ||
597 | |||
598 | static void | ||
599 | iucv_remove_pathid(__u16 pathid) | ||
600 | { | ||
601 | ulong flags; | ||
602 | |||
603 | if (pathid > (max_connections - 1)) | ||
604 | return; | ||
605 | |||
606 | spin_lock_irqsave (&iucv_lock, flags); | ||
607 | iucv_pathid_table[pathid] = NULL; | ||
608 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
609 | } | ||
610 | |||
611 | /** | ||
612 | * iucv_declare_buffer_cpuid | ||
613 | * Register at VM for subsequent IUCV operations. This is executed | ||
614 | * on the reserved CPU iucv_cpuid. Called from iucv_declare_buffer(). | ||
615 | */ | ||
616 | static void | ||
617 | iucv_declare_buffer_cpuid (void *result) | ||
618 | { | ||
619 | iparml_db *parm; | ||
620 | |||
621 | parm = (iparml_db *)grab_param(); | ||
622 | parm->ipbfadr1 = virt_to_phys(iucv_external_int_buffer); | ||
623 | if ((*((ulong *)result) = b2f0(DECLARE_BUFFER, parm)) == 1) | ||
624 | *((ulong *)result) = parm->iprcode; | ||
625 | release_param(parm); | ||
626 | } | ||
627 | |||
628 | /** | ||
629 | * iucv_retrieve_buffer_cpuid: | ||
630 | * Unregister IUCV usage at VM. This is always executed on the same | ||
631 | * cpu that registered the buffer to VM. | ||
632 | * Called from iucv_retrieve_buffer(). | ||
633 | */ | ||
634 | static void | ||
635 | iucv_retrieve_buffer_cpuid (void *cpu) | ||
636 | { | ||
637 | iparml_control *parm; | ||
638 | |||
639 | parm = (iparml_control *)grab_param(); | ||
640 | b2f0(RETRIEVE_BUFFER, parm); | ||
641 | release_param(parm); | ||
642 | } | ||
643 | |||
644 | /** | ||
645 | * Name: iucv_declare_buffer | ||
646 | * Purpose: Specifies the guests real address of an external | ||
647 | * interrupt. | ||
648 | * Input: void | ||
649 | * Output: iprcode - return code from b2f0 call | ||
650 | */ | ||
651 | static int | ||
652 | iucv_declare_buffer (void) | ||
653 | { | ||
654 | unsigned long flags; | ||
655 | ulong b2f0_result; | ||
656 | |||
657 | iucv_debug(1, "entering"); | ||
658 | b2f0_result = -ENODEV; | ||
659 | spin_lock_irqsave (&iucv_lock, flags); | ||
660 | if (iucv_cpuid == -1) { | ||
661 | /* Reserve any cpu for use by iucv. */ | ||
662 | iucv_cpuid = smp_get_cpu(CPU_MASK_ALL); | ||
663 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
664 | smp_call_function_on(iucv_declare_buffer_cpuid, | ||
665 | &b2f0_result, 0, 1, iucv_cpuid); | ||
666 | if (b2f0_result) { | ||
667 | smp_put_cpu(iucv_cpuid); | ||
668 | iucv_cpuid = -1; | ||
669 | } | ||
670 | iucv_debug(1, "Address of EIB = %p", iucv_external_int_buffer); | ||
671 | } else { | ||
672 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
673 | b2f0_result = 0; | ||
674 | } | ||
675 | iucv_debug(1, "exiting"); | ||
676 | return b2f0_result; | ||
677 | } | ||
678 | |||
679 | /** | ||
680 | * iucv_retrieve_buffer: | ||
681 | * | ||
682 | * Terminates all use of IUCV. | ||
683 | * Returns: return code from CP | ||
684 | */ | ||
685 | static int | ||
686 | iucv_retrieve_buffer (void) | ||
687 | { | ||
688 | iucv_debug(1, "entering"); | ||
689 | if (iucv_cpuid != -1) { | ||
690 | smp_call_function_on(iucv_retrieve_buffer_cpuid, | ||
691 | NULL, 0, 1, iucv_cpuid); | ||
692 | /* Release the cpu reserved by iucv_declare_buffer. */ | ||
693 | smp_put_cpu(iucv_cpuid); | ||
694 | iucv_cpuid = -1; | ||
695 | } | ||
696 | iucv_debug(1, "exiting"); | ||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | /** | ||
701 | * iucv_remove_handler: | ||
702 | * @users_handler: handler to be removed | ||
703 | * | ||
704 | * Remove handler when application unregisters. | ||
705 | */ | ||
706 | static void | ||
707 | iucv_remove_handler(handler *handler) | ||
708 | { | ||
709 | unsigned long flags; | ||
710 | |||
711 | if ((!iucv_pathid_table) || (!handler)) | ||
712 | return; | ||
713 | |||
714 | iucv_debug(1, "entering"); | ||
715 | |||
716 | spin_lock_irqsave (&iucv_lock, flags); | ||
717 | list_del(&handler->list); | ||
718 | if (list_empty(&iucv_handler_table)) { | ||
719 | if (register_flag) { | ||
720 | unregister_external_interrupt(0x4000, iucv_irq_handler); | ||
721 | register_flag = 0; | ||
722 | } | ||
723 | } | ||
724 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
725 | |||
726 | iucv_debug(1, "exiting"); | ||
727 | return; | ||
728 | } | ||
729 | |||
730 | /** | ||
731 | * iucv_register_program: | ||
732 | * @pgmname: user identification | ||
733 | * @userid: machine identification | ||
734 | * @pgmmask: Indicates which bits in the pgmname and userid combined will be | ||
735 | * used to determine who is given control. | ||
736 | * @ops: Address of interrupt handler table. | ||
737 | * @pgm_data: Application data to be passed to interrupt handlers. | ||
738 | * | ||
739 | * Registers an application with IUCV. | ||
740 | * Returns: | ||
741 | * The address of handler, or NULL on failure. | ||
742 | * NOTE on pgmmask: | ||
743 | * If pgmname, userid and pgmmask are provided, pgmmask is entered into the | ||
744 | * handler as is. | ||
745 | * If pgmmask is NULL, the internal mask is set to all 0xff's | ||
746 | * When userid is NULL, the first 8 bytes of the internal mask are forced | ||
747 | * to 0x00. | ||
748 | * If pgmmask and userid are NULL, the first 8 bytes of the internal mask | ||
749 | * are forced to 0x00 and the last 16 bytes to 0xff. | ||
750 | */ | ||
751 | |||
752 | iucv_handle_t | ||
753 | iucv_register_program (__u8 pgmname[16], | ||
754 | __u8 userid[8], | ||
755 | __u8 pgmmask[24], | ||
756 | iucv_interrupt_ops_t * ops, void *pgm_data) | ||
757 | { | ||
758 | ulong rc = 0; /* return code from function calls */ | ||
759 | handler *new_handler; | ||
760 | |||
761 | iucv_debug(1, "entering"); | ||
762 | |||
763 | if (ops == NULL) { | ||
764 | /* interrupt table is not defined */ | ||
765 | printk(KERN_WARNING "%s: Interrupt table is not defined, " | ||
766 | "exiting\n", __FUNCTION__); | ||
767 | return NULL; | ||
768 | } | ||
769 | if (!pgmname) { | ||
770 | printk(KERN_WARNING "%s: pgmname not provided\n", __FUNCTION__); | ||
771 | return NULL; | ||
772 | } | ||
773 | |||
774 | /* Allocate handler entry */ | ||
775 | new_handler = kmalloc(sizeof(handler), GFP_ATOMIC); | ||
776 | if (new_handler == NULL) { | ||
777 | printk(KERN_WARNING "%s: storage allocation for new handler " | ||
778 | "failed.\n", __FUNCTION__); | ||
779 | return NULL; | ||
780 | } | ||
781 | |||
782 | if (!iucv_pathid_table) { | ||
783 | if (iucv_init()) { | ||
784 | kfree(new_handler); | ||
785 | return NULL; | ||
786 | } | ||
787 | |||
788 | max_connections = iucv_query_maxconn(); | ||
789 | iucv_pathid_table = kcalloc(max_connections, sizeof(handler *), | ||
790 | GFP_ATOMIC); | ||
791 | if (iucv_pathid_table == NULL) { | ||
792 | printk(KERN_WARNING "%s: iucv_pathid_table storage " | ||
793 | "allocation failed\n", __FUNCTION__); | ||
794 | kfree(new_handler); | ||
795 | return NULL; | ||
796 | } | ||
797 | } | ||
798 | memset(new_handler, 0, sizeof (handler)); | ||
799 | memcpy(new_handler->id.user_data, pgmname, | ||
800 | sizeof (new_handler->id.user_data)); | ||
801 | if (userid) { | ||
802 | memcpy (new_handler->id.userid, userid, | ||
803 | sizeof (new_handler->id.userid)); | ||
804 | ASCEBC (new_handler->id.userid, | ||
805 | sizeof (new_handler->id.userid)); | ||
806 | EBC_TOUPPER (new_handler->id.userid, | ||
807 | sizeof (new_handler->id.userid)); | ||
808 | |||
809 | if (pgmmask) { | ||
810 | memcpy (new_handler->id.mask, pgmmask, | ||
811 | sizeof (new_handler->id.mask)); | ||
812 | } else { | ||
813 | memset (new_handler->id.mask, 0xFF, | ||
814 | sizeof (new_handler->id.mask)); | ||
815 | } | ||
816 | } else { | ||
817 | if (pgmmask) { | ||
818 | memcpy (new_handler->id.mask, pgmmask, | ||
819 | sizeof (new_handler->id.mask)); | ||
820 | } else { | ||
821 | memset (new_handler->id.mask, 0xFF, | ||
822 | sizeof (new_handler->id.mask)); | ||
823 | } | ||
824 | memset (new_handler->id.userid, 0x00, | ||
825 | sizeof (new_handler->id.userid)); | ||
826 | } | ||
827 | /* fill in the rest of handler */ | ||
828 | new_handler->pgm_data = pgm_data; | ||
829 | new_handler->interrupt_table = ops; | ||
830 | |||
831 | /* | ||
832 | * Check if someone else is registered with same pgmname, userid | ||
833 | * and mask. If someone is already registered with same pgmname, | ||
834 | * userid and mask, registration will fail and NULL will be returned | ||
835 | * to the application. | ||
836 | * If identical handler not found, then handler is added to list. | ||
837 | */ | ||
838 | rc = iucv_add_handler(new_handler); | ||
839 | if (rc) { | ||
840 | printk(KERN_WARNING "%s: Someone already registered with same " | ||
841 | "pgmname, userid, pgmmask\n", __FUNCTION__); | ||
842 | kfree (new_handler); | ||
843 | return NULL; | ||
844 | } | ||
845 | |||
846 | rc = iucv_declare_buffer(); | ||
847 | if (rc) { | ||
848 | char *err = "Unknown"; | ||
849 | iucv_remove_handler(new_handler); | ||
850 | kfree(new_handler); | ||
851 | switch(rc) { | ||
852 | case 0x03: | ||
853 | err = "Directory error"; | ||
854 | break; | ||
855 | case 0x0a: | ||
856 | err = "Invalid length"; | ||
857 | break; | ||
858 | case 0x13: | ||
859 | err = "Buffer already exists"; | ||
860 | break; | ||
861 | case 0x3e: | ||
862 | err = "Buffer overlap"; | ||
863 | break; | ||
864 | case 0x5c: | ||
865 | err = "Paging or storage error"; | ||
866 | break; | ||
867 | } | ||
868 | printk(KERN_WARNING "%s: iucv_declare_buffer " | ||
869 | "returned error 0x%02lx (%s)\n", __FUNCTION__, rc, err); | ||
870 | return NULL; | ||
871 | } | ||
872 | if (!register_flag) { | ||
873 | /* request the 0x4000 external interrupt */ | ||
874 | rc = register_external_interrupt (0x4000, iucv_irq_handler); | ||
875 | if (rc) { | ||
876 | iucv_remove_handler(new_handler); | ||
877 | kfree (new_handler); | ||
878 | printk(KERN_WARNING "%s: " | ||
879 | "register_external_interrupt returned %ld\n", | ||
880 | __FUNCTION__, rc); | ||
881 | return NULL; | ||
882 | |||
883 | } | ||
884 | register_flag = 1; | ||
885 | } | ||
886 | iucv_debug(1, "exiting"); | ||
887 | return new_handler; | ||
888 | } /* end of register function */ | ||
889 | |||
890 | /** | ||
891 | * iucv_unregister_program: | ||
892 | * @handle: address of handler | ||
893 | * | ||
894 | * Unregister application with IUCV. | ||
895 | * Returns: | ||
896 | * 0 on success, -EINVAL, if specified handle is invalid. | ||
897 | */ | ||
898 | |||
899 | int | ||
900 | iucv_unregister_program (iucv_handle_t handle) | ||
901 | { | ||
902 | handler *h = NULL; | ||
903 | struct list_head *lh; | ||
904 | int i; | ||
905 | ulong flags; | ||
906 | |||
907 | iucv_debug(1, "entering"); | ||
908 | iucv_debug(1, "address of handler is %p", h); | ||
909 | |||
910 | /* Checking if handle is valid */ | ||
911 | spin_lock_irqsave (&iucv_lock, flags); | ||
912 | list_for_each(lh, &iucv_handler_table) { | ||
913 | if ((handler *)handle == list_entry(lh, handler, list)) { | ||
914 | h = (handler *)handle; | ||
915 | break; | ||
916 | } | ||
917 | } | ||
918 | if (!h) { | ||
919 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
920 | if (handle) | ||
921 | printk(KERN_WARNING | ||
922 | "%s: Handler not found in iucv_handler_table.\n", | ||
923 | __FUNCTION__); | ||
924 | else | ||
925 | printk(KERN_WARNING | ||
926 | "%s: NULL handle passed by application.\n", | ||
927 | __FUNCTION__); | ||
928 | return -EINVAL; | ||
929 | } | ||
930 | |||
931 | /** | ||
932 | * First, walk thru iucv_pathid_table and sever any pathid which is | ||
933 | * still pointing to the handler to be removed. | ||
934 | */ | ||
935 | for (i = 0; i < max_connections; i++) | ||
936 | if (iucv_pathid_table[i] == h) { | ||
937 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
938 | iucv_sever(i, h->id.user_data); | ||
939 | spin_lock_irqsave(&iucv_lock, flags); | ||
940 | } | ||
941 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
942 | |||
943 | iucv_remove_handler(h); | ||
944 | kfree(h); | ||
945 | |||
946 | iucv_debug(1, "exiting"); | ||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | /** | ||
951 | * iucv_accept: | ||
952 | * @pathid: Path identification number | ||
953 | * @msglim_reqstd: The number of outstanding messages requested. | ||
954 | * @user_data: Data specified by the iucv_connect function. | ||
955 | * @flags1: Contains options for this path. | ||
956 | * - IPPRTY (0x20) Specifies if you want to send priority message. | ||
957 | * - IPRMDATA (0x80) Specifies whether your program can handle a message | ||
958 | * in the parameter list. | ||
959 | * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being | ||
960 | * established. | ||
961 | * @handle: Address of handler. | ||
962 | * @pgm_data: Application data passed to interrupt handlers. | ||
963 | * @flags1_out: Pointer to an int. If not NULL, on return the options for | ||
964 | * the path are stored at the given location: | ||
965 | * - IPPRTY (0x20) Indicates you may send a priority message. | ||
966 | * @msglim: Pointer to an __u16. If not NULL, on return the maximum | ||
967 | * number of outstanding messages is stored at the given | ||
968 | * location. | ||
969 | * | ||
970 | * This function is issued after the user receives a Connection Pending external | ||
971 | * interrupt and now wishes to complete the IUCV communication path. | ||
972 | * Returns: | ||
973 | * return code from CP | ||
974 | */ | ||
975 | int | ||
976 | iucv_accept(__u16 pathid, __u16 msglim_reqstd, | ||
977 | __u8 user_data[16], int flags1, | ||
978 | iucv_handle_t handle, void *pgm_data, | ||
979 | int *flags1_out, __u16 * msglim) | ||
980 | { | ||
981 | ulong b2f0_result = 0; | ||
982 | ulong flags; | ||
983 | struct list_head *lh; | ||
984 | handler *h = NULL; | ||
985 | iparml_control *parm; | ||
986 | |||
987 | iucv_debug(1, "entering"); | ||
988 | iucv_debug(1, "pathid = %d", pathid); | ||
989 | |||
990 | /* Checking if handle is valid */ | ||
991 | spin_lock_irqsave (&iucv_lock, flags); | ||
992 | list_for_each(lh, &iucv_handler_table) { | ||
993 | if ((handler *)handle == list_entry(lh, handler, list)) { | ||
994 | h = (handler *)handle; | ||
995 | break; | ||
996 | } | ||
997 | } | ||
998 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
999 | |||
1000 | if (!h) { | ||
1001 | if (handle) | ||
1002 | printk(KERN_WARNING | ||
1003 | "%s: Handler not found in iucv_handler_table.\n", | ||
1004 | __FUNCTION__); | ||
1005 | else | ||
1006 | printk(KERN_WARNING | ||
1007 | "%s: NULL handle passed by application.\n", | ||
1008 | __FUNCTION__); | ||
1009 | return -EINVAL; | ||
1010 | } | ||
1011 | |||
1012 | parm = (iparml_control *)grab_param(); | ||
1013 | |||
1014 | parm->ippathid = pathid; | ||
1015 | parm->ipmsglim = msglim_reqstd; | ||
1016 | if (user_data) | ||
1017 | memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); | ||
1018 | |||
1019 | parm->ipflags1 = (__u8)flags1; | ||
1020 | b2f0_result = b2f0(ACCEPT, parm); | ||
1021 | |||
1022 | if (!b2f0_result) { | ||
1023 | if (msglim) | ||
1024 | *msglim = parm->ipmsglim; | ||
1025 | if (pgm_data) | ||
1026 | h->pgm_data = pgm_data; | ||
1027 | if (flags1_out) | ||
1028 | *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; | ||
1029 | } | ||
1030 | release_param(parm); | ||
1031 | |||
1032 | iucv_debug(1, "exiting"); | ||
1033 | return b2f0_result; | ||
1034 | } | ||
1035 | |||
1036 | /** | ||
1037 | * iucv_connect: | ||
1038 | * @pathid: Path identification number | ||
1039 | * @msglim_reqstd: Number of outstanding messages requested | ||
1040 | * @user_data: 16-byte user data | ||
1041 | * @userid: 8-byte of user identification | ||
1042 | * @system_name: 8-byte identifying the system name | ||
1043 | * @flags1: Specifies options for this path: | ||
1044 | * - IPPRTY (0x20) Specifies if you want to send priority message. | ||
1045 | * - IPRMDATA (0x80) Specifies whether your program can handle a message | ||
1046 | * in the parameter list. | ||
1047 | * - IPQUSCE (0x40) Specifies whether you want to quiesce the path being | ||
1048 | * established. | ||
1049 | * - IPLOCAL (0x01) Allows an application to force the partner to be on the | ||
1050 | * local system. If local is specified then target class | ||
1051 | * cannot be specified. | ||
1052 | * @flags1_out: Pointer to an int. If not NULL, on return the options for | ||
1053 | * the path are stored at the given location: | ||
1054 | * - IPPRTY (0x20) Indicates you may send a priority message. | ||
1055 | * @msglim: Pointer to an __u16. If not NULL, on return the maximum | ||
1056 | * number of outstanding messages is stored at the given | ||
1057 | * location. | ||
1058 | * @handle: Address of handler. | ||
1059 | * @pgm_data: Application data to be passed to interrupt handlers. | ||
1060 | * | ||
1061 | * This function establishes an IUCV path. Although the connect may complete | ||
1062 | * successfully, you are not able to use the path until you receive an IUCV | ||
1063 | * Connection Complete external interrupt. | ||
1064 | * Returns: return code from CP, or one of the following | ||
1065 | * - ENOMEM | ||
1066 | * - return code from iucv_declare_buffer | ||
1067 | * - EINVAL - invalid handle passed by application | ||
1068 | * - EINVAL - pathid address is NULL | ||
1069 | * - ENOMEM - pathid table storage allocation failed | ||
1070 | * - return code from internal function add_pathid | ||
1071 | */ | ||
1072 | int | ||
1073 | iucv_connect (__u16 *pathid, __u16 msglim_reqstd, | ||
1074 | __u8 user_data[16], __u8 userid[8], | ||
1075 | __u8 system_name[8], int flags1, | ||
1076 | int *flags1_out, __u16 * msglim, | ||
1077 | iucv_handle_t handle, void *pgm_data) | ||
1078 | { | ||
1079 | iparml_control *parm; | ||
1080 | iparml_control local_parm; | ||
1081 | struct list_head *lh; | ||
1082 | ulong b2f0_result = 0; | ||
1083 | ulong flags; | ||
1084 | int add_pathid_result = 0; | ||
1085 | handler *h = NULL; | ||
1086 | __u8 no_memory[16] = "NO MEMORY"; | ||
1087 | |||
1088 | iucv_debug(1, "entering"); | ||
1089 | |||
1090 | /* Checking if handle is valid */ | ||
1091 | spin_lock_irqsave (&iucv_lock, flags); | ||
1092 | list_for_each(lh, &iucv_handler_table) { | ||
1093 | if ((handler *)handle == list_entry(lh, handler, list)) { | ||
1094 | h = (handler *)handle; | ||
1095 | break; | ||
1096 | } | ||
1097 | } | ||
1098 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
1099 | |||
1100 | if (!h) { | ||
1101 | if (handle) | ||
1102 | printk(KERN_WARNING | ||
1103 | "%s: Handler not found in iucv_handler_table.\n", | ||
1104 | __FUNCTION__); | ||
1105 | else | ||
1106 | printk(KERN_WARNING | ||
1107 | "%s: NULL handle passed by application.\n", | ||
1108 | __FUNCTION__); | ||
1109 | return -EINVAL; | ||
1110 | } | ||
1111 | |||
1112 | if (pathid == NULL) { | ||
1113 | printk(KERN_WARNING "%s: NULL pathid pointer\n", | ||
1114 | __FUNCTION__); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | parm = (iparml_control *)grab_param(); | ||
1119 | |||
1120 | parm->ipmsglim = msglim_reqstd; | ||
1121 | |||
1122 | if (user_data) | ||
1123 | memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); | ||
1124 | |||
1125 | if (userid) { | ||
1126 | memcpy(parm->ipvmid, userid, sizeof(parm->ipvmid)); | ||
1127 | ASCEBC(parm->ipvmid, sizeof(parm->ipvmid)); | ||
1128 | EBC_TOUPPER(parm->ipvmid, sizeof(parm->ipvmid)); | ||
1129 | } | ||
1130 | |||
1131 | if (system_name) { | ||
1132 | memcpy(parm->iptarget, system_name, sizeof(parm->iptarget)); | ||
1133 | ASCEBC(parm->iptarget, sizeof(parm->iptarget)); | ||
1134 | EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget)); | ||
1135 | } | ||
1136 | |||
1137 | /* In order to establish an IUCV connection, the procedure is: | ||
1138 | * | ||
1139 | * b2f0(CONNECT) | ||
1140 | * take the ippathid from the b2f0 call | ||
1141 | * register the handler to the ippathid | ||
1142 | * | ||
1143 | * Unfortunately, the ConnectionEstablished message gets sent after the | ||
1144 | * b2f0(CONNECT) call but before the register is handled. | ||
1145 | * | ||
1146 | * In order for this race condition to be eliminated, the IUCV Control | ||
1147 | * Interrupts must be disabled for the above procedure. | ||
1148 | * | ||
1149 | * David Kennedy <dkennedy@linuxcare.com> | ||
1150 | */ | ||
1151 | |||
1152 | /* Enable everything but IUCV Control messages */ | ||
1153 | iucv_setmask(~(AllInterrupts)); | ||
1154 | messagesDisabled = 1; | ||
1155 | |||
1156 | spin_lock_irqsave (&iucv_lock, flags); | ||
1157 | parm->ipflags1 = (__u8)flags1; | ||
1158 | b2f0_result = b2f0(CONNECT, parm); | ||
1159 | memcpy(&local_parm, parm, sizeof(local_parm)); | ||
1160 | release_param(parm); | ||
1161 | parm = &local_parm; | ||
1162 | if (!b2f0_result) | ||
1163 | add_pathid_result = __iucv_add_pathid(parm->ippathid, h); | ||
1164 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
1165 | |||
1166 | if (b2f0_result) { | ||
1167 | iucv_setmask(~0); | ||
1168 | messagesDisabled = 0; | ||
1169 | return b2f0_result; | ||
1170 | } | ||
1171 | |||
1172 | *pathid = parm->ippathid; | ||
1173 | |||
1174 | /* Enable everything again */ | ||
1175 | iucv_setmask(IUCVControlInterruptsFlag); | ||
1176 | |||
1177 | if (msglim) | ||
1178 | *msglim = parm->ipmsglim; | ||
1179 | if (flags1_out) | ||
1180 | *flags1_out = (parm->ipflags1 & IPPRTY) ? IPPRTY : 0; | ||
1181 | |||
1182 | if (add_pathid_result) { | ||
1183 | iucv_sever(*pathid, no_memory); | ||
1184 | printk(KERN_WARNING "%s: add_pathid failed with rc =" | ||
1185 | " %d\n", __FUNCTION__, add_pathid_result); | ||
1186 | return(add_pathid_result); | ||
1187 | } | ||
1188 | |||
1189 | iucv_debug(1, "exiting"); | ||
1190 | return b2f0_result; | ||
1191 | } | ||
1192 | |||
1193 | /** | ||
1194 | * iucv_purge: | ||
1195 | * @pathid: Path identification number | ||
1196 | * @msgid: Message ID of message to purge. | ||
1197 | * @srccls: Message class of the message to purge. | ||
1198 | * @audit: Pointer to an __u32. If not NULL, on return, information about | ||
1199 | * asynchronous errors that may have affected the normal completion | ||
1200 | * of this message ist stored at the given location. | ||
1201 | * | ||
1202 | * Cancels a message you have sent. | ||
1203 | * Returns: return code from CP | ||
1204 | */ | ||
1205 | int | ||
1206 | iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit) | ||
1207 | { | ||
1208 | iparml_purge *parm; | ||
1209 | ulong b2f0_result = 0; | ||
1210 | |||
1211 | iucv_debug(1, "entering"); | ||
1212 | iucv_debug(1, "pathid = %d", pathid); | ||
1213 | |||
1214 | parm = (iparml_purge *)grab_param(); | ||
1215 | |||
1216 | parm->ipmsgid = msgid; | ||
1217 | parm->ippathid = pathid; | ||
1218 | parm->ipsrccls = srccls; | ||
1219 | parm->ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID); | ||
1220 | b2f0_result = b2f0(PURGE, parm); | ||
1221 | |||
1222 | if (!b2f0_result && audit) { | ||
1223 | memcpy(audit, parm->ipaudit, sizeof(parm->ipaudit)); | ||
1224 | /* parm->ipaudit has only 3 bytes */ | ||
1225 | *audit >>= 8; | ||
1226 | } | ||
1227 | |||
1228 | release_param(parm); | ||
1229 | |||
1230 | iucv_debug(1, "b2f0_result = %ld", b2f0_result); | ||
1231 | iucv_debug(1, "exiting"); | ||
1232 | return b2f0_result; | ||
1233 | } | ||
1234 | |||
1235 | /** | ||
1236 | * iucv_query_generic: | ||
1237 | * @want_maxconn: Flag, describing which value is to be returned. | ||
1238 | * | ||
1239 | * Helper function for iucv_query_maxconn() and iucv_query_bufsize(). | ||
1240 | * | ||
1241 | * Returns: The buffersize, if want_maxconn is 0; the maximum number of | ||
1242 | * connections, if want_maxconn is 1 or an error-code < 0 on failure. | ||
1243 | */ | ||
1244 | static int | ||
1245 | iucv_query_generic(int want_maxconn) | ||
1246 | { | ||
1247 | register unsigned long reg0 asm ("0"); | ||
1248 | register unsigned long reg1 asm ("1"); | ||
1249 | iparml_purge *parm = (iparml_purge *)grab_param(); | ||
1250 | int bufsize, maxconn; | ||
1251 | int ccode; | ||
1252 | |||
1253 | /** | ||
1254 | * Call b2f0 and store R0 (max buffer size), | ||
1255 | * R1 (max connections) and CC. | ||
1256 | */ | ||
1257 | reg0 = QUERY; | ||
1258 | reg1 = virt_to_phys(parm); | ||
1259 | asm volatile( | ||
1260 | " .long 0xb2f01000\n" | ||
1261 | " ipm %0\n" | ||
1262 | " srl %0,28\n" | ||
1263 | : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc"); | ||
1264 | bufsize = reg0; | ||
1265 | maxconn = reg1; | ||
1266 | release_param(parm); | ||
1267 | |||
1268 | if (ccode) | ||
1269 | return -EPERM; | ||
1270 | if (want_maxconn) | ||
1271 | return maxconn; | ||
1272 | return bufsize; | ||
1273 | } | ||
1274 | |||
1275 | /** | ||
1276 | * iucv_query_maxconn: | ||
1277 | * | ||
1278 | * Determines the maximum number of connections thay may be established. | ||
1279 | * | ||
1280 | * Returns: Maximum number of connections that can be. | ||
1281 | */ | ||
1282 | ulong | ||
1283 | iucv_query_maxconn(void) | ||
1284 | { | ||
1285 | return iucv_query_generic(1); | ||
1286 | } | ||
1287 | |||
1288 | /** | ||
1289 | * iucv_query_bufsize: | ||
1290 | * | ||
1291 | * Determines the size of the external interrupt buffer. | ||
1292 | * | ||
1293 | * Returns: Size of external interrupt buffer. | ||
1294 | */ | ||
1295 | ulong | ||
1296 | iucv_query_bufsize (void) | ||
1297 | { | ||
1298 | return iucv_query_generic(0); | ||
1299 | } | ||
1300 | |||
1301 | /** | ||
1302 | * iucv_quiesce: | ||
1303 | * @pathid: Path identification number | ||
1304 | * @user_data: 16-byte user data | ||
1305 | * | ||
1306 | * Temporarily suspends incoming messages on an IUCV path. | ||
1307 | * You can later reactivate the path by invoking the iucv_resume function. | ||
1308 | * Returns: return code from CP | ||
1309 | */ | ||
1310 | int | ||
1311 | iucv_quiesce (__u16 pathid, __u8 user_data[16]) | ||
1312 | { | ||
1313 | iparml_control *parm; | ||
1314 | ulong b2f0_result = 0; | ||
1315 | |||
1316 | iucv_debug(1, "entering"); | ||
1317 | iucv_debug(1, "pathid = %d", pathid); | ||
1318 | |||
1319 | parm = (iparml_control *)grab_param(); | ||
1320 | |||
1321 | memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); | ||
1322 | parm->ippathid = pathid; | ||
1323 | |||
1324 | b2f0_result = b2f0(QUIESCE, parm); | ||
1325 | release_param(parm); | ||
1326 | |||
1327 | iucv_debug(1, "b2f0_result = %ld", b2f0_result); | ||
1328 | iucv_debug(1, "exiting"); | ||
1329 | |||
1330 | return b2f0_result; | ||
1331 | } | ||
1332 | |||
1333 | /** | ||
1334 | * iucv_receive: | ||
1335 | * @pathid: Path identification number. | ||
1336 | * @buffer: Address of buffer to receive. Must be below 2G. | ||
1337 | * @buflen: Length of buffer to receive. | ||
1338 | * @msgid: Specifies the message ID. | ||
1339 | * @trgcls: Specifies target class. | ||
1340 | * @flags1_out: Receives options for path on return. | ||
1341 | * - IPNORPY (0x10) Specifies whether a reply is required | ||
1342 | * - IPPRTY (0x20) Specifies if you want to send priority message | ||
1343 | * - IPRMDATA (0x80) Specifies the data is contained in the parameter list | ||
1344 | * @residual_buffer: Receives the address of buffer updated by the number | ||
1345 | * of bytes you have received on return. | ||
1346 | * @residual_length: On return, receives one of the following values: | ||
1347 | * - 0 If the receive buffer is the same length as | ||
1348 | * the message. | ||
1349 | * - Remaining bytes in buffer If the receive buffer is longer than the | ||
1350 | * message. | ||
1351 | * - Remaining bytes in message If the receive buffer is shorter than the | ||
1352 | * message. | ||
1353 | * | ||
1354 | * This function receives messages that are being sent to you over established | ||
1355 | * paths. | ||
1356 | * Returns: return code from CP IUCV call; If the receive buffer is shorter | ||
1357 | * than the message, always 5 | ||
1358 | * -EINVAL - buffer address is pointing to NULL | ||
1359 | */ | ||
1360 | int | ||
1361 | iucv_receive (__u16 pathid, __u32 msgid, __u32 trgcls, | ||
1362 | void *buffer, ulong buflen, | ||
1363 | int *flags1_out, ulong * residual_buffer, ulong * residual_length) | ||
1364 | { | ||
1365 | iparml_db *parm; | ||
1366 | ulong b2f0_result; | ||
1367 | int moved = 0; /* number of bytes moved from parmlist to buffer */ | ||
1368 | |||
1369 | iucv_debug(2, "entering"); | ||
1370 | |||
1371 | if (!buffer) | ||
1372 | return -EINVAL; | ||
1373 | |||
1374 | parm = (iparml_db *)grab_param(); | ||
1375 | |||
1376 | parm->ipbfadr1 = (__u32) (addr_t) buffer; | ||
1377 | parm->ipbfln1f = (__u32) ((ulong) buflen); | ||
1378 | parm->ipmsgid = msgid; | ||
1379 | parm->ippathid = pathid; | ||
1380 | parm->iptrgcls = trgcls; | ||
1381 | parm->ipflags1 = (IPFGPID | IPFGMID | IPFGMCL); | ||
1382 | |||
1383 | b2f0_result = b2f0(RECEIVE, parm); | ||
1384 | |||
1385 | if (!b2f0_result || b2f0_result == 5) { | ||
1386 | if (flags1_out) { | ||
1387 | iucv_debug(2, "*flags1_out = %d", *flags1_out); | ||
1388 | *flags1_out = (parm->ipflags1 & (~0x07)); | ||
1389 | iucv_debug(2, "*flags1_out = %d", *flags1_out); | ||
1390 | } | ||
1391 | |||
1392 | if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ | ||
1393 | if (residual_length) | ||
1394 | *residual_length = parm->ipbfln1f; | ||
1395 | |||
1396 | if (residual_buffer) | ||
1397 | *residual_buffer = parm->ipbfadr1; | ||
1398 | } else { | ||
1399 | moved = min_t (unsigned long, buflen, 8); | ||
1400 | |||
1401 | memcpy ((char *) buffer, | ||
1402 | (char *) &parm->ipbfadr1, moved); | ||
1403 | |||
1404 | if (buflen < 8) | ||
1405 | b2f0_result = 5; | ||
1406 | |||
1407 | if (residual_length) | ||
1408 | *residual_length = abs (buflen - 8); | ||
1409 | |||
1410 | if (residual_buffer) | ||
1411 | *residual_buffer = (ulong) (buffer + moved); | ||
1412 | } | ||
1413 | } | ||
1414 | release_param(parm); | ||
1415 | |||
1416 | iucv_debug(2, "exiting"); | ||
1417 | return b2f0_result; | ||
1418 | } | ||
1419 | |||
1420 | /* | ||
1421 | * Name: iucv_receive_array | ||
1422 | * Purpose: This function receives messages that are being sent to you | ||
1423 | * over established paths. | ||
1424 | * Input: pathid - path identification number | ||
1425 | * buffer - address of array of buffers | ||
1426 | * buflen - total length of buffers | ||
1427 | * msgid - specifies the message ID. | ||
1428 | * trgcls - specifies target class | ||
1429 | * Output: | ||
1430 | * flags1_out: Options for path. | ||
1431 | * IPNORPY - 0x10 specifies whether a reply is required | ||
1432 | * IPPRTY - 0x20 specifies if you want to send priority message | ||
1433 | * IPRMDATA - 0x80 specifies the data is contained in the parameter list | ||
1434 | * residual_buffer - address points to the current list entry IUCV | ||
1435 | * is working on. | ||
1436 | * residual_length - | ||
1437 | * Contains one of the following values, if the receive buffer is: | ||
1438 | * The same length as the message, this field is zero. | ||
1439 | * Longer than the message, this field contains the number of | ||
1440 | * bytes remaining in the buffer. | ||
1441 | * Shorter than the message, this field contains the residual | ||
1442 | * count (that is, the number of bytes remaining in the | ||
1443 | * message that does not fit into the buffer. In this case | ||
1444 | * b2f0_result = 5. | ||
1445 | * Return: b2f0_result - return code from CP | ||
1446 | * (-EINVAL) - buffer address is NULL | ||
1447 | */ | ||
1448 | int | ||
1449 | iucv_receive_array (__u16 pathid, | ||
1450 | __u32 msgid, __u32 trgcls, | ||
1451 | iucv_array_t * buffer, ulong buflen, | ||
1452 | int *flags1_out, | ||
1453 | ulong * residual_buffer, ulong * residual_length) | ||
1454 | { | ||
1455 | iparml_db *parm; | ||
1456 | ulong b2f0_result; | ||
1457 | int i = 0, moved = 0, need_to_move = 8, dyn_len; | ||
1458 | |||
1459 | iucv_debug(2, "entering"); | ||
1460 | |||
1461 | if (!buffer) | ||
1462 | return -EINVAL; | ||
1463 | |||
1464 | parm = (iparml_db *)grab_param(); | ||
1465 | |||
1466 | parm->ipbfadr1 = (__u32) ((ulong) buffer); | ||
1467 | parm->ipbfln1f = (__u32) buflen; | ||
1468 | parm->ipmsgid = msgid; | ||
1469 | parm->ippathid = pathid; | ||
1470 | parm->iptrgcls = trgcls; | ||
1471 | parm->ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL); | ||
1472 | |||
1473 | b2f0_result = b2f0(RECEIVE, parm); | ||
1474 | |||
1475 | if (!b2f0_result || b2f0_result == 5) { | ||
1476 | |||
1477 | if (flags1_out) { | ||
1478 | iucv_debug(2, "*flags1_out = %d", *flags1_out); | ||
1479 | *flags1_out = (parm->ipflags1 & (~0x07)); | ||
1480 | iucv_debug(2, "*flags1_out = %d", *flags1_out); | ||
1481 | } | ||
1482 | |||
1483 | if (!(parm->ipflags1 & IPRMDATA)) { /*msg not in parmlist */ | ||
1484 | |||
1485 | if (residual_length) | ||
1486 | *residual_length = parm->ipbfln1f; | ||
1487 | |||
1488 | if (residual_buffer) | ||
1489 | *residual_buffer = parm->ipbfadr1; | ||
1490 | |||
1491 | } else { | ||
1492 | /* copy msg from parmlist to users array. */ | ||
1493 | |||
1494 | while ((moved < 8) && (moved < buflen)) { | ||
1495 | dyn_len = | ||
1496 | min_t (unsigned int, | ||
1497 | (buffer + i)->length, need_to_move); | ||
1498 | |||
1499 | memcpy ((char *)((ulong)((buffer + i)->address)), | ||
1500 | ((char *) &parm->ipbfadr1) + moved, | ||
1501 | dyn_len); | ||
1502 | |||
1503 | moved += dyn_len; | ||
1504 | need_to_move -= dyn_len; | ||
1505 | |||
1506 | (buffer + i)->address = | ||
1507 | (__u32) | ||
1508 | ((ulong)(__u8 *) ((ulong)(buffer + i)->address) | ||
1509 | + dyn_len); | ||
1510 | |||
1511 | (buffer + i)->length -= dyn_len; | ||
1512 | i++; | ||
1513 | } | ||
1514 | |||
1515 | if (need_to_move) /* buflen < 8 bytes */ | ||
1516 | b2f0_result = 5; | ||
1517 | |||
1518 | if (residual_length) | ||
1519 | *residual_length = abs (buflen - 8); | ||
1520 | |||
1521 | if (residual_buffer) { | ||
1522 | if (!moved) | ||
1523 | *residual_buffer = (ulong) buffer; | ||
1524 | else | ||
1525 | *residual_buffer = | ||
1526 | (ulong) (buffer + (i - 1)); | ||
1527 | } | ||
1528 | |||
1529 | } | ||
1530 | } | ||
1531 | release_param(parm); | ||
1532 | |||
1533 | iucv_debug(2, "exiting"); | ||
1534 | return b2f0_result; | ||
1535 | } | ||
1536 | |||
1537 | /** | ||
1538 | * iucv_reject: | ||
1539 | * @pathid: Path identification number. | ||
1540 | * @msgid: Message ID of the message to reject. | ||
1541 | * @trgcls: Target class of the message to reject. | ||
1542 | * Returns: return code from CP | ||
1543 | * | ||
1544 | * Refuses a specified message. Between the time you are notified of a | ||
1545 | * message and the time that you complete the message, the message may | ||
1546 | * be rejected. | ||
1547 | */ | ||
1548 | int | ||
1549 | iucv_reject (__u16 pathid, __u32 msgid, __u32 trgcls) | ||
1550 | { | ||
1551 | iparml_db *parm; | ||
1552 | ulong b2f0_result = 0; | ||
1553 | |||
1554 | iucv_debug(1, "entering"); | ||
1555 | iucv_debug(1, "pathid = %d", pathid); | ||
1556 | |||
1557 | parm = (iparml_db *)grab_param(); | ||
1558 | |||
1559 | parm->ippathid = pathid; | ||
1560 | parm->ipmsgid = msgid; | ||
1561 | parm->iptrgcls = trgcls; | ||
1562 | parm->ipflags1 = (IPFGMCL | IPFGMID | IPFGPID); | ||
1563 | |||
1564 | b2f0_result = b2f0(REJECT, parm); | ||
1565 | release_param(parm); | ||
1566 | |||
1567 | iucv_debug(1, "b2f0_result = %ld", b2f0_result); | ||
1568 | iucv_debug(1, "exiting"); | ||
1569 | |||
1570 | return b2f0_result; | ||
1571 | } | ||
1572 | |||
1573 | /* | ||
1574 | * Name: iucv_reply | ||
1575 | * Purpose: This function responds to the two-way messages that you | ||
1576 | * receive. You must identify completely the message to | ||
1577 | * which you wish to reply. ie, pathid, msgid, and trgcls. | ||
1578 | * Input: pathid - path identification number | ||
1579 | * msgid - specifies the message ID. | ||
1580 | * trgcls - specifies target class | ||
1581 | * flags1 - option for path | ||
1582 | * IPPRTY- 0x20 - specifies if you want to send priority message | ||
1583 | * buffer - address of reply buffer | ||
1584 | * buflen - length of reply buffer | ||
1585 | * Output: ipbfadr2 - Address of buffer updated by the number | ||
1586 | * of bytes you have moved. | ||
1587 | * ipbfln2f - Contains one of the following values: | ||
1588 | * If the answer buffer is the same length as the reply, this field | ||
1589 | * contains zero. | ||
1590 | * If the answer buffer is longer than the reply, this field contains | ||
1591 | * the number of bytes remaining in the buffer. | ||
1592 | * If the answer buffer is shorter than the reply, this field contains | ||
1593 | * a residual count (that is, the number of bytes remianing in the | ||
1594 | * reply that does not fit into the buffer. In this | ||
1595 | * case b2f0_result = 5. | ||
1596 | * Return: b2f0_result - return code from CP | ||
1597 | * (-EINVAL) - buffer address is NULL | ||
1598 | */ | ||
1599 | int | ||
1600 | iucv_reply (__u16 pathid, | ||
1601 | __u32 msgid, __u32 trgcls, | ||
1602 | int flags1, | ||
1603 | void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) | ||
1604 | { | ||
1605 | iparml_db *parm; | ||
1606 | ulong b2f0_result; | ||
1607 | |||
1608 | iucv_debug(2, "entering"); | ||
1609 | |||
1610 | if (!buffer) | ||
1611 | return -EINVAL; | ||
1612 | |||
1613 | parm = (iparml_db *)grab_param(); | ||
1614 | |||
1615 | parm->ipbfadr2 = (__u32) ((ulong) buffer); | ||
1616 | parm->ipbfln2f = (__u32) buflen; /* length of message */ | ||
1617 | parm->ippathid = pathid; | ||
1618 | parm->ipmsgid = msgid; | ||
1619 | parm->iptrgcls = trgcls; | ||
1620 | parm->ipflags1 = (__u8) flags1; /* priority message */ | ||
1621 | |||
1622 | b2f0_result = b2f0(REPLY, parm); | ||
1623 | |||
1624 | if ((!b2f0_result) || (b2f0_result == 5)) { | ||
1625 | if (ipbfadr2) | ||
1626 | *ipbfadr2 = parm->ipbfadr2; | ||
1627 | if (ipbfln2f) | ||
1628 | *ipbfln2f = parm->ipbfln2f; | ||
1629 | } | ||
1630 | release_param(parm); | ||
1631 | |||
1632 | iucv_debug(2, "exiting"); | ||
1633 | |||
1634 | return b2f0_result; | ||
1635 | } | ||
1636 | |||
1637 | /* | ||
1638 | * Name: iucv_reply_array | ||
1639 | * Purpose: This function responds to the two-way messages that you | ||
1640 | * receive. You must identify completely the message to | ||
1641 | * which you wish to reply. ie, pathid, msgid, and trgcls. | ||
1642 | * The array identifies a list of addresses and lengths of | ||
1643 | * discontiguous buffers that contains the reply data. | ||
1644 | * Input: pathid - path identification number | ||
1645 | * msgid - specifies the message ID. | ||
1646 | * trgcls - specifies target class | ||
1647 | * flags1 - option for path | ||
1648 | * IPPRTY- specifies if you want to send priority message | ||
1649 | * buffer - address of array of reply buffers | ||
1650 | * buflen - total length of reply buffers | ||
1651 | * Output: ipbfadr2 - Address of buffer which IUCV is currently working on. | ||
1652 | * ipbfln2f - Contains one of the following values: | ||
1653 | * If the answer buffer is the same length as the reply, this field | ||
1654 | * contains zero. | ||
1655 | * If the answer buffer is longer than the reply, this field contains | ||
1656 | * the number of bytes remaining in the buffer. | ||
1657 | * If the answer buffer is shorter than the reply, this field contains | ||
1658 | * a residual count (that is, the number of bytes remianing in the | ||
1659 | * reply that does not fit into the buffer. In this | ||
1660 | * case b2f0_result = 5. | ||
1661 | * Return: b2f0_result - return code from CP | ||
1662 | * (-EINVAL) - buffer address is NULL | ||
1663 | */ | ||
1664 | int | ||
1665 | iucv_reply_array (__u16 pathid, | ||
1666 | __u32 msgid, __u32 trgcls, | ||
1667 | int flags1, | ||
1668 | iucv_array_t * buffer, | ||
1669 | ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f) | ||
1670 | { | ||
1671 | iparml_db *parm; | ||
1672 | ulong b2f0_result; | ||
1673 | |||
1674 | iucv_debug(2, "entering"); | ||
1675 | |||
1676 | if (!buffer) | ||
1677 | return -EINVAL; | ||
1678 | |||
1679 | parm = (iparml_db *)grab_param(); | ||
1680 | |||
1681 | parm->ipbfadr2 = (__u32) ((ulong) buffer); | ||
1682 | parm->ipbfln2f = buflen; /* length of message */ | ||
1683 | parm->ippathid = pathid; | ||
1684 | parm->ipmsgid = msgid; | ||
1685 | parm->iptrgcls = trgcls; | ||
1686 | parm->ipflags1 = (IPANSLST | flags1); | ||
1687 | |||
1688 | b2f0_result = b2f0(REPLY, parm); | ||
1689 | |||
1690 | if ((!b2f0_result) || (b2f0_result == 5)) { | ||
1691 | |||
1692 | if (ipbfadr2) | ||
1693 | *ipbfadr2 = parm->ipbfadr2; | ||
1694 | if (ipbfln2f) | ||
1695 | *ipbfln2f = parm->ipbfln2f; | ||
1696 | } | ||
1697 | release_param(parm); | ||
1698 | |||
1699 | iucv_debug(2, "exiting"); | ||
1700 | |||
1701 | return b2f0_result; | ||
1702 | } | ||
1703 | |||
1704 | /* | ||
1705 | * Name: iucv_reply_prmmsg | ||
1706 | * Purpose: This function responds to the two-way messages that you | ||
1707 | * receive. You must identify completely the message to | ||
1708 | * which you wish to reply. ie, pathid, msgid, and trgcls. | ||
1709 | * Prmmsg signifies the data is moved into the | ||
1710 | * parameter list. | ||
1711 | * Input: pathid - path identification number | ||
1712 | * msgid - specifies the message ID. | ||
1713 | * trgcls - specifies target class | ||
1714 | * flags1 - option for path | ||
1715 | * IPPRTY- specifies if you want to send priority message | ||
1716 | * prmmsg - 8-bytes of data to be placed into the parameter | ||
1717 | * list. | ||
1718 | * Output: NA | ||
1719 | * Return: b2f0_result - return code from CP | ||
1720 | */ | ||
1721 | int | ||
1722 | iucv_reply_prmmsg (__u16 pathid, | ||
1723 | __u32 msgid, __u32 trgcls, int flags1, __u8 prmmsg[8]) | ||
1724 | { | ||
1725 | iparml_dpl *parm; | ||
1726 | ulong b2f0_result; | ||
1727 | |||
1728 | iucv_debug(2, "entering"); | ||
1729 | |||
1730 | parm = (iparml_dpl *)grab_param(); | ||
1731 | |||
1732 | parm->ippathid = pathid; | ||
1733 | parm->ipmsgid = msgid; | ||
1734 | parm->iptrgcls = trgcls; | ||
1735 | memcpy(parm->iprmmsg, prmmsg, sizeof (parm->iprmmsg)); | ||
1736 | parm->ipflags1 = (IPRMDATA | flags1); | ||
1737 | |||
1738 | b2f0_result = b2f0(REPLY, parm); | ||
1739 | release_param(parm); | ||
1740 | |||
1741 | iucv_debug(2, "exiting"); | ||
1742 | |||
1743 | return b2f0_result; | ||
1744 | } | ||
1745 | |||
1746 | /** | ||
1747 | * iucv_resume: | ||
1748 | * @pathid: Path identification number | ||
1749 | * @user_data: 16-byte of user data | ||
1750 | * | ||
1751 | * This function restores communication over a quiesced path. | ||
1752 | * Returns: return code from CP | ||
1753 | */ | ||
1754 | int | ||
1755 | iucv_resume (__u16 pathid, __u8 user_data[16]) | ||
1756 | { | ||
1757 | iparml_control *parm; | ||
1758 | ulong b2f0_result = 0; | ||
1759 | |||
1760 | iucv_debug(1, "entering"); | ||
1761 | iucv_debug(1, "pathid = %d", pathid); | ||
1762 | |||
1763 | parm = (iparml_control *)grab_param(); | ||
1764 | |||
1765 | memcpy (parm->ipuser, user_data, sizeof (*user_data)); | ||
1766 | parm->ippathid = pathid; | ||
1767 | |||
1768 | b2f0_result = b2f0(RESUME, parm); | ||
1769 | release_param(parm); | ||
1770 | |||
1771 | iucv_debug(1, "exiting"); | ||
1772 | |||
1773 | return b2f0_result; | ||
1774 | } | ||
1775 | |||
1776 | /* | ||
1777 | * Name: iucv_send | ||
1778 | * Purpose: sends messages | ||
1779 | * Input: pathid - ushort, pathid | ||
1780 | * msgid - ulong *, id of message returned to caller | ||
1781 | * trgcls - ulong, target message class | ||
1782 | * srccls - ulong, source message class | ||
1783 | * msgtag - ulong, message tag | ||
1784 | * flags1 - Contains options for this path. | ||
1785 | * IPPRTY - Ox20 - specifies if you want to send a priority message. | ||
1786 | * buffer - pointer to buffer | ||
1787 | * buflen - ulong, length of buffer | ||
1788 | * Output: b2f0_result - return code from b2f0 call | ||
1789 | * msgid - returns message id | ||
1790 | */ | ||
1791 | int | ||
1792 | iucv_send (__u16 pathid, __u32 * msgid, | ||
1793 | __u32 trgcls, __u32 srccls, | ||
1794 | __u32 msgtag, int flags1, void *buffer, ulong buflen) | ||
1795 | { | ||
1796 | iparml_db *parm; | ||
1797 | ulong b2f0_result; | ||
1798 | |||
1799 | iucv_debug(2, "entering"); | ||
1800 | |||
1801 | if (!buffer) | ||
1802 | return -EINVAL; | ||
1803 | |||
1804 | parm = (iparml_db *)grab_param(); | ||
1805 | |||
1806 | parm->ipbfadr1 = (__u32) ((ulong) buffer); | ||
1807 | parm->ippathid = pathid; | ||
1808 | parm->iptrgcls = trgcls; | ||
1809 | parm->ipbfln1f = (__u32) buflen; /* length of message */ | ||
1810 | parm->ipsrccls = srccls; | ||
1811 | parm->ipmsgtag = msgtag; | ||
1812 | parm->ipflags1 = (IPNORPY | flags1); /* one way priority message */ | ||
1813 | |||
1814 | b2f0_result = b2f0(SEND, parm); | ||
1815 | |||
1816 | if ((!b2f0_result) && (msgid)) | ||
1817 | *msgid = parm->ipmsgid; | ||
1818 | release_param(parm); | ||
1819 | |||
1820 | iucv_debug(2, "exiting"); | ||
1821 | |||
1822 | return b2f0_result; | ||
1823 | } | ||
1824 | |||
1825 | /* | ||
1826 | * Name: iucv_send_array | ||
1827 | * Purpose: This function transmits data to another application. | ||
1828 | * The contents of buffer is the address of the array of | ||
1829 | * addresses and lengths of discontiguous buffers that hold | ||
1830 | * the message text. This is a one-way message and the | ||
1831 | * receiver will not reply to the message. | ||
1832 | * Input: pathid - path identification number | ||
1833 | * trgcls - specifies target class | ||
1834 | * srccls - specifies the source message class | ||
1835 | * msgtag - specifies a tag to be associated witht the message | ||
1836 | * flags1 - option for path | ||
1837 | * IPPRTY- specifies if you want to send priority message | ||
1838 | * buffer - address of array of send buffers | ||
1839 | * buflen - total length of send buffers | ||
1840 | * Output: msgid - specifies the message ID. | ||
1841 | * Return: b2f0_result - return code from CP | ||
1842 | * (-EINVAL) - buffer address is NULL | ||
1843 | */ | ||
1844 | int | ||
1845 | iucv_send_array (__u16 pathid, | ||
1846 | __u32 * msgid, | ||
1847 | __u32 trgcls, | ||
1848 | __u32 srccls, | ||
1849 | __u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen) | ||
1850 | { | ||
1851 | iparml_db *parm; | ||
1852 | ulong b2f0_result; | ||
1853 | |||
1854 | iucv_debug(2, "entering"); | ||
1855 | |||
1856 | if (!buffer) | ||
1857 | return -EINVAL; | ||
1858 | |||
1859 | parm = (iparml_db *)grab_param(); | ||
1860 | |||
1861 | parm->ippathid = pathid; | ||
1862 | parm->iptrgcls = trgcls; | ||
1863 | parm->ipbfadr1 = (__u32) ((ulong) buffer); | ||
1864 | parm->ipbfln1f = (__u32) buflen; /* length of message */ | ||
1865 | parm->ipsrccls = srccls; | ||
1866 | parm->ipmsgtag = msgtag; | ||
1867 | parm->ipflags1 = (IPNORPY | IPBUFLST | flags1); | ||
1868 | b2f0_result = b2f0(SEND, parm); | ||
1869 | |||
1870 | if ((!b2f0_result) && (msgid)) | ||
1871 | *msgid = parm->ipmsgid; | ||
1872 | release_param(parm); | ||
1873 | |||
1874 | iucv_debug(2, "exiting"); | ||
1875 | return b2f0_result; | ||
1876 | } | ||
1877 | |||
1878 | /* | ||
1879 | * Name: iucv_send_prmmsg | ||
1880 | * Purpose: This function transmits data to another application. | ||
1881 | * Prmmsg specifies that the 8-bytes of data are to be moved | ||
1882 | * into the parameter list. This is a one-way message and the | ||
1883 | * receiver will not reply to the message. | ||
1884 | * Input: pathid - path identification number | ||
1885 | * trgcls - specifies target class | ||
1886 | * srccls - specifies the source message class | ||
1887 | * msgtag - specifies a tag to be associated with the message | ||
1888 | * flags1 - option for path | ||
1889 | * IPPRTY- specifies if you want to send priority message | ||
1890 | * prmmsg - 8-bytes of data to be placed into parameter list | ||
1891 | * Output: msgid - specifies the message ID. | ||
1892 | * Return: b2f0_result - return code from CP | ||
1893 | */ | ||
1894 | int | ||
1895 | iucv_send_prmmsg (__u16 pathid, | ||
1896 | __u32 * msgid, | ||
1897 | __u32 trgcls, | ||
1898 | __u32 srccls, __u32 msgtag, int flags1, __u8 prmmsg[8]) | ||
1899 | { | ||
1900 | iparml_dpl *parm; | ||
1901 | ulong b2f0_result; | ||
1902 | |||
1903 | iucv_debug(2, "entering"); | ||
1904 | |||
1905 | parm = (iparml_dpl *)grab_param(); | ||
1906 | |||
1907 | parm->ippathid = pathid; | ||
1908 | parm->iptrgcls = trgcls; | ||
1909 | parm->ipsrccls = srccls; | ||
1910 | parm->ipmsgtag = msgtag; | ||
1911 | parm->ipflags1 = (IPRMDATA | IPNORPY | flags1); | ||
1912 | memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); | ||
1913 | |||
1914 | b2f0_result = b2f0(SEND, parm); | ||
1915 | |||
1916 | if ((!b2f0_result) && (msgid)) | ||
1917 | *msgid = parm->ipmsgid; | ||
1918 | release_param(parm); | ||
1919 | |||
1920 | iucv_debug(2, "exiting"); | ||
1921 | |||
1922 | return b2f0_result; | ||
1923 | } | ||
1924 | |||
1925 | /* | ||
1926 | * Name: iucv_send2way | ||
1927 | * Purpose: This function transmits data to another application. | ||
1928 | * Data to be transmitted is in a buffer. The receiver | ||
1929 | * of the send is expected to reply to the message and | ||
1930 | * a buffer is provided into which IUCV moves the reply | ||
1931 | * to this message. | ||
1932 | * Input: pathid - path identification number | ||
1933 | * trgcls - specifies target class | ||
1934 | * srccls - specifies the source message class | ||
1935 | * msgtag - specifies a tag associated with the message | ||
1936 | * flags1 - option for path | ||
1937 | * IPPRTY- specifies if you want to send priority message | ||
1938 | * buffer - address of send buffer | ||
1939 | * buflen - length of send buffer | ||
1940 | * ansbuf - address of buffer to reply with | ||
1941 | * anslen - length of buffer to reply with | ||
1942 | * Output: msgid - specifies the message ID. | ||
1943 | * Return: b2f0_result - return code from CP | ||
1944 | * (-EINVAL) - buffer or ansbuf address is NULL | ||
1945 | */ | ||
1946 | int | ||
1947 | iucv_send2way (__u16 pathid, | ||
1948 | __u32 * msgid, | ||
1949 | __u32 trgcls, | ||
1950 | __u32 srccls, | ||
1951 | __u32 msgtag, | ||
1952 | int flags1, | ||
1953 | void *buffer, ulong buflen, void *ansbuf, ulong anslen) | ||
1954 | { | ||
1955 | iparml_db *parm; | ||
1956 | ulong b2f0_result; | ||
1957 | |||
1958 | iucv_debug(2, "entering"); | ||
1959 | |||
1960 | if (!buffer || !ansbuf) | ||
1961 | return -EINVAL; | ||
1962 | |||
1963 | parm = (iparml_db *)grab_param(); | ||
1964 | |||
1965 | parm->ippathid = pathid; | ||
1966 | parm->iptrgcls = trgcls; | ||
1967 | parm->ipbfadr1 = (__u32) ((ulong) buffer); | ||
1968 | parm->ipbfln1f = (__u32) buflen; /* length of message */ | ||
1969 | parm->ipbfadr2 = (__u32) ((ulong) ansbuf); | ||
1970 | parm->ipbfln2f = (__u32) anslen; | ||
1971 | parm->ipsrccls = srccls; | ||
1972 | parm->ipmsgtag = msgtag; | ||
1973 | parm->ipflags1 = flags1; /* priority message */ | ||
1974 | |||
1975 | b2f0_result = b2f0(SEND, parm); | ||
1976 | |||
1977 | if ((!b2f0_result) && (msgid)) | ||
1978 | *msgid = parm->ipmsgid; | ||
1979 | release_param(parm); | ||
1980 | |||
1981 | iucv_debug(2, "exiting"); | ||
1982 | |||
1983 | return b2f0_result; | ||
1984 | } | ||
1985 | |||
1986 | /* | ||
1987 | * Name: iucv_send2way_array | ||
1988 | * Purpose: This function transmits data to another application. | ||
1989 | * The contents of buffer is the address of the array of | ||
1990 | * addresses and lengths of discontiguous buffers that hold | ||
1991 | * the message text. The receiver of the send is expected to | ||
1992 | * reply to the message and a buffer is provided into which | ||
1993 | * IUCV moves the reply to this message. | ||
1994 | * Input: pathid - path identification number | ||
1995 | * trgcls - specifies target class | ||
1996 | * srccls - specifies the source message class | ||
1997 | * msgtag - spcifies a tag to be associated with the message | ||
1998 | * flags1 - option for path | ||
1999 | * IPPRTY- specifies if you want to send priority message | ||
2000 | * buffer - address of array of send buffers | ||
2001 | * buflen - total length of send buffers | ||
2002 | * ansbuf - address of buffer to reply with | ||
2003 | * anslen - length of buffer to reply with | ||
2004 | * Output: msgid - specifies the message ID. | ||
2005 | * Return: b2f0_result - return code from CP | ||
2006 | * (-EINVAL) - buffer address is NULL | ||
2007 | */ | ||
2008 | int | ||
2009 | iucv_send2way_array (__u16 pathid, | ||
2010 | __u32 * msgid, | ||
2011 | __u32 trgcls, | ||
2012 | __u32 srccls, | ||
2013 | __u32 msgtag, | ||
2014 | int flags1, | ||
2015 | iucv_array_t * buffer, | ||
2016 | ulong buflen, iucv_array_t * ansbuf, ulong anslen) | ||
2017 | { | ||
2018 | iparml_db *parm; | ||
2019 | ulong b2f0_result; | ||
2020 | |||
2021 | iucv_debug(2, "entering"); | ||
2022 | |||
2023 | if (!buffer || !ansbuf) | ||
2024 | return -EINVAL; | ||
2025 | |||
2026 | parm = (iparml_db *)grab_param(); | ||
2027 | |||
2028 | parm->ippathid = pathid; | ||
2029 | parm->iptrgcls = trgcls; | ||
2030 | parm->ipbfadr1 = (__u32) ((ulong) buffer); | ||
2031 | parm->ipbfln1f = (__u32) buflen; /* length of message */ | ||
2032 | parm->ipbfadr2 = (__u32) ((ulong) ansbuf); | ||
2033 | parm->ipbfln2f = (__u32) anslen; | ||
2034 | parm->ipsrccls = srccls; | ||
2035 | parm->ipmsgtag = msgtag; | ||
2036 | parm->ipflags1 = (IPBUFLST | IPANSLST | flags1); | ||
2037 | b2f0_result = b2f0(SEND, parm); | ||
2038 | if ((!b2f0_result) && (msgid)) | ||
2039 | *msgid = parm->ipmsgid; | ||
2040 | release_param(parm); | ||
2041 | |||
2042 | iucv_debug(2, "exiting"); | ||
2043 | return b2f0_result; | ||
2044 | } | ||
2045 | |||
2046 | /* | ||
2047 | * Name: iucv_send2way_prmmsg | ||
2048 | * Purpose: This function transmits data to another application. | ||
2049 | * Prmmsg specifies that the 8-bytes of data are to be moved | ||
2050 | * into the parameter list. This is a two-way message and the | ||
2051 | * receiver of the message is expected to reply. A buffer | ||
2052 | * is provided into which IUCV moves the reply to this | ||
2053 | * message. | ||
2054 | * Input: pathid - path identification number | ||
2055 | * trgcls - specifies target class | ||
2056 | * srccls - specifies the source message class | ||
2057 | * msgtag - specifies a tag to be associated with the message | ||
2058 | * flags1 - option for path | ||
2059 | * IPPRTY- specifies if you want to send priority message | ||
2060 | * prmmsg - 8-bytes of data to be placed in parameter list | ||
2061 | * ansbuf - address of buffer to reply with | ||
2062 | * anslen - length of buffer to reply with | ||
2063 | * Output: msgid - specifies the message ID. | ||
2064 | * Return: b2f0_result - return code from CP | ||
2065 | * (-EINVAL) - buffer address is NULL | ||
2066 | */ | ||
2067 | int | ||
2068 | iucv_send2way_prmmsg (__u16 pathid, | ||
2069 | __u32 * msgid, | ||
2070 | __u32 trgcls, | ||
2071 | __u32 srccls, | ||
2072 | __u32 msgtag, | ||
2073 | ulong flags1, __u8 prmmsg[8], void *ansbuf, ulong anslen) | ||
2074 | { | ||
2075 | iparml_dpl *parm; | ||
2076 | ulong b2f0_result; | ||
2077 | |||
2078 | iucv_debug(2, "entering"); | ||
2079 | |||
2080 | if (!ansbuf) | ||
2081 | return -EINVAL; | ||
2082 | |||
2083 | parm = (iparml_dpl *)grab_param(); | ||
2084 | |||
2085 | parm->ippathid = pathid; | ||
2086 | parm->iptrgcls = trgcls; | ||
2087 | parm->ipsrccls = srccls; | ||
2088 | parm->ipmsgtag = msgtag; | ||
2089 | parm->ipbfadr2 = (__u32) ((ulong) ansbuf); | ||
2090 | parm->ipbfln2f = (__u32) anslen; | ||
2091 | parm->ipflags1 = (IPRMDATA | flags1); /* message in prmlist */ | ||
2092 | memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); | ||
2093 | |||
2094 | b2f0_result = b2f0(SEND, parm); | ||
2095 | |||
2096 | if ((!b2f0_result) && (msgid)) | ||
2097 | *msgid = parm->ipmsgid; | ||
2098 | release_param(parm); | ||
2099 | |||
2100 | iucv_debug(2, "exiting"); | ||
2101 | |||
2102 | return b2f0_result; | ||
2103 | } | ||
2104 | |||
2105 | /* | ||
2106 | * Name: iucv_send2way_prmmsg_array | ||
2107 | * Purpose: This function transmits data to another application. | ||
2108 | * Prmmsg specifies that the 8-bytes of data are to be moved | ||
2109 | * into the parameter list. This is a two-way message and the | ||
2110 | * receiver of the message is expected to reply. A buffer | ||
2111 | * is provided into which IUCV moves the reply to this | ||
2112 | * message. The contents of ansbuf is the address of the | ||
2113 | * array of addresses and lengths of discontiguous buffers | ||
2114 | * that contain the reply. | ||
2115 | * Input: pathid - path identification number | ||
2116 | * trgcls - specifies target class | ||
2117 | * srccls - specifies the source message class | ||
2118 | * msgtag - specifies a tag to be associated with the message | ||
2119 | * flags1 - option for path | ||
2120 | * IPPRTY- specifies if you want to send priority message | ||
2121 | * prmmsg - 8-bytes of data to be placed into the parameter list | ||
2122 | * ansbuf - address of buffer to reply with | ||
2123 | * anslen - length of buffer to reply with | ||
2124 | * Output: msgid - specifies the message ID. | ||
2125 | * Return: b2f0_result - return code from CP | ||
2126 | * (-EINVAL) - ansbuf address is NULL | ||
2127 | */ | ||
2128 | int | ||
2129 | iucv_send2way_prmmsg_array (__u16 pathid, | ||
2130 | __u32 * msgid, | ||
2131 | __u32 trgcls, | ||
2132 | __u32 srccls, | ||
2133 | __u32 msgtag, | ||
2134 | int flags1, | ||
2135 | __u8 prmmsg[8], | ||
2136 | iucv_array_t * ansbuf, ulong anslen) | ||
2137 | { | ||
2138 | iparml_dpl *parm; | ||
2139 | ulong b2f0_result; | ||
2140 | |||
2141 | iucv_debug(2, "entering"); | ||
2142 | |||
2143 | if (!ansbuf) | ||
2144 | return -EINVAL; | ||
2145 | |||
2146 | parm = (iparml_dpl *)grab_param(); | ||
2147 | |||
2148 | parm->ippathid = pathid; | ||
2149 | parm->iptrgcls = trgcls; | ||
2150 | parm->ipsrccls = srccls; | ||
2151 | parm->ipmsgtag = msgtag; | ||
2152 | parm->ipbfadr2 = (__u32) ((ulong) ansbuf); | ||
2153 | parm->ipbfln2f = (__u32) anslen; | ||
2154 | parm->ipflags1 = (IPRMDATA | IPANSLST | flags1); | ||
2155 | memcpy(parm->iprmmsg, prmmsg, sizeof(parm->iprmmsg)); | ||
2156 | b2f0_result = b2f0(SEND, parm); | ||
2157 | if ((!b2f0_result) && (msgid)) | ||
2158 | *msgid = parm->ipmsgid; | ||
2159 | release_param(parm); | ||
2160 | |||
2161 | iucv_debug(2, "exiting"); | ||
2162 | return b2f0_result; | ||
2163 | } | ||
2164 | |||
2165 | void | ||
2166 | iucv_setmask_cpuid (void *result) | ||
2167 | { | ||
2168 | iparml_set_mask *parm; | ||
2169 | |||
2170 | iucv_debug(1, "entering"); | ||
2171 | parm = (iparml_set_mask *)grab_param(); | ||
2172 | parm->ipmask = *((__u8*)result); | ||
2173 | *((ulong *)result) = b2f0(SETMASK, parm); | ||
2174 | release_param(parm); | ||
2175 | |||
2176 | iucv_debug(1, "b2f0_result = %ld", *((ulong *)result)); | ||
2177 | iucv_debug(1, "exiting"); | ||
2178 | } | ||
2179 | |||
2180 | /* | ||
2181 | * Name: iucv_setmask | ||
2182 | * Purpose: This function enables or disables the following IUCV | ||
2183 | * external interruptions: Nonpriority and priority message | ||
2184 | * interrupts, nonpriority and priority reply interrupts. | ||
2185 | * Input: SetMaskFlag - options for interrupts | ||
2186 | * 0x80 - Nonpriority_MessagePendingInterruptsFlag | ||
2187 | * 0x40 - Priority_MessagePendingInterruptsFlag | ||
2188 | * 0x20 - Nonpriority_MessageCompletionInterruptsFlag | ||
2189 | * 0x10 - Priority_MessageCompletionInterruptsFlag | ||
2190 | * 0x08 - IUCVControlInterruptsFlag | ||
2191 | * Output: NA | ||
2192 | * Return: b2f0_result - return code from CP | ||
2193 | */ | ||
2194 | int | ||
2195 | iucv_setmask (int SetMaskFlag) | ||
2196 | { | ||
2197 | union { | ||
2198 | ulong result; | ||
2199 | __u8 param; | ||
2200 | } u; | ||
2201 | int cpu; | ||
2202 | |||
2203 | u.param = SetMaskFlag; | ||
2204 | cpu = get_cpu(); | ||
2205 | smp_call_function_on(iucv_setmask_cpuid, &u, 0, 1, iucv_cpuid); | ||
2206 | put_cpu(); | ||
2207 | |||
2208 | return u.result; | ||
2209 | } | ||
2210 | |||
2211 | /** | ||
2212 | * iucv_sever: | ||
2213 | * @pathid: Path identification number | ||
2214 | * @user_data: 16-byte of user data | ||
2215 | * | ||
2216 | * This function terminates an iucv path. | ||
2217 | * Returns: return code from CP | ||
2218 | */ | ||
2219 | int | ||
2220 | iucv_sever(__u16 pathid, __u8 user_data[16]) | ||
2221 | { | ||
2222 | iparml_control *parm; | ||
2223 | ulong b2f0_result = 0; | ||
2224 | |||
2225 | iucv_debug(1, "entering"); | ||
2226 | parm = (iparml_control *)grab_param(); | ||
2227 | |||
2228 | memcpy(parm->ipuser, user_data, sizeof(parm->ipuser)); | ||
2229 | parm->ippathid = pathid; | ||
2230 | |||
2231 | b2f0_result = b2f0(SEVER, parm); | ||
2232 | |||
2233 | if (!b2f0_result) | ||
2234 | iucv_remove_pathid(pathid); | ||
2235 | release_param(parm); | ||
2236 | |||
2237 | iucv_debug(1, "exiting"); | ||
2238 | return b2f0_result; | ||
2239 | } | ||
2240 | |||
2241 | /* | ||
2242 | * Interrupt Handlers | ||
2243 | *******************************************************************************/ | ||
2244 | |||
2245 | /** | ||
2246 | * iucv_irq_handler: | ||
2247 | * @regs: Current registers | ||
2248 | * @code: irq code | ||
2249 | * | ||
2250 | * Handles external interrupts coming in from CP. | ||
2251 | * Places the interrupt buffer on a queue and schedules iucv_tasklet_handler(). | ||
2252 | */ | ||
2253 | static void | ||
2254 | iucv_irq_handler(__u16 code) | ||
2255 | { | ||
2256 | iucv_irqdata *irqdata; | ||
2257 | |||
2258 | irqdata = kmalloc(sizeof(iucv_irqdata), GFP_ATOMIC); | ||
2259 | if (!irqdata) { | ||
2260 | printk(KERN_WARNING "%s: out of memory\n", __FUNCTION__); | ||
2261 | return; | ||
2262 | } | ||
2263 | |||
2264 | memcpy(&irqdata->data, iucv_external_int_buffer, | ||
2265 | sizeof(iucv_GeneralInterrupt)); | ||
2266 | |||
2267 | spin_lock(&iucv_irq_queue_lock); | ||
2268 | list_add_tail(&irqdata->queue, &iucv_irq_queue); | ||
2269 | spin_unlock(&iucv_irq_queue_lock); | ||
2270 | |||
2271 | tasklet_schedule(&iucv_tasklet); | ||
2272 | } | ||
2273 | |||
2274 | /** | ||
2275 | * iucv_do_int: | ||
2276 | * @int_buf: Pointer to copy of external interrupt buffer | ||
2277 | * | ||
2278 | * The workhorse for handling interrupts queued by iucv_irq_handler(). | ||
2279 | * This function is called from the bottom half iucv_tasklet_handler(). | ||
2280 | */ | ||
2281 | static void | ||
2282 | iucv_do_int(iucv_GeneralInterrupt * int_buf) | ||
2283 | { | ||
2284 | handler *h = NULL; | ||
2285 | struct list_head *lh; | ||
2286 | ulong flags; | ||
2287 | iucv_interrupt_ops_t *interrupt = NULL; /* interrupt addresses */ | ||
2288 | __u8 temp_buff1[24], temp_buff2[24]; /* masked handler id. */ | ||
2289 | int rc = 0, j = 0; | ||
2290 | __u8 no_listener[16] = "NO LISTENER"; | ||
2291 | |||
2292 | iucv_debug(2, "entering, pathid %d, type %02X", | ||
2293 | int_buf->ippathid, int_buf->iptype); | ||
2294 | iucv_dumpit("External Interrupt Buffer:", | ||
2295 | int_buf, sizeof(iucv_GeneralInterrupt)); | ||
2296 | |||
2297 | ASCEBC (no_listener, 16); | ||
2298 | |||
2299 | if (int_buf->iptype != 01) { | ||
2300 | if ((int_buf->ippathid) > (max_connections - 1)) { | ||
2301 | printk(KERN_WARNING "%s: Got interrupt with pathid %d" | ||
2302 | " > max_connections (%ld)\n", __FUNCTION__, | ||
2303 | int_buf->ippathid, max_connections - 1); | ||
2304 | } else { | ||
2305 | h = iucv_pathid_table[int_buf->ippathid]; | ||
2306 | interrupt = h->interrupt_table; | ||
2307 | iucv_dumpit("Handler:", h, sizeof(handler)); | ||
2308 | } | ||
2309 | } | ||
2310 | |||
2311 | /* end of if statement */ | ||
2312 | switch (int_buf->iptype) { | ||
2313 | case 0x01: /* connection pending */ | ||
2314 | if (messagesDisabled) { | ||
2315 | iucv_setmask(~0); | ||
2316 | messagesDisabled = 0; | ||
2317 | } | ||
2318 | spin_lock_irqsave(&iucv_lock, flags); | ||
2319 | list_for_each(lh, &iucv_handler_table) { | ||
2320 | h = list_entry(lh, handler, list); | ||
2321 | memcpy(temp_buff1, &(int_buf->ipvmid), 24); | ||
2322 | memcpy(temp_buff2, &(h->id.userid), 24); | ||
2323 | for (j = 0; j < 24; j++) { | ||
2324 | temp_buff1[j] &= (h->id.mask)[j]; | ||
2325 | temp_buff2[j] &= (h->id.mask)[j]; | ||
2326 | } | ||
2327 | |||
2328 | iucv_dumpit("temp_buff1:", | ||
2329 | temp_buff1, sizeof(temp_buff1)); | ||
2330 | iucv_dumpit("temp_buff2", | ||
2331 | temp_buff2, sizeof(temp_buff2)); | ||
2332 | |||
2333 | if (!memcmp (temp_buff1, temp_buff2, 24)) { | ||
2334 | |||
2335 | iucv_debug(2, | ||
2336 | "found a matching handler"); | ||
2337 | break; | ||
2338 | } else | ||
2339 | h = NULL; | ||
2340 | } | ||
2341 | spin_unlock_irqrestore (&iucv_lock, flags); | ||
2342 | if (h) { | ||
2343 | /* ADD PATH TO PATHID TABLE */ | ||
2344 | rc = iucv_add_pathid(int_buf->ippathid, h); | ||
2345 | if (rc) { | ||
2346 | iucv_sever (int_buf->ippathid, | ||
2347 | no_listener); | ||
2348 | iucv_debug(1, | ||
2349 | "add_pathid failed, rc = %d", | ||
2350 | rc); | ||
2351 | } else { | ||
2352 | interrupt = h->interrupt_table; | ||
2353 | if (interrupt->ConnectionPending) { | ||
2354 | EBCASC (int_buf->ipvmid, 8); | ||
2355 | interrupt->ConnectionPending( | ||
2356 | (iucv_ConnectionPending *)int_buf, | ||
2357 | h->pgm_data); | ||
2358 | } else | ||
2359 | iucv_sever(int_buf->ippathid, | ||
2360 | no_listener); | ||
2361 | } | ||
2362 | } else | ||
2363 | iucv_sever(int_buf->ippathid, no_listener); | ||
2364 | break; | ||
2365 | |||
2366 | case 0x02: /*connection complete */ | ||
2367 | if (messagesDisabled) { | ||
2368 | iucv_setmask(~0); | ||
2369 | messagesDisabled = 0; | ||
2370 | } | ||
2371 | if (h) { | ||
2372 | if (interrupt->ConnectionComplete) | ||
2373 | { | ||
2374 | interrupt->ConnectionComplete( | ||
2375 | (iucv_ConnectionComplete *)int_buf, | ||
2376 | h->pgm_data); | ||
2377 | } | ||
2378 | else | ||
2379 | iucv_debug(1, | ||
2380 | "ConnectionComplete not called"); | ||
2381 | } else | ||
2382 | iucv_sever(int_buf->ippathid, no_listener); | ||
2383 | break; | ||
2384 | |||
2385 | case 0x03: /* connection severed */ | ||
2386 | if (messagesDisabled) { | ||
2387 | iucv_setmask(~0); | ||
2388 | messagesDisabled = 0; | ||
2389 | } | ||
2390 | if (h) { | ||
2391 | if (interrupt->ConnectionSevered) | ||
2392 | interrupt->ConnectionSevered( | ||
2393 | (iucv_ConnectionSevered *)int_buf, | ||
2394 | h->pgm_data); | ||
2395 | |||
2396 | else | ||
2397 | iucv_sever (int_buf->ippathid, no_listener); | ||
2398 | } else | ||
2399 | iucv_sever(int_buf->ippathid, no_listener); | ||
2400 | break; | ||
2401 | |||
2402 | case 0x04: /* connection quiesced */ | ||
2403 | if (messagesDisabled) { | ||
2404 | iucv_setmask(~0); | ||
2405 | messagesDisabled = 0; | ||
2406 | } | ||
2407 | if (h) { | ||
2408 | if (interrupt->ConnectionQuiesced) | ||
2409 | interrupt->ConnectionQuiesced( | ||
2410 | (iucv_ConnectionQuiesced *)int_buf, | ||
2411 | h->pgm_data); | ||
2412 | else | ||
2413 | iucv_debug(1, | ||
2414 | "ConnectionQuiesced not called"); | ||
2415 | } | ||
2416 | break; | ||
2417 | |||
2418 | case 0x05: /* connection resumed */ | ||
2419 | if (messagesDisabled) { | ||
2420 | iucv_setmask(~0); | ||
2421 | messagesDisabled = 0; | ||
2422 | } | ||
2423 | if (h) { | ||
2424 | if (interrupt->ConnectionResumed) | ||
2425 | interrupt->ConnectionResumed( | ||
2426 | (iucv_ConnectionResumed *)int_buf, | ||
2427 | h->pgm_data); | ||
2428 | else | ||
2429 | iucv_debug(1, | ||
2430 | "ConnectionResumed not called"); | ||
2431 | } | ||
2432 | break; | ||
2433 | |||
2434 | case 0x06: /* priority message complete */ | ||
2435 | case 0x07: /* nonpriority message complete */ | ||
2436 | if (h) { | ||
2437 | if (interrupt->MessageComplete) | ||
2438 | interrupt->MessageComplete( | ||
2439 | (iucv_MessageComplete *)int_buf, | ||
2440 | h->pgm_data); | ||
2441 | else | ||
2442 | iucv_debug(2, | ||
2443 | "MessageComplete not called"); | ||
2444 | } | ||
2445 | break; | ||
2446 | |||
2447 | case 0x08: /* priority message pending */ | ||
2448 | case 0x09: /* nonpriority message pending */ | ||
2449 | if (h) { | ||
2450 | if (interrupt->MessagePending) | ||
2451 | interrupt->MessagePending( | ||
2452 | (iucv_MessagePending *) int_buf, | ||
2453 | h->pgm_data); | ||
2454 | else | ||
2455 | iucv_debug(2, | ||
2456 | "MessagePending not called"); | ||
2457 | } | ||
2458 | break; | ||
2459 | default: /* unknown iucv type */ | ||
2460 | printk(KERN_WARNING "%s: unknown iucv interrupt\n", | ||
2461 | __FUNCTION__); | ||
2462 | break; | ||
2463 | } /* end switch */ | ||
2464 | |||
2465 | iucv_debug(2, "exiting pathid %d, type %02X", | ||
2466 | int_buf->ippathid, int_buf->iptype); | ||
2467 | |||
2468 | return; | ||
2469 | } | ||
2470 | |||
2471 | /** | ||
2472 | * iucv_tasklet_handler: | ||
2473 | * | ||
2474 | * This function loops over the queue of irq buffers and runs iucv_do_int() | ||
2475 | * on every queue element. | ||
2476 | */ | ||
2477 | static void | ||
2478 | iucv_tasklet_handler(unsigned long ignored) | ||
2479 | { | ||
2480 | struct list_head head; | ||
2481 | struct list_head *next; | ||
2482 | ulong flags; | ||
2483 | |||
2484 | spin_lock_irqsave(&iucv_irq_queue_lock, flags); | ||
2485 | list_add(&head, &iucv_irq_queue); | ||
2486 | list_del_init(&iucv_irq_queue); | ||
2487 | spin_unlock_irqrestore (&iucv_irq_queue_lock, flags); | ||
2488 | |||
2489 | next = head.next; | ||
2490 | while (next != &head) { | ||
2491 | iucv_irqdata *p = list_entry(next, iucv_irqdata, queue); | ||
2492 | |||
2493 | next = next->next; | ||
2494 | iucv_do_int(&p->data); | ||
2495 | kfree(p); | ||
2496 | } | ||
2497 | |||
2498 | return; | ||
2499 | } | ||
2500 | |||
2501 | subsys_initcall(iucv_init); | ||
2502 | module_exit(iucv_exit); | ||
2503 | |||
2504 | /** | ||
2505 | * Export all public stuff | ||
2506 | */ | ||
2507 | EXPORT_SYMBOL (iucv_bus); | ||
2508 | EXPORT_SYMBOL (iucv_root); | ||
2509 | EXPORT_SYMBOL (iucv_accept); | ||
2510 | EXPORT_SYMBOL (iucv_connect); | ||
2511 | #if 0 | ||
2512 | EXPORT_SYMBOL (iucv_purge); | ||
2513 | EXPORT_SYMBOL (iucv_query_maxconn); | ||
2514 | EXPORT_SYMBOL (iucv_query_bufsize); | ||
2515 | EXPORT_SYMBOL (iucv_quiesce); | ||
2516 | #endif | ||
2517 | EXPORT_SYMBOL (iucv_receive); | ||
2518 | #if 0 | ||
2519 | EXPORT_SYMBOL (iucv_receive_array); | ||
2520 | #endif | ||
2521 | EXPORT_SYMBOL (iucv_reject); | ||
2522 | #if 0 | ||
2523 | EXPORT_SYMBOL (iucv_reply); | ||
2524 | EXPORT_SYMBOL (iucv_reply_array); | ||
2525 | EXPORT_SYMBOL (iucv_resume); | ||
2526 | #endif | ||
2527 | EXPORT_SYMBOL (iucv_reply_prmmsg); | ||
2528 | EXPORT_SYMBOL (iucv_send); | ||
2529 | EXPORT_SYMBOL (iucv_send2way); | ||
2530 | EXPORT_SYMBOL (iucv_send2way_array); | ||
2531 | EXPORT_SYMBOL (iucv_send2way_prmmsg); | ||
2532 | EXPORT_SYMBOL (iucv_send2way_prmmsg_array); | ||
2533 | #if 0 | ||
2534 | EXPORT_SYMBOL (iucv_send_array); | ||
2535 | EXPORT_SYMBOL (iucv_send_prmmsg); | ||
2536 | EXPORT_SYMBOL (iucv_setmask); | ||
2537 | #endif | ||
2538 | EXPORT_SYMBOL (iucv_sever); | ||
2539 | EXPORT_SYMBOL (iucv_register_program); | ||
2540 | EXPORT_SYMBOL (iucv_unregister_program); | ||
diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h deleted file mode 100644 index 5b6b1b7241c9..000000000000 --- a/drivers/s390/net/iucv.h +++ /dev/null | |||
@@ -1,849 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/s390/net/iucv.h | ||
3 | * IUCV base support. | ||
4 | * | ||
5 | * S390 version | ||
6 | * Copyright (C) 2000 IBM Corporation | ||
7 | * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com) | ||
8 | * Xenia Tkatschow (xenia@us.ibm.com) | ||
9 | * | ||
10 | * | ||
11 | * Functionality: | ||
12 | * To explore any of the IUCV functions, one must first register | ||
13 | * their program using iucv_register_program(). Once your program has | ||
14 | * successfully completed a register, it can exploit the other functions. | ||
15 | * For furthur reference on all IUCV functionality, refer to the | ||
16 | * CP Programming Services book, also available on the web | ||
17 | * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 | ||
18 | * | ||
19 | * Definition of Return Codes | ||
20 | * -All positive return codes including zero are reflected back | ||
21 | * from CP except for iucv_register_program. The definition of each | ||
22 | * return code can be found in CP Programming Services book. | ||
23 | * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760 | ||
24 | * - Return Code of: | ||
25 | * (-EINVAL) Invalid value | ||
26 | * (-ENOMEM) storage allocation failed | ||
27 | * pgmask defined in iucv_register_program will be set depending on input | ||
28 | * paramters. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/types.h> | ||
33 | #include <asm/debug.h> | ||
34 | |||
35 | /** | ||
36 | * Debug Facility stuff | ||
37 | */ | ||
38 | #define IUCV_DBF_SETUP_NAME "iucv_setup" | ||
39 | #define IUCV_DBF_SETUP_LEN 32 | ||
40 | #define IUCV_DBF_SETUP_PAGES 2 | ||
41 | #define IUCV_DBF_SETUP_NR_AREAS 1 | ||
42 | #define IUCV_DBF_SETUP_LEVEL 3 | ||
43 | |||
44 | #define IUCV_DBF_DATA_NAME "iucv_data" | ||
45 | #define IUCV_DBF_DATA_LEN 128 | ||
46 | #define IUCV_DBF_DATA_PAGES 2 | ||
47 | #define IUCV_DBF_DATA_NR_AREAS 1 | ||
48 | #define IUCV_DBF_DATA_LEVEL 2 | ||
49 | |||
50 | #define IUCV_DBF_TRACE_NAME "iucv_trace" | ||
51 | #define IUCV_DBF_TRACE_LEN 16 | ||
52 | #define IUCV_DBF_TRACE_PAGES 4 | ||
53 | #define IUCV_DBF_TRACE_NR_AREAS 1 | ||
54 | #define IUCV_DBF_TRACE_LEVEL 3 | ||
55 | |||
56 | #define IUCV_DBF_TEXT(name,level,text) \ | ||
57 | do { \ | ||
58 | debug_text_event(iucv_dbf_##name,level,text); \ | ||
59 | } while (0) | ||
60 | |||
61 | #define IUCV_DBF_HEX(name,level,addr,len) \ | ||
62 | do { \ | ||
63 | debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ | ||
64 | } while (0) | ||
65 | |||
66 | DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); | ||
67 | |||
68 | #define IUCV_DBF_TEXT_(name,level,text...) \ | ||
69 | do { \ | ||
70 | char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ | ||
71 | sprintf(iucv_dbf_txt_buf, text); \ | ||
72 | debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ | ||
73 | put_cpu_var(iucv_dbf_txt_buf); \ | ||
74 | } while (0) | ||
75 | |||
76 | #define IUCV_DBF_SPRINTF(name,level,text...) \ | ||
77 | do { \ | ||
78 | debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ | ||
79 | debug_sprintf_event(iucv_dbf_trace, level, text ); \ | ||
80 | } while (0) | ||
81 | |||
82 | /** | ||
83 | * some more debug stuff | ||
84 | */ | ||
85 | #define IUCV_HEXDUMP16(importance,header,ptr) \ | ||
86 | PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | ||
87 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ | ||
88 | *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ | ||
89 | *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ | ||
90 | *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ | ||
91 | *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ | ||
92 | *(((char*)ptr)+12),*(((char*)ptr)+13), \ | ||
93 | *(((char*)ptr)+14),*(((char*)ptr)+15)); \ | ||
94 | PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | ||
95 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ | ||
96 | *(((char*)ptr)+16),*(((char*)ptr)+17), \ | ||
97 | *(((char*)ptr)+18),*(((char*)ptr)+19), \ | ||
98 | *(((char*)ptr)+20),*(((char*)ptr)+21), \ | ||
99 | *(((char*)ptr)+22),*(((char*)ptr)+23), \ | ||
100 | *(((char*)ptr)+24),*(((char*)ptr)+25), \ | ||
101 | *(((char*)ptr)+26),*(((char*)ptr)+27), \ | ||
102 | *(((char*)ptr)+28),*(((char*)ptr)+29), \ | ||
103 | *(((char*)ptr)+30),*(((char*)ptr)+31)); | ||
104 | |||
105 | static inline void | ||
106 | iucv_hex_dump(unsigned char *buf, size_t len) | ||
107 | { | ||
108 | size_t i; | ||
109 | |||
110 | for (i = 0; i < len; i++) { | ||
111 | if (i && !(i % 16)) | ||
112 | printk("\n"); | ||
113 | printk("%02x ", *(buf + i)); | ||
114 | } | ||
115 | printk("\n"); | ||
116 | } | ||
117 | /** | ||
118 | * end of debug stuff | ||
119 | */ | ||
120 | |||
121 | #define uchar unsigned char | ||
122 | #define ushort unsigned short | ||
123 | #define ulong unsigned long | ||
124 | #define iucv_handle_t void * | ||
125 | |||
126 | /* flags1: | ||
127 | * All flags are defined in the field IPFLAGS1 of each function | ||
128 | * and can be found in CP Programming Services. | ||
129 | * IPLOCAL - Indicates the connect can only be satisfied on the | ||
130 | * local system | ||
131 | * IPPRTY - Indicates a priority message | ||
132 | * IPQUSCE - Indicates you do not want to receive messages on a | ||
133 | * path until an iucv_resume is issued | ||
134 | * IPRMDATA - Indicates that the message is in the parameter list | ||
135 | */ | ||
136 | #define IPLOCAL 0x01 | ||
137 | #define IPPRTY 0x20 | ||
138 | #define IPQUSCE 0x40 | ||
139 | #define IPRMDATA 0x80 | ||
140 | |||
141 | /* flags1_out: | ||
142 | * All flags are defined in the output field of IPFLAGS1 for each function | ||
143 | * and can be found in CP Programming Services. | ||
144 | * IPNORPY - Specifies this is a one-way message and no reply is expected. | ||
145 | * IPPRTY - Indicates a priority message is permitted. Defined in flags1. | ||
146 | */ | ||
147 | #define IPNORPY 0x10 | ||
148 | |||
149 | #define Nonpriority_MessagePendingInterruptsFlag 0x80 | ||
150 | #define Priority_MessagePendingInterruptsFlag 0x40 | ||
151 | #define Nonpriority_MessageCompletionInterruptsFlag 0x20 | ||
152 | #define Priority_MessageCompletionInterruptsFlag 0x10 | ||
153 | #define IUCVControlInterruptsFlag 0x08 | ||
154 | #define AllInterrupts 0xf8 | ||
155 | /* | ||
156 | * Mapping of external interrupt buffers should be used with the corresponding | ||
157 | * interrupt types. | ||
158 | * Names: iucv_ConnectionPending -> connection pending | ||
159 | * iucv_ConnectionComplete -> connection complete | ||
160 | * iucv_ConnectionSevered -> connection severed | ||
161 | * iucv_ConnectionQuiesced -> connection quiesced | ||
162 | * iucv_ConnectionResumed -> connection resumed | ||
163 | * iucv_MessagePending -> message pending | ||
164 | * iucv_MessageComplete -> message complete | ||
165 | */ | ||
166 | typedef struct { | ||
167 | u16 ippathid; | ||
168 | uchar ipflags1; | ||
169 | uchar iptype; | ||
170 | u16 ipmsglim; | ||
171 | u16 res1; | ||
172 | uchar ipvmid[8]; | ||
173 | uchar ipuser[16]; | ||
174 | u32 res3; | ||
175 | uchar ippollfg; | ||
176 | uchar res4[3]; | ||
177 | } iucv_ConnectionPending; | ||
178 | |||
179 | typedef struct { | ||
180 | u16 ippathid; | ||
181 | uchar ipflags1; | ||
182 | uchar iptype; | ||
183 | u16 ipmsglim; | ||
184 | u16 res1; | ||
185 | uchar res2[8]; | ||
186 | uchar ipuser[16]; | ||
187 | u32 res3; | ||
188 | uchar ippollfg; | ||
189 | uchar res4[3]; | ||
190 | } iucv_ConnectionComplete; | ||
191 | |||
192 | typedef struct { | ||
193 | u16 ippathid; | ||
194 | uchar res1; | ||
195 | uchar iptype; | ||
196 | u32 res2; | ||
197 | uchar res3[8]; | ||
198 | uchar ipuser[16]; | ||
199 | u32 res4; | ||
200 | uchar ippollfg; | ||
201 | uchar res5[3]; | ||
202 | } iucv_ConnectionSevered; | ||
203 | |||
204 | typedef struct { | ||
205 | u16 ippathid; | ||
206 | uchar res1; | ||
207 | uchar iptype; | ||
208 | u32 res2; | ||
209 | uchar res3[8]; | ||
210 | uchar ipuser[16]; | ||
211 | u32 res4; | ||
212 | uchar ippollfg; | ||
213 | uchar res5[3]; | ||
214 | } iucv_ConnectionQuiesced; | ||
215 | |||
216 | typedef struct { | ||
217 | u16 ippathid; | ||
218 | uchar res1; | ||
219 | uchar iptype; | ||
220 | u32 res2; | ||
221 | uchar res3[8]; | ||
222 | uchar ipuser[16]; | ||
223 | u32 res4; | ||
224 | uchar ippollfg; | ||
225 | uchar res5[3]; | ||
226 | } iucv_ConnectionResumed; | ||
227 | |||
228 | typedef struct { | ||
229 | u16 ippathid; | ||
230 | uchar ipflags1; | ||
231 | uchar iptype; | ||
232 | u32 ipmsgid; | ||
233 | u32 iptrgcls; | ||
234 | union u2 { | ||
235 | u32 iprmmsg1_u32; | ||
236 | uchar iprmmsg1[4]; | ||
237 | } ln1msg1; | ||
238 | union u1 { | ||
239 | u32 ipbfln1f; | ||
240 | uchar iprmmsg2[4]; | ||
241 | } ln1msg2; | ||
242 | u32 res1[3]; | ||
243 | u32 ipbfln2f; | ||
244 | uchar ippollfg; | ||
245 | uchar res2[3]; | ||
246 | } iucv_MessagePending; | ||
247 | |||
248 | typedef struct { | ||
249 | u16 ippathid; | ||
250 | uchar ipflags1; | ||
251 | uchar iptype; | ||
252 | u32 ipmsgid; | ||
253 | u32 ipaudit; | ||
254 | uchar iprmmsg[8]; | ||
255 | u32 ipsrccls; | ||
256 | u32 ipmsgtag; | ||
257 | u32 res; | ||
258 | u32 ipbfln2f; | ||
259 | uchar ippollfg; | ||
260 | uchar res2[3]; | ||
261 | } iucv_MessageComplete; | ||
262 | |||
263 | /* | ||
264 | * iucv_interrupt_ops_t: Is a vector of functions that handle | ||
265 | * IUCV interrupts. | ||
266 | * Parameter list: | ||
267 | * eib - is a pointer to a 40-byte area described | ||
268 | * with one of the structures above. | ||
269 | * pgm_data - this data is strictly for the | ||
270 | * interrupt handler that is passed by | ||
271 | * the application. This may be an address | ||
272 | * or token. | ||
273 | */ | ||
274 | typedef struct { | ||
275 | void (*ConnectionPending) (iucv_ConnectionPending * eib, | ||
276 | void *pgm_data); | ||
277 | void (*ConnectionComplete) (iucv_ConnectionComplete * eib, | ||
278 | void *pgm_data); | ||
279 | void (*ConnectionSevered) (iucv_ConnectionSevered * eib, | ||
280 | void *pgm_data); | ||
281 | void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib, | ||
282 | void *pgm_data); | ||
283 | void (*ConnectionResumed) (iucv_ConnectionResumed * eib, | ||
284 | void *pgm_data); | ||
285 | void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data); | ||
286 | void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data); | ||
287 | } iucv_interrupt_ops_t; | ||
288 | |||
289 | /* | ||
290 | *iucv_array_t : Defines buffer array. | ||
291 | * Inside the array may be 31- bit addresses and 31-bit lengths. | ||
292 | */ | ||
293 | typedef struct { | ||
294 | u32 address; | ||
295 | u32 length; | ||
296 | } iucv_array_t __attribute__ ((aligned (8))); | ||
297 | |||
298 | extern struct bus_type iucv_bus; | ||
299 | extern struct device *iucv_root; | ||
300 | |||
301 | /* -prototypes- */ | ||
302 | /* | ||
303 | * Name: iucv_register_program | ||
304 | * Purpose: Registers an application with IUCV | ||
305 | * Input: prmname - user identification | ||
306 | * userid - machine identification | ||
307 | * pgmmask - indicates which bits in the prmname and userid combined will be | ||
308 | * used to determine who is given control | ||
309 | * ops - address of vector of interrupt handlers | ||
310 | * pgm_data- application data passed to interrupt handlers | ||
311 | * Output: NA | ||
312 | * Return: address of handler | ||
313 | * (0) - Error occurred, registration not completed. | ||
314 | * NOTE: Exact cause of failure will be recorded in syslog. | ||
315 | */ | ||
316 | iucv_handle_t iucv_register_program (uchar pgmname[16], | ||
317 | uchar userid[8], | ||
318 | uchar pgmmask[24], | ||
319 | iucv_interrupt_ops_t * ops, | ||
320 | void *pgm_data); | ||
321 | |||
322 | /* | ||
323 | * Name: iucv_unregister_program | ||
324 | * Purpose: Unregister application with IUCV | ||
325 | * Input: address of handler | ||
326 | * Output: NA | ||
327 | * Return: (0) - Normal return | ||
328 | * (-EINVAL) - Internal error, wild pointer | ||
329 | */ | ||
330 | int iucv_unregister_program (iucv_handle_t handle); | ||
331 | |||
332 | /* | ||
333 | * Name: iucv_accept | ||
334 | * Purpose: This function is issued after the user receives a Connection Pending external | ||
335 | * interrupt and now wishes to complete the IUCV communication path. | ||
336 | * Input: pathid - u16 , Path identification number | ||
337 | * msglim_reqstd - u16, The number of outstanding messages requested. | ||
338 | * user_data - uchar[16], Data specified by the iucv_connect function. | ||
339 | * flags1 - int, Contains options for this path. | ||
340 | * -IPPRTY - 0x20- Specifies if you want to send priority message. | ||
341 | * -IPRMDATA - 0x80, Specifies whether your program can handle a message | ||
342 | * in the parameter list. | ||
343 | * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being | ||
344 | * established. | ||
345 | * handle - iucv_handle_t, Address of handler. | ||
346 | * pgm_data - void *, Application data passed to interrupt handlers. | ||
347 | * flags1_out - int * Contains information about the path | ||
348 | * - IPPRTY - 0x20, Indicates you may send priority messages. | ||
349 | * msglim - *u16, Number of outstanding messages. | ||
350 | * Output: return code from CP IUCV call. | ||
351 | */ | ||
352 | |||
353 | int iucv_accept (u16 pathid, | ||
354 | u16 msglim_reqstd, | ||
355 | uchar user_data[16], | ||
356 | int flags1, | ||
357 | iucv_handle_t handle, | ||
358 | void *pgm_data, int *flags1_out, u16 * msglim); | ||
359 | |||
360 | /* | ||
361 | * Name: iucv_connect | ||
362 | * Purpose: This function establishes an IUCV path. Although the connect may complete | ||
363 | * successfully, you are not able to use the path until you receive an IUCV | ||
364 | * Connection Complete external interrupt. | ||
365 | * Input: pathid - u16 *, Path identification number | ||
366 | * msglim_reqstd - u16, Number of outstanding messages requested | ||
367 | * user_data - uchar[16], 16-byte user data | ||
368 | * userid - uchar[8], User identification | ||
369 | * system_name - uchar[8], 8-byte identifying the system name | ||
370 | * flags1 - int, Contains options for this path. | ||
371 | * -IPPRTY - 0x20, Specifies if you want to send priority message. | ||
372 | * -IPRMDATA - 0x80, Specifies whether your program can handle a message | ||
373 | * in the parameter list. | ||
374 | * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being | ||
375 | * established. | ||
376 | * -IPLOCAL - 0X01, Allows an application to force the partner to be on | ||
377 | * the local system. If local is specified then target class cannot be | ||
378 | * specified. | ||
379 | * flags1_out - int * Contains information about the path | ||
380 | * - IPPRTY - 0x20, Indicates you may send priority messages. | ||
381 | * msglim - * u16, Number of outstanding messages | ||
382 | * handle - iucv_handle_t, Address of handler | ||
383 | * pgm_data - void *, Application data passed to interrupt handlers | ||
384 | * Output: return code from CP IUCV call | ||
385 | * rc - return code from iucv_declare_buffer | ||
386 | * -EINVAL - Invalid handle passed by application | ||
387 | * -EINVAL - Pathid address is NULL | ||
388 | * add_pathid_result - Return code from internal function add_pathid | ||
389 | */ | ||
390 | int | ||
391 | iucv_connect (u16 * pathid, | ||
392 | u16 msglim_reqstd, | ||
393 | uchar user_data[16], | ||
394 | uchar userid[8], | ||
395 | uchar system_name[8], | ||
396 | int flags1, | ||
397 | int *flags1_out, | ||
398 | u16 * msglim, iucv_handle_t handle, void *pgm_data); | ||
399 | |||
400 | /* | ||
401 | * Name: iucv_purge | ||
402 | * Purpose: This function cancels a message that you have sent. | ||
403 | * Input: pathid - Path identification number. | ||
404 | * msgid - Specifies the message ID of the message to be purged. | ||
405 | * srccls - Specifies the source message class. | ||
406 | * Output: audit - Contains information about asynchronous error | ||
407 | * that may have affected the normal completion | ||
408 | * of this message. | ||
409 | * Return: Return code from CP IUCV call. | ||
410 | */ | ||
411 | int iucv_purge (u16 pathid, u32 msgid, u32 srccls, __u32 *audit); | ||
412 | /* | ||
413 | * Name: iucv_query_maxconn | ||
414 | * Purpose: This function determines the maximum number of communication paths you | ||
415 | * may establish. | ||
416 | * Return: maxconn - ulong, Maximum number of connection the virtual machine may | ||
417 | * establish. | ||
418 | */ | ||
419 | ulong iucv_query_maxconn (void); | ||
420 | |||
421 | /* | ||
422 | * Name: iucv_query_bufsize | ||
423 | * Purpose: This function determines how large an external interrupt | ||
424 | * buffer IUCV requires to store information. | ||
425 | * Return: bufsize - ulong, Size of external interrupt buffer. | ||
426 | */ | ||
427 | ulong iucv_query_bufsize (void); | ||
428 | |||
429 | /* | ||
430 | * Name: iucv_quiesce | ||
431 | * Purpose: This function temporarily suspends incoming messages on an | ||
432 | * IUCV path. You can later reactivate the path by invoking | ||
433 | * the iucv_resume function. | ||
434 | * Input: pathid - Path identification number | ||
435 | * user_data - 16-bytes of user data | ||
436 | * Output: NA | ||
437 | * Return: Return code from CP IUCV call. | ||
438 | */ | ||
439 | int iucv_quiesce (u16 pathid, uchar user_data[16]); | ||
440 | |||
441 | /* | ||
442 | * Name: iucv_receive | ||
443 | * Purpose: This function receives messages that are being sent to you | ||
444 | * over established paths. Data will be returned in buffer for length of | ||
445 | * buflen. | ||
446 | * Input: | ||
447 | * pathid - Path identification number. | ||
448 | * buffer - Address of buffer to receive. | ||
449 | * buflen - Length of buffer to receive. | ||
450 | * msgid - Specifies the message ID. | ||
451 | * trgcls - Specifies target class. | ||
452 | * Output: | ||
453 | * flags1_out: int *, Contains information about this path. | ||
454 | * IPNORPY - 0x10 Specifies this is a one-way message and no reply is | ||
455 | * expected. | ||
456 | * IPPRTY - 0x20 Specifies if you want to send priority message. | ||
457 | * IPRMDATA - 0x80 specifies the data is contained in the parameter list | ||
458 | * residual_buffer - address of buffer updated by the number | ||
459 | * of bytes you have received. | ||
460 | * residual_length - | ||
461 | * Contains one of the following values, if the receive buffer is: | ||
462 | * The same length as the message, this field is zero. | ||
463 | * Longer than the message, this field contains the number of | ||
464 | * bytes remaining in the buffer. | ||
465 | * Shorter than the message, this field contains the residual | ||
466 | * count (that is, the number of bytes remaining in the | ||
467 | * message that does not fit into the buffer. In this | ||
468 | * case b2f0_result = 5. | ||
469 | * Return: Return code from CP IUCV call. | ||
470 | * (-EINVAL) - buffer address is pointing to NULL | ||
471 | */ | ||
472 | int iucv_receive (u16 pathid, | ||
473 | u32 msgid, | ||
474 | u32 trgcls, | ||
475 | void *buffer, | ||
476 | ulong buflen, | ||
477 | int *flags1_out, | ||
478 | ulong * residual_buffer, ulong * residual_length); | ||
479 | |||
480 | /* | ||
481 | * Name: iucv_receive_array | ||
482 | * Purpose: This function receives messages that are being sent to you | ||
483 | * over established paths. Data will be returned in first buffer for | ||
484 | * length of first buffer. | ||
485 | * Input: pathid - Path identification number. | ||
486 | * msgid - specifies the message ID. | ||
487 | * trgcls - Specifies target class. | ||
488 | * buffer - Address of array of buffers. | ||
489 | * buflen - Total length of buffers. | ||
490 | * Output: | ||
491 | * flags1_out: int *, Contains information about this path. | ||
492 | * IPNORPY - 0x10 Specifies this is a one-way message and no reply is | ||
493 | * expected. | ||
494 | * IPPRTY - 0x20 Specifies if you want to send priority message. | ||
495 | * IPRMDATA - 0x80 specifies the data is contained in the parameter list | ||
496 | * residual_buffer - address points to the current list entry IUCV | ||
497 | * is working on. | ||
498 | * residual_length - | ||
499 | * Contains one of the following values, if the receive buffer is: | ||
500 | * The same length as the message, this field is zero. | ||
501 | * Longer than the message, this field contains the number of | ||
502 | * bytes remaining in the buffer. | ||
503 | * Shorter than the message, this field contains the residual | ||
504 | * count (that is, the number of bytes remaining in the | ||
505 | * message that does not fit into the buffer. In this | ||
506 | * case b2f0_result = 5. | ||
507 | * Return: Return code from CP IUCV call. | ||
508 | * (-EINVAL) - Buffer address is NULL. | ||
509 | */ | ||
510 | int iucv_receive_array (u16 pathid, | ||
511 | u32 msgid, | ||
512 | u32 trgcls, | ||
513 | iucv_array_t * buffer, | ||
514 | ulong buflen, | ||
515 | int *flags1_out, | ||
516 | ulong * residual_buffer, ulong * residual_length); | ||
517 | |||
518 | /* | ||
519 | * Name: iucv_reject | ||
520 | * Purpose: The reject function refuses a specified message. Between the | ||
521 | * time you are notified of a message and the time that you | ||
522 | * complete the message, the message may be rejected. | ||
523 | * Input: pathid - Path identification number. | ||
524 | * msgid - Specifies the message ID. | ||
525 | * trgcls - Specifies target class. | ||
526 | * Output: NA | ||
527 | * Return: Return code from CP IUCV call. | ||
528 | */ | ||
529 | int iucv_reject (u16 pathid, u32 msgid, u32 trgcls); | ||
530 | |||
531 | /* | ||
532 | * Name: iucv_reply | ||
533 | * Purpose: This function responds to the two-way messages that you | ||
534 | * receive. You must identify completely the message to | ||
535 | * which you wish to reply. ie, pathid, msgid, and trgcls. | ||
536 | * Input: pathid - Path identification number. | ||
537 | * msgid - Specifies the message ID. | ||
538 | * trgcls - Specifies target class. | ||
539 | * flags1 - Option for path. | ||
540 | * IPPRTY- 0x20, Specifies if you want to send priority message. | ||
541 | * buffer - Address of reply buffer. | ||
542 | * buflen - Length of reply buffer. | ||
543 | * Output: residual_buffer - Address of buffer updated by the number | ||
544 | * of bytes you have moved. | ||
545 | * residual_length - Contains one of the following values: | ||
546 | * If the answer buffer is the same length as the reply, this field | ||
547 | * contains zero. | ||
548 | * If the answer buffer is longer than the reply, this field contains | ||
549 | * the number of bytes remaining in the buffer. | ||
550 | * If the answer buffer is shorter than the reply, this field contains | ||
551 | * a residual count (that is, the number of bytes remianing in the | ||
552 | * reply that does not fit into the buffer. In this | ||
553 | * case b2f0_result = 5. | ||
554 | * Return: Return code from CP IUCV call. | ||
555 | * (-EINVAL) - Buffer address is NULL. | ||
556 | */ | ||
557 | int iucv_reply (u16 pathid, | ||
558 | u32 msgid, | ||
559 | u32 trgcls, | ||
560 | int flags1, | ||
561 | void *buffer, ulong buflen, ulong * residual_buffer, | ||
562 | ulong * residual_length); | ||
563 | |||
564 | /* | ||
565 | * Name: iucv_reply_array | ||
566 | * Purpose: This function responds to the two-way messages that you | ||
567 | * receive. You must identify completely the message to | ||
568 | * which you wish to reply. ie, pathid, msgid, and trgcls. | ||
569 | * The array identifies a list of addresses and lengths of | ||
570 | * discontiguous buffers that contains the reply data. | ||
571 | * Input: pathid - Path identification number | ||
572 | * msgid - Specifies the message ID. | ||
573 | * trgcls - Specifies target class. | ||
574 | * flags1 - Option for path. | ||
575 | * IPPRTY- 0x20, Specifies if you want to send priority message. | ||
576 | * buffer - Address of array of reply buffers. | ||
577 | * buflen - Total length of reply buffers. | ||
578 | * Output: residual_buffer - Address of buffer which IUCV is currently working on. | ||
579 | * residual_length - Contains one of the following values: | ||
580 | * If the answer buffer is the same length as the reply, this field | ||
581 | * contains zero. | ||
582 | * If the answer buffer is longer than the reply, this field contains | ||
583 | * the number of bytes remaining in the buffer. | ||
584 | * If the answer buffer is shorter than the reply, this field contains | ||
585 | * a residual count (that is, the number of bytes remianing in the | ||
586 | * reply that does not fit into the buffer. In this | ||
587 | * case b2f0_result = 5. | ||
588 | * Return: Return code from CP IUCV call. | ||
589 | * (-EINVAL) - Buffer address is NULL. | ||
590 | */ | ||
591 | int iucv_reply_array (u16 pathid, | ||
592 | u32 msgid, | ||
593 | u32 trgcls, | ||
594 | int flags1, | ||
595 | iucv_array_t * buffer, | ||
596 | ulong buflen, ulong * residual_address, | ||
597 | ulong * residual_length); | ||
598 | |||
599 | /* | ||
600 | * Name: iucv_reply_prmmsg | ||
601 | * Purpose: This function responds to the two-way messages that you | ||
602 | * receive. You must identify completely the message to | ||
603 | * which you wish to reply. ie, pathid, msgid, and trgcls. | ||
604 | * Prmmsg signifies the data is moved into the | ||
605 | * parameter list. | ||
606 | * Input: pathid - Path identification number. | ||
607 | * msgid - Specifies the message ID. | ||
608 | * trgcls - Specifies target class. | ||
609 | * flags1 - Option for path. | ||
610 | * IPPRTY- 0x20 Specifies if you want to send priority message. | ||
611 | * prmmsg - 8-bytes of data to be placed into the parameter. | ||
612 | * list. | ||
613 | * Output: NA | ||
614 | * Return: Return code from CP IUCV call. | ||
615 | */ | ||
616 | int iucv_reply_prmmsg (u16 pathid, | ||
617 | u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]); | ||
618 | |||
619 | /* | ||
620 | * Name: iucv_resume | ||
621 | * Purpose: This function restores communications over a quiesced path | ||
622 | * Input: pathid - Path identification number. | ||
623 | * user_data - 16-bytes of user data. | ||
624 | * Output: NA | ||
625 | * Return: Return code from CP IUCV call. | ||
626 | */ | ||
627 | int iucv_resume (u16 pathid, uchar user_data[16]); | ||
628 | |||
629 | /* | ||
630 | * Name: iucv_send | ||
631 | * Purpose: This function transmits data to another application. | ||
632 | * Data to be transmitted is in a buffer and this is a | ||
633 | * one-way message and the receiver will not reply to the | ||
634 | * message. | ||
635 | * Input: pathid - Path identification number. | ||
636 | * trgcls - Specifies target class. | ||
637 | * srccls - Specifies the source message class. | ||
638 | * msgtag - Specifies a tag to be associated with the message. | ||
639 | * flags1 - Option for path. | ||
640 | * IPPRTY- 0x20 Specifies if you want to send priority message. | ||
641 | * buffer - Address of send buffer. | ||
642 | * buflen - Length of send buffer. | ||
643 | * Output: msgid - Specifies the message ID. | ||
644 | * Return: Return code from CP IUCV call. | ||
645 | * (-EINVAL) - Buffer address is NULL. | ||
646 | */ | ||
647 | int iucv_send (u16 pathid, | ||
648 | u32 * msgid, | ||
649 | u32 trgcls, | ||
650 | u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen); | ||
651 | |||
652 | /* | ||
653 | * Name: iucv_send_array | ||
654 | * Purpose: This function transmits data to another application. | ||
655 | * The contents of buffer is the address of the array of | ||
656 | * addresses and lengths of discontiguous buffers that hold | ||
657 | * the message text. This is a one-way message and the | ||
658 | * receiver will not reply to the message. | ||
659 | * Input: pathid - Path identification number. | ||
660 | * trgcls - Specifies target class. | ||
661 | * srccls - Specifies the source message class. | ||
662 | * msgtag - Specifies a tag to be associated witht the message. | ||
663 | * flags1 - Option for path. | ||
664 | * IPPRTY- specifies if you want to send priority message. | ||
665 | * buffer - Address of array of send buffers. | ||
666 | * buflen - Total length of send buffers. | ||
667 | * Output: msgid - Specifies the message ID. | ||
668 | * Return: Return code from CP IUCV call. | ||
669 | * (-EINVAL) - Buffer address is NULL. | ||
670 | */ | ||
671 | int iucv_send_array (u16 pathid, | ||
672 | u32 * msgid, | ||
673 | u32 trgcls, | ||
674 | u32 srccls, | ||
675 | u32 msgtag, | ||
676 | int flags1, iucv_array_t * buffer, ulong buflen); | ||
677 | |||
678 | /* | ||
679 | * Name: iucv_send_prmmsg | ||
680 | * Purpose: This function transmits data to another application. | ||
681 | * Prmmsg specifies that the 8-bytes of data are to be moved | ||
682 | * into the parameter list. This is a one-way message and the | ||
683 | * receiver will not reply to the message. | ||
684 | * Input: pathid - Path identification number. | ||
685 | * trgcls - Specifies target class. | ||
686 | * srccls - Specifies the source message class. | ||
687 | * msgtag - Specifies a tag to be associated with the message. | ||
688 | * flags1 - Option for path. | ||
689 | * IPPRTY- 0x20 specifies if you want to send priority message. | ||
690 | * prmmsg - 8-bytes of data to be placed into parameter list. | ||
691 | * Output: msgid - Specifies the message ID. | ||
692 | * Return: Return code from CP IUCV call. | ||
693 | */ | ||
694 | int iucv_send_prmmsg (u16 pathid, | ||
695 | u32 * msgid, | ||
696 | u32 trgcls, | ||
697 | u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]); | ||
698 | |||
699 | /* | ||
700 | * Name: iucv_send2way | ||
701 | * Purpose: This function transmits data to another application. | ||
702 | * Data to be transmitted is in a buffer. The receiver | ||
703 | * of the send is expected to reply to the message and | ||
704 | * a buffer is provided into which IUCV moves the reply | ||
705 | * to this message. | ||
706 | * Input: pathid - Path identification number. | ||
707 | * trgcls - Specifies target class. | ||
708 | * srccls - Specifies the source message class. | ||
709 | * msgtag - Specifies a tag associated with the message. | ||
710 | * flags1 - Option for path. | ||
711 | * IPPRTY- 0x20 Specifies if you want to send priority message. | ||
712 | * buffer - Address of send buffer. | ||
713 | * buflen - Length of send buffer. | ||
714 | * ansbuf - Address of buffer into which IUCV moves the reply of | ||
715 | * this message. | ||
716 | * anslen - Address of length of buffer. | ||
717 | * Output: msgid - Specifies the message ID. | ||
718 | * Return: Return code from CP IUCV call. | ||
719 | * (-EINVAL) - Buffer or ansbuf address is NULL. | ||
720 | */ | ||
721 | int iucv_send2way (u16 pathid, | ||
722 | u32 * msgid, | ||
723 | u32 trgcls, | ||
724 | u32 srccls, | ||
725 | u32 msgtag, | ||
726 | int flags1, | ||
727 | void *buffer, ulong buflen, void *ansbuf, ulong anslen); | ||
728 | |||
729 | /* | ||
730 | * Name: iucv_send2way_array | ||
731 | * Purpose: This function transmits data to another application. | ||
732 | * The contents of buffer is the address of the array of | ||
733 | * addresses and lengths of discontiguous buffers that hold | ||
734 | * the message text. The receiver of the send is expected to | ||
735 | * reply to the message and a buffer is provided into which | ||
736 | * IUCV moves the reply to this message. | ||
737 | * Input: pathid - Path identification number. | ||
738 | * trgcls - Specifies target class. | ||
739 | * srccls - Specifies the source message class. | ||
740 | * msgtag - Specifies a tag to be associated with the message. | ||
741 | * flags1 - Option for path. | ||
742 | * IPPRTY- 0x20 Specifies if you want to send priority message. | ||
743 | * buffer - Sddress of array of send buffers. | ||
744 | * buflen - Total length of send buffers. | ||
745 | * ansbuf - Address of array of buffer into which IUCV moves the reply | ||
746 | * of this message. | ||
747 | * anslen - Address of length reply buffers. | ||
748 | * Output: msgid - Specifies the message ID. | ||
749 | * Return: Return code from CP IUCV call. | ||
750 | * (-EINVAL) - Buffer address is NULL. | ||
751 | */ | ||
752 | int iucv_send2way_array (u16 pathid, | ||
753 | u32 * msgid, | ||
754 | u32 trgcls, | ||
755 | u32 srccls, | ||
756 | u32 msgtag, | ||
757 | int flags1, | ||
758 | iucv_array_t * buffer, | ||
759 | ulong buflen, iucv_array_t * ansbuf, ulong anslen); | ||
760 | |||
761 | /* | ||
762 | * Name: iucv_send2way_prmmsg | ||
763 | * Purpose: This function transmits data to another application. | ||
764 | * Prmmsg specifies that the 8-bytes of data are to be moved | ||
765 | * into the parameter list. This is a two-way message and the | ||
766 | * receiver of the message is expected to reply. A buffer | ||
767 | * is provided into which IUCV moves the reply to this | ||
768 | * message. | ||
769 | * Input: pathid - Rath identification number. | ||
770 | * trgcls - Specifies target class. | ||
771 | * srccls - Specifies the source message class. | ||
772 | * msgtag - Specifies a tag to be associated with the message. | ||
773 | * flags1 - Option for path. | ||
774 | * IPPRTY- 0x20 Specifies if you want to send priority message. | ||
775 | * prmmsg - 8-bytes of data to be placed in parameter list. | ||
776 | * ansbuf - Address of buffer into which IUCV moves the reply of | ||
777 | * this message. | ||
778 | * anslen - Address of length of buffer. | ||
779 | * Output: msgid - Specifies the message ID. | ||
780 | * Return: Return code from CP IUCV call. | ||
781 | * (-EINVAL) - Buffer address is NULL. | ||
782 | */ | ||
783 | int iucv_send2way_prmmsg (u16 pathid, | ||
784 | u32 * msgid, | ||
785 | u32 trgcls, | ||
786 | u32 srccls, | ||
787 | u32 msgtag, | ||
788 | ulong flags1, | ||
789 | uchar prmmsg[8], void *ansbuf, ulong anslen); | ||
790 | |||
791 | /* | ||
792 | * Name: iucv_send2way_prmmsg_array | ||
793 | * Purpose: This function transmits data to another application. | ||
794 | * Prmmsg specifies that the 8-bytes of data are to be moved | ||
795 | * into the parameter list. This is a two-way message and the | ||
796 | * receiver of the message is expected to reply. A buffer | ||
797 | * is provided into which IUCV moves the reply to this | ||
798 | * message. The contents of ansbuf is the address of the | ||
799 | * array of addresses and lengths of discontiguous buffers | ||
800 | * that contain the reply. | ||
801 | * Input: pathid - Path identification number. | ||
802 | * trgcls - Specifies target class. | ||
803 | * srccls - Specifies the source message class. | ||
804 | * msgtag - Specifies a tag to be associated with the message. | ||
805 | * flags1 - Option for path. | ||
806 | * IPPRTY- 0x20 specifies if you want to send priority message. | ||
807 | * prmmsg - 8-bytes of data to be placed into the parameter list. | ||
808 | * ansbuf - Address of array of buffer into which IUCV moves the reply | ||
809 | * of this message. | ||
810 | * anslen - Address of length of reply buffers. | ||
811 | * Output: msgid - Specifies the message ID. | ||
812 | * Return: Return code from CP IUCV call. | ||
813 | * (-EINVAL) - Ansbuf address is NULL. | ||
814 | */ | ||
815 | int iucv_send2way_prmmsg_array (u16 pathid, | ||
816 | u32 * msgid, | ||
817 | u32 trgcls, | ||
818 | u32 srccls, | ||
819 | u32 msgtag, | ||
820 | int flags1, | ||
821 | uchar prmmsg[8], | ||
822 | iucv_array_t * ansbuf, ulong anslen); | ||
823 | |||
824 | /* | ||
825 | * Name: iucv_setmask | ||
826 | * Purpose: This function enables or disables the following IUCV | ||
827 | * external interruptions: Nonpriority and priority message | ||
828 | * interrupts, nonpriority and priority reply interrupts. | ||
829 | * Input: SetMaskFlag - options for interrupts | ||
830 | * 0x80 - Nonpriority_MessagePendingInterruptsFlag | ||
831 | * 0x40 - Priority_MessagePendingInterruptsFlag | ||
832 | * 0x20 - Nonpriority_MessageCompletionInterruptsFlag | ||
833 | * 0x10 - Priority_MessageCompletionInterruptsFlag | ||
834 | * 0x08 - IUCVControlInterruptsFlag | ||
835 | * Output: NA | ||
836 | * Return: Return code from CP IUCV call. | ||
837 | */ | ||
838 | int iucv_setmask (int SetMaskFlag); | ||
839 | |||
840 | /* | ||
841 | * Name: iucv_sever | ||
842 | * Purpose: This function terminates an IUCV path. | ||
843 | * Input: pathid - Path identification number. | ||
844 | * user_data - 16-bytes of user data. | ||
845 | * Output: NA | ||
846 | * Return: Return code from CP IUCV call. | ||
847 | * (-EINVAL) - Interal error, wild pointer. | ||
848 | */ | ||
849 | int iucv_sever (u16 pathid, uchar user_data[16]); | ||
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 3346088f47e0..6387b483f2bf 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV network driver | 2 | * IUCV network driver |
3 | * | 3 | * |
4 | * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation |
5 | * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | 5 | * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) |
6 | * | 6 | * |
7 | * Sysfs integration and all bugs therein by Cornelia Huck | 7 | * Sysfs integration and all bugs therein by Cornelia Huck |
@@ -58,13 +58,94 @@ | |||
58 | #include <asm/io.h> | 58 | #include <asm/io.h> |
59 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
60 | 60 | ||
61 | #include "iucv.h" | 61 | #include <net/iucv/iucv.h> |
62 | #include "fsm.h" | 62 | #include "fsm.h" |
63 | 63 | ||
64 | MODULE_AUTHOR | 64 | MODULE_AUTHOR |
65 | ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); | 65 | ("(C) 2001 IBM Corporation by Fritz Elfert (felfert@millenux.com)"); |
66 | MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); | 66 | MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver"); |
67 | 67 | ||
68 | /** | ||
69 | * Debug Facility stuff | ||
70 | */ | ||
71 | #define IUCV_DBF_SETUP_NAME "iucv_setup" | ||
72 | #define IUCV_DBF_SETUP_LEN 32 | ||
73 | #define IUCV_DBF_SETUP_PAGES 2 | ||
74 | #define IUCV_DBF_SETUP_NR_AREAS 1 | ||
75 | #define IUCV_DBF_SETUP_LEVEL 3 | ||
76 | |||
77 | #define IUCV_DBF_DATA_NAME "iucv_data" | ||
78 | #define IUCV_DBF_DATA_LEN 128 | ||
79 | #define IUCV_DBF_DATA_PAGES 2 | ||
80 | #define IUCV_DBF_DATA_NR_AREAS 1 | ||
81 | #define IUCV_DBF_DATA_LEVEL 2 | ||
82 | |||
83 | #define IUCV_DBF_TRACE_NAME "iucv_trace" | ||
84 | #define IUCV_DBF_TRACE_LEN 16 | ||
85 | #define IUCV_DBF_TRACE_PAGES 4 | ||
86 | #define IUCV_DBF_TRACE_NR_AREAS 1 | ||
87 | #define IUCV_DBF_TRACE_LEVEL 3 | ||
88 | |||
89 | #define IUCV_DBF_TEXT(name,level,text) \ | ||
90 | do { \ | ||
91 | debug_text_event(iucv_dbf_##name,level,text); \ | ||
92 | } while (0) | ||
93 | |||
94 | #define IUCV_DBF_HEX(name,level,addr,len) \ | ||
95 | do { \ | ||
96 | debug_event(iucv_dbf_##name,level,(void*)(addr),len); \ | ||
97 | } while (0) | ||
98 | |||
99 | DECLARE_PER_CPU(char[256], iucv_dbf_txt_buf); | ||
100 | |||
101 | #define IUCV_DBF_TEXT_(name,level,text...) \ | ||
102 | do { \ | ||
103 | char* iucv_dbf_txt_buf = get_cpu_var(iucv_dbf_txt_buf); \ | ||
104 | sprintf(iucv_dbf_txt_buf, text); \ | ||
105 | debug_text_event(iucv_dbf_##name,level,iucv_dbf_txt_buf); \ | ||
106 | put_cpu_var(iucv_dbf_txt_buf); \ | ||
107 | } while (0) | ||
108 | |||
109 | #define IUCV_DBF_SPRINTF(name,level,text...) \ | ||
110 | do { \ | ||
111 | debug_sprintf_event(iucv_dbf_trace, level, ##text ); \ | ||
112 | debug_sprintf_event(iucv_dbf_trace, level, text ); \ | ||
113 | } while (0) | ||
114 | |||
115 | /** | ||
116 | * some more debug stuff | ||
117 | */ | ||
118 | #define IUCV_HEXDUMP16(importance,header,ptr) \ | ||
119 | PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | ||
120 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ | ||
121 | *(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \ | ||
122 | *(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \ | ||
123 | *(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \ | ||
124 | *(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \ | ||
125 | *(((char*)ptr)+12),*(((char*)ptr)+13), \ | ||
126 | *(((char*)ptr)+14),*(((char*)ptr)+15)); \ | ||
127 | PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | ||
128 | "%02x %02x %02x %02x %02x %02x %02x %02x\n", \ | ||
129 | *(((char*)ptr)+16),*(((char*)ptr)+17), \ | ||
130 | *(((char*)ptr)+18),*(((char*)ptr)+19), \ | ||
131 | *(((char*)ptr)+20),*(((char*)ptr)+21), \ | ||
132 | *(((char*)ptr)+22),*(((char*)ptr)+23), \ | ||
133 | *(((char*)ptr)+24),*(((char*)ptr)+25), \ | ||
134 | *(((char*)ptr)+26),*(((char*)ptr)+27), \ | ||
135 | *(((char*)ptr)+28),*(((char*)ptr)+29), \ | ||
136 | *(((char*)ptr)+30),*(((char*)ptr)+31)); | ||
137 | |||
138 | static inline void iucv_hex_dump(unsigned char *buf, size_t len) | ||
139 | { | ||
140 | size_t i; | ||
141 | |||
142 | for (i = 0; i < len; i++) { | ||
143 | if (i && !(i % 16)) | ||
144 | printk("\n"); | ||
145 | printk("%02x ", *(buf + i)); | ||
146 | } | ||
147 | printk("\n"); | ||
148 | } | ||
68 | 149 | ||
69 | #define PRINTK_HEADER " iucv: " /* for debugging */ | 150 | #define PRINTK_HEADER " iucv: " /* for debugging */ |
70 | 151 | ||
@@ -73,6 +154,25 @@ static struct device_driver netiucv_driver = { | |||
73 | .bus = &iucv_bus, | 154 | .bus = &iucv_bus, |
74 | }; | 155 | }; |
75 | 156 | ||
157 | static int netiucv_callback_connreq(struct iucv_path *, | ||
158 | u8 ipvmid[8], u8 ipuser[16]); | ||
159 | static void netiucv_callback_connack(struct iucv_path *, u8 ipuser[16]); | ||
160 | static void netiucv_callback_connrej(struct iucv_path *, u8 ipuser[16]); | ||
161 | static void netiucv_callback_connsusp(struct iucv_path *, u8 ipuser[16]); | ||
162 | static void netiucv_callback_connres(struct iucv_path *, u8 ipuser[16]); | ||
163 | static void netiucv_callback_rx(struct iucv_path *, struct iucv_message *); | ||
164 | static void netiucv_callback_txdone(struct iucv_path *, struct iucv_message *); | ||
165 | |||
166 | static struct iucv_handler netiucv_handler = { | ||
167 | .path_pending = netiucv_callback_connreq, | ||
168 | .path_complete = netiucv_callback_connack, | ||
169 | .path_severed = netiucv_callback_connrej, | ||
170 | .path_quiesced = netiucv_callback_connsusp, | ||
171 | .path_resumed = netiucv_callback_connres, | ||
172 | .message_pending = netiucv_callback_rx, | ||
173 | .message_complete = netiucv_callback_txdone | ||
174 | }; | ||
175 | |||
76 | /** | 176 | /** |
77 | * Per connection profiling data | 177 | * Per connection profiling data |
78 | */ | 178 | */ |
@@ -92,9 +192,8 @@ struct connection_profile { | |||
92 | * Representation of one iucv connection | 192 | * Representation of one iucv connection |
93 | */ | 193 | */ |
94 | struct iucv_connection { | 194 | struct iucv_connection { |
95 | struct iucv_connection *next; | 195 | struct list_head list; |
96 | iucv_handle_t handle; | 196 | struct iucv_path *path; |
97 | __u16 pathid; | ||
98 | struct sk_buff *rx_buff; | 197 | struct sk_buff *rx_buff; |
99 | struct sk_buff *tx_buff; | 198 | struct sk_buff *tx_buff; |
100 | struct sk_buff_head collect_queue; | 199 | struct sk_buff_head collect_queue; |
@@ -112,12 +211,9 @@ struct iucv_connection { | |||
112 | /** | 211 | /** |
113 | * Linked list of all connection structs. | 212 | * Linked list of all connection structs. |
114 | */ | 213 | */ |
115 | struct iucv_connection_struct { | 214 | static struct list_head iucv_connection_list = |
116 | struct iucv_connection *iucv_connections; | 215 | LIST_HEAD_INIT(iucv_connection_list); |
117 | rwlock_t iucv_rwlock; | 216 | static rwlock_t iucv_connection_rwlock = RW_LOCK_UNLOCKED; |
118 | }; | ||
119 | |||
120 | static struct iucv_connection_struct iucv_conns; | ||
121 | 217 | ||
122 | /** | 218 | /** |
123 | * Representation of event-data for the | 219 | * Representation of event-data for the |
@@ -142,11 +238,11 @@ struct netiucv_priv { | |||
142 | /** | 238 | /** |
143 | * Link level header for a packet. | 239 | * Link level header for a packet. |
144 | */ | 240 | */ |
145 | typedef struct ll_header_t { | 241 | struct ll_header { |
146 | __u16 next; | 242 | u16 next; |
147 | } ll_header; | 243 | }; |
148 | 244 | ||
149 | #define NETIUCV_HDRLEN (sizeof(ll_header)) | 245 | #define NETIUCV_HDRLEN (sizeof(struct ll_header)) |
150 | #define NETIUCV_BUFSIZE_MAX 32768 | 246 | #define NETIUCV_BUFSIZE_MAX 32768 |
151 | #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX | 247 | #define NETIUCV_BUFSIZE_DEFAULT NETIUCV_BUFSIZE_MAX |
152 | #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) | 248 | #define NETIUCV_MTU_MAX (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN) |
@@ -158,36 +254,26 @@ typedef struct ll_header_t { | |||
158 | * Compatibility macros for busy handling | 254 | * Compatibility macros for busy handling |
159 | * of network devices. | 255 | * of network devices. |
160 | */ | 256 | */ |
161 | static __inline__ void netiucv_clear_busy(struct net_device *dev) | 257 | static inline void netiucv_clear_busy(struct net_device *dev) |
162 | { | 258 | { |
163 | clear_bit(0, &(((struct netiucv_priv *)dev->priv)->tbusy)); | 259 | struct netiucv_priv *priv = netdev_priv(dev); |
260 | clear_bit(0, &priv->tbusy); | ||
164 | netif_wake_queue(dev); | 261 | netif_wake_queue(dev); |
165 | } | 262 | } |
166 | 263 | ||
167 | static __inline__ int netiucv_test_and_set_busy(struct net_device *dev) | 264 | static inline int netiucv_test_and_set_busy(struct net_device *dev) |
168 | { | 265 | { |
266 | struct netiucv_priv *priv = netdev_priv(dev); | ||
169 | netif_stop_queue(dev); | 267 | netif_stop_queue(dev); |
170 | return test_and_set_bit(0, &((struct netiucv_priv *)dev->priv)->tbusy); | 268 | return test_and_set_bit(0, &priv->tbusy); |
171 | } | 269 | } |
172 | 270 | ||
173 | static __u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | 271 | static u8 iucvMagic[16] = { |
174 | static __u8 iucvMagic[16] = { | ||
175 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, | 272 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, |
176 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 | 273 | 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 |
177 | }; | 274 | }; |
178 | 275 | ||
179 | /** | 276 | /** |
180 | * This mask means the 16-byte IUCV "magic" and the origin userid must | ||
181 | * match exactly as specified in order to give connection_pending() | ||
182 | * control. | ||
183 | */ | ||
184 | static __u8 netiucv_mask[] = { | ||
185 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
186 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
187 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
188 | }; | ||
189 | |||
190 | /** | ||
191 | * Convert an iucv userId to its printable | 277 | * Convert an iucv userId to its printable |
192 | * form (strip whitespace at end). | 278 | * form (strip whitespace at end). |
193 | * | 279 | * |
@@ -195,8 +281,7 @@ static __u8 netiucv_mask[] = { | |||
195 | * | 281 | * |
196 | * @returns The printable string (static data!!) | 282 | * @returns The printable string (static data!!) |
197 | */ | 283 | */ |
198 | static __inline__ char * | 284 | static inline char *netiucv_printname(char *name) |
199 | netiucv_printname(char *name) | ||
200 | { | 285 | { |
201 | static char tmp[9]; | 286 | static char tmp[9]; |
202 | char *p = tmp; | 287 | char *p = tmp; |
@@ -379,8 +464,7 @@ static debug_info_t *iucv_dbf_trace = NULL; | |||
379 | 464 | ||
380 | DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); | 465 | DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf); |
381 | 466 | ||
382 | static void | 467 | static void iucv_unregister_dbf_views(void) |
383 | iucv_unregister_dbf_views(void) | ||
384 | { | 468 | { |
385 | if (iucv_dbf_setup) | 469 | if (iucv_dbf_setup) |
386 | debug_unregister(iucv_dbf_setup); | 470 | debug_unregister(iucv_dbf_setup); |
@@ -389,8 +473,7 @@ iucv_unregister_dbf_views(void) | |||
389 | if (iucv_dbf_trace) | 473 | if (iucv_dbf_trace) |
390 | debug_unregister(iucv_dbf_trace); | 474 | debug_unregister(iucv_dbf_trace); |
391 | } | 475 | } |
392 | static int | 476 | static int iucv_register_dbf_views(void) |
393 | iucv_register_dbf_views(void) | ||
394 | { | 477 | { |
395 | iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, | 478 | iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME, |
396 | IUCV_DBF_SETUP_PAGES, | 479 | IUCV_DBF_SETUP_PAGES, |
@@ -422,125 +505,111 @@ iucv_register_dbf_views(void) | |||
422 | return 0; | 505 | return 0; |
423 | } | 506 | } |
424 | 507 | ||
425 | /** | 508 | /* |
426 | * Callback-wrappers, called from lowlevel iucv layer. | 509 | * Callback-wrappers, called from lowlevel iucv layer. |
427 | *****************************************************************************/ | 510 | */ |
428 | 511 | ||
429 | static void | 512 | static void netiucv_callback_rx(struct iucv_path *path, |
430 | netiucv_callback_rx(iucv_MessagePending *eib, void *pgm_data) | 513 | struct iucv_message *msg) |
431 | { | 514 | { |
432 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 515 | struct iucv_connection *conn = path->private; |
433 | struct iucv_event ev; | 516 | struct iucv_event ev; |
434 | 517 | ||
435 | ev.conn = conn; | 518 | ev.conn = conn; |
436 | ev.data = (void *)eib; | 519 | ev.data = msg; |
437 | |||
438 | fsm_event(conn->fsm, CONN_EVENT_RX, &ev); | 520 | fsm_event(conn->fsm, CONN_EVENT_RX, &ev); |
439 | } | 521 | } |
440 | 522 | ||
441 | static void | 523 | static void netiucv_callback_txdone(struct iucv_path *path, |
442 | netiucv_callback_txdone(iucv_MessageComplete *eib, void *pgm_data) | 524 | struct iucv_message *msg) |
443 | { | 525 | { |
444 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 526 | struct iucv_connection *conn = path->private; |
445 | struct iucv_event ev; | 527 | struct iucv_event ev; |
446 | 528 | ||
447 | ev.conn = conn; | 529 | ev.conn = conn; |
448 | ev.data = (void *)eib; | 530 | ev.data = msg; |
449 | fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); | 531 | fsm_event(conn->fsm, CONN_EVENT_TXDONE, &ev); |
450 | } | 532 | } |
451 | 533 | ||
452 | static void | 534 | static void netiucv_callback_connack(struct iucv_path *path, u8 ipuser[16]) |
453 | netiucv_callback_connack(iucv_ConnectionComplete *eib, void *pgm_data) | ||
454 | { | 535 | { |
455 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 536 | struct iucv_connection *conn = path->private; |
456 | struct iucv_event ev; | ||
457 | 537 | ||
458 | ev.conn = conn; | 538 | fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, conn); |
459 | ev.data = (void *)eib; | ||
460 | fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev); | ||
461 | } | 539 | } |
462 | 540 | ||
463 | static void | 541 | static int netiucv_callback_connreq(struct iucv_path *path, |
464 | netiucv_callback_connreq(iucv_ConnectionPending *eib, void *pgm_data) | 542 | u8 ipvmid[8], u8 ipuser[16]) |
465 | { | 543 | { |
466 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 544 | struct iucv_connection *conn = path->private; |
467 | struct iucv_event ev; | 545 | struct iucv_event ev; |
546 | int rc; | ||
468 | 547 | ||
469 | ev.conn = conn; | 548 | if (memcmp(iucvMagic, ipuser, sizeof(ipuser))) |
470 | ev.data = (void *)eib; | 549 | /* ipuser must match iucvMagic. */ |
471 | fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); | 550 | return -EINVAL; |
551 | rc = -EINVAL; | ||
552 | read_lock_bh(&iucv_connection_rwlock); | ||
553 | list_for_each_entry(conn, &iucv_connection_list, list) { | ||
554 | if (strncmp(ipvmid, conn->userid, 8)) | ||
555 | continue; | ||
556 | /* Found a matching connection for this path. */ | ||
557 | conn->path = path; | ||
558 | ev.conn = conn; | ||
559 | ev.data = path; | ||
560 | fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev); | ||
561 | rc = 0; | ||
562 | } | ||
563 | read_unlock_bh(&iucv_connection_rwlock); | ||
564 | return rc; | ||
472 | } | 565 | } |
473 | 566 | ||
474 | static void | 567 | static void netiucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) |
475 | netiucv_callback_connrej(iucv_ConnectionSevered *eib, void *pgm_data) | ||
476 | { | 568 | { |
477 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 569 | struct iucv_connection *conn = path->private; |
478 | struct iucv_event ev; | ||
479 | 570 | ||
480 | ev.conn = conn; | 571 | fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, conn); |
481 | ev.data = (void *)eib; | ||
482 | fsm_event(conn->fsm, CONN_EVENT_CONN_REJ, &ev); | ||
483 | } | 572 | } |
484 | 573 | ||
485 | static void | 574 | static void netiucv_callback_connsusp(struct iucv_path *path, u8 ipuser[16]) |
486 | netiucv_callback_connsusp(iucv_ConnectionQuiesced *eib, void *pgm_data) | ||
487 | { | 575 | { |
488 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 576 | struct iucv_connection *conn = path->private; |
489 | struct iucv_event ev; | ||
490 | 577 | ||
491 | ev.conn = conn; | 578 | fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, conn); |
492 | ev.data = (void *)eib; | ||
493 | fsm_event(conn->fsm, CONN_EVENT_CONN_SUS, &ev); | ||
494 | } | 579 | } |
495 | 580 | ||
496 | static void | 581 | static void netiucv_callback_connres(struct iucv_path *path, u8 ipuser[16]) |
497 | netiucv_callback_connres(iucv_ConnectionResumed *eib, void *pgm_data) | ||
498 | { | 582 | { |
499 | struct iucv_connection *conn = (struct iucv_connection *)pgm_data; | 583 | struct iucv_connection *conn = path->private; |
500 | struct iucv_event ev; | ||
501 | 584 | ||
502 | ev.conn = conn; | 585 | fsm_event(conn->fsm, CONN_EVENT_CONN_RES, conn); |
503 | ev.data = (void *)eib; | 586 | } |
504 | fsm_event(conn->fsm, CONN_EVENT_CONN_RES, &ev); | ||
505 | } | ||
506 | |||
507 | static iucv_interrupt_ops_t netiucv_ops = { | ||
508 | .ConnectionPending = netiucv_callback_connreq, | ||
509 | .ConnectionComplete = netiucv_callback_connack, | ||
510 | .ConnectionSevered = netiucv_callback_connrej, | ||
511 | .ConnectionQuiesced = netiucv_callback_connsusp, | ||
512 | .ConnectionResumed = netiucv_callback_connres, | ||
513 | .MessagePending = netiucv_callback_rx, | ||
514 | .MessageComplete = netiucv_callback_txdone | ||
515 | }; | ||
516 | 587 | ||
517 | /** | 588 | /** |
518 | * Dummy NOP action for all statemachines | 589 | * Dummy NOP action for all statemachines |
519 | */ | 590 | */ |
520 | static void | 591 | static void fsm_action_nop(fsm_instance *fi, int event, void *arg) |
521 | fsm_action_nop(fsm_instance *fi, int event, void *arg) | ||
522 | { | 592 | { |
523 | } | 593 | } |
524 | 594 | ||
525 | /** | 595 | /* |
526 | * Actions of the connection statemachine | 596 | * Actions of the connection statemachine |
527 | *****************************************************************************/ | 597 | */ |
528 | 598 | ||
529 | /** | 599 | /** |
530 | * Helper function for conn_action_rx() | 600 | * netiucv_unpack_skb |
531 | * Unpack a just received skb and hand it over to | 601 | * @conn: The connection where this skb has been received. |
532 | * upper layers. | 602 | * @pskb: The received skb. |
533 | * | 603 | * |
534 | * @param conn The connection where this skb has been received. | 604 | * Unpack a just received skb and hand it over to upper layers. |
535 | * @param pskb The received skb. | 605 | * Helper function for conn_action_rx. |
536 | */ | 606 | */ |
537 | //static __inline__ void | 607 | static void netiucv_unpack_skb(struct iucv_connection *conn, |
538 | static void | 608 | struct sk_buff *pskb) |
539 | netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) | ||
540 | { | 609 | { |
541 | struct net_device *dev = conn->netdev; | 610 | struct net_device *dev = conn->netdev; |
542 | struct netiucv_priv *privptr = dev->priv; | 611 | struct netiucv_priv *privptr = netdev_priv(dev); |
543 | __u16 offset = 0; | 612 | u16 offset = 0; |
544 | 613 | ||
545 | skb_put(pskb, NETIUCV_HDRLEN); | 614 | skb_put(pskb, NETIUCV_HDRLEN); |
546 | pskb->dev = dev; | 615 | pskb->dev = dev; |
@@ -549,7 +618,7 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) | |||
549 | 618 | ||
550 | while (1) { | 619 | while (1) { |
551 | struct sk_buff *skb; | 620 | struct sk_buff *skb; |
552 | ll_header *header = (ll_header *)pskb->data; | 621 | struct ll_header *header = (struct ll_header *) pskb->data; |
553 | 622 | ||
554 | if (!header->next) | 623 | if (!header->next) |
555 | break; | 624 | break; |
@@ -595,40 +664,37 @@ netiucv_unpack_skb(struct iucv_connection *conn, struct sk_buff *pskb) | |||
595 | } | 664 | } |
596 | } | 665 | } |
597 | 666 | ||
598 | static void | 667 | static void conn_action_rx(fsm_instance *fi, int event, void *arg) |
599 | conn_action_rx(fsm_instance *fi, int event, void *arg) | ||
600 | { | 668 | { |
601 | struct iucv_event *ev = (struct iucv_event *)arg; | 669 | struct iucv_event *ev = arg; |
602 | struct iucv_connection *conn = ev->conn; | 670 | struct iucv_connection *conn = ev->conn; |
603 | iucv_MessagePending *eib = (iucv_MessagePending *)ev->data; | 671 | struct iucv_message *msg = ev->data; |
604 | struct netiucv_priv *privptr =(struct netiucv_priv *)conn->netdev->priv; | 672 | struct netiucv_priv *privptr = netdev_priv(conn->netdev); |
605 | |||
606 | __u32 msglen = eib->ln1msg2.ipbfln1f; | ||
607 | int rc; | 673 | int rc; |
608 | 674 | ||
609 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); | 675 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); |
610 | 676 | ||
611 | if (!conn->netdev) { | 677 | if (!conn->netdev) { |
612 | /* FRITZ: How to tell iucv LL to drop the msg? */ | 678 | iucv_message_reject(conn->path, msg); |
613 | PRINT_WARN("Received data for unlinked connection\n"); | 679 | PRINT_WARN("Received data for unlinked connection\n"); |
614 | IUCV_DBF_TEXT(data, 2, | 680 | IUCV_DBF_TEXT(data, 2, |
615 | "Received data for unlinked connection\n"); | 681 | "Received data for unlinked connection\n"); |
616 | return; | 682 | return; |
617 | } | 683 | } |
618 | if (msglen > conn->max_buffsize) { | 684 | if (msg->length > conn->max_buffsize) { |
619 | /* FRITZ: How to tell iucv LL to drop the msg? */ | 685 | iucv_message_reject(conn->path, msg); |
620 | privptr->stats.rx_dropped++; | 686 | privptr->stats.rx_dropped++; |
621 | PRINT_WARN("msglen %d > max_buffsize %d\n", | 687 | PRINT_WARN("msglen %d > max_buffsize %d\n", |
622 | msglen, conn->max_buffsize); | 688 | msg->length, conn->max_buffsize); |
623 | IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", | 689 | IUCV_DBF_TEXT_(data, 2, "msglen %d > max_buffsize %d\n", |
624 | msglen, conn->max_buffsize); | 690 | msg->length, conn->max_buffsize); |
625 | return; | 691 | return; |
626 | } | 692 | } |
627 | conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; | 693 | conn->rx_buff->data = conn->rx_buff->tail = conn->rx_buff->head; |
628 | conn->rx_buff->len = 0; | 694 | conn->rx_buff->len = 0; |
629 | rc = iucv_receive(conn->pathid, eib->ipmsgid, eib->iptrgcls, | 695 | rc = iucv_message_receive(conn->path, msg, 0, conn->rx_buff->data, |
630 | conn->rx_buff->data, msglen, NULL, NULL, NULL); | 696 | msg->length, NULL); |
631 | if (rc || msglen < 5) { | 697 | if (rc || msg->length < 5) { |
632 | privptr->stats.rx_errors++; | 698 | privptr->stats.rx_errors++; |
633 | PRINT_WARN("iucv_receive returned %08x\n", rc); | 699 | PRINT_WARN("iucv_receive returned %08x\n", rc); |
634 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); | 700 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_receive\n", rc); |
@@ -637,26 +703,26 @@ conn_action_rx(fsm_instance *fi, int event, void *arg) | |||
637 | netiucv_unpack_skb(conn, conn->rx_buff); | 703 | netiucv_unpack_skb(conn, conn->rx_buff); |
638 | } | 704 | } |
639 | 705 | ||
640 | static void | 706 | static void conn_action_txdone(fsm_instance *fi, int event, void *arg) |
641 | conn_action_txdone(fsm_instance *fi, int event, void *arg) | ||
642 | { | 707 | { |
643 | struct iucv_event *ev = (struct iucv_event *)arg; | 708 | struct iucv_event *ev = arg; |
644 | struct iucv_connection *conn = ev->conn; | 709 | struct iucv_connection *conn = ev->conn; |
645 | iucv_MessageComplete *eib = (iucv_MessageComplete *)ev->data; | 710 | struct iucv_message *msg = ev->data; |
711 | struct iucv_message txmsg; | ||
646 | struct netiucv_priv *privptr = NULL; | 712 | struct netiucv_priv *privptr = NULL; |
647 | /* Shut up, gcc! skb is always below 2G. */ | 713 | u32 single_flag = msg->tag; |
648 | __u32 single_flag = eib->ipmsgtag; | 714 | u32 txbytes = 0; |
649 | __u32 txbytes = 0; | 715 | u32 txpackets = 0; |
650 | __u32 txpackets = 0; | 716 | u32 stat_maxcq = 0; |
651 | __u32 stat_maxcq = 0; | ||
652 | struct sk_buff *skb; | 717 | struct sk_buff *skb; |
653 | unsigned long saveflags; | 718 | unsigned long saveflags; |
654 | ll_header header; | 719 | struct ll_header header; |
720 | int rc; | ||
655 | 721 | ||
656 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); | 722 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); |
657 | 723 | ||
658 | if (conn && conn->netdev && conn->netdev->priv) | 724 | if (conn && conn->netdev) |
659 | privptr = (struct netiucv_priv *)conn->netdev->priv; | 725 | privptr = netdev_priv(conn->netdev); |
660 | conn->prof.tx_pending--; | 726 | conn->prof.tx_pending--; |
661 | if (single_flag) { | 727 | if (single_flag) { |
662 | if ((skb = skb_dequeue(&conn->commit_queue))) { | 728 | if ((skb = skb_dequeue(&conn->commit_queue))) { |
@@ -688,56 +754,55 @@ conn_action_txdone(fsm_instance *fi, int event, void *arg) | |||
688 | conn->prof.maxmulti = conn->collect_len; | 754 | conn->prof.maxmulti = conn->collect_len; |
689 | conn->collect_len = 0; | 755 | conn->collect_len = 0; |
690 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); | 756 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); |
691 | if (conn->tx_buff->len) { | 757 | if (conn->tx_buff->len == 0) { |
692 | int rc; | 758 | fsm_newstate(fi, CONN_STATE_IDLE); |
693 | 759 | return; | |
694 | header.next = 0; | 760 | } |
695 | memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, | ||
696 | NETIUCV_HDRLEN); | ||
697 | 761 | ||
698 | conn->prof.send_stamp = xtime; | 762 | header.next = 0; |
699 | rc = iucv_send(conn->pathid, NULL, 0, 0, 0, 0, | 763 | memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN); |
764 | conn->prof.send_stamp = xtime; | ||
765 | txmsg.class = 0; | ||
766 | txmsg.tag = 0; | ||
767 | rc = iucv_message_send(conn->path, &txmsg, 0, 0, | ||
700 | conn->tx_buff->data, conn->tx_buff->len); | 768 | conn->tx_buff->data, conn->tx_buff->len); |
701 | conn->prof.doios_multi++; | 769 | conn->prof.doios_multi++; |
702 | conn->prof.txlen += conn->tx_buff->len; | 770 | conn->prof.txlen += conn->tx_buff->len; |
703 | conn->prof.tx_pending++; | 771 | conn->prof.tx_pending++; |
704 | if (conn->prof.tx_pending > conn->prof.tx_max_pending) | 772 | if (conn->prof.tx_pending > conn->prof.tx_max_pending) |
705 | conn->prof.tx_max_pending = conn->prof.tx_pending; | 773 | conn->prof.tx_max_pending = conn->prof.tx_pending; |
706 | if (rc) { | 774 | if (rc) { |
707 | conn->prof.tx_pending--; | 775 | conn->prof.tx_pending--; |
708 | fsm_newstate(fi, CONN_STATE_IDLE); | ||
709 | if (privptr) | ||
710 | privptr->stats.tx_errors += txpackets; | ||
711 | PRINT_WARN("iucv_send returned %08x\n", rc); | ||
712 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); | ||
713 | } else { | ||
714 | if (privptr) { | ||
715 | privptr->stats.tx_packets += txpackets; | ||
716 | privptr->stats.tx_bytes += txbytes; | ||
717 | } | ||
718 | if (stat_maxcq > conn->prof.maxcqueue) | ||
719 | conn->prof.maxcqueue = stat_maxcq; | ||
720 | } | ||
721 | } else | ||
722 | fsm_newstate(fi, CONN_STATE_IDLE); | 776 | fsm_newstate(fi, CONN_STATE_IDLE); |
777 | if (privptr) | ||
778 | privptr->stats.tx_errors += txpackets; | ||
779 | PRINT_WARN("iucv_send returned %08x\n", rc); | ||
780 | IUCV_DBF_TEXT_(data, 2, "rc %d from iucv_send\n", rc); | ||
781 | } else { | ||
782 | if (privptr) { | ||
783 | privptr->stats.tx_packets += txpackets; | ||
784 | privptr->stats.tx_bytes += txbytes; | ||
785 | } | ||
786 | if (stat_maxcq > conn->prof.maxcqueue) | ||
787 | conn->prof.maxcqueue = stat_maxcq; | ||
788 | } | ||
723 | } | 789 | } |
724 | 790 | ||
725 | static void | 791 | static void conn_action_connaccept(fsm_instance *fi, int event, void *arg) |
726 | conn_action_connaccept(fsm_instance *fi, int event, void *arg) | ||
727 | { | 792 | { |
728 | struct iucv_event *ev = (struct iucv_event *)arg; | 793 | struct iucv_event *ev = arg; |
729 | struct iucv_connection *conn = ev->conn; | 794 | struct iucv_connection *conn = ev->conn; |
730 | iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; | 795 | struct iucv_path *path = ev->data; |
731 | struct net_device *netdev = conn->netdev; | 796 | struct net_device *netdev = conn->netdev; |
732 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 797 | struct netiucv_priv *privptr = netdev_priv(netdev); |
733 | int rc; | 798 | int rc; |
734 | __u16 msglimit; | ||
735 | __u8 udata[16]; | ||
736 | 799 | ||
737 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 800 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
738 | 801 | ||
739 | rc = iucv_accept(eib->ippathid, NETIUCV_QUEUELEN_DEFAULT, udata, 0, | 802 | conn->path = path; |
740 | conn->handle, conn, NULL, &msglimit); | 803 | path->msglim = NETIUCV_QUEUELEN_DEFAULT; |
804 | path->flags = 0; | ||
805 | rc = iucv_path_accept(path, &netiucv_handler, NULL, conn); | ||
741 | if (rc) { | 806 | if (rc) { |
742 | PRINT_WARN("%s: IUCV accept failed with error %d\n", | 807 | PRINT_WARN("%s: IUCV accept failed with error %d\n", |
743 | netdev->name, rc); | 808 | netdev->name, rc); |
@@ -745,183 +810,126 @@ conn_action_connaccept(fsm_instance *fi, int event, void *arg) | |||
745 | return; | 810 | return; |
746 | } | 811 | } |
747 | fsm_newstate(fi, CONN_STATE_IDLE); | 812 | fsm_newstate(fi, CONN_STATE_IDLE); |
748 | conn->pathid = eib->ippathid; | 813 | netdev->tx_queue_len = conn->path->msglim; |
749 | netdev->tx_queue_len = msglimit; | ||
750 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); | 814 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); |
751 | } | 815 | } |
752 | 816 | ||
753 | static void | 817 | static void conn_action_connreject(fsm_instance *fi, int event, void *arg) |
754 | conn_action_connreject(fsm_instance *fi, int event, void *arg) | ||
755 | { | 818 | { |
756 | struct iucv_event *ev = (struct iucv_event *)arg; | 819 | struct iucv_event *ev = arg; |
757 | struct iucv_connection *conn = ev->conn; | 820 | struct iucv_path *path = ev->data; |
758 | struct net_device *netdev = conn->netdev; | ||
759 | iucv_ConnectionPending *eib = (iucv_ConnectionPending *)ev->data; | ||
760 | __u8 udata[16]; | ||
761 | 821 | ||
762 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 822 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
763 | 823 | iucv_path_sever(path, NULL); | |
764 | iucv_sever(eib->ippathid, udata); | ||
765 | if (eib->ippathid != conn->pathid) { | ||
766 | PRINT_INFO("%s: IR Connection Pending; " | ||
767 | "pathid %d does not match original pathid %d\n", | ||
768 | netdev->name, eib->ippathid, conn->pathid); | ||
769 | IUCV_DBF_TEXT_(data, 2, | ||
770 | "connreject: IR pathid %d, conn. pathid %d\n", | ||
771 | eib->ippathid, conn->pathid); | ||
772 | iucv_sever(conn->pathid, udata); | ||
773 | } | ||
774 | } | 824 | } |
775 | 825 | ||
776 | static void | 826 | static void conn_action_connack(fsm_instance *fi, int event, void *arg) |
777 | conn_action_connack(fsm_instance *fi, int event, void *arg) | ||
778 | { | 827 | { |
779 | struct iucv_event *ev = (struct iucv_event *)arg; | 828 | struct iucv_connection *conn = arg; |
780 | struct iucv_connection *conn = ev->conn; | ||
781 | iucv_ConnectionComplete *eib = (iucv_ConnectionComplete *)ev->data; | ||
782 | struct net_device *netdev = conn->netdev; | 829 | struct net_device *netdev = conn->netdev; |
783 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 830 | struct netiucv_priv *privptr = netdev_priv(netdev); |
784 | 831 | ||
785 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 832 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
786 | |||
787 | fsm_deltimer(&conn->timer); | 833 | fsm_deltimer(&conn->timer); |
788 | fsm_newstate(fi, CONN_STATE_IDLE); | 834 | fsm_newstate(fi, CONN_STATE_IDLE); |
789 | if (eib->ippathid != conn->pathid) { | 835 | netdev->tx_queue_len = conn->path->msglim; |
790 | PRINT_INFO("%s: IR Connection Complete; " | ||
791 | "pathid %d does not match original pathid %d\n", | ||
792 | netdev->name, eib->ippathid, conn->pathid); | ||
793 | IUCV_DBF_TEXT_(data, 2, | ||
794 | "connack: IR pathid %d, conn. pathid %d\n", | ||
795 | eib->ippathid, conn->pathid); | ||
796 | conn->pathid = eib->ippathid; | ||
797 | } | ||
798 | netdev->tx_queue_len = eib->ipmsglim; | ||
799 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); | 836 | fsm_event(privptr->fsm, DEV_EVENT_CONUP, netdev); |
800 | } | 837 | } |
801 | 838 | ||
802 | static void | 839 | static void conn_action_conntimsev(fsm_instance *fi, int event, void *arg) |
803 | conn_action_conntimsev(fsm_instance *fi, int event, void *arg) | ||
804 | { | 840 | { |
805 | struct iucv_connection *conn = (struct iucv_connection *)arg; | 841 | struct iucv_connection *conn = arg; |
806 | __u8 udata[16]; | ||
807 | 842 | ||
808 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 843 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
809 | |||
810 | fsm_deltimer(&conn->timer); | 844 | fsm_deltimer(&conn->timer); |
811 | iucv_sever(conn->pathid, udata); | 845 | iucv_path_sever(conn->path, NULL); |
812 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 846 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
813 | } | 847 | } |
814 | 848 | ||
815 | static void | 849 | static void conn_action_connsever(fsm_instance *fi, int event, void *arg) |
816 | conn_action_connsever(fsm_instance *fi, int event, void *arg) | ||
817 | { | 850 | { |
818 | struct iucv_event *ev = (struct iucv_event *)arg; | 851 | struct iucv_connection *conn = arg; |
819 | struct iucv_connection *conn = ev->conn; | ||
820 | struct net_device *netdev = conn->netdev; | 852 | struct net_device *netdev = conn->netdev; |
821 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 853 | struct netiucv_priv *privptr = netdev_priv(netdev); |
822 | __u8 udata[16]; | ||
823 | 854 | ||
824 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 855 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
825 | 856 | ||
826 | fsm_deltimer(&conn->timer); | 857 | fsm_deltimer(&conn->timer); |
827 | iucv_sever(conn->pathid, udata); | 858 | iucv_path_sever(conn->path, NULL); |
828 | PRINT_INFO("%s: Remote dropped connection\n", netdev->name); | 859 | PRINT_INFO("%s: Remote dropped connection\n", netdev->name); |
829 | IUCV_DBF_TEXT(data, 2, | 860 | IUCV_DBF_TEXT(data, 2, |
830 | "conn_action_connsever: Remote dropped connection\n"); | 861 | "conn_action_connsever: Remote dropped connection\n"); |
831 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 862 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
832 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); | 863 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); |
833 | } | 864 | } |
834 | 865 | ||
835 | static void | 866 | static void conn_action_start(fsm_instance *fi, int event, void *arg) |
836 | conn_action_start(fsm_instance *fi, int event, void *arg) | ||
837 | { | 867 | { |
838 | struct iucv_event *ev = (struct iucv_event *)arg; | 868 | struct iucv_connection *conn = arg; |
839 | struct iucv_connection *conn = ev->conn; | ||
840 | __u16 msglimit; | ||
841 | int rc; | 869 | int rc; |
842 | 870 | ||
843 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 871 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
844 | 872 | ||
845 | if (!conn->handle) { | 873 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
846 | IUCV_DBF_TEXT(trace, 5, "calling iucv_register_program\n"); | ||
847 | conn->handle = | ||
848 | iucv_register_program(iucvMagic, conn->userid, | ||
849 | netiucv_mask, | ||
850 | &netiucv_ops, conn); | ||
851 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | ||
852 | if (!conn->handle) { | ||
853 | fsm_newstate(fi, CONN_STATE_REGERR); | ||
854 | conn->handle = NULL; | ||
855 | IUCV_DBF_TEXT(setup, 2, | ||
856 | "NULL from iucv_register_program\n"); | ||
857 | return; | ||
858 | } | ||
859 | |||
860 | PRINT_DEBUG("%s('%s'): registered successfully\n", | ||
861 | conn->netdev->name, conn->userid); | ||
862 | } | ||
863 | |||
864 | PRINT_DEBUG("%s('%s'): connecting ...\n", | 874 | PRINT_DEBUG("%s('%s'): connecting ...\n", |
865 | conn->netdev->name, conn->userid); | 875 | conn->netdev->name, conn->userid); |
866 | 876 | ||
867 | /* We must set the state before calling iucv_connect because the callback | 877 | /* |
868 | * handler could be called at any point after the connection request is | 878 | * We must set the state before calling iucv_connect because the |
869 | * sent */ | 879 | * callback handler could be called at any point after the connection |
880 | * request is sent | ||
881 | */ | ||
870 | 882 | ||
871 | fsm_newstate(fi, CONN_STATE_SETUPWAIT); | 883 | fsm_newstate(fi, CONN_STATE_SETUPWAIT); |
872 | rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic, | 884 | conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL); |
873 | conn->userid, iucv_host, 0, NULL, &msglimit, | 885 | rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid, |
874 | conn->handle, conn); | 886 | NULL, iucvMagic, conn); |
875 | switch (rc) { | 887 | switch (rc) { |
876 | case 0: | 888 | case 0: |
877 | conn->netdev->tx_queue_len = msglimit; | 889 | conn->netdev->tx_queue_len = conn->path->msglim; |
878 | fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, | 890 | fsm_addtimer(&conn->timer, NETIUCV_TIMEOUT_5SEC, |
879 | CONN_EVENT_TIMER, conn); | 891 | CONN_EVENT_TIMER, conn); |
880 | return; | 892 | return; |
881 | case 11: | 893 | case 11: |
882 | PRINT_INFO("%s: User %s is currently not available.\n", | 894 | PRINT_INFO("%s: User %s is currently not available.\n", |
883 | conn->netdev->name, | 895 | conn->netdev->name, |
884 | netiucv_printname(conn->userid)); | 896 | netiucv_printname(conn->userid)); |
885 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 897 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
886 | return; | 898 | break; |
887 | case 12: | 899 | case 12: |
888 | PRINT_INFO("%s: User %s is currently not ready.\n", | 900 | PRINT_INFO("%s: User %s is currently not ready.\n", |
889 | conn->netdev->name, | 901 | conn->netdev->name, |
890 | netiucv_printname(conn->userid)); | 902 | netiucv_printname(conn->userid)); |
891 | fsm_newstate(fi, CONN_STATE_STARTWAIT); | 903 | fsm_newstate(fi, CONN_STATE_STARTWAIT); |
892 | return; | 904 | break; |
893 | case 13: | 905 | case 13: |
894 | PRINT_WARN("%s: Too many IUCV connections.\n", | 906 | PRINT_WARN("%s: Too many IUCV connections.\n", |
895 | conn->netdev->name); | 907 | conn->netdev->name); |
896 | fsm_newstate(fi, CONN_STATE_CONNERR); | 908 | fsm_newstate(fi, CONN_STATE_CONNERR); |
897 | break; | 909 | break; |
898 | case 14: | 910 | case 14: |
899 | PRINT_WARN( | 911 | PRINT_WARN("%s: User %s has too many IUCV connections.\n", |
900 | "%s: User %s has too many IUCV connections.\n", | 912 | conn->netdev->name, |
901 | conn->netdev->name, | 913 | netiucv_printname(conn->userid)); |
902 | netiucv_printname(conn->userid)); | 914 | fsm_newstate(fi, CONN_STATE_CONNERR); |
903 | fsm_newstate(fi, CONN_STATE_CONNERR); | 915 | break; |
904 | break; | 916 | case 15: |
905 | case 15: | 917 | PRINT_WARN("%s: No IUCV authorization in CP directory.\n", |
906 | PRINT_WARN( | 918 | conn->netdev->name); |
907 | "%s: No IUCV authorization in CP directory.\n", | 919 | fsm_newstate(fi, CONN_STATE_CONNERR); |
908 | conn->netdev->name); | 920 | break; |
909 | fsm_newstate(fi, CONN_STATE_CONNERR); | 921 | default: |
910 | break; | 922 | PRINT_WARN("%s: iucv_connect returned error %d\n", |
911 | default: | 923 | conn->netdev->name, rc); |
912 | PRINT_WARN("%s: iucv_connect returned error %d\n", | 924 | fsm_newstate(fi, CONN_STATE_CONNERR); |
913 | conn->netdev->name, rc); | 925 | break; |
914 | fsm_newstate(fi, CONN_STATE_CONNERR); | ||
915 | break; | ||
916 | } | 926 | } |
917 | IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); | 927 | IUCV_DBF_TEXT_(setup, 5, "iucv_connect rc is %d\n", rc); |
918 | IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); | 928 | kfree(conn->path); |
919 | iucv_unregister_program(conn->handle); | 929 | conn->path = NULL; |
920 | conn->handle = NULL; | ||
921 | } | 930 | } |
922 | 931 | ||
923 | static void | 932 | static void netiucv_purge_skb_queue(struct sk_buff_head *q) |
924 | netiucv_purge_skb_queue(struct sk_buff_head *q) | ||
925 | { | 933 | { |
926 | struct sk_buff *skb; | 934 | struct sk_buff *skb; |
927 | 935 | ||
@@ -931,36 +939,34 @@ netiucv_purge_skb_queue(struct sk_buff_head *q) | |||
931 | } | 939 | } |
932 | } | 940 | } |
933 | 941 | ||
934 | static void | 942 | static void conn_action_stop(fsm_instance *fi, int event, void *arg) |
935 | conn_action_stop(fsm_instance *fi, int event, void *arg) | ||
936 | { | 943 | { |
937 | struct iucv_event *ev = (struct iucv_event *)arg; | 944 | struct iucv_event *ev = arg; |
938 | struct iucv_connection *conn = ev->conn; | 945 | struct iucv_connection *conn = ev->conn; |
939 | struct net_device *netdev = conn->netdev; | 946 | struct net_device *netdev = conn->netdev; |
940 | struct netiucv_priv *privptr = (struct netiucv_priv *)netdev->priv; | 947 | struct netiucv_priv *privptr = netdev_priv(netdev); |
941 | 948 | ||
942 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 949 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
943 | 950 | ||
944 | fsm_deltimer(&conn->timer); | 951 | fsm_deltimer(&conn->timer); |
945 | fsm_newstate(fi, CONN_STATE_STOPPED); | 952 | fsm_newstate(fi, CONN_STATE_STOPPED); |
946 | netiucv_purge_skb_queue(&conn->collect_queue); | 953 | netiucv_purge_skb_queue(&conn->collect_queue); |
947 | if (conn->handle) | 954 | if (conn->path) { |
948 | IUCV_DBF_TEXT(trace, 5, "calling iucv_unregister_program\n"); | 955 | IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n"); |
949 | iucv_unregister_program(conn->handle); | 956 | iucv_path_sever(conn->path, iucvMagic); |
950 | conn->handle = NULL; | 957 | kfree(conn->path); |
958 | conn->path = NULL; | ||
959 | } | ||
951 | netiucv_purge_skb_queue(&conn->commit_queue); | 960 | netiucv_purge_skb_queue(&conn->commit_queue); |
952 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); | 961 | fsm_event(privptr->fsm, DEV_EVENT_CONDOWN, netdev); |
953 | } | 962 | } |
954 | 963 | ||
955 | static void | 964 | static void conn_action_inval(fsm_instance *fi, int event, void *arg) |
956 | conn_action_inval(fsm_instance *fi, int event, void *arg) | ||
957 | { | 965 | { |
958 | struct iucv_event *ev = (struct iucv_event *)arg; | 966 | struct iucv_connection *conn = arg; |
959 | struct iucv_connection *conn = ev->conn; | ||
960 | struct net_device *netdev = conn->netdev; | 967 | struct net_device *netdev = conn->netdev; |
961 | 968 | ||
962 | PRINT_WARN("%s: Cannot connect without username\n", | 969 | PRINT_WARN("%s: Cannot connect without username\n", netdev->name); |
963 | netdev->name); | ||
964 | IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); | 970 | IUCV_DBF_TEXT(data, 2, "conn_action_inval called\n"); |
965 | } | 971 | } |
966 | 972 | ||
@@ -999,29 +1005,27 @@ static const fsm_node conn_fsm[] = { | |||
999 | static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); | 1005 | static const int CONN_FSM_LEN = sizeof(conn_fsm) / sizeof(fsm_node); |
1000 | 1006 | ||
1001 | 1007 | ||
1002 | /** | 1008 | /* |
1003 | * Actions for interface - statemachine. | 1009 | * Actions for interface - statemachine. |
1004 | *****************************************************************************/ | 1010 | */ |
1005 | 1011 | ||
1006 | /** | 1012 | /** |
1007 | * Startup connection by sending CONN_EVENT_START to it. | 1013 | * dev_action_start |
1014 | * @fi: An instance of an interface statemachine. | ||
1015 | * @event: The event, just happened. | ||
1016 | * @arg: Generic pointer, casted from struct net_device * upon call. | ||
1008 | * | 1017 | * |
1009 | * @param fi An instance of an interface statemachine. | 1018 | * Startup connection by sending CONN_EVENT_START to it. |
1010 | * @param event The event, just happened. | ||
1011 | * @param arg Generic pointer, casted from struct net_device * upon call. | ||
1012 | */ | 1019 | */ |
1013 | static void | 1020 | static void dev_action_start(fsm_instance *fi, int event, void *arg) |
1014 | dev_action_start(fsm_instance *fi, int event, void *arg) | ||
1015 | { | 1021 | { |
1016 | struct net_device *dev = (struct net_device *)arg; | 1022 | struct net_device *dev = arg; |
1017 | struct netiucv_priv *privptr = dev->priv; | 1023 | struct netiucv_priv *privptr = netdev_priv(dev); |
1018 | struct iucv_event ev; | ||
1019 | 1024 | ||
1020 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1025 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1021 | 1026 | ||
1022 | ev.conn = privptr->conn; | ||
1023 | fsm_newstate(fi, DEV_STATE_STARTWAIT); | 1027 | fsm_newstate(fi, DEV_STATE_STARTWAIT); |
1024 | fsm_event(privptr->conn->fsm, CONN_EVENT_START, &ev); | 1028 | fsm_event(privptr->conn->fsm, CONN_EVENT_START, privptr->conn); |
1025 | } | 1029 | } |
1026 | 1030 | ||
1027 | /** | 1031 | /** |
@@ -1034,8 +1038,8 @@ dev_action_start(fsm_instance *fi, int event, void *arg) | |||
1034 | static void | 1038 | static void |
1035 | dev_action_stop(fsm_instance *fi, int event, void *arg) | 1039 | dev_action_stop(fsm_instance *fi, int event, void *arg) |
1036 | { | 1040 | { |
1037 | struct net_device *dev = (struct net_device *)arg; | 1041 | struct net_device *dev = arg; |
1038 | struct netiucv_priv *privptr = dev->priv; | 1042 | struct netiucv_priv *privptr = netdev_priv(dev); |
1039 | struct iucv_event ev; | 1043 | struct iucv_event ev; |
1040 | 1044 | ||
1041 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1045 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
@@ -1057,8 +1061,8 @@ dev_action_stop(fsm_instance *fi, int event, void *arg) | |||
1057 | static void | 1061 | static void |
1058 | dev_action_connup(fsm_instance *fi, int event, void *arg) | 1062 | dev_action_connup(fsm_instance *fi, int event, void *arg) |
1059 | { | 1063 | { |
1060 | struct net_device *dev = (struct net_device *)arg; | 1064 | struct net_device *dev = arg; |
1061 | struct netiucv_priv *privptr = dev->priv; | 1065 | struct netiucv_priv *privptr = netdev_priv(dev); |
1062 | 1066 | ||
1063 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1067 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1064 | 1068 | ||
@@ -1131,11 +1135,13 @@ static const int DEV_FSM_LEN = sizeof(dev_fsm) / sizeof(fsm_node); | |||
1131 | * | 1135 | * |
1132 | * @return 0 on success, -ERRNO on failure. (Never fails.) | 1136 | * @return 0 on success, -ERRNO on failure. (Never fails.) |
1133 | */ | 1137 | */ |
1134 | static int | 1138 | static int netiucv_transmit_skb(struct iucv_connection *conn, |
1135 | netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | 1139 | struct sk_buff *skb) |
1140 | { | ||
1141 | struct iucv_message msg; | ||
1136 | unsigned long saveflags; | 1142 | unsigned long saveflags; |
1137 | ll_header header; | 1143 | struct ll_header header; |
1138 | int rc = 0; | 1144 | int rc; |
1139 | 1145 | ||
1140 | if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { | 1146 | if (fsm_getstate(conn->fsm) != CONN_STATE_IDLE) { |
1141 | int l = skb->len + NETIUCV_HDRLEN; | 1147 | int l = skb->len + NETIUCV_HDRLEN; |
@@ -1145,11 +1151,12 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1145 | (conn->max_buffsize - NETIUCV_HDRLEN)) { | 1151 | (conn->max_buffsize - NETIUCV_HDRLEN)) { |
1146 | rc = -EBUSY; | 1152 | rc = -EBUSY; |
1147 | IUCV_DBF_TEXT(data, 2, | 1153 | IUCV_DBF_TEXT(data, 2, |
1148 | "EBUSY from netiucv_transmit_skb\n"); | 1154 | "EBUSY from netiucv_transmit_skb\n"); |
1149 | } else { | 1155 | } else { |
1150 | atomic_inc(&skb->users); | 1156 | atomic_inc(&skb->users); |
1151 | skb_queue_tail(&conn->collect_queue, skb); | 1157 | skb_queue_tail(&conn->collect_queue, skb); |
1152 | conn->collect_len += l; | 1158 | conn->collect_len += l; |
1159 | rc = 0; | ||
1153 | } | 1160 | } |
1154 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); | 1161 | spin_unlock_irqrestore(&conn->collect_lock, saveflags); |
1155 | } else { | 1162 | } else { |
@@ -1188,9 +1195,10 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1188 | fsm_newstate(conn->fsm, CONN_STATE_TX); | 1195 | fsm_newstate(conn->fsm, CONN_STATE_TX); |
1189 | conn->prof.send_stamp = xtime; | 1196 | conn->prof.send_stamp = xtime; |
1190 | 1197 | ||
1191 | rc = iucv_send(conn->pathid, NULL, 0, 0, 1 /* single_flag */, | 1198 | msg.tag = 1; |
1192 | 0, nskb->data, nskb->len); | 1199 | msg.class = 0; |
1193 | /* Shut up, gcc! nskb is always below 2G. */ | 1200 | rc = iucv_message_send(conn->path, &msg, 0, 0, |
1201 | nskb->data, nskb->len); | ||
1194 | conn->prof.doios_single++; | 1202 | conn->prof.doios_single++; |
1195 | conn->prof.txlen += skb->len; | 1203 | conn->prof.txlen += skb->len; |
1196 | conn->prof.tx_pending++; | 1204 | conn->prof.tx_pending++; |
@@ -1200,7 +1208,7 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1200 | struct netiucv_priv *privptr; | 1208 | struct netiucv_priv *privptr; |
1201 | fsm_newstate(conn->fsm, CONN_STATE_IDLE); | 1209 | fsm_newstate(conn->fsm, CONN_STATE_IDLE); |
1202 | conn->prof.tx_pending--; | 1210 | conn->prof.tx_pending--; |
1203 | privptr = (struct netiucv_priv *)conn->netdev->priv; | 1211 | privptr = netdev_priv(conn->netdev); |
1204 | if (privptr) | 1212 | if (privptr) |
1205 | privptr->stats.tx_errors++; | 1213 | privptr->stats.tx_errors++; |
1206 | if (copied) | 1214 | if (copied) |
@@ -1226,9 +1234,9 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1226 | return rc; | 1234 | return rc; |
1227 | } | 1235 | } |
1228 | 1236 | ||
1229 | /** | 1237 | /* |
1230 | * Interface API for upper network layers | 1238 | * Interface API for upper network layers |
1231 | *****************************************************************************/ | 1239 | */ |
1232 | 1240 | ||
1233 | /** | 1241 | /** |
1234 | * Open an interface. | 1242 | * Open an interface. |
@@ -1238,9 +1246,11 @@ netiucv_transmit_skb(struct iucv_connection *conn, struct sk_buff *skb) { | |||
1238 | * | 1246 | * |
1239 | * @return 0 on success, -ERRNO on failure. (Never fails.) | 1247 | * @return 0 on success, -ERRNO on failure. (Never fails.) |
1240 | */ | 1248 | */ |
1241 | static int | 1249 | static int netiucv_open(struct net_device *dev) |
1242 | netiucv_open(struct net_device *dev) { | 1250 | { |
1243 | fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_START,dev); | 1251 | struct netiucv_priv *priv = netdev_priv(dev); |
1252 | |||
1253 | fsm_event(priv->fsm, DEV_EVENT_START, dev); | ||
1244 | return 0; | 1254 | return 0; |
1245 | } | 1255 | } |
1246 | 1256 | ||
@@ -1252,9 +1262,11 @@ netiucv_open(struct net_device *dev) { | |||
1252 | * | 1262 | * |
1253 | * @return 0 on success, -ERRNO on failure. (Never fails.) | 1263 | * @return 0 on success, -ERRNO on failure. (Never fails.) |
1254 | */ | 1264 | */ |
1255 | static int | 1265 | static int netiucv_close(struct net_device *dev) |
1256 | netiucv_close(struct net_device *dev) { | 1266 | { |
1257 | fsm_event(((struct netiucv_priv *)dev->priv)->fsm, DEV_EVENT_STOP, dev); | 1267 | struct netiucv_priv *priv = netdev_priv(dev); |
1268 | |||
1269 | fsm_event(priv->fsm, DEV_EVENT_STOP, dev); | ||
1258 | return 0; | 1270 | return 0; |
1259 | } | 1271 | } |
1260 | 1272 | ||
@@ -1271,8 +1283,8 @@ netiucv_close(struct net_device *dev) { | |||
1271 | */ | 1283 | */ |
1272 | static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) | 1284 | static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) |
1273 | { | 1285 | { |
1274 | int rc = 0; | 1286 | struct netiucv_priv *privptr = netdev_priv(dev); |
1275 | struct netiucv_priv *privptr = dev->priv; | 1287 | int rc; |
1276 | 1288 | ||
1277 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); | 1289 | IUCV_DBF_TEXT(trace, 4, __FUNCTION__); |
1278 | /** | 1290 | /** |
@@ -1312,40 +1324,41 @@ static int netiucv_tx(struct sk_buff *skb, struct net_device *dev) | |||
1312 | return -EBUSY; | 1324 | return -EBUSY; |
1313 | } | 1325 | } |
1314 | dev->trans_start = jiffies; | 1326 | dev->trans_start = jiffies; |
1315 | if (netiucv_transmit_skb(privptr->conn, skb)) | 1327 | rc = netiucv_transmit_skb(privptr->conn, skb) != 0; |
1316 | rc = 1; | ||
1317 | netiucv_clear_busy(dev); | 1328 | netiucv_clear_busy(dev); |
1318 | return rc; | 1329 | return rc; |
1319 | } | 1330 | } |
1320 | 1331 | ||
1321 | /** | 1332 | /** |
1322 | * Returns interface statistics of a device. | 1333 | * netiucv_stats |
1334 | * @dev: Pointer to interface struct. | ||
1323 | * | 1335 | * |
1324 | * @param dev Pointer to interface struct. | 1336 | * Returns interface statistics of a device. |
1325 | * | 1337 | * |
1326 | * @return Pointer to stats struct of this interface. | 1338 | * Returns pointer to stats struct of this interface. |
1327 | */ | 1339 | */ |
1328 | static struct net_device_stats * | 1340 | static struct net_device_stats *netiucv_stats (struct net_device * dev) |
1329 | netiucv_stats (struct net_device * dev) | ||
1330 | { | 1341 | { |
1342 | struct netiucv_priv *priv = netdev_priv(dev); | ||
1343 | |||
1331 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); | 1344 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); |
1332 | return &((struct netiucv_priv *)dev->priv)->stats; | 1345 | return &priv->stats; |
1333 | } | 1346 | } |
1334 | 1347 | ||
1335 | /** | 1348 | /** |
1336 | * Sets MTU of an interface. | 1349 | * netiucv_change_mtu |
1350 | * @dev: Pointer to interface struct. | ||
1351 | * @new_mtu: The new MTU to use for this interface. | ||
1337 | * | 1352 | * |
1338 | * @param dev Pointer to interface struct. | 1353 | * Sets MTU of an interface. |
1339 | * @param new_mtu The new MTU to use for this interface. | ||
1340 | * | 1354 | * |
1341 | * @return 0 on success, -EINVAL if MTU is out of valid range. | 1355 | * Returns 0 on success, -EINVAL if MTU is out of valid range. |
1342 | * (valid range is 576 .. NETIUCV_MTU_MAX). | 1356 | * (valid range is 576 .. NETIUCV_MTU_MAX). |
1343 | */ | 1357 | */ |
1344 | static int | 1358 | static int netiucv_change_mtu(struct net_device * dev, int new_mtu) |
1345 | netiucv_change_mtu (struct net_device * dev, int new_mtu) | ||
1346 | { | 1359 | { |
1347 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1360 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1348 | if ((new_mtu < 576) || (new_mtu > NETIUCV_MTU_MAX)) { | 1361 | if (new_mtu < 576 || new_mtu > NETIUCV_MTU_MAX) { |
1349 | IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); | 1362 | IUCV_DBF_TEXT(setup, 2, "given MTU out of valid range\n"); |
1350 | return -EINVAL; | 1363 | return -EINVAL; |
1351 | } | 1364 | } |
@@ -1353,12 +1366,12 @@ netiucv_change_mtu (struct net_device * dev, int new_mtu) | |||
1353 | return 0; | 1366 | return 0; |
1354 | } | 1367 | } |
1355 | 1368 | ||
1356 | /** | 1369 | /* |
1357 | * attributes in sysfs | 1370 | * attributes in sysfs |
1358 | *****************************************************************************/ | 1371 | */ |
1359 | 1372 | ||
1360 | static ssize_t | 1373 | static ssize_t user_show(struct device *dev, struct device_attribute *attr, |
1361 | user_show (struct device *dev, struct device_attribute *attr, char *buf) | 1374 | char *buf) |
1362 | { | 1375 | { |
1363 | struct netiucv_priv *priv = dev->driver_data; | 1376 | struct netiucv_priv *priv = dev->driver_data; |
1364 | 1377 | ||
@@ -1366,8 +1379,8 @@ user_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1366 | return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); | 1379 | return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid)); |
1367 | } | 1380 | } |
1368 | 1381 | ||
1369 | static ssize_t | 1382 | static ssize_t user_write(struct device *dev, struct device_attribute *attr, |
1370 | user_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1383 | const char *buf, size_t count) |
1371 | { | 1384 | { |
1372 | struct netiucv_priv *priv = dev->driver_data; | 1385 | struct netiucv_priv *priv = dev->driver_data; |
1373 | struct net_device *ndev = priv->conn->netdev; | 1386 | struct net_device *ndev = priv->conn->netdev; |
@@ -1375,80 +1388,70 @@ user_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1375 | char *tmp; | 1388 | char *tmp; |
1376 | char username[9]; | 1389 | char username[9]; |
1377 | int i; | 1390 | int i; |
1378 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | 1391 | struct iucv_connection *cp; |
1379 | unsigned long flags; | ||
1380 | 1392 | ||
1381 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1393 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1382 | if (count>9) { | 1394 | if (count > 9) { |
1383 | PRINT_WARN("netiucv: username too long (%d)!\n", (int)count); | 1395 | PRINT_WARN("netiucv: username too long (%d)!\n", (int) count); |
1384 | IUCV_DBF_TEXT_(setup, 2, | 1396 | IUCV_DBF_TEXT_(setup, 2, |
1385 | "%d is length of username\n", (int)count); | 1397 | "%d is length of username\n", (int) count); |
1386 | return -EINVAL; | 1398 | return -EINVAL; |
1387 | } | 1399 | } |
1388 | 1400 | ||
1389 | tmp = strsep((char **) &buf, "\n"); | 1401 | tmp = strsep((char **) &buf, "\n"); |
1390 | for (i=0, p=tmp; i<8 && *p; i++, p++) { | 1402 | for (i = 0, p = tmp; i < 8 && *p; i++, p++) { |
1391 | if (isalnum(*p) || (*p == '$')) | 1403 | if (isalnum(*p) || (*p == '$')) { |
1392 | username[i]= toupper(*p); | 1404 | username[i]= toupper(*p); |
1393 | else if (*p == '\n') { | 1405 | continue; |
1406 | } | ||
1407 | if (*p == '\n') { | ||
1394 | /* trailing lf, grr */ | 1408 | /* trailing lf, grr */ |
1395 | break; | 1409 | break; |
1396 | } else { | ||
1397 | PRINT_WARN("netiucv: Invalid char %c in username!\n", | ||
1398 | *p); | ||
1399 | IUCV_DBF_TEXT_(setup, 2, | ||
1400 | "username: invalid character %c\n", | ||
1401 | *p); | ||
1402 | return -EINVAL; | ||
1403 | } | 1410 | } |
1411 | PRINT_WARN("netiucv: Invalid char %c in username!\n", *p); | ||
1412 | IUCV_DBF_TEXT_(setup, 2, | ||
1413 | "username: invalid character %c\n", *p); | ||
1414 | return -EINVAL; | ||
1404 | } | 1415 | } |
1405 | while (i<8) | 1416 | while (i < 8) |
1406 | username[i++] = ' '; | 1417 | username[i++] = ' '; |
1407 | username[8] = '\0'; | 1418 | username[8] = '\0'; |
1408 | 1419 | ||
1409 | if (memcmp(username, priv->conn->userid, 9)) { | 1420 | if (memcmp(username, priv->conn->userid, 9) && |
1410 | /* username changed */ | 1421 | (ndev->flags & (IFF_UP | IFF_RUNNING))) { |
1411 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 1422 | /* username changed while the interface is active. */ |
1412 | PRINT_WARN( | 1423 | PRINT_WARN("netiucv: device %s active, connected to %s\n", |
1413 | "netiucv: device %s active, connected to %s\n", | 1424 | dev->bus_id, priv->conn->userid); |
1414 | dev->bus_id, priv->conn->userid); | 1425 | PRINT_WARN("netiucv: user cannot be updated\n"); |
1415 | PRINT_WARN("netiucv: user cannot be updated\n"); | 1426 | IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); |
1416 | IUCV_DBF_TEXT(setup, 2, "user_write: device active\n"); | 1427 | return -EBUSY; |
1417 | return -EBUSY; | 1428 | } |
1429 | read_lock_bh(&iucv_connection_rwlock); | ||
1430 | list_for_each_entry(cp, &iucv_connection_list, list) { | ||
1431 | if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) { | ||
1432 | read_unlock_bh(&iucv_connection_rwlock); | ||
1433 | PRINT_WARN("netiucv: Connection to %s already " | ||
1434 | "exists\n", username); | ||
1435 | return -EEXIST; | ||
1418 | } | 1436 | } |
1419 | } | 1437 | } |
1420 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1438 | read_unlock_bh(&iucv_connection_rwlock); |
1421 | while (*clist) { | ||
1422 | if (!strncmp(username, (*clist)->userid, 9) || | ||
1423 | ((*clist)->netdev != ndev)) | ||
1424 | break; | ||
1425 | clist = &((*clist)->next); | ||
1426 | } | ||
1427 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
1428 | if (*clist) { | ||
1429 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
1430 | username); | ||
1431 | return -EEXIST; | ||
1432 | } | ||
1433 | memcpy(priv->conn->userid, username, 9); | 1439 | memcpy(priv->conn->userid, username, 9); |
1434 | |||
1435 | return count; | 1440 | return count; |
1436 | |||
1437 | } | 1441 | } |
1438 | 1442 | ||
1439 | static DEVICE_ATTR(user, 0644, user_show, user_write); | 1443 | static DEVICE_ATTR(user, 0644, user_show, user_write); |
1440 | 1444 | ||
1441 | static ssize_t | 1445 | static ssize_t buffer_show (struct device *dev, struct device_attribute *attr, |
1442 | buffer_show (struct device *dev, struct device_attribute *attr, char *buf) | 1446 | char *buf) |
1443 | { | 1447 | { struct netiucv_priv *priv = dev->driver_data; |
1444 | struct netiucv_priv *priv = dev->driver_data; | ||
1445 | 1448 | ||
1446 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); | 1449 | IUCV_DBF_TEXT(trace, 5, __FUNCTION__); |
1447 | return sprintf(buf, "%d\n", priv->conn->max_buffsize); | 1450 | return sprintf(buf, "%d\n", priv->conn->max_buffsize); |
1448 | } | 1451 | } |
1449 | 1452 | ||
1450 | static ssize_t | 1453 | static ssize_t buffer_write (struct device *dev, struct device_attribute *attr, |
1451 | buffer_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1454 | const char *buf, size_t count) |
1452 | { | 1455 | { |
1453 | struct netiucv_priv *priv = dev->driver_data; | 1456 | struct netiucv_priv *priv = dev->driver_data; |
1454 | struct net_device *ndev = priv->conn->netdev; | 1457 | struct net_device *ndev = priv->conn->netdev; |
@@ -1502,8 +1505,8 @@ buffer_write (struct device *dev, struct device_attribute *attr, const char *buf | |||
1502 | 1505 | ||
1503 | static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); | 1506 | static DEVICE_ATTR(buffer, 0644, buffer_show, buffer_write); |
1504 | 1507 | ||
1505 | static ssize_t | 1508 | static ssize_t dev_fsm_show (struct device *dev, struct device_attribute *attr, |
1506 | dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | 1509 | char *buf) |
1507 | { | 1510 | { |
1508 | struct netiucv_priv *priv = dev->driver_data; | 1511 | struct netiucv_priv *priv = dev->driver_data; |
1509 | 1512 | ||
@@ -1513,8 +1516,8 @@ dev_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1513 | 1516 | ||
1514 | static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); | 1517 | static DEVICE_ATTR(device_fsm_state, 0444, dev_fsm_show, NULL); |
1515 | 1518 | ||
1516 | static ssize_t | 1519 | static ssize_t conn_fsm_show (struct device *dev, |
1517 | conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | 1520 | struct device_attribute *attr, char *buf) |
1518 | { | 1521 | { |
1519 | struct netiucv_priv *priv = dev->driver_data; | 1522 | struct netiucv_priv *priv = dev->driver_data; |
1520 | 1523 | ||
@@ -1524,8 +1527,8 @@ conn_fsm_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1524 | 1527 | ||
1525 | static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); | 1528 | static DEVICE_ATTR(connection_fsm_state, 0444, conn_fsm_show, NULL); |
1526 | 1529 | ||
1527 | static ssize_t | 1530 | static ssize_t maxmulti_show (struct device *dev, |
1528 | maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) | 1531 | struct device_attribute *attr, char *buf) |
1529 | { | 1532 | { |
1530 | struct netiucv_priv *priv = dev->driver_data; | 1533 | struct netiucv_priv *priv = dev->driver_data; |
1531 | 1534 | ||
@@ -1533,8 +1536,9 @@ maxmulti_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1533 | return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); | 1536 | return sprintf(buf, "%ld\n", priv->conn->prof.maxmulti); |
1534 | } | 1537 | } |
1535 | 1538 | ||
1536 | static ssize_t | 1539 | static ssize_t maxmulti_write (struct device *dev, |
1537 | maxmulti_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1540 | struct device_attribute *attr, |
1541 | const char *buf, size_t count) | ||
1538 | { | 1542 | { |
1539 | struct netiucv_priv *priv = dev->driver_data; | 1543 | struct netiucv_priv *priv = dev->driver_data; |
1540 | 1544 | ||
@@ -1545,8 +1549,8 @@ maxmulti_write (struct device *dev, struct device_attribute *attr, const char *b | |||
1545 | 1549 | ||
1546 | static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); | 1550 | static DEVICE_ATTR(max_tx_buffer_used, 0644, maxmulti_show, maxmulti_write); |
1547 | 1551 | ||
1548 | static ssize_t | 1552 | static ssize_t maxcq_show (struct device *dev, struct device_attribute *attr, |
1549 | maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) | 1553 | char *buf) |
1550 | { | 1554 | { |
1551 | struct netiucv_priv *priv = dev->driver_data; | 1555 | struct netiucv_priv *priv = dev->driver_data; |
1552 | 1556 | ||
@@ -1554,8 +1558,8 @@ maxcq_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1554 | return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); | 1558 | return sprintf(buf, "%ld\n", priv->conn->prof.maxcqueue); |
1555 | } | 1559 | } |
1556 | 1560 | ||
1557 | static ssize_t | 1561 | static ssize_t maxcq_write (struct device *dev, struct device_attribute *attr, |
1558 | maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1562 | const char *buf, size_t count) |
1559 | { | 1563 | { |
1560 | struct netiucv_priv *priv = dev->driver_data; | 1564 | struct netiucv_priv *priv = dev->driver_data; |
1561 | 1565 | ||
@@ -1566,8 +1570,8 @@ maxcq_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1566 | 1570 | ||
1567 | static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); | 1571 | static DEVICE_ATTR(max_chained_skbs, 0644, maxcq_show, maxcq_write); |
1568 | 1572 | ||
1569 | static ssize_t | 1573 | static ssize_t sdoio_show (struct device *dev, struct device_attribute *attr, |
1570 | sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | 1574 | char *buf) |
1571 | { | 1575 | { |
1572 | struct netiucv_priv *priv = dev->driver_data; | 1576 | struct netiucv_priv *priv = dev->driver_data; |
1573 | 1577 | ||
@@ -1575,8 +1579,8 @@ sdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1575 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); | 1579 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_single); |
1576 | } | 1580 | } |
1577 | 1581 | ||
1578 | static ssize_t | 1582 | static ssize_t sdoio_write (struct device *dev, struct device_attribute *attr, |
1579 | sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1583 | const char *buf, size_t count) |
1580 | { | 1584 | { |
1581 | struct netiucv_priv *priv = dev->driver_data; | 1585 | struct netiucv_priv *priv = dev->driver_data; |
1582 | 1586 | ||
@@ -1587,8 +1591,8 @@ sdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1587 | 1591 | ||
1588 | static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); | 1592 | static DEVICE_ATTR(tx_single_write_ops, 0644, sdoio_show, sdoio_write); |
1589 | 1593 | ||
1590 | static ssize_t | 1594 | static ssize_t mdoio_show (struct device *dev, struct device_attribute *attr, |
1591 | mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | 1595 | char *buf) |
1592 | { | 1596 | { |
1593 | struct netiucv_priv *priv = dev->driver_data; | 1597 | struct netiucv_priv *priv = dev->driver_data; |
1594 | 1598 | ||
@@ -1596,8 +1600,8 @@ mdoio_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1596 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); | 1600 | return sprintf(buf, "%ld\n", priv->conn->prof.doios_multi); |
1597 | } | 1601 | } |
1598 | 1602 | ||
1599 | static ssize_t | 1603 | static ssize_t mdoio_write (struct device *dev, struct device_attribute *attr, |
1600 | mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1604 | const char *buf, size_t count) |
1601 | { | 1605 | { |
1602 | struct netiucv_priv *priv = dev->driver_data; | 1606 | struct netiucv_priv *priv = dev->driver_data; |
1603 | 1607 | ||
@@ -1608,8 +1612,8 @@ mdoio_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1608 | 1612 | ||
1609 | static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); | 1613 | static DEVICE_ATTR(tx_multi_write_ops, 0644, mdoio_show, mdoio_write); |
1610 | 1614 | ||
1611 | static ssize_t | 1615 | static ssize_t txlen_show (struct device *dev, struct device_attribute *attr, |
1612 | txlen_show (struct device *dev, struct device_attribute *attr, char *buf) | 1616 | char *buf) |
1613 | { | 1617 | { |
1614 | struct netiucv_priv *priv = dev->driver_data; | 1618 | struct netiucv_priv *priv = dev->driver_data; |
1615 | 1619 | ||
@@ -1617,8 +1621,8 @@ txlen_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1617 | return sprintf(buf, "%ld\n", priv->conn->prof.txlen); | 1621 | return sprintf(buf, "%ld\n", priv->conn->prof.txlen); |
1618 | } | 1622 | } |
1619 | 1623 | ||
1620 | static ssize_t | 1624 | static ssize_t txlen_write (struct device *dev, struct device_attribute *attr, |
1621 | txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1625 | const char *buf, size_t count) |
1622 | { | 1626 | { |
1623 | struct netiucv_priv *priv = dev->driver_data; | 1627 | struct netiucv_priv *priv = dev->driver_data; |
1624 | 1628 | ||
@@ -1629,8 +1633,8 @@ txlen_write (struct device *dev, struct device_attribute *attr, const char *buf, | |||
1629 | 1633 | ||
1630 | static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); | 1634 | static DEVICE_ATTR(netto_bytes, 0644, txlen_show, txlen_write); |
1631 | 1635 | ||
1632 | static ssize_t | 1636 | static ssize_t txtime_show (struct device *dev, struct device_attribute *attr, |
1633 | txtime_show (struct device *dev, struct device_attribute *attr, char *buf) | 1637 | char *buf) |
1634 | { | 1638 | { |
1635 | struct netiucv_priv *priv = dev->driver_data; | 1639 | struct netiucv_priv *priv = dev->driver_data; |
1636 | 1640 | ||
@@ -1638,8 +1642,8 @@ txtime_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1638 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); | 1642 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_time); |
1639 | } | 1643 | } |
1640 | 1644 | ||
1641 | static ssize_t | 1645 | static ssize_t txtime_write (struct device *dev, struct device_attribute *attr, |
1642 | txtime_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1646 | const char *buf, size_t count) |
1643 | { | 1647 | { |
1644 | struct netiucv_priv *priv = dev->driver_data; | 1648 | struct netiucv_priv *priv = dev->driver_data; |
1645 | 1649 | ||
@@ -1650,8 +1654,8 @@ txtime_write (struct device *dev, struct device_attribute *attr, const char *buf | |||
1650 | 1654 | ||
1651 | static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); | 1655 | static DEVICE_ATTR(max_tx_io_time, 0644, txtime_show, txtime_write); |
1652 | 1656 | ||
1653 | static ssize_t | 1657 | static ssize_t txpend_show (struct device *dev, struct device_attribute *attr, |
1654 | txpend_show (struct device *dev, struct device_attribute *attr, char *buf) | 1658 | char *buf) |
1655 | { | 1659 | { |
1656 | struct netiucv_priv *priv = dev->driver_data; | 1660 | struct netiucv_priv *priv = dev->driver_data; |
1657 | 1661 | ||
@@ -1659,8 +1663,8 @@ txpend_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1659 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); | 1663 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_pending); |
1660 | } | 1664 | } |
1661 | 1665 | ||
1662 | static ssize_t | 1666 | static ssize_t txpend_write (struct device *dev, struct device_attribute *attr, |
1663 | txpend_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1667 | const char *buf, size_t count) |
1664 | { | 1668 | { |
1665 | struct netiucv_priv *priv = dev->driver_data; | 1669 | struct netiucv_priv *priv = dev->driver_data; |
1666 | 1670 | ||
@@ -1671,8 +1675,8 @@ txpend_write (struct device *dev, struct device_attribute *attr, const char *buf | |||
1671 | 1675 | ||
1672 | static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); | 1676 | static DEVICE_ATTR(tx_pending, 0644, txpend_show, txpend_write); |
1673 | 1677 | ||
1674 | static ssize_t | 1678 | static ssize_t txmpnd_show (struct device *dev, struct device_attribute *attr, |
1675 | txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) | 1679 | char *buf) |
1676 | { | 1680 | { |
1677 | struct netiucv_priv *priv = dev->driver_data; | 1681 | struct netiucv_priv *priv = dev->driver_data; |
1678 | 1682 | ||
@@ -1680,8 +1684,8 @@ txmpnd_show (struct device *dev, struct device_attribute *attr, char *buf) | |||
1680 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); | 1684 | return sprintf(buf, "%ld\n", priv->conn->prof.tx_max_pending); |
1681 | } | 1685 | } |
1682 | 1686 | ||
1683 | static ssize_t | 1687 | static ssize_t txmpnd_write (struct device *dev, struct device_attribute *attr, |
1684 | txmpnd_write (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) | 1688 | const char *buf, size_t count) |
1685 | { | 1689 | { |
1686 | struct netiucv_priv *priv = dev->driver_data; | 1690 | struct netiucv_priv *priv = dev->driver_data; |
1687 | 1691 | ||
@@ -1721,8 +1725,7 @@ static struct attribute_group netiucv_stat_attr_group = { | |||
1721 | .attrs = netiucv_stat_attrs, | 1725 | .attrs = netiucv_stat_attrs, |
1722 | }; | 1726 | }; |
1723 | 1727 | ||
1724 | static inline int | 1728 | static inline int netiucv_add_files(struct device *dev) |
1725 | netiucv_add_files(struct device *dev) | ||
1726 | { | 1729 | { |
1727 | int ret; | 1730 | int ret; |
1728 | 1731 | ||
@@ -1736,18 +1739,16 @@ netiucv_add_files(struct device *dev) | |||
1736 | return ret; | 1739 | return ret; |
1737 | } | 1740 | } |
1738 | 1741 | ||
1739 | static inline void | 1742 | static inline void netiucv_remove_files(struct device *dev) |
1740 | netiucv_remove_files(struct device *dev) | ||
1741 | { | 1743 | { |
1742 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1744 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1743 | sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); | 1745 | sysfs_remove_group(&dev->kobj, &netiucv_stat_attr_group); |
1744 | sysfs_remove_group(&dev->kobj, &netiucv_attr_group); | 1746 | sysfs_remove_group(&dev->kobj, &netiucv_attr_group); |
1745 | } | 1747 | } |
1746 | 1748 | ||
1747 | static int | 1749 | static int netiucv_register_device(struct net_device *ndev) |
1748 | netiucv_register_device(struct net_device *ndev) | ||
1749 | { | 1750 | { |
1750 | struct netiucv_priv *priv = ndev->priv; | 1751 | struct netiucv_priv *priv = netdev_priv(ndev); |
1751 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 1752 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
1752 | int ret; | 1753 | int ret; |
1753 | 1754 | ||
@@ -1786,8 +1787,7 @@ out_unreg: | |||
1786 | return ret; | 1787 | return ret; |
1787 | } | 1788 | } |
1788 | 1789 | ||
1789 | static void | 1790 | static void netiucv_unregister_device(struct device *dev) |
1790 | netiucv_unregister_device(struct device *dev) | ||
1791 | { | 1791 | { |
1792 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1792 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1793 | netiucv_remove_files(dev); | 1793 | netiucv_remove_files(dev); |
@@ -1798,107 +1798,89 @@ netiucv_unregister_device(struct device *dev) | |||
1798 | * Allocate and initialize a new connection structure. | 1798 | * Allocate and initialize a new connection structure. |
1799 | * Add it to the list of netiucv connections; | 1799 | * Add it to the list of netiucv connections; |
1800 | */ | 1800 | */ |
1801 | static struct iucv_connection * | 1801 | static struct iucv_connection *netiucv_new_connection(struct net_device *dev, |
1802 | netiucv_new_connection(struct net_device *dev, char *username) | 1802 | char *username) |
1803 | { | 1803 | { |
1804 | unsigned long flags; | 1804 | struct iucv_connection *conn; |
1805 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
1806 | struct iucv_connection *conn = | ||
1807 | kzalloc(sizeof(struct iucv_connection), GFP_KERNEL); | ||
1808 | |||
1809 | if (conn) { | ||
1810 | skb_queue_head_init(&conn->collect_queue); | ||
1811 | skb_queue_head_init(&conn->commit_queue); | ||
1812 | spin_lock_init(&conn->collect_lock); | ||
1813 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; | ||
1814 | conn->netdev = dev; | ||
1815 | |||
1816 | conn->rx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, | ||
1817 | GFP_KERNEL | GFP_DMA); | ||
1818 | if (!conn->rx_buff) { | ||
1819 | kfree(conn); | ||
1820 | return NULL; | ||
1821 | } | ||
1822 | conn->tx_buff = alloc_skb(NETIUCV_BUFSIZE_DEFAULT, | ||
1823 | GFP_KERNEL | GFP_DMA); | ||
1824 | if (!conn->tx_buff) { | ||
1825 | kfree_skb(conn->rx_buff); | ||
1826 | kfree(conn); | ||
1827 | return NULL; | ||
1828 | } | ||
1829 | conn->fsm = init_fsm("netiucvconn", conn_state_names, | ||
1830 | conn_event_names, NR_CONN_STATES, | ||
1831 | NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, | ||
1832 | GFP_KERNEL); | ||
1833 | if (!conn->fsm) { | ||
1834 | kfree_skb(conn->tx_buff); | ||
1835 | kfree_skb(conn->rx_buff); | ||
1836 | kfree(conn); | ||
1837 | return NULL; | ||
1838 | } | ||
1839 | fsm_settimer(conn->fsm, &conn->timer); | ||
1840 | fsm_newstate(conn->fsm, CONN_STATE_INVALID); | ||
1841 | |||
1842 | if (username) { | ||
1843 | memcpy(conn->userid, username, 9); | ||
1844 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); | ||
1845 | } | ||
1846 | 1805 | ||
1847 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1806 | conn = kzalloc(sizeof(*conn), GFP_KERNEL); |
1848 | conn->next = *clist; | 1807 | if (!conn) |
1849 | *clist = conn; | 1808 | goto out; |
1850 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1809 | skb_queue_head_init(&conn->collect_queue); |
1810 | skb_queue_head_init(&conn->commit_queue); | ||
1811 | spin_lock_init(&conn->collect_lock); | ||
1812 | conn->max_buffsize = NETIUCV_BUFSIZE_DEFAULT; | ||
1813 | conn->netdev = dev; | ||
1814 | |||
1815 | conn->rx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); | ||
1816 | if (!conn->rx_buff) | ||
1817 | goto out_conn; | ||
1818 | conn->tx_buff = alloc_skb(conn->max_buffsize, GFP_KERNEL | GFP_DMA); | ||
1819 | if (!conn->tx_buff) | ||
1820 | goto out_rx; | ||
1821 | conn->fsm = init_fsm("netiucvconn", conn_state_names, | ||
1822 | conn_event_names, NR_CONN_STATES, | ||
1823 | NR_CONN_EVENTS, conn_fsm, CONN_FSM_LEN, | ||
1824 | GFP_KERNEL); | ||
1825 | if (!conn->fsm) | ||
1826 | goto out_tx; | ||
1827 | |||
1828 | fsm_settimer(conn->fsm, &conn->timer); | ||
1829 | fsm_newstate(conn->fsm, CONN_STATE_INVALID); | ||
1830 | |||
1831 | if (username) { | ||
1832 | memcpy(conn->userid, username, 9); | ||
1833 | fsm_newstate(conn->fsm, CONN_STATE_STOPPED); | ||
1851 | } | 1834 | } |
1835 | |||
1836 | write_lock_bh(&iucv_connection_rwlock); | ||
1837 | list_add_tail(&conn->list, &iucv_connection_list); | ||
1838 | write_unlock_bh(&iucv_connection_rwlock); | ||
1852 | return conn; | 1839 | return conn; |
1840 | |||
1841 | out_tx: | ||
1842 | kfree_skb(conn->tx_buff); | ||
1843 | out_rx: | ||
1844 | kfree_skb(conn->rx_buff); | ||
1845 | out_conn: | ||
1846 | kfree(conn); | ||
1847 | out: | ||
1848 | return NULL; | ||
1853 | } | 1849 | } |
1854 | 1850 | ||
1855 | /** | 1851 | /** |
1856 | * Release a connection structure and remove it from the | 1852 | * Release a connection structure and remove it from the |
1857 | * list of netiucv connections. | 1853 | * list of netiucv connections. |
1858 | */ | 1854 | */ |
1859 | static void | 1855 | static void netiucv_remove_connection(struct iucv_connection *conn) |
1860 | netiucv_remove_connection(struct iucv_connection *conn) | ||
1861 | { | 1856 | { |
1862 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | ||
1863 | unsigned long flags; | ||
1864 | |||
1865 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1857 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1866 | if (conn == NULL) | 1858 | write_lock_bh(&iucv_connection_rwlock); |
1867 | return; | 1859 | list_del_init(&conn->list); |
1868 | write_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1860 | write_unlock_bh(&iucv_connection_rwlock); |
1869 | while (*clist) { | 1861 | if (conn->path) { |
1870 | if (*clist == conn) { | 1862 | iucv_path_sever(conn->path, iucvMagic); |
1871 | *clist = conn->next; | 1863 | kfree(conn->path); |
1872 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1864 | conn->path = NULL; |
1873 | if (conn->handle) { | ||
1874 | iucv_unregister_program(conn->handle); | ||
1875 | conn->handle = NULL; | ||
1876 | } | ||
1877 | fsm_deltimer(&conn->timer); | ||
1878 | kfree_fsm(conn->fsm); | ||
1879 | kfree_skb(conn->rx_buff); | ||
1880 | kfree_skb(conn->tx_buff); | ||
1881 | return; | ||
1882 | } | ||
1883 | clist = &((*clist)->next); | ||
1884 | } | 1865 | } |
1885 | write_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1866 | fsm_deltimer(&conn->timer); |
1867 | kfree_fsm(conn->fsm); | ||
1868 | kfree_skb(conn->rx_buff); | ||
1869 | kfree_skb(conn->tx_buff); | ||
1886 | } | 1870 | } |
1887 | 1871 | ||
1888 | /** | 1872 | /** |
1889 | * Release everything of a net device. | 1873 | * Release everything of a net device. |
1890 | */ | 1874 | */ |
1891 | static void | 1875 | static void netiucv_free_netdevice(struct net_device *dev) |
1892 | netiucv_free_netdevice(struct net_device *dev) | ||
1893 | { | 1876 | { |
1894 | struct netiucv_priv *privptr; | 1877 | struct netiucv_priv *privptr = netdev_priv(dev); |
1895 | 1878 | ||
1896 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1879 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1897 | 1880 | ||
1898 | if (!dev) | 1881 | if (!dev) |
1899 | return; | 1882 | return; |
1900 | 1883 | ||
1901 | privptr = (struct netiucv_priv *)dev->priv; | ||
1902 | if (privptr) { | 1884 | if (privptr) { |
1903 | if (privptr->conn) | 1885 | if (privptr->conn) |
1904 | netiucv_remove_connection(privptr->conn); | 1886 | netiucv_remove_connection(privptr->conn); |
@@ -1913,11 +1895,8 @@ netiucv_free_netdevice(struct net_device *dev) | |||
1913 | /** | 1895 | /** |
1914 | * Initialize a net device. (Called from kernel in alloc_netdev()) | 1896 | * Initialize a net device. (Called from kernel in alloc_netdev()) |
1915 | */ | 1897 | */ |
1916 | static void | 1898 | static void netiucv_setup_netdevice(struct net_device *dev) |
1917 | netiucv_setup_netdevice(struct net_device *dev) | ||
1918 | { | 1899 | { |
1919 | memset(dev->priv, 0, sizeof(struct netiucv_priv)); | ||
1920 | |||
1921 | dev->mtu = NETIUCV_MTU_DEFAULT; | 1900 | dev->mtu = NETIUCV_MTU_DEFAULT; |
1922 | dev->hard_start_xmit = netiucv_tx; | 1901 | dev->hard_start_xmit = netiucv_tx; |
1923 | dev->open = netiucv_open; | 1902 | dev->open = netiucv_open; |
@@ -1936,8 +1915,7 @@ netiucv_setup_netdevice(struct net_device *dev) | |||
1936 | /** | 1915 | /** |
1937 | * Allocate and initialize everything of a net device. | 1916 | * Allocate and initialize everything of a net device. |
1938 | */ | 1917 | */ |
1939 | static struct net_device * | 1918 | static struct net_device *netiucv_init_netdevice(char *username) |
1940 | netiucv_init_netdevice(char *username) | ||
1941 | { | 1919 | { |
1942 | struct netiucv_priv *privptr; | 1920 | struct netiucv_priv *privptr; |
1943 | struct net_device *dev; | 1921 | struct net_device *dev; |
@@ -1946,40 +1924,40 @@ netiucv_init_netdevice(char *username) | |||
1946 | netiucv_setup_netdevice); | 1924 | netiucv_setup_netdevice); |
1947 | if (!dev) | 1925 | if (!dev) |
1948 | return NULL; | 1926 | return NULL; |
1949 | if (dev_alloc_name(dev, dev->name) < 0) { | 1927 | if (dev_alloc_name(dev, dev->name) < 0) |
1950 | free_netdev(dev); | 1928 | goto out_netdev; |
1951 | return NULL; | ||
1952 | } | ||
1953 | 1929 | ||
1954 | privptr = (struct netiucv_priv *)dev->priv; | 1930 | privptr = netdev_priv(dev); |
1955 | privptr->fsm = init_fsm("netiucvdev", dev_state_names, | 1931 | privptr->fsm = init_fsm("netiucvdev", dev_state_names, |
1956 | dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, | 1932 | dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS, |
1957 | dev_fsm, DEV_FSM_LEN, GFP_KERNEL); | 1933 | dev_fsm, DEV_FSM_LEN, GFP_KERNEL); |
1958 | if (!privptr->fsm) { | 1934 | if (!privptr->fsm) |
1959 | free_netdev(dev); | 1935 | goto out_netdev; |
1960 | return NULL; | 1936 | |
1961 | } | ||
1962 | privptr->conn = netiucv_new_connection(dev, username); | 1937 | privptr->conn = netiucv_new_connection(dev, username); |
1963 | if (!privptr->conn) { | 1938 | if (!privptr->conn) { |
1964 | kfree_fsm(privptr->fsm); | ||
1965 | free_netdev(dev); | ||
1966 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); | 1939 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n"); |
1967 | return NULL; | 1940 | goto out_fsm; |
1968 | } | 1941 | } |
1969 | fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); | 1942 | fsm_newstate(privptr->fsm, DEV_STATE_STOPPED); |
1970 | |||
1971 | return dev; | 1943 | return dev; |
1944 | |||
1945 | out_fsm: | ||
1946 | kfree_fsm(privptr->fsm); | ||
1947 | out_netdev: | ||
1948 | free_netdev(dev); | ||
1949 | return NULL; | ||
1972 | } | 1950 | } |
1973 | 1951 | ||
1974 | static ssize_t | 1952 | static ssize_t conn_write(struct device_driver *drv, |
1975 | conn_write(struct device_driver *drv, const char *buf, size_t count) | 1953 | const char *buf, size_t count) |
1976 | { | 1954 | { |
1977 | char *p; | 1955 | const char *p; |
1978 | char username[9]; | 1956 | char username[9]; |
1979 | int i, ret; | 1957 | int i, rc; |
1980 | struct net_device *dev; | 1958 | struct net_device *dev; |
1981 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | 1959 | struct netiucv_priv *priv; |
1982 | unsigned long flags; | 1960 | struct iucv_connection *cp; |
1983 | 1961 | ||
1984 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 1962 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
1985 | if (count>9) { | 1963 | if (count>9) { |
@@ -1988,83 +1966,82 @@ conn_write(struct device_driver *drv, const char *buf, size_t count) | |||
1988 | return -EINVAL; | 1966 | return -EINVAL; |
1989 | } | 1967 | } |
1990 | 1968 | ||
1991 | for (i=0, p=(char *)buf; i<8 && *p; i++, p++) { | 1969 | for (i = 0, p = buf; i < 8 && *p; i++, p++) { |
1992 | if (isalnum(*p) || (*p == '$')) | 1970 | if (isalnum(*p) || *p == '$') { |
1993 | username[i]= toupper(*p); | 1971 | username[i] = toupper(*p); |
1994 | else if (*p == '\n') { | 1972 | continue; |
1973 | } | ||
1974 | if (*p == '\n') | ||
1995 | /* trailing lf, grr */ | 1975 | /* trailing lf, grr */ |
1996 | break; | 1976 | break; |
1997 | } else { | 1977 | PRINT_WARN("netiucv: Invalid character in username!\n"); |
1998 | PRINT_WARN("netiucv: Invalid character in username!\n"); | 1978 | IUCV_DBF_TEXT_(setup, 2, |
1999 | IUCV_DBF_TEXT_(setup, 2, | 1979 | "conn_write: invalid character %c\n", *p); |
2000 | "conn_write: invalid character %c\n", *p); | 1980 | return -EINVAL; |
2001 | return -EINVAL; | ||
2002 | } | ||
2003 | } | 1981 | } |
2004 | while (i<8) | 1982 | while (i < 8) |
2005 | username[i++] = ' '; | 1983 | username[i++] = ' '; |
2006 | username[8] = '\0'; | 1984 | username[8] = '\0'; |
2007 | 1985 | ||
2008 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 1986 | read_lock_bh(&iucv_connection_rwlock); |
2009 | while (*clist) { | 1987 | list_for_each_entry(cp, &iucv_connection_list, list) { |
2010 | if (!strncmp(username, (*clist)->userid, 9)) | 1988 | if (!strncmp(username, cp->userid, 9)) { |
2011 | break; | 1989 | read_unlock_bh(&iucv_connection_rwlock); |
2012 | clist = &((*clist)->next); | 1990 | PRINT_WARN("netiucv: Connection to %s already " |
2013 | } | 1991 | "exists\n", username); |
2014 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 1992 | return -EEXIST; |
2015 | if (*clist) { | 1993 | } |
2016 | PRINT_WARN("netiucv: Connection to %s already exists\n", | ||
2017 | username); | ||
2018 | return -EEXIST; | ||
2019 | } | 1994 | } |
1995 | read_unlock_bh(&iucv_connection_rwlock); | ||
1996 | |||
2020 | dev = netiucv_init_netdevice(username); | 1997 | dev = netiucv_init_netdevice(username); |
2021 | if (!dev) { | 1998 | if (!dev) { |
2022 | PRINT_WARN( | 1999 | PRINT_WARN("netiucv: Could not allocate network device " |
2023 | "netiucv: Could not allocate network device structure " | 2000 | "structure for user '%s'\n", |
2024 | "for user '%s'\n", netiucv_printname(username)); | 2001 | netiucv_printname(username)); |
2025 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); | 2002 | IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n"); |
2026 | return -ENODEV; | 2003 | return -ENODEV; |
2027 | } | 2004 | } |
2028 | 2005 | ||
2029 | if ((ret = netiucv_register_device(dev))) { | 2006 | rc = netiucv_register_device(dev); |
2007 | if (rc) { | ||
2030 | IUCV_DBF_TEXT_(setup, 2, | 2008 | IUCV_DBF_TEXT_(setup, 2, |
2031 | "ret %d from netiucv_register_device\n", ret); | 2009 | "ret %d from netiucv_register_device\n", rc); |
2032 | goto out_free_ndev; | 2010 | goto out_free_ndev; |
2033 | } | 2011 | } |
2034 | 2012 | ||
2035 | /* sysfs magic */ | 2013 | /* sysfs magic */ |
2036 | SET_NETDEV_DEV(dev, | 2014 | priv = netdev_priv(dev); |
2037 | (struct device*)((struct netiucv_priv*)dev->priv)->dev); | 2015 | SET_NETDEV_DEV(dev, priv->dev); |
2038 | 2016 | ||
2039 | if ((ret = register_netdev(dev))) { | 2017 | rc = register_netdev(dev); |
2040 | netiucv_unregister_device((struct device*) | 2018 | if (rc) |
2041 | ((struct netiucv_priv*)dev->priv)->dev); | 2019 | goto out_unreg; |
2042 | goto out_free_ndev; | ||
2043 | } | ||
2044 | 2020 | ||
2045 | PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); | 2021 | PRINT_INFO("%s: '%s'\n", dev->name, netiucv_printname(username)); |
2046 | 2022 | ||
2047 | return count; | 2023 | return count; |
2048 | 2024 | ||
2025 | out_unreg: | ||
2026 | netiucv_unregister_device(priv->dev); | ||
2049 | out_free_ndev: | 2027 | out_free_ndev: |
2050 | PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); | 2028 | PRINT_WARN("netiucv: Could not register '%s'\n", dev->name); |
2051 | IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); | 2029 | IUCV_DBF_TEXT(setup, 2, "conn_write: could not register\n"); |
2052 | netiucv_free_netdevice(dev); | 2030 | netiucv_free_netdevice(dev); |
2053 | return ret; | 2031 | return rc; |
2054 | } | 2032 | } |
2055 | 2033 | ||
2056 | static DRIVER_ATTR(connection, 0200, NULL, conn_write); | 2034 | static DRIVER_ATTR(connection, 0200, NULL, conn_write); |
2057 | 2035 | ||
2058 | static ssize_t | 2036 | static ssize_t remove_write (struct device_driver *drv, |
2059 | remove_write (struct device_driver *drv, const char *buf, size_t count) | 2037 | const char *buf, size_t count) |
2060 | { | 2038 | { |
2061 | struct iucv_connection **clist = &iucv_conns.iucv_connections; | 2039 | struct iucv_connection *cp; |
2062 | unsigned long flags; | ||
2063 | struct net_device *ndev; | 2040 | struct net_device *ndev; |
2064 | struct netiucv_priv *priv; | 2041 | struct netiucv_priv *priv; |
2065 | struct device *dev; | 2042 | struct device *dev; |
2066 | char name[IFNAMSIZ]; | 2043 | char name[IFNAMSIZ]; |
2067 | char *p; | 2044 | const char *p; |
2068 | int i; | 2045 | int i; |
2069 | 2046 | ||
2070 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2047 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
@@ -2072,33 +2049,27 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2072 | if (count >= IFNAMSIZ) | 2049 | if (count >= IFNAMSIZ) |
2073 | count = IFNAMSIZ - 1;; | 2050 | count = IFNAMSIZ - 1;; |
2074 | 2051 | ||
2075 | for (i=0, p=(char *)buf; i<count && *p; i++, p++) { | 2052 | for (i = 0, p = buf; i < count && *p; i++, p++) { |
2076 | if ((*p == '\n') || (*p == ' ')) { | 2053 | if (*p == '\n' || *p == ' ') |
2077 | /* trailing lf, grr */ | 2054 | /* trailing lf, grr */ |
2078 | break; | 2055 | break; |
2079 | } else { | 2056 | name[i] = *p; |
2080 | name[i]=*p; | ||
2081 | } | ||
2082 | } | 2057 | } |
2083 | name[i] = '\0'; | 2058 | name[i] = '\0'; |
2084 | 2059 | ||
2085 | read_lock_irqsave(&iucv_conns.iucv_rwlock, flags); | 2060 | read_lock_bh(&iucv_connection_rwlock); |
2086 | while (*clist) { | 2061 | list_for_each_entry(cp, &iucv_connection_list, list) { |
2087 | ndev = (*clist)->netdev; | 2062 | ndev = cp->netdev; |
2088 | priv = (struct netiucv_priv*)ndev->priv; | 2063 | priv = netdev_priv(ndev); |
2089 | dev = priv->dev; | 2064 | dev = priv->dev; |
2090 | 2065 | if (strncmp(name, ndev->name, count)) | |
2091 | if (strncmp(name, ndev->name, count)) { | 2066 | continue; |
2092 | clist = &((*clist)->next); | 2067 | read_unlock_bh(&iucv_connection_rwlock); |
2093 | continue; | ||
2094 | } | ||
2095 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | ||
2096 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { | 2068 | if (ndev->flags & (IFF_UP | IFF_RUNNING)) { |
2097 | PRINT_WARN( | 2069 | PRINT_WARN("netiucv: net device %s active with peer " |
2098 | "netiucv: net device %s active with peer %s\n", | 2070 | "%s\n", ndev->name, priv->conn->userid); |
2099 | ndev->name, priv->conn->userid); | ||
2100 | PRINT_WARN("netiucv: %s cannot be removed\n", | 2071 | PRINT_WARN("netiucv: %s cannot be removed\n", |
2101 | ndev->name); | 2072 | ndev->name); |
2102 | IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); | 2073 | IUCV_DBF_TEXT(data, 2, "remove_write: still active\n"); |
2103 | return -EBUSY; | 2074 | return -EBUSY; |
2104 | } | 2075 | } |
@@ -2106,7 +2077,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2106 | netiucv_unregister_device(dev); | 2077 | netiucv_unregister_device(dev); |
2107 | return count; | 2078 | return count; |
2108 | } | 2079 | } |
2109 | read_unlock_irqrestore(&iucv_conns.iucv_rwlock, flags); | 2080 | read_unlock_bh(&iucv_connection_rwlock); |
2110 | PRINT_WARN("netiucv: net device %s unknown\n", name); | 2081 | PRINT_WARN("netiucv: net device %s unknown\n", name); |
2111 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); | 2082 | IUCV_DBF_TEXT(data, 2, "remove_write: unknown device\n"); |
2112 | return -EINVAL; | 2083 | return -EINVAL; |
@@ -2114,67 +2085,86 @@ remove_write (struct device_driver *drv, const char *buf, size_t count) | |||
2114 | 2085 | ||
2115 | static DRIVER_ATTR(remove, 0200, NULL, remove_write); | 2086 | static DRIVER_ATTR(remove, 0200, NULL, remove_write); |
2116 | 2087 | ||
2117 | static void | 2088 | static struct attribute * netiucv_drv_attrs[] = { |
2118 | netiucv_banner(void) | 2089 | &driver_attr_connection.attr, |
2090 | &driver_attr_remove.attr, | ||
2091 | NULL, | ||
2092 | }; | ||
2093 | |||
2094 | static struct attribute_group netiucv_drv_attr_group = { | ||
2095 | .attrs = netiucv_drv_attrs, | ||
2096 | }; | ||
2097 | |||
2098 | static void netiucv_banner(void) | ||
2119 | { | 2099 | { |
2120 | PRINT_INFO("NETIUCV driver initialized\n"); | 2100 | PRINT_INFO("NETIUCV driver initialized\n"); |
2121 | } | 2101 | } |
2122 | 2102 | ||
2123 | static void __exit | 2103 | static void __exit netiucv_exit(void) |
2124 | netiucv_exit(void) | ||
2125 | { | 2104 | { |
2105 | struct iucv_connection *cp; | ||
2106 | struct net_device *ndev; | ||
2107 | struct netiucv_priv *priv; | ||
2108 | struct device *dev; | ||
2109 | |||
2126 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2110 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
2127 | while (iucv_conns.iucv_connections) { | 2111 | while (!list_empty(&iucv_connection_list)) { |
2128 | struct net_device *ndev = iucv_conns.iucv_connections->netdev; | 2112 | cp = list_entry(iucv_connection_list.next, |
2129 | struct netiucv_priv *priv = (struct netiucv_priv*)ndev->priv; | 2113 | struct iucv_connection, list); |
2130 | struct device *dev = priv->dev; | 2114 | list_del(&cp->list); |
2115 | ndev = cp->netdev; | ||
2116 | priv = netdev_priv(ndev); | ||
2117 | dev = priv->dev; | ||
2131 | 2118 | ||
2132 | unregister_netdev(ndev); | 2119 | unregister_netdev(ndev); |
2133 | netiucv_unregister_device(dev); | 2120 | netiucv_unregister_device(dev); |
2134 | } | 2121 | } |
2135 | 2122 | ||
2136 | driver_remove_file(&netiucv_driver, &driver_attr_connection); | 2123 | sysfs_remove_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); |
2137 | driver_remove_file(&netiucv_driver, &driver_attr_remove); | ||
2138 | driver_unregister(&netiucv_driver); | 2124 | driver_unregister(&netiucv_driver); |
2125 | iucv_unregister(&netiucv_handler, 1); | ||
2139 | iucv_unregister_dbf_views(); | 2126 | iucv_unregister_dbf_views(); |
2140 | 2127 | ||
2141 | PRINT_INFO("NETIUCV driver unloaded\n"); | 2128 | PRINT_INFO("NETIUCV driver unloaded\n"); |
2142 | return; | 2129 | return; |
2143 | } | 2130 | } |
2144 | 2131 | ||
2145 | static int __init | 2132 | static int __init netiucv_init(void) |
2146 | netiucv_init(void) | ||
2147 | { | 2133 | { |
2148 | int ret; | 2134 | int rc; |
2149 | 2135 | ||
2150 | ret = iucv_register_dbf_views(); | 2136 | rc = iucv_register_dbf_views(); |
2151 | if (ret) { | 2137 | if (rc) |
2152 | PRINT_WARN("netiucv_init failed, " | 2138 | goto out; |
2153 | "iucv_register_dbf_views rc = %d\n", ret); | 2139 | rc = iucv_register(&netiucv_handler, 1); |
2154 | return ret; | 2140 | if (rc) |
2155 | } | 2141 | goto out_dbf; |
2156 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); | 2142 | IUCV_DBF_TEXT(trace, 3, __FUNCTION__); |
2157 | ret = driver_register(&netiucv_driver); | 2143 | rc = driver_register(&netiucv_driver); |
2158 | if (ret) { | 2144 | if (rc) { |
2159 | PRINT_ERR("NETIUCV: failed to register driver.\n"); | 2145 | PRINT_ERR("NETIUCV: failed to register driver.\n"); |
2160 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", ret); | 2146 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); |
2161 | iucv_unregister_dbf_views(); | 2147 | goto out_iucv; |
2162 | return ret; | ||
2163 | } | 2148 | } |
2164 | 2149 | ||
2165 | /* Add entry for specifying connections. */ | 2150 | rc = sysfs_create_group(&netiucv_driver.kobj, &netiucv_drv_attr_group); |
2166 | ret = driver_create_file(&netiucv_driver, &driver_attr_connection); | 2151 | if (rc) { |
2167 | if (!ret) { | 2152 | PRINT_ERR("NETIUCV: failed to add driver attributes.\n"); |
2168 | ret = driver_create_file(&netiucv_driver, &driver_attr_remove); | 2153 | IUCV_DBF_TEXT_(setup, 2, |
2169 | netiucv_banner(); | 2154 | "ret %d - netiucv_drv_attr_group\n", rc); |
2170 | rwlock_init(&iucv_conns.iucv_rwlock); | 2155 | goto out_driver; |
2171 | } else { | ||
2172 | PRINT_ERR("NETIUCV: failed to add driver attribute.\n"); | ||
2173 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_create_file\n", ret); | ||
2174 | driver_unregister(&netiucv_driver); | ||
2175 | iucv_unregister_dbf_views(); | ||
2176 | } | 2156 | } |
2177 | return ret; | 2157 | netiucv_banner(); |
2158 | return rc; | ||
2159 | |||
2160 | out_driver: | ||
2161 | driver_unregister(&netiucv_driver); | ||
2162 | out_iucv: | ||
2163 | iucv_unregister(&netiucv_handler, 1); | ||
2164 | out_dbf: | ||
2165 | iucv_unregister_dbf_views(); | ||
2166 | out: | ||
2167 | return rc; | ||
2178 | } | 2168 | } |
2179 | 2169 | ||
2180 | module_init(netiucv_init); | 2170 | module_init(netiucv_init); |
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index b8179c27ceb6..3ccca5871fdf 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV special message driver | 2 | * IUCV special message driver |
3 | * | 3 | * |
4 | * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation |
5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | 5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
@@ -23,10 +23,10 @@ | |||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/errno.h> | 24 | #include <linux/errno.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <net/iucv/iucv.h> | ||
26 | #include <asm/cpcmd.h> | 27 | #include <asm/cpcmd.h> |
27 | #include <asm/ebcdic.h> | 28 | #include <asm/ebcdic.h> |
28 | 29 | #include "smsgiucv.h" | |
29 | #include "iucv.h" | ||
30 | 30 | ||
31 | struct smsg_callback { | 31 | struct smsg_callback { |
32 | struct list_head list; | 32 | struct list_head list; |
@@ -39,38 +39,46 @@ MODULE_AUTHOR | |||
39 | ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)"); | 39 | ("(C) 2003 IBM Corporation by Martin Schwidefsky (schwidefsky@de.ibm.com)"); |
40 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); | 40 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); |
41 | 41 | ||
42 | static iucv_handle_t smsg_handle; | 42 | static struct iucv_path *smsg_path; |
43 | static unsigned short smsg_pathid; | 43 | |
44 | static DEFINE_SPINLOCK(smsg_list_lock); | 44 | static DEFINE_SPINLOCK(smsg_list_lock); |
45 | static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list); | 45 | static struct list_head smsg_list = LIST_HEAD_INIT(smsg_list); |
46 | 46 | ||
47 | static void | 47 | static int smsg_path_pending(struct iucv_path *, u8 ipvmid[8], u8 ipuser[16]); |
48 | smsg_connection_complete(iucv_ConnectionComplete *eib, void *pgm_data) | 48 | static void smsg_message_pending(struct iucv_path *, struct iucv_message *); |
49 | |||
50 | static struct iucv_handler smsg_handler = { | ||
51 | .path_pending = smsg_path_pending, | ||
52 | .message_pending = smsg_message_pending, | ||
53 | }; | ||
54 | |||
55 | static int smsg_path_pending(struct iucv_path *path, u8 ipvmid[8], | ||
56 | u8 ipuser[16]) | ||
49 | { | 57 | { |
58 | if (strncmp(ipvmid, "*MSG ", sizeof(ipvmid)) != 0) | ||
59 | return -EINVAL; | ||
60 | /* Path pending from *MSG. */ | ||
61 | return iucv_path_accept(path, &smsg_handler, "SMSGIUCV ", NULL); | ||
50 | } | 62 | } |
51 | 63 | ||
52 | 64 | static void smsg_message_pending(struct iucv_path *path, | |
53 | static void | 65 | struct iucv_message *msg) |
54 | smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) | ||
55 | { | 66 | { |
56 | struct smsg_callback *cb; | 67 | struct smsg_callback *cb; |
57 | unsigned char *msg; | 68 | unsigned char *buffer; |
58 | unsigned char sender[9]; | 69 | unsigned char sender[9]; |
59 | unsigned short len; | ||
60 | int rc, i; | 70 | int rc, i; |
61 | 71 | ||
62 | len = eib->ln1msg2.ipbfln1f; | 72 | buffer = kmalloc(msg->length + 1, GFP_ATOMIC | GFP_DMA); |
63 | msg = kmalloc(len + 1, GFP_ATOMIC|GFP_DMA); | 73 | if (!buffer) { |
64 | if (!msg) { | 74 | iucv_message_reject(path, msg); |
65 | iucv_reject(eib->ippathid, eib->ipmsgid, eib->iptrgcls); | ||
66 | return; | 75 | return; |
67 | } | 76 | } |
68 | rc = iucv_receive(eib->ippathid, eib->ipmsgid, eib->iptrgcls, | 77 | rc = iucv_message_receive(path, msg, 0, buffer, msg->length, NULL); |
69 | msg, len, NULL, NULL, NULL); | ||
70 | if (rc == 0) { | 78 | if (rc == 0) { |
71 | msg[len] = 0; | 79 | buffer[msg->length] = 0; |
72 | EBCASC(msg, len); | 80 | EBCASC(buffer, msg->length); |
73 | memcpy(sender, msg, 8); | 81 | memcpy(sender, buffer, 8); |
74 | sender[8] = 0; | 82 | sender[8] = 0; |
75 | /* Remove trailing whitespace from the sender name. */ | 83 | /* Remove trailing whitespace from the sender name. */ |
76 | for (i = 7; i >= 0; i--) { | 84 | for (i = 7; i >= 0; i--) { |
@@ -80,27 +88,17 @@ smsg_message_pending(iucv_MessagePending *eib, void *pgm_data) | |||
80 | } | 88 | } |
81 | spin_lock(&smsg_list_lock); | 89 | spin_lock(&smsg_list_lock); |
82 | list_for_each_entry(cb, &smsg_list, list) | 90 | list_for_each_entry(cb, &smsg_list, list) |
83 | if (strncmp(msg + 8, cb->prefix, cb->len) == 0) { | 91 | if (strncmp(buffer + 8, cb->prefix, cb->len) == 0) { |
84 | cb->callback(sender, msg + 8); | 92 | cb->callback(sender, buffer + 8); |
85 | break; | 93 | break; |
86 | } | 94 | } |
87 | spin_unlock(&smsg_list_lock); | 95 | spin_unlock(&smsg_list_lock); |
88 | } | 96 | } |
89 | kfree(msg); | 97 | kfree(buffer); |
90 | } | 98 | } |
91 | 99 | ||
92 | static iucv_interrupt_ops_t smsg_ops = { | 100 | int smsg_register_callback(char *prefix, |
93 | .ConnectionComplete = smsg_connection_complete, | 101 | void (*callback)(char *from, char *str)) |
94 | .MessagePending = smsg_message_pending, | ||
95 | }; | ||
96 | |||
97 | static struct device_driver smsg_driver = { | ||
98 | .name = "SMSGIUCV", | ||
99 | .bus = &iucv_bus, | ||
100 | }; | ||
101 | |||
102 | int | ||
103 | smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) | ||
104 | { | 102 | { |
105 | struct smsg_callback *cb; | 103 | struct smsg_callback *cb; |
106 | 104 | ||
@@ -110,18 +108,18 @@ smsg_register_callback(char *prefix, void (*callback)(char *from, char *str)) | |||
110 | cb->prefix = prefix; | 108 | cb->prefix = prefix; |
111 | cb->len = strlen(prefix); | 109 | cb->len = strlen(prefix); |
112 | cb->callback = callback; | 110 | cb->callback = callback; |
113 | spin_lock(&smsg_list_lock); | 111 | spin_lock_bh(&smsg_list_lock); |
114 | list_add_tail(&cb->list, &smsg_list); | 112 | list_add_tail(&cb->list, &smsg_list); |
115 | spin_unlock(&smsg_list_lock); | 113 | spin_unlock_bh(&smsg_list_lock); |
116 | return 0; | 114 | return 0; |
117 | } | 115 | } |
118 | 116 | ||
119 | void | 117 | void smsg_unregister_callback(char *prefix, |
120 | smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) | 118 | void (*callback)(char *from, char *str)) |
121 | { | 119 | { |
122 | struct smsg_callback *cb, *tmp; | 120 | struct smsg_callback *cb, *tmp; |
123 | 121 | ||
124 | spin_lock(&smsg_list_lock); | 122 | spin_lock_bh(&smsg_list_lock); |
125 | cb = NULL; | 123 | cb = NULL; |
126 | list_for_each_entry(tmp, &smsg_list, list) | 124 | list_for_each_entry(tmp, &smsg_list, list) |
127 | if (tmp->callback == callback && | 125 | if (tmp->callback == callback && |
@@ -130,55 +128,58 @@ smsg_unregister_callback(char *prefix, void (*callback)(char *from, char *str)) | |||
130 | list_del(&cb->list); | 128 | list_del(&cb->list); |
131 | break; | 129 | break; |
132 | } | 130 | } |
133 | spin_unlock(&smsg_list_lock); | 131 | spin_unlock_bh(&smsg_list_lock); |
134 | kfree(cb); | 132 | kfree(cb); |
135 | } | 133 | } |
136 | 134 | ||
137 | static void __exit | 135 | static struct device_driver smsg_driver = { |
138 | smsg_exit(void) | 136 | .name = "SMSGIUCV", |
137 | .bus = &iucv_bus, | ||
138 | }; | ||
139 | |||
140 | static void __exit smsg_exit(void) | ||
139 | { | 141 | { |
140 | if (smsg_handle > 0) { | 142 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
141 | cpcmd("SET SMSG OFF", NULL, 0, NULL); | 143 | iucv_unregister(&smsg_handler, 1); |
142 | iucv_sever(smsg_pathid, NULL); | 144 | driver_unregister(&smsg_driver); |
143 | iucv_unregister_program(smsg_handle); | ||
144 | driver_unregister(&smsg_driver); | ||
145 | } | ||
146 | return; | ||
147 | } | 145 | } |
148 | 146 | ||
149 | static int __init | 147 | static int __init smsg_init(void) |
150 | smsg_init(void) | ||
151 | { | 148 | { |
152 | static unsigned char pgmmask[24] = { | ||
153 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
154 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | ||
155 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
156 | }; | ||
157 | int rc; | 149 | int rc; |
158 | 150 | ||
159 | rc = driver_register(&smsg_driver); | 151 | rc = driver_register(&smsg_driver); |
160 | if (rc != 0) { | 152 | if (rc != 0) |
161 | printk(KERN_ERR "SMSGIUCV: failed to register driver.\n"); | 153 | goto out; |
162 | return rc; | 154 | rc = iucv_register(&smsg_handler, 1); |
163 | } | 155 | if (rc) { |
164 | smsg_handle = iucv_register_program("SMSGIUCV ", "*MSG ", | ||
165 | pgmmask, &smsg_ops, NULL); | ||
166 | if (!smsg_handle) { | ||
167 | printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); | 156 | printk(KERN_ERR "SMSGIUCV: failed to register to iucv"); |
168 | driver_unregister(&smsg_driver); | 157 | rc = -EIO; /* better errno ? */ |
169 | return -EIO; /* better errno ? */ | 158 | goto out_driver; |
159 | } | ||
160 | smsg_path = iucv_path_alloc(255, 0, GFP_KERNEL); | ||
161 | if (!smsg_path) { | ||
162 | rc = -ENOMEM; | ||
163 | goto out_register; | ||
170 | } | 164 | } |
171 | rc = iucv_connect (&smsg_pathid, 255, NULL, "*MSG ", NULL, 0, | 165 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", |
172 | NULL, NULL, smsg_handle, NULL); | 166 | NULL, NULL, NULL); |
173 | if (rc) { | 167 | if (rc) { |
174 | printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); | 168 | printk(KERN_ERR "SMSGIUCV: failed to connect to *MSG"); |
175 | iucv_unregister_program(smsg_handle); | 169 | rc = -EIO; /* better errno ? */ |
176 | driver_unregister(&smsg_driver); | 170 | goto out_free; |
177 | smsg_handle = NULL; | ||
178 | return -EIO; | ||
179 | } | 171 | } |
180 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 172 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
181 | return 0; | 173 | return 0; |
174 | |||
175 | out_free: | ||
176 | iucv_path_free(smsg_path); | ||
177 | out_register: | ||
178 | iucv_unregister(&smsg_handler, 1); | ||
179 | out_driver: | ||
180 | driver_unregister(&smsg_driver); | ||
181 | out: | ||
182 | return rc; | ||
182 | } | 183 | } |
183 | 184 | ||
184 | module_init(smsg_init); | 185 | module_init(smsg_init); |