diff options
Diffstat (limited to 'drivers/s390/net/ctcm_main.c')
-rw-r--r-- | drivers/s390/net/ctcm_main.c | 1772 |
1 files changed, 1772 insertions, 0 deletions
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c new file mode 100644 index 000000000000..d52843da4f55 --- /dev/null +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -0,0 +1,1772 @@ | |||
1 | /* | ||
2 | * drivers/s390/net/ctcm_main.c | ||
3 | * | ||
4 | * Copyright IBM Corp. 2001, 2007 | ||
5 | * Author(s): | ||
6 | * Original CTC driver(s): | ||
7 | * Fritz Elfert (felfert@millenux.com) | ||
8 | * Dieter Wellerdiek (wel@de.ibm.com) | ||
9 | * Martin Schwidefsky (schwidefsky@de.ibm.com) | ||
10 | * Denis Joseph Barrow (barrow_dj@yahoo.com) | ||
11 | * Jochen Roehrig (roehrig@de.ibm.com) | ||
12 | * Cornelia Huck <cornelia.huck@de.ibm.com> | ||
13 | * MPC additions: | ||
14 | * Belinda Thompson (belindat@us.ibm.com) | ||
15 | * Andy Richter (richtera@us.ibm.com) | ||
16 | * Revived by: | ||
17 | * Peter Tiedemann (ptiedem@de.ibm.com) | ||
18 | */ | ||
19 | |||
20 | #undef DEBUG | ||
21 | #undef DEBUGDATA | ||
22 | #undef DEBUGCCW | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/timer.h> | ||
32 | #include <linux/bitops.h> | ||
33 | |||
34 | #include <linux/signal.h> | ||
35 | #include <linux/string.h> | ||
36 | |||
37 | #include <linux/ip.h> | ||
38 | #include <linux/if_arp.h> | ||
39 | #include <linux/tcp.h> | ||
40 | #include <linux/skbuff.h> | ||
41 | #include <linux/ctype.h> | ||
42 | #include <net/dst.h> | ||
43 | |||
44 | #include <linux/io.h> | ||
45 | #include <asm/ccwdev.h> | ||
46 | #include <asm/ccwgroup.h> | ||
47 | #include <linux/uaccess.h> | ||
48 | |||
49 | #include <asm/idals.h> | ||
50 | |||
51 | #include "cu3088.h" | ||
52 | #include "ctcm_fsms.h" | ||
53 | #include "ctcm_main.h" | ||
54 | |||
55 | /* Some common global variables */ | ||
56 | |||
57 | /* | ||
58 | * Linked list of all detected channels. | ||
59 | */ | ||
60 | struct channel *channels; | ||
61 | |||
62 | /** | ||
63 | * Unpack a just received skb and hand it over to | ||
64 | * upper layers. | ||
65 | * | ||
66 | * ch The channel where this skb has been received. | ||
67 | * pskb The received skb. | ||
68 | */ | ||
69 | void ctcm_unpack_skb(struct channel *ch, struct sk_buff *pskb) | ||
70 | { | ||
71 | struct net_device *dev = ch->netdev; | ||
72 | struct ctcm_priv *priv = dev->priv; | ||
73 | __u16 len = *((__u16 *) pskb->data); | ||
74 | |||
75 | skb_put(pskb, 2 + LL_HEADER_LENGTH); | ||
76 | skb_pull(pskb, 2); | ||
77 | pskb->dev = dev; | ||
78 | pskb->ip_summed = CHECKSUM_UNNECESSARY; | ||
79 | while (len > 0) { | ||
80 | struct sk_buff *skb; | ||
81 | int skblen; | ||
82 | struct ll_header *header = (struct ll_header *)pskb->data; | ||
83 | |||
84 | skb_pull(pskb, LL_HEADER_LENGTH); | ||
85 | if ((ch->protocol == CTCM_PROTO_S390) && | ||
86 | (header->type != ETH_P_IP)) { | ||
87 | |||
88 | if (!(ch->logflags & LOG_FLAG_ILLEGALPKT)) { | ||
89 | /* | ||
90 | * Check packet type only if we stick strictly | ||
91 | * to S/390's protocol of OS390. This only | ||
92 | * supports IP. Otherwise allow any packet | ||
93 | * type. | ||
94 | */ | ||
95 | ctcm_pr_warn("%s Illegal packet type 0x%04x " | ||
96 | "received, dropping\n", | ||
97 | dev->name, header->type); | ||
98 | ch->logflags |= LOG_FLAG_ILLEGALPKT; | ||
99 | } | ||
100 | |||
101 | priv->stats.rx_dropped++; | ||
102 | priv->stats.rx_frame_errors++; | ||
103 | return; | ||
104 | } | ||
105 | pskb->protocol = ntohs(header->type); | ||
106 | if (header->length <= LL_HEADER_LENGTH) { | ||
107 | if (!(ch->logflags & LOG_FLAG_ILLEGALSIZE)) { | ||
108 | ctcm_pr_warn( | ||
109 | "%s Illegal packet size %d " | ||
110 | "received (MTU=%d blocklen=%d), " | ||
111 | "dropping\n", dev->name, header->length, | ||
112 | dev->mtu, len); | ||
113 | ch->logflags |= LOG_FLAG_ILLEGALSIZE; | ||
114 | } | ||
115 | |||
116 | priv->stats.rx_dropped++; | ||
117 | priv->stats.rx_length_errors++; | ||
118 | return; | ||
119 | } | ||
120 | header->length -= LL_HEADER_LENGTH; | ||
121 | len -= LL_HEADER_LENGTH; | ||
122 | if ((header->length > skb_tailroom(pskb)) || | ||
123 | (header->length > len)) { | ||
124 | if (!(ch->logflags & LOG_FLAG_OVERRUN)) { | ||
125 | ctcm_pr_warn( | ||
126 | "%s Illegal packet size %d (beyond the" | ||
127 | " end of received data), dropping\n", | ||
128 | dev->name, header->length); | ||
129 | ch->logflags |= LOG_FLAG_OVERRUN; | ||
130 | } | ||
131 | |||
132 | priv->stats.rx_dropped++; | ||
133 | priv->stats.rx_length_errors++; | ||
134 | return; | ||
135 | } | ||
136 | skb_put(pskb, header->length); | ||
137 | skb_reset_mac_header(pskb); | ||
138 | len -= header->length; | ||
139 | skb = dev_alloc_skb(pskb->len); | ||
140 | if (!skb) { | ||
141 | if (!(ch->logflags & LOG_FLAG_NOMEM)) { | ||
142 | ctcm_pr_warn( | ||
143 | "%s Out of memory in ctcm_unpack_skb\n", | ||
144 | dev->name); | ||
145 | ch->logflags |= LOG_FLAG_NOMEM; | ||
146 | } | ||
147 | priv->stats.rx_dropped++; | ||
148 | return; | ||
149 | } | ||
150 | skb_copy_from_linear_data(pskb, skb_put(skb, pskb->len), | ||
151 | pskb->len); | ||
152 | skb_reset_mac_header(skb); | ||
153 | skb->dev = pskb->dev; | ||
154 | skb->protocol = pskb->protocol; | ||
155 | pskb->ip_summed = CHECKSUM_UNNECESSARY; | ||
156 | skblen = skb->len; | ||
157 | /* | ||
158 | * reset logflags | ||
159 | */ | ||
160 | ch->logflags = 0; | ||
161 | priv->stats.rx_packets++; | ||
162 | priv->stats.rx_bytes += skblen; | ||
163 | netif_rx_ni(skb); | ||
164 | dev->last_rx = jiffies; | ||
165 | if (len > 0) { | ||
166 | skb_pull(pskb, header->length); | ||
167 | if (skb_tailroom(pskb) < LL_HEADER_LENGTH) { | ||
168 | if (!(ch->logflags & LOG_FLAG_OVERRUN)) { | ||
169 | CTCM_DBF_DEV_NAME(TRACE, dev, | ||
170 | "Overrun in ctcm_unpack_skb"); | ||
171 | ch->logflags |= LOG_FLAG_OVERRUN; | ||
172 | } | ||
173 | return; | ||
174 | } | ||
175 | skb_put(pskb, LL_HEADER_LENGTH); | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /** | ||
181 | * Release a specific channel in the channel list. | ||
182 | * | ||
183 | * ch Pointer to channel struct to be released. | ||
184 | */ | ||
185 | static void channel_free(struct channel *ch) | ||
186 | { | ||
187 | CTCM_DBF_TEXT(TRACE, 2, __FUNCTION__); | ||
188 | ch->flags &= ~CHANNEL_FLAGS_INUSE; | ||
189 | fsm_newstate(ch->fsm, CTC_STATE_IDLE); | ||
190 | } | ||
191 | |||
192 | /** | ||
193 | * Remove a specific channel in the channel list. | ||
194 | * | ||
195 | * ch Pointer to channel struct to be released. | ||
196 | */ | ||
197 | static void channel_remove(struct channel *ch) | ||
198 | { | ||
199 | struct channel **c = &channels; | ||
200 | char chid[CTCM_ID_SIZE+1]; | ||
201 | int ok = 0; | ||
202 | |||
203 | if (ch == NULL) | ||
204 | return; | ||
205 | else | ||
206 | strncpy(chid, ch->id, CTCM_ID_SIZE); | ||
207 | |||
208 | channel_free(ch); | ||
209 | while (*c) { | ||
210 | if (*c == ch) { | ||
211 | *c = ch->next; | ||
212 | fsm_deltimer(&ch->timer); | ||
213 | if (IS_MPC(ch)) | ||
214 | fsm_deltimer(&ch->sweep_timer); | ||
215 | |||
216 | kfree_fsm(ch->fsm); | ||
217 | clear_normalized_cda(&ch->ccw[4]); | ||
218 | if (ch->trans_skb != NULL) { | ||
219 | clear_normalized_cda(&ch->ccw[1]); | ||
220 | dev_kfree_skb_any(ch->trans_skb); | ||
221 | } | ||
222 | if (IS_MPC(ch)) { | ||
223 | tasklet_kill(&ch->ch_tasklet); | ||
224 | tasklet_kill(&ch->ch_disc_tasklet); | ||
225 | kfree(ch->discontact_th); | ||
226 | } | ||
227 | kfree(ch->ccw); | ||
228 | kfree(ch->irb); | ||
229 | kfree(ch); | ||
230 | ok = 1; | ||
231 | break; | ||
232 | } | ||
233 | c = &((*c)->next); | ||
234 | } | ||
235 | |||
236 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, "%s(%s) %s", CTCM_FUNTAIL, | ||
237 | chid, ok ? "OK" : "failed"); | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * Get a specific channel from the channel list. | ||
242 | * | ||
243 | * type Type of channel we are interested in. | ||
244 | * id Id of channel we are interested in. | ||
245 | * direction Direction we want to use this channel for. | ||
246 | * | ||
247 | * returns Pointer to a channel or NULL if no matching channel available. | ||
248 | */ | ||
249 | static struct channel *channel_get(enum channel_types type, | ||
250 | char *id, int direction) | ||
251 | { | ||
252 | struct channel *ch = channels; | ||
253 | |||
254 | if (do_debug) { | ||
255 | char buf[64]; | ||
256 | sprintf(buf, "%s(%d, %s, %d)\n", | ||
257 | CTCM_FUNTAIL, type, id, direction); | ||
258 | CTCM_DBF_TEXT(TRACE, CTC_DBF_INFO, buf); | ||
259 | } | ||
260 | while (ch && (strncmp(ch->id, id, CTCM_ID_SIZE) || (ch->type != type))) | ||
261 | ch = ch->next; | ||
262 | if (!ch) { | ||
263 | char buf[64]; | ||
264 | sprintf(buf, "%s(%d, %s, %d) not found in channel list\n", | ||
265 | CTCM_FUNTAIL, type, id, direction); | ||
266 | CTCM_DBF_TEXT(ERROR, CTC_DBF_ERROR, buf); | ||
267 | } else { | ||
268 | if (ch->flags & CHANNEL_FLAGS_INUSE) | ||
269 | ch = NULL; | ||
270 | else { | ||
271 | ch->flags |= CHANNEL_FLAGS_INUSE; | ||
272 | ch->flags &= ~CHANNEL_FLAGS_RWMASK; | ||
273 | ch->flags |= (direction == WRITE) | ||
274 | ? CHANNEL_FLAGS_WRITE : CHANNEL_FLAGS_READ; | ||
275 | fsm_newstate(ch->fsm, CTC_STATE_STOPPED); | ||
276 | } | ||
277 | } | ||
278 | return ch; | ||
279 | } | ||
280 | |||
281 | static long ctcm_check_irb_error(struct ccw_device *cdev, struct irb *irb) | ||
282 | { | ||
283 | if (!IS_ERR(irb)) | ||
284 | return 0; | ||
285 | |||
286 | CTCM_DBF_TEXT_(ERROR, CTC_DBF_WARN, "irb error %ld on device %s\n", | ||
287 | PTR_ERR(irb), cdev->dev.bus_id); | ||
288 | |||
289 | switch (PTR_ERR(irb)) { | ||
290 | case -EIO: | ||
291 | ctcm_pr_warn("i/o-error on device %s\n", cdev->dev.bus_id); | ||
292 | break; | ||
293 | case -ETIMEDOUT: | ||
294 | ctcm_pr_warn("timeout on device %s\n", cdev->dev.bus_id); | ||
295 | break; | ||
296 | default: | ||
297 | ctcm_pr_warn("unknown error %ld on device %s\n", | ||
298 | PTR_ERR(irb), cdev->dev.bus_id); | ||
299 | } | ||
300 | return PTR_ERR(irb); | ||
301 | } | ||
302 | |||
303 | |||
304 | /** | ||
305 | * Check sense of a unit check. | ||
306 | * | ||
307 | * ch The channel, the sense code belongs to. | ||
308 | * sense The sense code to inspect. | ||
309 | */ | ||
310 | static inline void ccw_unit_check(struct channel *ch, unsigned char sense) | ||
311 | { | ||
312 | CTCM_DBF_TEXT(TRACE, 5, __FUNCTION__); | ||
313 | if (sense & SNS0_INTERVENTION_REQ) { | ||
314 | if (sense & 0x01) { | ||
315 | ctcm_pr_debug("%s: Interface disc. or Sel. reset " | ||
316 | "(remote)\n", ch->id); | ||
317 | fsm_event(ch->fsm, CTC_EVENT_UC_RCRESET, ch); | ||
318 | } else { | ||
319 | ctcm_pr_debug("%s: System reset (remote)\n", ch->id); | ||
320 | fsm_event(ch->fsm, CTC_EVENT_UC_RSRESET, ch); | ||
321 | } | ||
322 | } else if (sense & SNS0_EQUIPMENT_CHECK) { | ||
323 | if (sense & SNS0_BUS_OUT_CHECK) { | ||
324 | ctcm_pr_warn("%s: Hardware malfunction (remote)\n", | ||
325 | ch->id); | ||
326 | fsm_event(ch->fsm, CTC_EVENT_UC_HWFAIL, ch); | ||
327 | } else { | ||
328 | ctcm_pr_warn("%s: Read-data parity error (remote)\n", | ||
329 | ch->id); | ||
330 | fsm_event(ch->fsm, CTC_EVENT_UC_RXPARITY, ch); | ||
331 | } | ||
332 | } else if (sense & SNS0_BUS_OUT_CHECK) { | ||
333 | if (sense & 0x04) { | ||
334 | ctcm_pr_warn("%s: Data-streaming timeout)\n", ch->id); | ||
335 | fsm_event(ch->fsm, CTC_EVENT_UC_TXTIMEOUT, ch); | ||
336 | } else { | ||
337 | ctcm_pr_warn("%s: Data-transfer parity error\n", | ||
338 | ch->id); | ||
339 | fsm_event(ch->fsm, CTC_EVENT_UC_TXPARITY, ch); | ||
340 | } | ||
341 | } else if (sense & SNS0_CMD_REJECT) { | ||
342 | ctcm_pr_warn("%s: Command reject\n", ch->id); | ||
343 | } else if (sense == 0) { | ||
344 | ctcm_pr_debug("%s: Unit check ZERO\n", ch->id); | ||
345 | fsm_event(ch->fsm, CTC_EVENT_UC_ZERO, ch); | ||
346 | } else { | ||
347 | ctcm_pr_warn("%s: Unit Check with sense code: %02x\n", | ||
348 | ch->id, sense); | ||
349 | fsm_event(ch->fsm, CTC_EVENT_UC_UNKNOWN, ch); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | int ctcm_ch_alloc_buffer(struct channel *ch) | ||
354 | { | ||
355 | CTCM_DBF_TEXT(TRACE, 5, __FUNCTION__); | ||
356 | |||
357 | clear_normalized_cda(&ch->ccw[1]); | ||
358 | ch->trans_skb = __dev_alloc_skb(ch->max_bufsize, GFP_ATOMIC | GFP_DMA); | ||
359 | if (ch->trans_skb == NULL) { | ||
360 | ctcm_pr_warn("%s: Couldn't alloc %s trans_skb\n", | ||
361 | ch->id, | ||
362 | (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX"); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | |||
366 | ch->ccw[1].count = ch->max_bufsize; | ||
367 | if (set_normalized_cda(&ch->ccw[1], ch->trans_skb->data)) { | ||
368 | dev_kfree_skb(ch->trans_skb); | ||
369 | ch->trans_skb = NULL; | ||
370 | ctcm_pr_warn("%s: set_normalized_cda for %s " | ||
371 | "trans_skb failed, dropping packets\n", | ||
372 | ch->id, | ||
373 | (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX"); | ||
374 | return -ENOMEM; | ||
375 | } | ||
376 | |||
377 | ch->ccw[1].count = 0; | ||
378 | ch->trans_skb_data = ch->trans_skb->data; | ||
379 | ch->flags &= ~CHANNEL_FLAGS_BUFSIZE_CHANGED; | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | /* | ||
384 | * Interface API for upper network layers | ||
385 | */ | ||
386 | |||
387 | /** | ||
388 | * Open an interface. | ||
389 | * Called from generic network layer when ifconfig up is run. | ||
390 | * | ||
391 | * dev Pointer to interface struct. | ||
392 | * | ||
393 | * returns 0 on success, -ERRNO on failure. (Never fails.) | ||
394 | */ | ||
395 | int ctcm_open(struct net_device *dev) | ||
396 | { | ||
397 | struct ctcm_priv *priv = dev->priv; | ||
398 | |||
399 | CTCMY_DBF_DEV_NAME(SETUP, dev, ""); | ||
400 | if (!IS_MPC(priv)) | ||
401 | fsm_event(priv->fsm, DEV_EVENT_START, dev); | ||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | /** | ||
406 | * Close an interface. | ||
407 | * Called from generic network layer when ifconfig down is run. | ||
408 | * | ||
409 | * dev Pointer to interface struct. | ||
410 | * | ||
411 | * returns 0 on success, -ERRNO on failure. (Never fails.) | ||
412 | */ | ||
413 | int ctcm_close(struct net_device *dev) | ||
414 | { | ||
415 | struct ctcm_priv *priv = dev->priv; | ||
416 | |||
417 | CTCMY_DBF_DEV_NAME(SETUP, dev, ""); | ||
418 | if (!IS_MPC(priv)) | ||
419 | fsm_event(priv->fsm, DEV_EVENT_STOP, dev); | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | |||
424 | /** | ||
425 | * Transmit a packet. | ||
426 | * This is a helper function for ctcm_tx(). | ||
427 | * | ||
428 | * ch Channel to be used for sending. | ||
429 | * skb Pointer to struct sk_buff of packet to send. | ||
430 | * The linklevel header has already been set up | ||
431 | * by ctcm_tx(). | ||
432 | * | ||
433 | * returns 0 on success, -ERRNO on failure. (Never fails.) | ||
434 | */ | ||
435 | static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb) | ||
436 | { | ||
437 | unsigned long saveflags; | ||
438 | struct ll_header header; | ||
439 | int rc = 0; | ||
440 | __u16 block_len; | ||
441 | int ccw_idx; | ||
442 | struct sk_buff *nskb; | ||
443 | unsigned long hi; | ||
444 | |||
445 | /* we need to acquire the lock for testing the state | ||
446 | * otherwise we can have an IRQ changing the state to | ||
447 | * TXIDLE after the test but before acquiring the lock. | ||
448 | */ | ||
449 | spin_lock_irqsave(&ch->collect_lock, saveflags); | ||
450 | if (fsm_getstate(ch->fsm) != CTC_STATE_TXIDLE) { | ||
451 | int l = skb->len + LL_HEADER_LENGTH; | ||
452 | |||
453 | if (ch->collect_len + l > ch->max_bufsize - 2) { | ||
454 | spin_unlock_irqrestore(&ch->collect_lock, saveflags); | ||
455 | return -EBUSY; | ||
456 | } else { | ||
457 | atomic_inc(&skb->users); | ||
458 | header.length = l; | ||
459 | header.type = skb->protocol; | ||
460 | header.unused = 0; | ||
461 | memcpy(skb_push(skb, LL_HEADER_LENGTH), &header, | ||
462 | LL_HEADER_LENGTH); | ||
463 | skb_queue_tail(&ch->collect_queue, skb); | ||
464 | ch->collect_len += l; | ||
465 | } | ||
466 | spin_unlock_irqrestore(&ch->collect_lock, saveflags); | ||
467 | goto done; | ||
468 | } | ||
469 | spin_unlock_irqrestore(&ch->collect_lock, saveflags); | ||
470 | /* | ||
471 | * Protect skb against beeing free'd by upper | ||
472 | * layers. | ||
473 | */ | ||
474 | atomic_inc(&skb->users); | ||
475 | ch->prof.txlen += skb->len; | ||
476 | header.length = skb->len + LL_HEADER_LENGTH; | ||
477 | header.type = skb->protocol; | ||
478 | header.unused = 0; | ||
479 | memcpy(skb_push(skb, LL_HEADER_LENGTH), &header, LL_HEADER_LENGTH); | ||
480 | block_len = skb->len + 2; | ||
481 | *((__u16 *)skb_push(skb, 2)) = block_len; | ||
482 | |||
483 | /* | ||
484 | * IDAL support in CTCM is broken, so we have to | ||
485 | * care about skb's above 2G ourselves. | ||
486 | */ | ||
487 | hi = ((unsigned long)skb_tail_pointer(skb) + LL_HEADER_LENGTH) >> 31; | ||
488 | if (hi) { | ||
489 | nskb = alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); | ||
490 | if (!nskb) { | ||
491 | atomic_dec(&skb->users); | ||
492 | skb_pull(skb, LL_HEADER_LENGTH + 2); | ||
493 | ctcm_clear_busy(ch->netdev); | ||
494 | return -ENOMEM; | ||
495 | } else { | ||
496 | memcpy(skb_put(nskb, skb->len), skb->data, skb->len); | ||
497 | atomic_inc(&nskb->users); | ||
498 | atomic_dec(&skb->users); | ||
499 | dev_kfree_skb_irq(skb); | ||
500 | skb = nskb; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | ch->ccw[4].count = block_len; | ||
505 | if (set_normalized_cda(&ch->ccw[4], skb->data)) { | ||
506 | /* | ||
507 | * idal allocation failed, try via copying to | ||
508 | * trans_skb. trans_skb usually has a pre-allocated | ||
509 | * idal. | ||
510 | */ | ||
511 | if (ctcm_checkalloc_buffer(ch)) { | ||
512 | /* | ||
513 | * Remove our header. It gets added | ||
514 | * again on retransmit. | ||
515 | */ | ||
516 | atomic_dec(&skb->users); | ||
517 | skb_pull(skb, LL_HEADER_LENGTH + 2); | ||
518 | ctcm_clear_busy(ch->netdev); | ||
519 | return -EBUSY; | ||
520 | } | ||
521 | |||
522 | skb_reset_tail_pointer(ch->trans_skb); | ||
523 | ch->trans_skb->len = 0; | ||
524 | ch->ccw[1].count = skb->len; | ||
525 | skb_copy_from_linear_data(skb, | ||
526 | skb_put(ch->trans_skb, skb->len), skb->len); | ||
527 | atomic_dec(&skb->users); | ||
528 | dev_kfree_skb_irq(skb); | ||
529 | ccw_idx = 0; | ||
530 | } else { | ||
531 | skb_queue_tail(&ch->io_queue, skb); | ||
532 | ccw_idx = 3; | ||
533 | } | ||
534 | ch->retry = 0; | ||
535 | fsm_newstate(ch->fsm, CTC_STATE_TX); | ||
536 | fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch); | ||
537 | spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); | ||
538 | ch->prof.send_stamp = current_kernel_time(); /* xtime */ | ||
539 | rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx], | ||
540 | (unsigned long)ch, 0xff, 0); | ||
541 | spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); | ||
542 | if (ccw_idx == 3) | ||
543 | ch->prof.doios_single++; | ||
544 | if (rc != 0) { | ||
545 | fsm_deltimer(&ch->timer); | ||
546 | ctcm_ccw_check_rc(ch, rc, "single skb TX"); | ||
547 | if (ccw_idx == 3) | ||
548 | skb_dequeue_tail(&ch->io_queue); | ||
549 | /* | ||
550 | * Remove our header. It gets added | ||
551 | * again on retransmit. | ||
552 | */ | ||
553 | skb_pull(skb, LL_HEADER_LENGTH + 2); | ||
554 | } else if (ccw_idx == 0) { | ||
555 | struct net_device *dev = ch->netdev; | ||
556 | struct ctcm_priv *priv = dev->priv; | ||
557 | priv->stats.tx_packets++; | ||
558 | priv->stats.tx_bytes += skb->len - LL_HEADER_LENGTH; | ||
559 | } | ||
560 | done: | ||
561 | ctcm_clear_busy(ch->netdev); | ||
562 | return rc; | ||
563 | } | ||
564 | |||
565 | static void ctcmpc_send_sweep_req(struct channel *rch) | ||
566 | { | ||
567 | struct net_device *dev = rch->netdev; | ||
568 | struct ctcm_priv *priv; | ||
569 | struct mpc_group *grp; | ||
570 | struct th_sweep *header; | ||
571 | struct sk_buff *sweep_skb; | ||
572 | struct channel *ch; | ||
573 | int rc = 0; | ||
574 | |||
575 | priv = dev->priv; | ||
576 | grp = priv->mpcg; | ||
577 | ch = priv->channel[WRITE]; | ||
578 | |||
579 | if (do_debug) | ||
580 | MPC_DBF_DEV_NAME(TRACE, dev, ch->id); | ||
581 | |||
582 | /* sweep processing is not complete until response and request */ | ||
583 | /* has completed for all read channels in group */ | ||
584 | if (grp->in_sweep == 0) { | ||
585 | grp->in_sweep = 1; | ||
586 | grp->sweep_rsp_pend_num = grp->active_channels[READ]; | ||
587 | grp->sweep_req_pend_num = grp->active_channels[READ]; | ||
588 | } | ||
589 | |||
590 | sweep_skb = __dev_alloc_skb(MPC_BUFSIZE_DEFAULT, GFP_ATOMIC|GFP_DMA); | ||
591 | |||
592 | if (sweep_skb == NULL) { | ||
593 | printk(KERN_INFO "Couldn't alloc sweep_skb\n"); | ||
594 | rc = -ENOMEM; | ||
595 | goto done; | ||
596 | } | ||
597 | |||
598 | header = kmalloc(TH_SWEEP_LENGTH, gfp_type()); | ||
599 | |||
600 | if (!header) { | ||
601 | dev_kfree_skb_any(sweep_skb); | ||
602 | rc = -ENOMEM; | ||
603 | goto done; | ||
604 | } | ||
605 | |||
606 | header->th.th_seg = 0x00 ; | ||
607 | header->th.th_ch_flag = TH_SWEEP_REQ; /* 0x0f */ | ||
608 | header->th.th_blk_flag = 0x00; | ||
609 | header->th.th_is_xid = 0x00; | ||
610 | header->th.th_seq_num = 0x00; | ||
611 | header->sw.th_last_seq = ch->th_seq_num; | ||
612 | |||
613 | memcpy(skb_put(sweep_skb, TH_SWEEP_LENGTH), header, TH_SWEEP_LENGTH); | ||
614 | |||
615 | kfree(header); | ||
616 | |||
617 | dev->trans_start = jiffies; | ||
618 | skb_queue_tail(&ch->sweep_queue, sweep_skb); | ||
619 | |||
620 | fsm_addtimer(&ch->sweep_timer, 100, CTC_EVENT_RSWEEP_TIMER, ch); | ||
621 | |||
622 | return; | ||
623 | |||
624 | done: | ||
625 | if (rc != 0) { | ||
626 | grp->in_sweep = 0; | ||
627 | ctcm_clear_busy(dev); | ||
628 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
629 | } | ||
630 | |||
631 | return; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * MPC mode version of transmit_skb | ||
636 | */ | ||
637 | static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb) | ||
638 | { | ||
639 | struct pdu *p_header; | ||
640 | struct net_device *dev = ch->netdev; | ||
641 | struct ctcm_priv *priv = dev->priv; | ||
642 | struct mpc_group *grp = priv->mpcg; | ||
643 | struct th_header *header; | ||
644 | struct sk_buff *nskb; | ||
645 | int rc = 0; | ||
646 | int ccw_idx; | ||
647 | unsigned long hi; | ||
648 | unsigned long saveflags = 0; /* avoids compiler warning */ | ||
649 | __u16 block_len; | ||
650 | |||
651 | if (do_debug) | ||
652 | ctcm_pr_debug( | ||
653 | "ctcm enter: %s(): %s cp=%i ch=0x%p id=%s state=%s\n", | ||
654 | __FUNCTION__, dev->name, smp_processor_id(), ch, | ||
655 | ch->id, fsm_getstate_str(ch->fsm)); | ||
656 | |||
657 | if ((fsm_getstate(ch->fsm) != CTC_STATE_TXIDLE) || grp->in_sweep) { | ||
658 | spin_lock_irqsave(&ch->collect_lock, saveflags); | ||
659 | atomic_inc(&skb->users); | ||
660 | p_header = kmalloc(PDU_HEADER_LENGTH, gfp_type()); | ||
661 | |||
662 | if (!p_header) { | ||
663 | printk(KERN_WARNING "ctcm: OUT OF MEMORY IN %s():" | ||
664 | " Data Lost \n", __FUNCTION__); | ||
665 | |||
666 | atomic_dec(&skb->users); | ||
667 | dev_kfree_skb_any(skb); | ||
668 | spin_unlock_irqrestore(&ch->collect_lock, saveflags); | ||
669 | fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev); | ||
670 | goto done; | ||
671 | } | ||
672 | |||
673 | p_header->pdu_offset = skb->len; | ||
674 | p_header->pdu_proto = 0x01; | ||
675 | p_header->pdu_flag = 0x00; | ||
676 | if (skb->protocol == ntohs(ETH_P_SNAP)) { | ||
677 | p_header->pdu_flag |= PDU_FIRST | PDU_CNTL; | ||
678 | } else { | ||
679 | p_header->pdu_flag |= PDU_FIRST; | ||
680 | } | ||
681 | p_header->pdu_seq = 0; | ||
682 | memcpy(skb_push(skb, PDU_HEADER_LENGTH), p_header, | ||
683 | PDU_HEADER_LENGTH); | ||
684 | |||
685 | if (do_debug_data) { | ||
686 | ctcm_pr_debug("ctcm: %s() Putting on collect_q" | ||
687 | " - skb len: %04x \n", __FUNCTION__, skb->len); | ||
688 | ctcm_pr_debug("ctcm: %s() pdu header and data" | ||
689 | " for up to 32 bytes\n", __FUNCTION__); | ||
690 | ctcmpc_dump32((char *)skb->data, skb->len); | ||
691 | } | ||
692 | |||
693 | skb_queue_tail(&ch->collect_queue, skb); | ||
694 | ch->collect_len += skb->len; | ||
695 | kfree(p_header); | ||
696 | |||
697 | spin_unlock_irqrestore(&ch->collect_lock, saveflags); | ||
698 | goto done; | ||
699 | } | ||
700 | |||
701 | /* | ||
702 | * Protect skb against beeing free'd by upper | ||
703 | * layers. | ||
704 | */ | ||
705 | atomic_inc(&skb->users); | ||
706 | |||
707 | block_len = skb->len + TH_HEADER_LENGTH + PDU_HEADER_LENGTH; | ||
708 | /* | ||
709 | * IDAL support in CTCM is broken, so we have to | ||
710 | * care about skb's above 2G ourselves. | ||
711 | */ | ||
712 | hi = ((unsigned long)skb->tail + TH_HEADER_LENGTH) >> 31; | ||
713 | if (hi) { | ||
714 | nskb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); | ||
715 | if (!nskb) { | ||
716 | printk(KERN_WARNING "ctcm: %s() OUT OF MEMORY" | ||
717 | "- Data Lost \n", __FUNCTION__); | ||
718 | atomic_dec(&skb->users); | ||
719 | dev_kfree_skb_any(skb); | ||
720 | fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev); | ||
721 | goto done; | ||
722 | } else { | ||
723 | memcpy(skb_put(nskb, skb->len), skb->data, skb->len); | ||
724 | atomic_inc(&nskb->users); | ||
725 | atomic_dec(&skb->users); | ||
726 | dev_kfree_skb_irq(skb); | ||
727 | skb = nskb; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | p_header = kmalloc(PDU_HEADER_LENGTH, gfp_type()); | ||
732 | |||
733 | if (!p_header) { | ||
734 | printk(KERN_WARNING "ctcm: %s() OUT OF MEMORY" | ||
735 | ": Data Lost \n", __FUNCTION__); | ||
736 | |||
737 | atomic_dec(&skb->users); | ||
738 | dev_kfree_skb_any(skb); | ||
739 | fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev); | ||
740 | goto done; | ||
741 | } | ||
742 | |||
743 | p_header->pdu_offset = skb->len; | ||
744 | p_header->pdu_proto = 0x01; | ||
745 | p_header->pdu_flag = 0x00; | ||
746 | p_header->pdu_seq = 0; | ||
747 | if (skb->protocol == ntohs(ETH_P_SNAP)) { | ||
748 | p_header->pdu_flag |= PDU_FIRST | PDU_CNTL; | ||
749 | } else { | ||
750 | p_header->pdu_flag |= PDU_FIRST; | ||
751 | } | ||
752 | memcpy(skb_push(skb, PDU_HEADER_LENGTH), p_header, PDU_HEADER_LENGTH); | ||
753 | |||
754 | kfree(p_header); | ||
755 | |||
756 | if (ch->collect_len > 0) { | ||
757 | spin_lock_irqsave(&ch->collect_lock, saveflags); | ||
758 | skb_queue_tail(&ch->collect_queue, skb); | ||
759 | ch->collect_len += skb->len; | ||
760 | skb = skb_dequeue(&ch->collect_queue); | ||
761 | ch->collect_len -= skb->len; | ||
762 | spin_unlock_irqrestore(&ch->collect_lock, saveflags); | ||
763 | } | ||
764 | |||
765 | p_header = (struct pdu *)skb->data; | ||
766 | p_header->pdu_flag |= PDU_LAST; | ||
767 | |||
768 | ch->prof.txlen += skb->len - PDU_HEADER_LENGTH; | ||
769 | |||
770 | header = kmalloc(TH_HEADER_LENGTH, gfp_type()); | ||
771 | |||
772 | if (!header) { | ||
773 | printk(KERN_WARNING "ctcm: %s() OUT OF MEMORY: Data Lost \n", | ||
774 | __FUNCTION__); | ||
775 | atomic_dec(&skb->users); | ||
776 | dev_kfree_skb_any(skb); | ||
777 | fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev); | ||
778 | goto done; | ||
779 | } | ||
780 | |||
781 | header->th_seg = 0x00; | ||
782 | header->th_ch_flag = TH_HAS_PDU; /* Normal data */ | ||
783 | header->th_blk_flag = 0x00; | ||
784 | header->th_is_xid = 0x00; /* Just data here */ | ||
785 | ch->th_seq_num++; | ||
786 | header->th_seq_num = ch->th_seq_num; | ||
787 | |||
788 | if (do_debug_data) | ||
789 | ctcm_pr_debug("ctcm: %s() ToVTAM_th_seq= %08x\n" , | ||
790 | __FUNCTION__, ch->th_seq_num); | ||
791 | |||
792 | /* put the TH on the packet */ | ||
793 | memcpy(skb_push(skb, TH_HEADER_LENGTH), header, TH_HEADER_LENGTH); | ||
794 | |||
795 | kfree(header); | ||
796 | |||
797 | if (do_debug_data) { | ||
798 | ctcm_pr_debug("ctcm: %s(): skb len: %04x \n", | ||
799 | __FUNCTION__, skb->len); | ||
800 | ctcm_pr_debug("ctcm: %s(): pdu header and data for up to 32 " | ||
801 | "bytes sent to vtam\n", __FUNCTION__); | ||
802 | ctcmpc_dump32((char *)skb->data, skb->len); | ||
803 | } | ||
804 | |||
805 | ch->ccw[4].count = skb->len; | ||
806 | if (set_normalized_cda(&ch->ccw[4], skb->data)) { | ||
807 | /* | ||
808 | * idal allocation failed, try via copying to | ||
809 | * trans_skb. trans_skb usually has a pre-allocated | ||
810 | * idal. | ||
811 | */ | ||
812 | if (ctcm_checkalloc_buffer(ch)) { | ||
813 | /* | ||
814 | * Remove our header. It gets added | ||
815 | * again on retransmit. | ||
816 | */ | ||
817 | atomic_dec(&skb->users); | ||
818 | dev_kfree_skb_any(skb); | ||
819 | printk(KERN_WARNING "ctcm: %s()OUT OF MEMORY:" | ||
820 | " Data Lost \n", __FUNCTION__); | ||
821 | fsm_event(priv->mpcg->fsm, MPCG_EVENT_INOP, dev); | ||
822 | goto done; | ||
823 | } | ||
824 | |||
825 | skb_reset_tail_pointer(ch->trans_skb); | ||
826 | ch->trans_skb->len = 0; | ||
827 | ch->ccw[1].count = skb->len; | ||
828 | memcpy(skb_put(ch->trans_skb, skb->len), skb->data, skb->len); | ||
829 | atomic_dec(&skb->users); | ||
830 | dev_kfree_skb_irq(skb); | ||
831 | ccw_idx = 0; | ||
832 | if (do_debug_data) { | ||
833 | ctcm_pr_debug("ctcm: %s() TRANS skb len: %d \n", | ||
834 | __FUNCTION__, ch->trans_skb->len); | ||
835 | ctcm_pr_debug("ctcm: %s up to 32 bytes of data" | ||
836 | " sent to vtam\n", __FUNCTION__); | ||
837 | ctcmpc_dump32((char *)ch->trans_skb->data, | ||
838 | ch->trans_skb->len); | ||
839 | } | ||
840 | } else { | ||
841 | skb_queue_tail(&ch->io_queue, skb); | ||
842 | ccw_idx = 3; | ||
843 | } | ||
844 | ch->retry = 0; | ||
845 | fsm_newstate(ch->fsm, CTC_STATE_TX); | ||
846 | fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch); | ||
847 | |||
848 | if (do_debug_ccw) | ||
849 | ctcmpc_dumpit((char *)&ch->ccw[ccw_idx], | ||
850 | sizeof(struct ccw1) * 3); | ||
851 | |||
852 | spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags); | ||
853 | ch->prof.send_stamp = current_kernel_time(); /* xtime */ | ||
854 | rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx], | ||
855 | (unsigned long)ch, 0xff, 0); | ||
856 | spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags); | ||
857 | if (ccw_idx == 3) | ||
858 | ch->prof.doios_single++; | ||
859 | if (rc != 0) { | ||
860 | fsm_deltimer(&ch->timer); | ||
861 | ctcm_ccw_check_rc(ch, rc, "single skb TX"); | ||
862 | if (ccw_idx == 3) | ||
863 | skb_dequeue_tail(&ch->io_queue); | ||
864 | } else if (ccw_idx == 0) { | ||
865 | priv->stats.tx_packets++; | ||
866 | priv->stats.tx_bytes += skb->len - TH_HEADER_LENGTH; | ||
867 | } | ||
868 | if (ch->th_seq_num > 0xf0000000) /* Chose 4Billion at random. */ | ||
869 | ctcmpc_send_sweep_req(ch); | ||
870 | |||
871 | done: | ||
872 | if (do_debug) | ||
873 | ctcm_pr_debug("ctcm exit: %s %s()\n", dev->name, __FUNCTION__); | ||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | /** | ||
878 | * Start transmission of a packet. | ||
879 | * Called from generic network device layer. | ||
880 | * | ||
881 | * skb Pointer to buffer containing the packet. | ||
882 | * dev Pointer to interface struct. | ||
883 | * | ||
884 | * returns 0 if packet consumed, !0 if packet rejected. | ||
885 | * Note: If we return !0, then the packet is free'd by | ||
886 | * the generic network layer. | ||
887 | */ | ||
888 | /* first merge version - leaving both functions separated */ | ||
889 | static int ctcm_tx(struct sk_buff *skb, struct net_device *dev) | ||
890 | { | ||
891 | int rc = 0; | ||
892 | struct ctcm_priv *priv; | ||
893 | |||
894 | CTCM_DBF_TEXT(TRACE, 5, __FUNCTION__); | ||
895 | priv = dev->priv; | ||
896 | |||
897 | if (skb == NULL) { | ||
898 | ctcm_pr_warn("%s: NULL sk_buff passed\n", dev->name); | ||
899 | priv->stats.tx_dropped++; | ||
900 | return 0; | ||
901 | } | ||
902 | if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) { | ||
903 | ctcm_pr_warn("%s: Got sk_buff with head room < %ld bytes\n", | ||
904 | dev->name, LL_HEADER_LENGTH + 2); | ||
905 | dev_kfree_skb(skb); | ||
906 | priv->stats.tx_dropped++; | ||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | /* | ||
911 | * If channels are not running, try to restart them | ||
912 | * and throw away packet. | ||
913 | */ | ||
914 | if (fsm_getstate(priv->fsm) != DEV_STATE_RUNNING) { | ||
915 | fsm_event(priv->fsm, DEV_EVENT_START, dev); | ||
916 | dev_kfree_skb(skb); | ||
917 | priv->stats.tx_dropped++; | ||
918 | priv->stats.tx_errors++; | ||
919 | priv->stats.tx_carrier_errors++; | ||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | if (ctcm_test_and_set_busy(dev)) | ||
924 | return -EBUSY; | ||
925 | |||
926 | dev->trans_start = jiffies; | ||
927 | if (ctcm_transmit_skb(priv->channel[WRITE], skb) != 0) | ||
928 | rc = 1; | ||
929 | return rc; | ||
930 | } | ||
931 | |||
932 | /* unmerged MPC variant of ctcm_tx */ | ||
933 | static int ctcmpc_tx(struct sk_buff *skb, struct net_device *dev) | ||
934 | { | ||
935 | int len = 0; | ||
936 | struct ctcm_priv *priv = NULL; | ||
937 | struct mpc_group *grp = NULL; | ||
938 | struct sk_buff *newskb = NULL; | ||
939 | |||
940 | if (do_debug) | ||
941 | ctcm_pr_debug("ctcmpc enter: %s(): skb:%0lx\n", | ||
942 | __FUNCTION__, (unsigned long)skb); | ||
943 | |||
944 | CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_DEBUG, | ||
945 | "ctcmpc enter: %s(): skb:%0lx\n", | ||
946 | __FUNCTION__, (unsigned long)skb); | ||
947 | |||
948 | priv = dev->priv; | ||
949 | grp = priv->mpcg; | ||
950 | /* | ||
951 | * Some sanity checks ... | ||
952 | */ | ||
953 | if (skb == NULL) { | ||
954 | ctcm_pr_warn("ctcmpc: %s: NULL sk_buff passed\n", dev->name); | ||
955 | priv->stats.tx_dropped++; | ||
956 | goto done; | ||
957 | } | ||
958 | if (skb_headroom(skb) < (TH_HEADER_LENGTH + PDU_HEADER_LENGTH)) { | ||
959 | CTCM_DBF_TEXT_(MPC_TRACE, CTC_DBF_WARN, | ||
960 | "%s: Got sk_buff with head room < %ld bytes\n", | ||
961 | dev->name, TH_HEADER_LENGTH + PDU_HEADER_LENGTH); | ||
962 | |||
963 | if (do_debug_data) | ||
964 | ctcmpc_dump32((char *)skb->data, skb->len); | ||
965 | |||
966 | len = skb->len + TH_HEADER_LENGTH + PDU_HEADER_LENGTH; | ||
967 | newskb = __dev_alloc_skb(len, gfp_type() | GFP_DMA); | ||
968 | |||
969 | if (!newskb) { | ||
970 | printk(KERN_WARNING "ctcmpc: %s() OUT OF MEMORY-" | ||
971 | "Data Lost\n", | ||
972 | __FUNCTION__); | ||
973 | |||
974 | dev_kfree_skb_any(skb); | ||
975 | priv->stats.tx_dropped++; | ||
976 | priv->stats.tx_errors++; | ||
977 | priv->stats.tx_carrier_errors++; | ||
978 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
979 | goto done; | ||
980 | } | ||
981 | newskb->protocol = skb->protocol; | ||
982 | skb_reserve(newskb, TH_HEADER_LENGTH + PDU_HEADER_LENGTH); | ||
983 | memcpy(skb_put(newskb, skb->len), skb->data, skb->len); | ||
984 | dev_kfree_skb_any(skb); | ||
985 | skb = newskb; | ||
986 | } | ||
987 | |||
988 | /* | ||
989 | * If channels are not running, | ||
990 | * notify anybody about a link failure and throw | ||
991 | * away packet. | ||
992 | */ | ||
993 | if ((fsm_getstate(priv->fsm) != DEV_STATE_RUNNING) || | ||
994 | (fsm_getstate(grp->fsm) < MPCG_STATE_XID2INITW)) { | ||
995 | dev_kfree_skb_any(skb); | ||
996 | printk(KERN_INFO "ctcmpc: %s() DATA RCVD - MPC GROUP " | ||
997 | "NOT ACTIVE - DROPPED\n", | ||
998 | __FUNCTION__); | ||
999 | priv->stats.tx_dropped++; | ||
1000 | priv->stats.tx_errors++; | ||
1001 | priv->stats.tx_carrier_errors++; | ||
1002 | goto done; | ||
1003 | } | ||
1004 | |||
1005 | if (ctcm_test_and_set_busy(dev)) { | ||
1006 | printk(KERN_WARNING "%s:DEVICE ERR - UNRECOVERABLE DATA LOSS\n", | ||
1007 | __FUNCTION__); | ||
1008 | dev_kfree_skb_any(skb); | ||
1009 | priv->stats.tx_dropped++; | ||
1010 | priv->stats.tx_errors++; | ||
1011 | priv->stats.tx_carrier_errors++; | ||
1012 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1013 | goto done; | ||
1014 | } | ||
1015 | |||
1016 | dev->trans_start = jiffies; | ||
1017 | if (ctcmpc_transmit_skb(priv->channel[WRITE], skb) != 0) { | ||
1018 | printk(KERN_WARNING "ctcmpc: %s() DEVICE ERROR" | ||
1019 | ": Data Lost \n", | ||
1020 | __FUNCTION__); | ||
1021 | printk(KERN_WARNING "ctcmpc: %s() DEVICE ERROR" | ||
1022 | " - UNRECOVERABLE DATA LOSS\n", | ||
1023 | __FUNCTION__); | ||
1024 | dev_kfree_skb_any(skb); | ||
1025 | priv->stats.tx_dropped++; | ||
1026 | priv->stats.tx_errors++; | ||
1027 | priv->stats.tx_carrier_errors++; | ||
1028 | ctcm_clear_busy(dev); | ||
1029 | fsm_event(grp->fsm, MPCG_EVENT_INOP, dev); | ||
1030 | goto done; | ||
1031 | } | ||
1032 | ctcm_clear_busy(dev); | ||
1033 | done: | ||
1034 | if (do_debug) | ||
1035 | MPC_DBF_DEV_NAME(TRACE, dev, "exit"); | ||
1036 | |||
1037 | return 0; /* handle freeing of skb here */ | ||
1038 | } | ||
1039 | |||
1040 | |||
1041 | /** | ||
1042 | * Sets MTU of an interface. | ||
1043 | * | ||
1044 | * dev Pointer to interface struct. | ||
1045 | * new_mtu The new MTU to use for this interface. | ||
1046 | * | ||
1047 | * returns 0 on success, -EINVAL if MTU is out of valid range. | ||
1048 | * (valid range is 576 .. 65527). If VM is on the | ||
1049 | * remote side, maximum MTU is 32760, however this is | ||
1050 | * not checked here. | ||
1051 | */ | ||
1052 | static int ctcm_change_mtu(struct net_device *dev, int new_mtu) | ||
1053 | { | ||
1054 | struct ctcm_priv *priv; | ||
1055 | int max_bufsize; | ||
1056 | |||
1057 | CTCM_DBF_TEXT(SETUP, CTC_DBF_INFO, __FUNCTION__); | ||
1058 | |||
1059 | if (new_mtu < 576 || new_mtu > 65527) | ||
1060 | return -EINVAL; | ||
1061 | |||
1062 | priv = dev->priv; | ||
1063 | max_bufsize = priv->channel[READ]->max_bufsize; | ||
1064 | |||
1065 | if (IS_MPC(priv)) { | ||
1066 | if (new_mtu > max_bufsize - TH_HEADER_LENGTH) | ||
1067 | return -EINVAL; | ||
1068 | dev->hard_header_len = TH_HEADER_LENGTH + PDU_HEADER_LENGTH; | ||
1069 | } else { | ||
1070 | if (new_mtu > max_bufsize - LL_HEADER_LENGTH - 2) | ||
1071 | return -EINVAL; | ||
1072 | dev->hard_header_len = LL_HEADER_LENGTH + 2; | ||
1073 | } | ||
1074 | dev->mtu = new_mtu; | ||
1075 | return 0; | ||
1076 | } | ||
1077 | |||
1078 | /** | ||
1079 | * Returns interface statistics of a device. | ||
1080 | * | ||
1081 | * dev Pointer to interface struct. | ||
1082 | * | ||
1083 | * returns Pointer to stats struct of this interface. | ||
1084 | */ | ||
1085 | static struct net_device_stats *ctcm_stats(struct net_device *dev) | ||
1086 | { | ||
1087 | return &((struct ctcm_priv *)dev->priv)->stats; | ||
1088 | } | ||
1089 | |||
1090 | |||
1091 | static void ctcm_netdev_unregister(struct net_device *dev) | ||
1092 | { | ||
1093 | CTCM_DBF_TEXT(SETUP, CTC_DBF_INFO, __FUNCTION__); | ||
1094 | if (!dev) | ||
1095 | return; | ||
1096 | unregister_netdev(dev); | ||
1097 | } | ||
1098 | |||
1099 | static int ctcm_netdev_register(struct net_device *dev) | ||
1100 | { | ||
1101 | CTCM_DBF_TEXT(SETUP, CTC_DBF_INFO, __FUNCTION__); | ||
1102 | return register_netdev(dev); | ||
1103 | } | ||
1104 | |||
1105 | static void ctcm_free_netdevice(struct net_device *dev) | ||
1106 | { | ||
1107 | struct ctcm_priv *priv; | ||
1108 | struct mpc_group *grp; | ||
1109 | |||
1110 | CTCM_DBF_TEXT(SETUP, CTC_DBF_INFO, __FUNCTION__); | ||
1111 | |||
1112 | if (!dev) | ||
1113 | return; | ||
1114 | priv = dev->priv; | ||
1115 | if (priv) { | ||
1116 | grp = priv->mpcg; | ||
1117 | if (grp) { | ||
1118 | if (grp->fsm) | ||
1119 | kfree_fsm(grp->fsm); | ||
1120 | if (grp->xid_skb) | ||
1121 | dev_kfree_skb(grp->xid_skb); | ||
1122 | if (grp->rcvd_xid_skb) | ||
1123 | dev_kfree_skb(grp->rcvd_xid_skb); | ||
1124 | tasklet_kill(&grp->mpc_tasklet2); | ||
1125 | kfree(grp); | ||
1126 | priv->mpcg = NULL; | ||
1127 | } | ||
1128 | if (priv->fsm) { | ||
1129 | kfree_fsm(priv->fsm); | ||
1130 | priv->fsm = NULL; | ||
1131 | } | ||
1132 | kfree(priv->xid); | ||
1133 | priv->xid = NULL; | ||
1134 | /* | ||
1135 | * Note: kfree(priv); is done in "opposite" function of | ||
1136 | * allocator function probe_device which is remove_device. | ||
1137 | */ | ||
1138 | } | ||
1139 | #ifdef MODULE | ||
1140 | free_netdev(dev); | ||
1141 | #endif | ||
1142 | } | ||
1143 | |||
1144 | struct mpc_group *ctcmpc_init_mpc_group(struct ctcm_priv *priv); | ||
1145 | |||
1146 | void static ctcm_dev_setup(struct net_device *dev) | ||
1147 | { | ||
1148 | dev->open = ctcm_open; | ||
1149 | dev->stop = ctcm_close; | ||
1150 | dev->get_stats = ctcm_stats; | ||
1151 | dev->change_mtu = ctcm_change_mtu; | ||
1152 | dev->type = ARPHRD_SLIP; | ||
1153 | dev->tx_queue_len = 100; | ||
1154 | dev->flags = IFF_POINTOPOINT | IFF_NOARP; | ||
1155 | } | ||
1156 | |||
1157 | /* | ||
1158 | * Initialize everything of the net device except the name and the | ||
1159 | * channel structs. | ||
1160 | */ | ||
1161 | static struct net_device *ctcm_init_netdevice(struct ctcm_priv *priv) | ||
1162 | { | ||
1163 | struct net_device *dev; | ||
1164 | struct mpc_group *grp; | ||
1165 | if (!priv) | ||
1166 | return NULL; | ||
1167 | |||
1168 | if (IS_MPC(priv)) | ||
1169 | dev = alloc_netdev(0, MPC_DEVICE_GENE, ctcm_dev_setup); | ||
1170 | else | ||
1171 | dev = alloc_netdev(0, CTC_DEVICE_GENE, ctcm_dev_setup); | ||
1172 | |||
1173 | if (!dev) { | ||
1174 | ctcm_pr_err("%s: Out of memory\n", __FUNCTION__); | ||
1175 | return NULL; | ||
1176 | } | ||
1177 | dev->priv = priv; | ||
1178 | priv->fsm = init_fsm("ctcmdev", dev_state_names, dev_event_names, | ||
1179 | CTCM_NR_DEV_STATES, CTCM_NR_DEV_EVENTS, | ||
1180 | dev_fsm, dev_fsm_len, GFP_KERNEL); | ||
1181 | if (priv->fsm == NULL) { | ||
1182 | CTCMY_DBF_DEV(SETUP, dev, "init_fsm error"); | ||
1183 | kfree(dev); | ||
1184 | return NULL; | ||
1185 | } | ||
1186 | fsm_newstate(priv->fsm, DEV_STATE_STOPPED); | ||
1187 | fsm_settimer(priv->fsm, &priv->restart_timer); | ||
1188 | |||
1189 | if (IS_MPC(priv)) { | ||
1190 | /* MPC Group Initializations */ | ||
1191 | grp = ctcmpc_init_mpc_group(priv); | ||
1192 | if (grp == NULL) { | ||
1193 | MPC_DBF_DEV(SETUP, dev, "init_mpc_group error"); | ||
1194 | kfree(dev); | ||
1195 | return NULL; | ||
1196 | } | ||
1197 | tasklet_init(&grp->mpc_tasklet2, | ||
1198 | mpc_group_ready, (unsigned long)dev); | ||
1199 | dev->mtu = MPC_BUFSIZE_DEFAULT - | ||
1200 | TH_HEADER_LENGTH - PDU_HEADER_LENGTH; | ||
1201 | |||
1202 | dev->hard_start_xmit = ctcmpc_tx; | ||
1203 | dev->hard_header_len = TH_HEADER_LENGTH + PDU_HEADER_LENGTH; | ||
1204 | priv->buffer_size = MPC_BUFSIZE_DEFAULT; | ||
1205 | } else { | ||
1206 | dev->mtu = CTCM_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2; | ||
1207 | dev->hard_start_xmit = ctcm_tx; | ||
1208 | dev->hard_header_len = LL_HEADER_LENGTH + 2; | ||
1209 | } | ||
1210 | |||
1211 | CTCMY_DBF_DEV(SETUP, dev, "finished"); | ||
1212 | return dev; | ||
1213 | } | ||
1214 | |||
1215 | /** | ||
1216 | * Main IRQ handler. | ||
1217 | * | ||
1218 | * cdev The ccw_device the interrupt is for. | ||
1219 | * intparm interruption parameter. | ||
1220 | * irb interruption response block. | ||
1221 | */ | ||
1222 | static void ctcm_irq_handler(struct ccw_device *cdev, | ||
1223 | unsigned long intparm, struct irb *irb) | ||
1224 | { | ||
1225 | struct channel *ch; | ||
1226 | struct net_device *dev; | ||
1227 | struct ctcm_priv *priv; | ||
1228 | struct ccwgroup_device *cgdev; | ||
1229 | |||
1230 | CTCM_DBF_TEXT(TRACE, CTC_DBF_DEBUG, __FUNCTION__); | ||
1231 | if (ctcm_check_irb_error(cdev, irb)) | ||
1232 | return; | ||
1233 | |||
1234 | cgdev = dev_get_drvdata(&cdev->dev); | ||
1235 | |||
1236 | /* Check for unsolicited interrupts. */ | ||
1237 | if (cgdev == NULL) { | ||
1238 | ctcm_pr_warn("ctcm: Got unsolicited irq: %s c-%02x d-%02x\n", | ||
1239 | cdev->dev.bus_id, irb->scsw.cstat, | ||
1240 | irb->scsw.dstat); | ||
1241 | return; | ||
1242 | } | ||
1243 | |||
1244 | priv = dev_get_drvdata(&cgdev->dev); | ||
1245 | |||
1246 | /* Try to extract channel from driver data. */ | ||
1247 | if (priv->channel[READ]->cdev == cdev) | ||
1248 | ch = priv->channel[READ]; | ||
1249 | else if (priv->channel[WRITE]->cdev == cdev) | ||
1250 | ch = priv->channel[WRITE]; | ||
1251 | else { | ||
1252 | ctcm_pr_err("ctcm: Can't determine channel for interrupt, " | ||
1253 | "device %s\n", cdev->dev.bus_id); | ||
1254 | return; | ||
1255 | } | ||
1256 | |||
1257 | dev = (struct net_device *)(ch->netdev); | ||
1258 | if (dev == NULL) { | ||
1259 | ctcm_pr_crit("ctcm: %s dev=NULL bus_id=%s, ch=0x%p\n", | ||
1260 | __FUNCTION__, cdev->dev.bus_id, ch); | ||
1261 | return; | ||
1262 | } | ||
1263 | |||
1264 | if (do_debug) | ||
1265 | ctcm_pr_debug("%s: interrupt for device: %s " | ||
1266 | "received c-%02x d-%02x\n", | ||
1267 | dev->name, | ||
1268 | ch->id, | ||
1269 | irb->scsw.cstat, | ||
1270 | irb->scsw.dstat); | ||
1271 | |||
1272 | /* Copy interruption response block. */ | ||
1273 | memcpy(ch->irb, irb, sizeof(struct irb)); | ||
1274 | |||
1275 | /* Check for good subchannel return code, otherwise error message */ | ||
1276 | if (irb->scsw.cstat) { | ||
1277 | fsm_event(ch->fsm, CTC_EVENT_SC_UNKNOWN, ch); | ||
1278 | ctcm_pr_warn("%s: subchannel check for dev: %s - %02x %02x\n", | ||
1279 | dev->name, ch->id, irb->scsw.cstat, | ||
1280 | irb->scsw.dstat); | ||
1281 | return; | ||
1282 | } | ||
1283 | |||
1284 | /* Check the reason-code of a unit check */ | ||
1285 | if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) { | ||
1286 | ccw_unit_check(ch, irb->ecw[0]); | ||
1287 | return; | ||
1288 | } | ||
1289 | if (irb->scsw.dstat & DEV_STAT_BUSY) { | ||
1290 | if (irb->scsw.dstat & DEV_STAT_ATTENTION) | ||
1291 | fsm_event(ch->fsm, CTC_EVENT_ATTNBUSY, ch); | ||
1292 | else | ||
1293 | fsm_event(ch->fsm, CTC_EVENT_BUSY, ch); | ||
1294 | return; | ||
1295 | } | ||
1296 | if (irb->scsw.dstat & DEV_STAT_ATTENTION) { | ||
1297 | fsm_event(ch->fsm, CTC_EVENT_ATTN, ch); | ||
1298 | return; | ||
1299 | } | ||
1300 | if ((irb->scsw.stctl & SCSW_STCTL_SEC_STATUS) || | ||
1301 | (irb->scsw.stctl == SCSW_STCTL_STATUS_PEND) || | ||
1302 | (irb->scsw.stctl == | ||
1303 | (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) | ||
1304 | fsm_event(ch->fsm, CTC_EVENT_FINSTAT, ch); | ||
1305 | else | ||
1306 | fsm_event(ch->fsm, CTC_EVENT_IRQ, ch); | ||
1307 | |||
1308 | } | ||
1309 | |||
1310 | /** | ||
1311 | * Add ctcm specific attributes. | ||
1312 | * Add ctcm private data. | ||
1313 | * | ||
1314 | * cgdev pointer to ccwgroup_device just added | ||
1315 | * | ||
1316 | * returns 0 on success, !0 on failure. | ||
1317 | */ | ||
1318 | static int ctcm_probe_device(struct ccwgroup_device *cgdev) | ||
1319 | { | ||
1320 | struct ctcm_priv *priv; | ||
1321 | int rc; | ||
1322 | |||
1323 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, "%s %p", __FUNCTION__, cgdev); | ||
1324 | |||
1325 | if (!get_device(&cgdev->dev)) | ||
1326 | return -ENODEV; | ||
1327 | |||
1328 | priv = kzalloc(sizeof(struct ctcm_priv), GFP_KERNEL); | ||
1329 | if (!priv) { | ||
1330 | ctcm_pr_err("%s: Out of memory\n", __FUNCTION__); | ||
1331 | put_device(&cgdev->dev); | ||
1332 | return -ENOMEM; | ||
1333 | } | ||
1334 | |||
1335 | rc = ctcm_add_files(&cgdev->dev); | ||
1336 | if (rc) { | ||
1337 | kfree(priv); | ||
1338 | put_device(&cgdev->dev); | ||
1339 | return rc; | ||
1340 | } | ||
1341 | priv->buffer_size = CTCM_BUFSIZE_DEFAULT; | ||
1342 | cgdev->cdev[0]->handler = ctcm_irq_handler; | ||
1343 | cgdev->cdev[1]->handler = ctcm_irq_handler; | ||
1344 | dev_set_drvdata(&cgdev->dev, priv); | ||
1345 | |||
1346 | return 0; | ||
1347 | } | ||
1348 | |||
1349 | /** | ||
1350 | * Add a new channel to the list of channels. | ||
1351 | * Keeps the channel list sorted. | ||
1352 | * | ||
1353 | * cdev The ccw_device to be added. | ||
1354 | * type The type class of the new channel. | ||
1355 | * priv Points to the private data of the ccwgroup_device. | ||
1356 | * | ||
1357 | * returns 0 on success, !0 on error. | ||
1358 | */ | ||
1359 | static int add_channel(struct ccw_device *cdev, enum channel_types type, | ||
1360 | struct ctcm_priv *priv) | ||
1361 | { | ||
1362 | struct channel **c = &channels; | ||
1363 | struct channel *ch; | ||
1364 | int ccw_num; | ||
1365 | int rc = 0; | ||
1366 | |||
1367 | CTCM_DBF_TEXT(TRACE, 2, __FUNCTION__); | ||
1368 | ch = kzalloc(sizeof(struct channel), GFP_KERNEL); | ||
1369 | if (ch == NULL) | ||
1370 | goto nomem_return; | ||
1371 | |||
1372 | ch->protocol = priv->protocol; | ||
1373 | if (IS_MPC(priv)) { | ||
1374 | ch->discontact_th = (struct th_header *) | ||
1375 | kzalloc(TH_HEADER_LENGTH, gfp_type()); | ||
1376 | if (ch->discontact_th == NULL) | ||
1377 | goto nomem_return; | ||
1378 | |||
1379 | ch->discontact_th->th_blk_flag = TH_DISCONTACT; | ||
1380 | tasklet_init(&ch->ch_disc_tasklet, | ||
1381 | mpc_action_send_discontact, (unsigned long)ch); | ||
1382 | |||
1383 | tasklet_init(&ch->ch_tasklet, ctcmpc_bh, (unsigned long)ch); | ||
1384 | ch->max_bufsize = (MPC_BUFSIZE_DEFAULT - 35); | ||
1385 | ccw_num = 17; | ||
1386 | } else | ||
1387 | ccw_num = 8; | ||
1388 | |||
1389 | ch->ccw = (struct ccw1 *) | ||
1390 | kzalloc(ccw_num * sizeof(struct ccw1), GFP_KERNEL | GFP_DMA); | ||
1391 | if (ch->ccw == NULL) | ||
1392 | goto nomem_return; | ||
1393 | |||
1394 | ch->cdev = cdev; | ||
1395 | snprintf(ch->id, CTCM_ID_SIZE, "ch-%s", cdev->dev.bus_id); | ||
1396 | ch->type = type; | ||
1397 | |||
1398 | /** | ||
1399 | * "static" ccws are used in the following way: | ||
1400 | * | ||
1401 | * ccw[0..2] (Channel program for generic I/O): | ||
1402 | * 0: prepare | ||
1403 | * 1: read or write (depending on direction) with fixed | ||
1404 | * buffer (idal allocated once when buffer is allocated) | ||
1405 | * 2: nop | ||
1406 | * ccw[3..5] (Channel program for direct write of packets) | ||
1407 | * 3: prepare | ||
1408 | * 4: write (idal allocated on every write). | ||
1409 | * 5: nop | ||
1410 | * ccw[6..7] (Channel program for initial channel setup): | ||
1411 | * 6: set extended mode | ||
1412 | * 7: nop | ||
1413 | * | ||
1414 | * ch->ccw[0..5] are initialized in ch_action_start because | ||
1415 | * the channel's direction is yet unknown here. | ||
1416 | * | ||
1417 | * ccws used for xid2 negotiations | ||
1418 | * ch-ccw[8-14] need to be used for the XID exchange either | ||
1419 | * X side XID2 Processing | ||
1420 | * 8: write control | ||
1421 | * 9: write th | ||
1422 | * 10: write XID | ||
1423 | * 11: read th from secondary | ||
1424 | * 12: read XID from secondary | ||
1425 | * 13: read 4 byte ID | ||
1426 | * 14: nop | ||
1427 | * Y side XID Processing | ||
1428 | * 8: sense | ||
1429 | * 9: read th | ||
1430 | * 10: read XID | ||
1431 | * 11: write th | ||
1432 | * 12: write XID | ||
1433 | * 13: write 4 byte ID | ||
1434 | * 14: nop | ||
1435 | * | ||
1436 | * ccws used for double noop due to VM timing issues | ||
1437 | * which result in unrecoverable Busy on channel | ||
1438 | * 15: nop | ||
1439 | * 16: nop | ||
1440 | */ | ||
1441 | ch->ccw[6].cmd_code = CCW_CMD_SET_EXTENDED; | ||
1442 | ch->ccw[6].flags = CCW_FLAG_SLI; | ||
1443 | |||
1444 | ch->ccw[7].cmd_code = CCW_CMD_NOOP; | ||
1445 | ch->ccw[7].flags = CCW_FLAG_SLI; | ||
1446 | |||
1447 | if (IS_MPC(priv)) { | ||
1448 | ch->ccw[15].cmd_code = CCW_CMD_WRITE; | ||
1449 | ch->ccw[15].flags = CCW_FLAG_SLI | CCW_FLAG_CC; | ||
1450 | ch->ccw[15].count = TH_HEADER_LENGTH; | ||
1451 | ch->ccw[15].cda = virt_to_phys(ch->discontact_th); | ||
1452 | |||
1453 | ch->ccw[16].cmd_code = CCW_CMD_NOOP; | ||
1454 | ch->ccw[16].flags = CCW_FLAG_SLI; | ||
1455 | |||
1456 | ch->fsm = init_fsm(ch->id, ctc_ch_state_names, | ||
1457 | ctc_ch_event_names, CTC_MPC_NR_STATES, | ||
1458 | CTC_MPC_NR_EVENTS, ctcmpc_ch_fsm, | ||
1459 | mpc_ch_fsm_len, GFP_KERNEL); | ||
1460 | } else { | ||
1461 | ch->fsm = init_fsm(ch->id, ctc_ch_state_names, | ||
1462 | ctc_ch_event_names, CTC_NR_STATES, | ||
1463 | CTC_NR_EVENTS, ch_fsm, | ||
1464 | ch_fsm_len, GFP_KERNEL); | ||
1465 | } | ||
1466 | if (ch->fsm == NULL) | ||
1467 | goto free_return; | ||
1468 | |||
1469 | fsm_newstate(ch->fsm, CTC_STATE_IDLE); | ||
1470 | |||
1471 | ch->irb = kzalloc(sizeof(struct irb), GFP_KERNEL); | ||
1472 | if (ch->irb == NULL) | ||
1473 | goto nomem_return; | ||
1474 | |||
1475 | while (*c && ctcm_less_than((*c)->id, ch->id)) | ||
1476 | c = &(*c)->next; | ||
1477 | |||
1478 | if (*c && (!strncmp((*c)->id, ch->id, CTCM_ID_SIZE))) { | ||
1479 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, | ||
1480 | "%s (%s) already in list, using old entry", | ||
1481 | __FUNCTION__, (*c)->id); | ||
1482 | |||
1483 | goto free_return; | ||
1484 | } | ||
1485 | |||
1486 | spin_lock_init(&ch->collect_lock); | ||
1487 | |||
1488 | fsm_settimer(ch->fsm, &ch->timer); | ||
1489 | skb_queue_head_init(&ch->io_queue); | ||
1490 | skb_queue_head_init(&ch->collect_queue); | ||
1491 | |||
1492 | if (IS_MPC(priv)) { | ||
1493 | fsm_settimer(ch->fsm, &ch->sweep_timer); | ||
1494 | skb_queue_head_init(&ch->sweep_queue); | ||
1495 | } | ||
1496 | ch->next = *c; | ||
1497 | *c = ch; | ||
1498 | return 0; | ||
1499 | |||
1500 | nomem_return: | ||
1501 | ctcm_pr_warn("ctcm: Out of memory in %s\n", __FUNCTION__); | ||
1502 | rc = -ENOMEM; | ||
1503 | |||
1504 | free_return: /* note that all channel pointers are 0 or valid */ | ||
1505 | kfree(ch->ccw); /* TODO: check that again */ | ||
1506 | kfree(ch->discontact_th); | ||
1507 | kfree_fsm(ch->fsm); | ||
1508 | kfree(ch->irb); | ||
1509 | kfree(ch); | ||
1510 | return rc; | ||
1511 | } | ||
1512 | |||
1513 | /* | ||
1514 | * Return type of a detected device. | ||
1515 | */ | ||
1516 | static enum channel_types get_channel_type(struct ccw_device_id *id) | ||
1517 | { | ||
1518 | enum channel_types type; | ||
1519 | type = (enum channel_types)id->driver_info; | ||
1520 | |||
1521 | if (type == channel_type_ficon) | ||
1522 | type = channel_type_escon; | ||
1523 | |||
1524 | return type; | ||
1525 | } | ||
1526 | |||
1527 | /** | ||
1528 | * | ||
1529 | * Setup an interface. | ||
1530 | * | ||
1531 | * cgdev Device to be setup. | ||
1532 | * | ||
1533 | * returns 0 on success, !0 on failure. | ||
1534 | */ | ||
1535 | static int ctcm_new_device(struct ccwgroup_device *cgdev) | ||
1536 | { | ||
1537 | char read_id[CTCM_ID_SIZE]; | ||
1538 | char write_id[CTCM_ID_SIZE]; | ||
1539 | int direction; | ||
1540 | enum channel_types type; | ||
1541 | struct ctcm_priv *priv; | ||
1542 | struct net_device *dev; | ||
1543 | int ret; | ||
1544 | |||
1545 | CTCM_DBF_TEXT(SETUP, CTC_DBF_INFO, __FUNCTION__); | ||
1546 | |||
1547 | priv = dev_get_drvdata(&cgdev->dev); | ||
1548 | if (!priv) | ||
1549 | return -ENODEV; | ||
1550 | |||
1551 | type = get_channel_type(&cgdev->cdev[0]->id); | ||
1552 | |||
1553 | snprintf(read_id, CTCM_ID_SIZE, "ch-%s", cgdev->cdev[0]->dev.bus_id); | ||
1554 | snprintf(write_id, CTCM_ID_SIZE, "ch-%s", cgdev->cdev[1]->dev.bus_id); | ||
1555 | |||
1556 | ret = add_channel(cgdev->cdev[0], type, priv); | ||
1557 | if (ret) | ||
1558 | return ret; | ||
1559 | ret = add_channel(cgdev->cdev[1], type, priv); | ||
1560 | if (ret) | ||
1561 | return ret; | ||
1562 | |||
1563 | ret = ccw_device_set_online(cgdev->cdev[0]); | ||
1564 | if (ret != 0) { | ||
1565 | CTCM_DBF_TEXT(SETUP, CTC_DBF_WARN, | ||
1566 | "ccw_device_set_online (cdev[0]) failed "); | ||
1567 | ctcm_pr_warn("ccw_device_set_online (cdev[0]) failed " | ||
1568 | "with ret = %d\n", ret); | ||
1569 | } | ||
1570 | |||
1571 | ret = ccw_device_set_online(cgdev->cdev[1]); | ||
1572 | if (ret != 0) { | ||
1573 | CTCM_DBF_TEXT(SETUP, CTC_DBF_WARN, | ||
1574 | "ccw_device_set_online (cdev[1]) failed "); | ||
1575 | ctcm_pr_warn("ccw_device_set_online (cdev[1]) failed " | ||
1576 | "with ret = %d\n", ret); | ||
1577 | } | ||
1578 | |||
1579 | dev = ctcm_init_netdevice(priv); | ||
1580 | |||
1581 | if (dev == NULL) { | ||
1582 | ctcm_pr_warn("ctcm_init_netdevice failed\n"); | ||
1583 | goto out; | ||
1584 | } | ||
1585 | |||
1586 | for (direction = READ; direction <= WRITE; direction++) { | ||
1587 | priv->channel[direction] = | ||
1588 | channel_get(type, direction == READ ? read_id : write_id, | ||
1589 | direction); | ||
1590 | if (priv->channel[direction] == NULL) { | ||
1591 | if (direction == WRITE) | ||
1592 | channel_free(priv->channel[READ]); | ||
1593 | ctcm_free_netdevice(dev); | ||
1594 | goto out; | ||
1595 | } | ||
1596 | priv->channel[direction]->netdev = dev; | ||
1597 | priv->channel[direction]->protocol = priv->protocol; | ||
1598 | priv->channel[direction]->max_bufsize = priv->buffer_size; | ||
1599 | } | ||
1600 | /* sysfs magic */ | ||
1601 | SET_NETDEV_DEV(dev, &cgdev->dev); | ||
1602 | |||
1603 | if (ctcm_netdev_register(dev) != 0) { | ||
1604 | ctcm_free_netdevice(dev); | ||
1605 | goto out; | ||
1606 | } | ||
1607 | |||
1608 | if (ctcm_add_attributes(&cgdev->dev)) { | ||
1609 | ctcm_netdev_unregister(dev); | ||
1610 | /* dev->priv = NULL; why that ???? */ | ||
1611 | ctcm_free_netdevice(dev); | ||
1612 | goto out; | ||
1613 | } | ||
1614 | |||
1615 | strlcpy(priv->fsm->name, dev->name, sizeof(priv->fsm->name)); | ||
1616 | |||
1617 | CTCM_DBF_TEXT_(SETUP, CTC_DBF_INFO, | ||
1618 | "setup(%s) ok : r/w = %s / %s, proto : %d", | ||
1619 | dev->name, priv->channel[READ]->id, | ||
1620 | priv->channel[WRITE]->id, priv->protocol); | ||
1621 | |||
1622 | return 0; | ||
1623 | out: | ||
1624 | ccw_device_set_offline(cgdev->cdev[1]); | ||
1625 | ccw_device_set_offline(cgdev->cdev[0]); | ||
1626 | |||
1627 | return -ENODEV; | ||
1628 | } | ||
1629 | |||
1630 | /** | ||
1631 | * Shutdown an interface. | ||
1632 | * | ||
1633 | * cgdev Device to be shut down. | ||
1634 | * | ||
1635 | * returns 0 on success, !0 on failure. | ||
1636 | */ | ||
1637 | static int ctcm_shutdown_device(struct ccwgroup_device *cgdev) | ||
1638 | { | ||
1639 | struct ctcm_priv *priv; | ||
1640 | struct net_device *dev; | ||
1641 | |||
1642 | priv = dev_get_drvdata(&cgdev->dev); | ||
1643 | if (!priv) | ||
1644 | return -ENODEV; | ||
1645 | |||
1646 | if (priv->channel[READ]) { | ||
1647 | dev = priv->channel[READ]->netdev; | ||
1648 | CTCM_DBF_DEV(SETUP, dev, ""); | ||
1649 | /* Close the device */ | ||
1650 | ctcm_close(dev); | ||
1651 | dev->flags &= ~IFF_RUNNING; | ||
1652 | ctcm_remove_attributes(&cgdev->dev); | ||
1653 | channel_free(priv->channel[READ]); | ||
1654 | } else | ||
1655 | dev = NULL; | ||
1656 | |||
1657 | if (priv->channel[WRITE]) | ||
1658 | channel_free(priv->channel[WRITE]); | ||
1659 | |||
1660 | if (dev) { | ||
1661 | ctcm_netdev_unregister(dev); | ||
1662 | /* dev->priv = NULL; why that ??? */ | ||
1663 | ctcm_free_netdevice(dev); | ||
1664 | } | ||
1665 | |||
1666 | if (priv->fsm) | ||
1667 | kfree_fsm(priv->fsm); | ||
1668 | |||
1669 | ccw_device_set_offline(cgdev->cdev[1]); | ||
1670 | ccw_device_set_offline(cgdev->cdev[0]); | ||
1671 | |||
1672 | if (priv->channel[READ]) | ||
1673 | channel_remove(priv->channel[READ]); | ||
1674 | if (priv->channel[WRITE]) | ||
1675 | channel_remove(priv->channel[WRITE]); | ||
1676 | priv->channel[READ] = priv->channel[WRITE] = NULL; | ||
1677 | |||
1678 | return 0; | ||
1679 | |||
1680 | } | ||
1681 | |||
1682 | |||
1683 | static void ctcm_remove_device(struct ccwgroup_device *cgdev) | ||
1684 | { | ||
1685 | struct ctcm_priv *priv; | ||
1686 | |||
1687 | CTCM_DBF_TEXT(SETUP, CTC_DBF_ERROR, __FUNCTION__); | ||
1688 | |||
1689 | priv = dev_get_drvdata(&cgdev->dev); | ||
1690 | if (!priv) | ||
1691 | return; | ||
1692 | if (cgdev->state == CCWGROUP_ONLINE) | ||
1693 | ctcm_shutdown_device(cgdev); | ||
1694 | ctcm_remove_files(&cgdev->dev); | ||
1695 | dev_set_drvdata(&cgdev->dev, NULL); | ||
1696 | kfree(priv); | ||
1697 | put_device(&cgdev->dev); | ||
1698 | } | ||
1699 | |||
1700 | static struct ccwgroup_driver ctcm_group_driver = { | ||
1701 | .owner = THIS_MODULE, | ||
1702 | .name = CTC_DRIVER_NAME, | ||
1703 | .max_slaves = 2, | ||
1704 | .driver_id = 0xC3E3C3D4, /* CTCM */ | ||
1705 | .probe = ctcm_probe_device, | ||
1706 | .remove = ctcm_remove_device, | ||
1707 | .set_online = ctcm_new_device, | ||
1708 | .set_offline = ctcm_shutdown_device, | ||
1709 | }; | ||
1710 | |||
1711 | |||
1712 | /* | ||
1713 | * Module related routines | ||
1714 | */ | ||
1715 | |||
1716 | /* | ||
1717 | * Prepare to be unloaded. Free IRQ's and release all resources. | ||
1718 | * This is called just before this module is unloaded. It is | ||
1719 | * not called, if the usage count is !0, so we don't need to check | ||
1720 | * for that. | ||
1721 | */ | ||
1722 | static void __exit ctcm_exit(void) | ||
1723 | { | ||
1724 | unregister_cu3088_discipline(&ctcm_group_driver); | ||
1725 | ctcm_unregister_dbf_views(); | ||
1726 | ctcm_pr_info("CTCM driver unloaded\n"); | ||
1727 | } | ||
1728 | |||
1729 | /* | ||
1730 | * Print Banner. | ||
1731 | */ | ||
1732 | static void print_banner(void) | ||
1733 | { | ||
1734 | printk(KERN_INFO "CTCM driver initialized\n"); | ||
1735 | } | ||
1736 | |||
1737 | /** | ||
1738 | * Initialize module. | ||
1739 | * This is called just after the module is loaded. | ||
1740 | * | ||
1741 | * returns 0 on success, !0 on error. | ||
1742 | */ | ||
1743 | static int __init ctcm_init(void) | ||
1744 | { | ||
1745 | int ret; | ||
1746 | |||
1747 | channels = NULL; | ||
1748 | |||
1749 | ret = ctcm_register_dbf_views(); | ||
1750 | if (ret) { | ||
1751 | ctcm_pr_crit("ctcm_init failed with ctcm_register_dbf_views " | ||
1752 | "rc = %d\n", ret); | ||
1753 | return ret; | ||
1754 | } | ||
1755 | ret = register_cu3088_discipline(&ctcm_group_driver); | ||
1756 | if (ret) { | ||
1757 | ctcm_unregister_dbf_views(); | ||
1758 | ctcm_pr_crit("ctcm_init failed with register_cu3088_discipline " | ||
1759 | "(rc = %d)\n", ret); | ||
1760 | return ret; | ||
1761 | } | ||
1762 | print_banner(); | ||
1763 | return ret; | ||
1764 | } | ||
1765 | |||
1766 | module_init(ctcm_init); | ||
1767 | module_exit(ctcm_exit); | ||
1768 | |||
1769 | MODULE_AUTHOR("Peter Tiedemann <ptiedem@de.ibm.com>"); | ||
1770 | MODULE_DESCRIPTION("Network driver for S/390 CTC + CTCMPC (SNA)"); | ||
1771 | MODULE_LICENSE("GPL"); | ||
1772 | |||