}
static long
-__qeth_check_irb_error(struct ccw_device *cdev, struct irb *irb)
+__qeth_check_irb_error(struct ccw_device *cdev, unsigned long intparm,
+ struct irb *irb)
{
if (!IS_ERR(irb))
return 0;
PRINT_WARN("timeout on device %s\n", cdev->dev.bus_id);
QETH_DBF_TEXT(trace, 2, "ckirberr");
QETH_DBF_TEXT_(trace, 2, " rc%d", -ETIMEDOUT);
+ if (intparm == QETH_RCD_PARM) {
+ struct qeth_card *card = CARD_FROM_CDEV(cdev);
+
+ if (card && (card->data.ccwdev == cdev)) {
+ card->data.state = CH_STATE_DOWN;
+ wake_up(&card->wait_q);
+ }
+ }
break;
default:
PRINT_WARN("unknown error %ld on device %s\n", PTR_ERR(irb),
QETH_DBF_TEXT(trace,5,"irq");
- if (__qeth_check_irb_error(cdev, irb))
+ if (__qeth_check_irb_error(cdev, intparm, irb))
return;
cstat = irb->scsw.cstat;
dstat = irb->scsw.dstat;
channel->state = CH_STATE_HALTED;
/*let's wake up immediately on data channel*/
- if ((channel == &card->data) && (intparm != 0))
+ if ((channel == &card->data) && (intparm != 0) &&
+ (intparm != QETH_RCD_PARM))
goto out;
if (intparm == QETH_CLEAR_CHANNEL_PARM) {
HEXDUMP16(WARN,"irb: ",irb);
HEXDUMP16(WARN,"sense data: ",irb->ecw);
}
+ if (intparm == QETH_RCD_PARM) {
+ channel->state = CH_STATE_DOWN;
+ goto out;
+ }
rc = qeth_get_problem(cdev,irb);
if (rc) {
qeth_schedule_recovery(card);
}
}
+ if (intparm == QETH_RCD_PARM) {
+ channel->state = CH_STATE_RCD_DONE;
+ goto out;
+ }
if (intparm) {
buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
buffer->state = BUF_STATE_PROCESSED;
}
+static int qeth_read_conf_data(struct qeth_card *card, void **buffer,
+ int *length)
+{
+ struct ciw *ciw;
+ char *rcd_buf;
+ int ret;
+ struct qeth_channel *channel = &card->data;
+ unsigned long flags;
+
+ /*
+ * scan for RCD command in extended SenseID data
+ */
+ ciw = ccw_device_get_ciw(channel->ccwdev, CIW_TYPE_RCD);
+ if (!ciw || ciw->cmd == 0)
+ return -EOPNOTSUPP;
+ rcd_buf = kzalloc(ciw->count, GFP_KERNEL | GFP_DMA);
+ if (!rcd_buf)
+ return -ENOMEM;
+
+ channel->ccw.cmd_code = ciw->cmd;
+ channel->ccw.cda = (__u32) __pa (rcd_buf);
+ channel->ccw.count = ciw->count;
+ channel->ccw.flags = CCW_FLAG_SLI;
+ channel->state = CH_STATE_RCD;
+ spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
+ ret = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
+ QETH_RCD_PARM, LPM_ANYPATH, 0,
+ QETH_RCD_TIMEOUT);
+ spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
+ if (!ret)
+ wait_event(card->wait_q,
+ (channel->state == CH_STATE_RCD_DONE ||
+ channel->state == CH_STATE_DOWN));
+ if (channel->state == CH_STATE_DOWN)
+ ret = -EIO;
+ else
+ channel->state = CH_STATE_DOWN;
+ if (ret) {
+ kfree(rcd_buf);
+ *buffer = NULL;
+ *length = 0;
+ } else {
+ *length = ciw->count;
+ *buffer = rcd_buf;
+ }
+ return ret;
+}
+
static int
qeth_get_unitaddr(struct qeth_card *card)
{
int rc;
QETH_DBF_TEXT(setup, 2, "getunit");
- rc = read_conf_data(CARD_DDEV(card), (void **) &prcd, &length);
+ rc = qeth_read_conf_data(card, (void **) &prcd, &length);
if (rc) {
- PRINT_ERR("read_conf_data for device %s returned %i\n",
+ PRINT_ERR("qeth_read_conf_data for device %s returned %i\n",
CARD_DDEV_ID(card), rc);
return rc;
}
card->info.cula = prcd[63];
card->info.guestlan = ((prcd[0x10] == _ascebc['V']) &&
(prcd[0x11] == _ascebc['M']));
+ kfree(prcd);
return 0;
}
kfree(reply);
}
+static void
+qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, struct qeth_card *card)
+{
+ int rc;
+ int com;
+ char * ipa_name;
+
+ com = cmd->hdr.command;
+ rc = cmd->hdr.return_code;
+ ipa_name = qeth_get_ipa_cmd_name(com);
+
+ PRINT_ERR("%s(x%X) for %s returned x%X \"%s\"\n", ipa_name, com,
+ QETH_CARD_IFNAME(card), rc, qeth_get_ipa_msg(rc));
+}
+
static struct qeth_ipa_cmd *
qeth_check_ipa_data(struct qeth_card *card, struct qeth_cmd_buffer *iob)
{
QETH_DBF_TEXT(trace,5,"chkipad");
if (IS_IPA(iob->data)){
cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
- if (IS_IPA_REPLY(cmd))
+ if (IS_IPA_REPLY(cmd)) {
+ if (cmd->hdr.return_code)
+ qeth_issue_ipa_msg(cmd, card);
return cmd;
+ }
else {
switch (cmd->hdr.command) {
case IPA_CMD_STOPLAN:
(card->info.link_type == QETH_LINK_TYPE_LANE_TR))
return tr_type_trans(skb,dev);
#endif /* CONFIG_TR */
- skb->mac.raw = skb->data;
+ skb_reset_mac_header(skb);
skb_pull(skb, ETH_HLEN );
eth = eth_hdr(skb);
struct iphdr *ip_hdr;
QETH_DBF_TEXT(trace,5,"skbfktr");
- skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_TR;
+ skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_TR);
/* this is a fake ethernet header */
- fake_hdr = (struct trh_hdr *) skb->mac.raw;
+ fake_hdr = tr_hdr(skb);
/* the destination MAC address */
switch (skb->pkt_type){
struct iphdr *ip_hdr;
QETH_DBF_TEXT(trace,5,"skbfketh");
- skb->mac.raw = skb->data - QETH_FAKE_LL_LEN_ETH;
+ skb_set_mac_header(skb, -QETH_FAKE_LL_LEN_ETH);
/* this is a fake ethernet header */
- fake_hdr = (struct ethhdr *) skb->mac.raw;
+ fake_hdr = eth_hdr(skb);
/* the destination MAC address */
switch (skb->pkt_type){
if (card->options.fake_ll)
qeth_rebuild_skb_fake_ll(card, skb, hdr);
else
- skb->mac.raw = skb->data;
+ skb_reset_mac_header(skb);
skb->ip_summed = card->options.checksum_type;
if (card->options.checksum_type == HW_CHECKSUMMING){
if ( (hdr->hdr.l3.ext_flags &
vlan_tag = qeth_rebuild_skb(card, skb, hdr);
else { /*in case of OSN*/
skb_push(skb, sizeof(struct qeth_hdr));
- memcpy(skb->data, hdr, sizeof(struct qeth_hdr));
+ skb_copy_to_linear_data(skb, hdr,
+ sizeof(struct qeth_hdr));
}
/* is device UP ? */
if (!(card->dev->flags & IFF_UP)){
struct qeth_qdio_out_buffer *buf;
int rc;
int i;
+ unsigned int qdio_flags;
QETH_DBF_TEXT(trace, 6, "flushbuf");
queue->card->perf_stats.outbound_do_qdio_start_time =
qeth_get_micros();
}
+ qdio_flags = QDIO_FLAG_SYNC_OUTPUT;
if (under_int)
- rc = do_QDIO(CARD_DDEV(queue->card),
- QDIO_FLAG_SYNC_OUTPUT | QDIO_FLAG_UNDER_INTERRUPT,
- queue->queue_no, index, count, NULL);
- else
- rc = do_QDIO(CARD_DDEV(queue->card), QDIO_FLAG_SYNC_OUTPUT,
- queue->queue_no, index, count, NULL);
+ qdio_flags |= QDIO_FLAG_UNDER_INTERRUPT;
+ if (atomic_read(&queue->set_pci_flags_count))
+ qdio_flags |= QDIO_FLAG_PCI_OUT;
+ rc = do_QDIO(CARD_DDEV(queue->card), qdio_flags,
+ queue->queue_no, index, count, NULL);
if (queue->card->options.performance_stats)
queue->card->perf_stats.outbound_do_qdio_time +=
qeth_get_micros() -
return rc;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++){
- if (vg->vlan_devices[i] == dev){
+ if (vlan_group_get_device(vg, i) == dev){
rc = QETH_VLAN_CARD;
break;
}
}
/* try something else */
if (skb->protocol == ETH_P_IPV6)
- return (skb->nh.raw[24] == 0xff) ? RTN_MULTICAST : 0;
+ return (skb_network_header(skb)[24] == 0xff) ?
+ RTN_MULTICAST : 0;
else if (skb->protocol == ETH_P_IP)
- return ((skb->nh.raw[16] & 0xf0) == 0xe0) ? RTN_MULTICAST : 0;
+ return ((skb_network_header(skb)[16] & 0xf0) == 0xe0) ?
+ RTN_MULTICAST : 0;
/* ... */
if (!memcmp(skb->data, skb->dev->broadcast, 6))
return RTN_BROADCAST;
return card->info.is_multicast_different &
(card->qdio.no_out_queues - 1);
if (card->qdio.do_prio_queueing && (ipv == 4)) {
+ const u8 tos = ip_hdr(skb)->tos;
+
if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_TOS){
- if (skb->nh.iph->tos & IP_TOS_NOTIMPORTANT)
+ if (tos & IP_TOS_NOTIMPORTANT)
return 3;
- if (skb->nh.iph->tos & IP_TOS_HIGHRELIABILITY)
+ if (tos & IP_TOS_HIGHRELIABILITY)
return 2;
- if (skb->nh.iph->tos & IP_TOS_HIGHTHROUGHPUT)
+ if (tos & IP_TOS_HIGHTHROUGHPUT)
return 1;
- if (skb->nh.iph->tos & IP_TOS_LOWDELAY)
+ if (tos & IP_TOS_LOWDELAY)
return 0;
}
if (card->qdio.do_prio_queueing==QETH_PRIO_Q_ING_PREC)
- return 3 - (skb->nh.iph->tos >> 6);
+ return 3 - (tos >> 6);
} else if (card->qdio.do_prio_queueing && (ipv == 6)) {
/* TODO: IPv6!!! */
}
* memcpys instead of one memmove to save cycles.
*/
skb_push(skb, VLAN_HLEN);
- memcpy(skb->data, skb->data + 4, 4);
- memcpy(skb->data + 4, skb->data + 8, 4);
- memcpy(skb->data + 8, skb->data + 12, 4);
+ skb_copy_to_linear_data(skb, skb->data + 4, 4);
+ skb_copy_to_linear_data_offset(skb, 4, skb->data + 8, 4);
+ skb_copy_to_linear_data_offset(skb, 8, skb->data + 12, 4);
tag = (u16 *)(skb->data + 12);
/*
* first two bytes = ETH_P_8021Q (0x8100)
*((u32 *) skb->dst->neighbour->primary_key);
} else {
/* fill in destination address used in ip header */
- *((u32 *) (&hdr->hdr.l3.dest_addr[12])) = skb->nh.iph->daddr;
+ *((u32 *)(&hdr->hdr.l3.dest_addr[12])) =
+ ip_hdr(skb)->daddr;
}
} else if (ipv == 6) { /* IPv6 or passthru */
hdr->hdr.l3.flags = qeth_get_qeth_hdr_flags6(cast_type);
skb->dst->neighbour->primary_key, 16);
} else {
/* fill in destination address used in ip header */
- memcpy(hdr->hdr.l3.dest_addr, &skb->nh.ipv6h->daddr, 16);
+ memcpy(hdr->hdr.l3.dest_addr,
+ &ipv6_hdr(skb)->daddr, 16);
}
} else { /* passthrough */
if((skb->dev->type == ARPHRD_IEEE802_TR) &&
qeth_fill_header(card, hdr, new_skb, ipv, cast_type);
}
if (large_send == QETH_LARGE_SEND_EDDP) {
- ctx = qeth_eddp_create_context(card, new_skb, hdr);
+ ctx = qeth_eddp_create_context(card, new_skb, hdr,
+ skb->sk->sk_protocol);
if (ctx == NULL) {
__qeth_free_new_skb(skb, new_skb);
PRINT_WARN("could not create eddp context\n");
QETH_DBF_TEXT(trace, 4, "frvaddr4");
rcu_read_lock();
- in_dev = __in_dev_get_rcu(card->vlangrp->vlan_devices[vid]);
+ in_dev = __in_dev_get_rcu(vlan_group_get_device(card->vlangrp, vid));
if (!in_dev)
goto out;
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
QETH_DBF_TEXT(trace, 4, "frvaddr6");
- in6_dev = in6_dev_get(card->vlangrp->vlan_devices[vid]);
+ in6_dev = in6_dev_get(vlan_group_get_device(card->vlangrp, vid));
if (!in6_dev)
return;
for (ifa = in6_dev->addr_list; ifa; ifa = ifa->lst_next){
if (!card->vlangrp)
return;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
- if (card->vlangrp->vlan_devices[i] == NULL)
+ if (vlan_group_get_device(card->vlangrp, i) == NULL)
continue;
if (clear)
qeth_layer2_send_setdelvlan(card, i, IPA_CMD_DELVLAN);
spin_lock_irqsave(&card->vlanlock, flags);
/* unregister IP addresses of vlan device */
qeth_free_vlan_addresses(card, vid);
- if (card->vlangrp)
- card->vlangrp->vlan_devices[vid] = NULL;
+ vlan_group_set_device(card->vlangrp, vid, NULL);
spin_unlock_irqrestore(&card->vlanlock, flags);
if (card->options.layer2)
qeth_layer2_send_setdelvlan(card, vid, IPA_CMD_DELVLAN);
vg = card->vlangrp;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
- if (vg->vlan_devices[i] == NULL ||
- !(vg->vlan_devices[i]->flags & IFF_UP))
+ struct net_device *netdev = vlan_group_get_device(vg, i);
+ if (netdev == NULL ||
+ !(netdev->flags & IFF_UP))
continue;
- in_dev = in_dev_get(vg->vlan_devices[i]);
+ in_dev = in_dev_get(netdev);
if (!in_dev)
continue;
read_lock(&in_dev->mc_list_lock);
vg = card->vlangrp;
for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
- if (vg->vlan_devices[i] == NULL ||
- !(vg->vlan_devices[i]->flags & IFF_UP))
+ struct net_device *netdev = vlan_group_get_device(vg, i);
+ if (netdev == NULL ||
+ !(netdev->flags & IFF_UP))
continue;
- in_dev = in6_dev_get(vg->vlan_devices[i]);
+ in_dev = in6_dev_get(netdev);
if (!in_dev)
continue;
read_lock(&in_dev->lock);
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
QETH_DBF_TEXT_(trace, 2, "L2er%x", cmd->hdr.return_code);
- PRINT_WARN("Error in registering MAC address on " \
- "device %s: x%x\n", CARD_BUS_ID(card),
- cmd->hdr.return_code);
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
cmd->hdr.return_code = -EIO;
} else {
QETH_DBF_TEXT(trace, 2, "L2Dmaccb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code) {
- PRINT_WARN("Error in deregistering MAC address on " \
- "device %s: x%x\n", CARD_BUS_ID(card),
- cmd->hdr.return_code);
QETH_DBF_TEXT_(trace, 2, "err%d", cmd->hdr.return_code);
cmd->hdr.return_code = -EIO;
return 0;
QETH_DBF_TEXT(trace,4,"chgmaccb");
cmd = (struct qeth_ipa_cmd *) data;
- if (!card->options.layer2 || card->info.guestlan ||
+ if (!card->options.layer2 ||
!(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
memcpy(card->dev->dev_addr,
&cmd->data.setadapterparms.data.change_addr.addr,
card = (struct qeth_card *) dev->driver_data;
qeth_clear_ip_list(card, 0, 0);
qeth_qdio_clear_card(card, 0);
+ qeth_clear_qdio_buffers(card);
return 0;
}