diff options
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/net/qeth.h | 4 | ||||
-rw-r--r-- | drivers/s390/net/qeth_main.c | 158 | ||||
-rw-r--r-- | drivers/s390/net/qeth_mpc.h | 1 | ||||
-rw-r--r-- | drivers/s390/net/qeth_sys.c | 8 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_aux.c | 4 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_qdio.c | 10 | ||||
-rw-r--r-- | drivers/s390/scsi/zfcp_scsi.c | 4 |
7 files changed, 133 insertions, 56 deletions
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h index ec18bae..6d49598 100644 --- a/drivers/s390/net/qeth.h +++ b/drivers/s390/net/qeth.h @@ -1178,9 +1178,9 @@ qeth_ipaddr_to_string(enum qeth_prot_versions proto, const __u8 *addr, char *buf) { if (proto == QETH_PROT_IPV4) - return qeth_ipaddr4_to_string(addr, buf); + qeth_ipaddr4_to_string(addr, buf); else if (proto == QETH_PROT_IPV6) - return qeth_ipaddr6_to_string(addr, buf); + qeth_ipaddr6_to_string(addr, buf); } static inline int diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c index 57f6943..f3e6fbe 100644 --- a/drivers/s390/net/qeth_main.c +++ b/drivers/s390/net/qeth_main.c @@ -561,7 +561,7 @@ qeth_set_offline(struct ccwgroup_device *cgdev) } static int -qeth_wait_for_threads(struct qeth_card *card, unsigned long threads); +qeth_threads_running(struct qeth_card *card, unsigned long threads); static void @@ -576,8 +576,7 @@ qeth_remove_device(struct ccwgroup_device *cgdev) if (!card) return; - if (qeth_wait_for_threads(card, 0xffffffff)) - return; + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); if (cgdev->state == CCWGROUP_ONLINE){ card->use_hard_stop = 1; @@ -1542,16 +1541,21 @@ qeth_idx_write_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob) card = CARD_FROM_CDEV(channel->ccwdev); if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { - PRINT_ERR("IDX_ACTIVATE on write channel device %s: negative " - "reply\n", CARD_WDEV_ID(card)); + if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) + PRINT_ERR("IDX_ACTIVATE on write channel device %s: " + "adapter exclusively used by another host\n", + CARD_WDEV_ID(card)); + else + PRINT_ERR("IDX_ACTIVATE on write channel device %s: " + "negative reply\n", CARD_WDEV_ID(card)); goto out; } memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); if ((temp & ~0x0100) != qeth_peer_func_level(card->info.func_level)) { PRINT_WARN("IDX_ACTIVATE on write channel device %s: " - "function level mismatch " - "(sent: 0x%x, received: 0x%x)\n", - CARD_WDEV_ID(card), card->info.func_level, temp); + "function level mismatch " + "(sent: 0x%x, received: 0x%x)\n", + CARD_WDEV_ID(card), card->info.func_level, temp); goto out; } channel->state = CH_STATE_UP; @@ -1597,8 +1601,13 @@ qeth_idx_read_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob) goto out; } if (!(QETH_IS_IDX_ACT_POS_REPLY(iob->data))) { - PRINT_ERR("IDX_ACTIVATE on read channel device %s: negative " - "reply\n", CARD_RDEV_ID(card)); + if (QETH_IDX_ACT_CAUSE_CODE(iob->data) == 0x19) + PRINT_ERR("IDX_ACTIVATE on read channel device %s: " + "adapter exclusively used by another host\n", + CARD_RDEV_ID(card)); + else + PRINT_ERR("IDX_ACTIVATE on read channel device %s: " + "negative reply\n", CARD_RDEV_ID(card)); goto out; } @@ -1613,8 +1622,8 @@ qeth_idx_read_cb(struct qeth_channel *channel, struct qeth_cmd_buffer *iob) memcpy(&temp, QETH_IDX_ACT_FUNC_LEVEL(iob->data), 2); if (temp != qeth_peer_func_level(card->info.func_level)) { PRINT_WARN("IDX_ACTIVATE on read channel device %s: function " - "level mismatch (sent: 0x%x, received: 0x%x)\n", - CARD_RDEV_ID(card), card->info.func_level, temp); + "level mismatch (sent: 0x%x, received: 0x%x)\n", + CARD_RDEV_ID(card), card->info.func_level, temp); goto out; } memcpy(&card->token.issuer_rm_r, @@ -2496,7 +2505,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb, struct iphdr *ip_hdr; QETH_DBF_TEXT(trace,5,"skbfktr"); - skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_TR); + skb_set_mac_header(skb, (int)-QETH_FAKE_LL_LEN_TR); /* this is a fake ethernet header */ fake_hdr = tr_hdr(skb); @@ -2804,13 +2813,16 @@ qeth_queue_input_buffer(struct qeth_card *card, int index) if (newcount < count) { /* we are in memory shortage so we switch back to traditional skb allocation and drop packages */ - if (atomic_cmpxchg(&card->force_alloc_skb, 0, 1)) - printk(KERN_WARNING - "qeth: switch to alloc skb\n"); + if (!atomic_read(&card->force_alloc_skb) && + net_ratelimit()) + PRINT_WARN("Switch to alloc skb\n"); + atomic_set(&card->force_alloc_skb, 3); count = newcount; } else { - if (atomic_cmpxchg(&card->force_alloc_skb, 1, 0)) - printk(KERN_WARNING "qeth: switch to sg\n"); + if ((atomic_read(&card->force_alloc_skb) == 1) && + net_ratelimit()) + PRINT_WARN("Switch to sg\n"); + atomic_add_unless(&card->force_alloc_skb, -1, 0); } /* @@ -3354,10 +3366,12 @@ out_freeoutq: while (i > 0) kfree(card->qdio.out_qs[--i]); kfree(card->qdio.out_qs); + card->qdio.out_qs = NULL; out_freepool: qeth_free_buffer_pool(card); out_freeinq: kfree(card->qdio.in_q); + card->qdio.in_q = NULL; out_nomem: atomic_set(&card->qdio.state, QETH_QDIO_UNINITIALIZED); return -ENOMEM; @@ -3373,16 +3387,20 @@ qeth_free_qdio_buffers(struct qeth_card *card) QETH_QDIO_UNINITIALIZED) return; kfree(card->qdio.in_q); + card->qdio.in_q = NULL; /* inbound buffer pool */ qeth_free_buffer_pool(card); /* free outbound qdio_qs */ - for (i = 0; i < card->qdio.no_out_queues; ++i){ - for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) - qeth_clear_output_buffer(card->qdio.out_qs[i], - &card->qdio.out_qs[i]->bufs[j]); - kfree(card->qdio.out_qs[i]); + if (card->qdio.out_qs) { + for (i = 0; i < card->qdio.no_out_queues; ++i) { + for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) + qeth_clear_output_buffer(card->qdio.out_qs[i], + &card->qdio.out_qs[i]->bufs[j]); + kfree(card->qdio.out_qs[i]); + } + kfree(card->qdio.out_qs); + card->qdio.out_qs = NULL; } - kfree(card->qdio.out_qs); } static void @@ -3393,7 +3411,7 @@ qeth_clear_qdio_buffers(struct qeth_card *card) QETH_DBF_TEXT(trace, 2, "clearqdbf"); /* clear outbound buffers to free skbs */ for (i = 0; i < card->qdio.no_out_queues; ++i) - if (card->qdio.out_qs[i]){ + if (card->qdio.out_qs && card->qdio.out_qs[i]) { for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) qeth_clear_output_buffer(card->qdio.out_qs[i], &card->qdio.out_qs[i]->bufs[j]); @@ -4553,6 +4571,53 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr, return elements_needed; } +static void qeth_tx_csum(struct sk_buff *skb) +{ + int tlen; + + if (skb->protocol == htons(ETH_P_IP)) { + tlen = ntohs(ip_hdr(skb)->tot_len) - (ip_hdr(skb)->ihl << 2); + switch (ip_hdr(skb)->protocol) { + case IPPROTO_TCP: + tcp_hdr(skb)->check = 0; + tcp_hdr(skb)->check = csum_tcpudp_magic( + ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, + tlen, ip_hdr(skb)->protocol, + skb_checksum(skb, skb_transport_offset(skb), + tlen, 0)); + break; + case IPPROTO_UDP: + udp_hdr(skb)->check = 0; + udp_hdr(skb)->check = csum_tcpudp_magic( + ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, + tlen, ip_hdr(skb)->protocol, + skb_checksum(skb, skb_transport_offset(skb), + tlen, 0)); + break; + } + } else if (skb->protocol == htons(ETH_P_IPV6)) { + switch (ipv6_hdr(skb)->nexthdr) { + case IPPROTO_TCP: + tcp_hdr(skb)->check = 0; + tcp_hdr(skb)->check = csum_ipv6_magic( + &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + ipv6_hdr(skb)->payload_len, + ipv6_hdr(skb)->nexthdr, + skb_checksum(skb, skb_transport_offset(skb), + ipv6_hdr(skb)->payload_len, 0)); + break; + case IPPROTO_UDP: + udp_hdr(skb)->check = 0; + udp_hdr(skb)->check = csum_ipv6_magic( + &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, + ipv6_hdr(skb)->payload_len, + ipv6_hdr(skb)->nexthdr, + skb_checksum(skb, skb_transport_offset(skb), + ipv6_hdr(skb)->payload_len, 0)); + break; + } + } +} static int qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) @@ -4638,12 +4703,22 @@ qeth_send_packet(struct qeth_card *card, struct sk_buff *skb) elements_needed += elems; } + if ((large_send == QETH_LARGE_SEND_NO) && + (skb->ip_summed == CHECKSUM_PARTIAL)) + qeth_tx_csum(new_skb); + if (card->info.type != QETH_CARD_TYPE_IQD) rc = qeth_do_send_packet(card, queue, new_skb, hdr, elements_needed, ctx); - else + else { + if ((skb->protocol == htons(ETH_P_ARP)) && + (card->dev->flags & IFF_NOARP)) { + __qeth_free_new_skb(skb, new_skb); + return -EPERM; + } rc = qeth_do_send_packet_fast(card, queue, new_skb, hdr, elements_needed, ctx); + } if (!rc) { card->stats.tx_packets++; card->stats.tx_bytes += tx_bytes; @@ -6385,20 +6460,18 @@ qeth_deregister_addr_entry(struct qeth_card *card, struct qeth_ipaddr *addr) static u32 qeth_ethtool_get_tx_csum(struct net_device *dev) { - /* We may need to say that we support tx csum offload if - * we do EDDP or TSO. There are discussions going on to - * enforce rules in the stack and in ethtool that make - * SG and TSO depend on HW_CSUM. At the moment there are - * no such rules.... - * If we say yes here, we have to checksum outbound packets - * any time. */ - return 0; + return (dev->features & NETIF_F_HW_CSUM) != 0; } static int qeth_ethtool_set_tx_csum(struct net_device *dev, u32 data) { - return -EINVAL; + if (data) + dev->features |= NETIF_F_HW_CSUM; + else + dev->features &= ~NETIF_F_HW_CSUM; + + return 0; } static u32 @@ -7412,7 +7485,8 @@ qeth_start_ipa_tso(struct qeth_card *card) } if (rc && (card->options.large_send == QETH_LARGE_SEND_TSO)){ card->options.large_send = QETH_LARGE_SEND_NO; - card->dev->features &= ~ (NETIF_F_TSO | NETIF_F_SG); + card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | + NETIF_F_HW_CSUM); } return rc; } @@ -7552,22 +7626,26 @@ qeth_set_large_send(struct qeth_card *card, enum qeth_large_send_types type) card->options.large_send = type; switch (card->options.large_send) { case QETH_LARGE_SEND_EDDP: - card->dev->features |= NETIF_F_TSO | NETIF_F_SG; + card->dev->features |= NETIF_F_TSO | NETIF_F_SG | + NETIF_F_HW_CSUM; break; case QETH_LARGE_SEND_TSO: if (qeth_is_supported(card, IPA_OUTBOUND_TSO)){ - card->dev->features |= NETIF_F_TSO | NETIF_F_SG; + card->dev->features |= NETIF_F_TSO | NETIF_F_SG | + NETIF_F_HW_CSUM; } else { PRINT_WARN("TSO not supported on %s. " "large_send set to 'no'.\n", card->dev->name); - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); + card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | + NETIF_F_HW_CSUM); card->options.large_send = QETH_LARGE_SEND_NO; rc = -EOPNOTSUPP; } break; default: /* includes QETH_LARGE_SEND_NO */ - card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG); + card->dev->features &= ~(NETIF_F_TSO | NETIF_F_SG | + NETIF_F_HW_CSUM); break; } if (card->state == CARD_STATE_UP) diff --git a/drivers/s390/net/qeth_mpc.h b/drivers/s390/net/qeth_mpc.h index 1d8083c..6de2da5 100644 --- a/drivers/s390/net/qeth_mpc.h +++ b/drivers/s390/net/qeth_mpc.h @@ -565,6 +565,7 @@ extern unsigned char IDX_ACTIVATE_WRITE[]; #define QETH_IDX_ACT_QDIO_DEV_REALADDR(buffer) (buffer+0x20) #define QETH_IS_IDX_ACT_POS_REPLY(buffer) (((buffer)[0x08]&3)==2) #define QETH_IDX_REPLY_LEVEL(buffer) (buffer+0x12) +#define QETH_IDX_ACT_CAUSE_CODE(buffer) (buffer)[0x09] #define PDU_ENCAPSULATION(buffer) \ (buffer + *(buffer + (*(buffer+0x0b)) + \ diff --git a/drivers/s390/net/qeth_sys.c b/drivers/s390/net/qeth_sys.c index bb0287a..2cc3f3a 100644 --- a/drivers/s390/net/qeth_sys.c +++ b/drivers/s390/net/qeth_sys.c @@ -1760,10 +1760,10 @@ qeth_remove_device_attributes(struct device *dev) { struct qeth_card *card = dev->driver_data; - if (card->info.type == QETH_CARD_TYPE_OSN) - return sysfs_remove_group(&dev->kobj, - &qeth_osn_device_attr_group); - + if (card->info.type == QETH_CARD_TYPE_OSN) { + sysfs_remove_group(&dev->kobj, &qeth_osn_device_attr_group); + return; + } sysfs_remove_group(&dev->kobj, &qeth_device_attr_group); sysfs_remove_group(&dev->kobj, &qeth_device_ipato_group); sysfs_remove_group(&dev->kobj, &qeth_device_vipa_group); diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index ab5ec1fe..90aa53f 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -1503,7 +1503,7 @@ zfcp_gid_pn_buffers_alloc(struct zfcp_gid_pn_data **gid_pn, mempool_t *pool) data->ct.pool = pool; } } else { - data = kmalloc(sizeof(struct zfcp_gid_pn_data), GFP_ATOMIC); + data = kmem_cache_alloc(zfcp_data.gid_pn_cache, GFP_ATOMIC); } if (NULL == data) @@ -1531,7 +1531,7 @@ static void zfcp_gid_pn_buffers_free(struct zfcp_gid_pn_data *gid_pn) if (gid_pn->ct.pool) mempool_free(gid_pn, gid_pn->ct.pool); else - kfree(gid_pn); + kmem_cache_free(zfcp_data.gid_pn_cache, gid_pn); } /** diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 81daa82..c6899ef 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -640,13 +640,9 @@ int zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req, unsigned long sbtype, struct scsi_cmnd *scsi_cmnd) { - if (scsi_sg_count(scsi_cmnd)) - return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, - scsi_sglist(scsi_cmnd), - scsi_sg_count(scsi_cmnd), - ZFCP_MAX_SBALS_PER_REQ); - else - return 0; + return zfcp_qdio_sbals_from_sg(fsf_req, sbtype, scsi_sglist(scsi_cmnd), + scsi_sg_count(scsi_cmnd), + ZFCP_MAX_SBALS_PER_REQ); } /** diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 0acf6db..ad7eb4a 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -764,7 +764,9 @@ zfcp_reset_fc_host_stats(struct Scsi_Host *shost) return; ret = zfcp_fsf_exchange_port_data(NULL, adapter, data); - if (ret == 0) { + if (ret) { + kfree(data); + } else { adapter->stats_reset = jiffies/HZ; old_data = adapter->stats_reset_data; adapter->stats_reset_data = data; /* finally freed in |