Commit 353697e6 authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-fixes'

Julian Wiedmann says:

====================
s390/qeth: fixes 2018-04-19

Please apply the following qeth fixes for 4.17. The common theme
seems to be error handling improvements in various areas of cmd IO.

Patches 1-3 should also go back to stable.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 83beed7b b7493e91
...@@ -557,7 +557,6 @@ enum qeth_prot_versions { ...@@ -557,7 +557,6 @@ enum qeth_prot_versions {
enum qeth_cmd_buffer_state { enum qeth_cmd_buffer_state {
BUF_STATE_FREE, BUF_STATE_FREE,
BUF_STATE_LOCKED, BUF_STATE_LOCKED,
BUF_STATE_PROCESSED,
}; };
enum qeth_cq { enum qeth_cq {
...@@ -601,7 +600,6 @@ struct qeth_channel { ...@@ -601,7 +600,6 @@ struct qeth_channel {
struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO]; struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
atomic_t irq_pending; atomic_t irq_pending;
int io_buf_no; int io_buf_no;
int buf_no;
}; };
/** /**
......
...@@ -706,7 +706,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card) ...@@ -706,7 +706,6 @@ void qeth_clear_ipacmd_list(struct qeth_card *card)
qeth_put_reply(reply); qeth_put_reply(reply);
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
atomic_set(&card->write.irq_pending, 0);
} }
EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list); EXPORT_SYMBOL_GPL(qeth_clear_ipacmd_list);
...@@ -818,7 +817,6 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel) ...@@ -818,7 +817,6 @@ void qeth_clear_cmd_buffers(struct qeth_channel *channel)
for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++) for (cnt = 0; cnt < QETH_CMD_BUFFER_NO; cnt++)
qeth_release_buffer(channel, &channel->iob[cnt]); qeth_release_buffer(channel, &channel->iob[cnt]);
channel->buf_no = 0;
channel->io_buf_no = 0; channel->io_buf_no = 0;
} }
EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers); EXPORT_SYMBOL_GPL(qeth_clear_cmd_buffers);
...@@ -924,7 +922,6 @@ static int qeth_setup_channel(struct qeth_channel *channel) ...@@ -924,7 +922,6 @@ static int qeth_setup_channel(struct qeth_channel *channel)
kfree(channel->iob[cnt].data); kfree(channel->iob[cnt].data);
return -ENOMEM; return -ENOMEM;
} }
channel->buf_no = 0;
channel->io_buf_no = 0; channel->io_buf_no = 0;
atomic_set(&channel->irq_pending, 0); atomic_set(&channel->irq_pending, 0);
spin_lock_init(&channel->iob_lock); spin_lock_init(&channel->iob_lock);
...@@ -1100,16 +1097,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -1100,16 +1097,9 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
{ {
int rc; int rc;
int cstat, dstat; int cstat, dstat;
struct qeth_cmd_buffer *buffer; struct qeth_cmd_buffer *iob = NULL;
struct qeth_channel *channel; struct qeth_channel *channel;
struct qeth_card *card; struct qeth_card *card;
struct qeth_cmd_buffer *iob;
__u8 index;
if (__qeth_check_irb_error(cdev, intparm, irb))
return;
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
card = CARD_FROM_CDEV(cdev); card = CARD_FROM_CDEV(cdev);
if (!card) if (!card)
...@@ -1127,6 +1117,19 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -1127,6 +1117,19 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
channel = &card->data; channel = &card->data;
QETH_CARD_TEXT(card, 5, "data"); QETH_CARD_TEXT(card, 5, "data");
} }
if (qeth_intparm_is_iob(intparm))
iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
if (__qeth_check_irb_error(cdev, intparm, irb)) {
/* IO was terminated, free its resources. */
if (iob)
qeth_release_buffer(iob->channel, iob);
atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q);
return;
}
atomic_set(&channel->irq_pending, 0); atomic_set(&channel->irq_pending, 0);
if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC)) if (irb->scsw.cmd.fctl & (SCSW_FCTL_CLEAR_FUNC))
...@@ -1150,6 +1153,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -1150,6 +1153,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
/* we don't have to handle this further */ /* we don't have to handle this further */
intparm = 0; intparm = 0;
} }
cstat = irb->scsw.cmd.cstat;
dstat = irb->scsw.cmd.dstat;
if ((dstat & DEV_STAT_UNIT_EXCEP) || if ((dstat & DEV_STAT_UNIT_EXCEP) ||
(dstat & DEV_STAT_UNIT_CHECK) || (dstat & DEV_STAT_UNIT_CHECK) ||
(cstat)) { (cstat)) {
...@@ -1182,25 +1189,15 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -1182,25 +1189,15 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
channel->state = CH_STATE_RCD_DONE; channel->state = CH_STATE_RCD_DONE;
goto out; goto out;
} }
if (intparm) {
buffer = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
buffer->state = BUF_STATE_PROCESSED;
}
if (channel == &card->data) if (channel == &card->data)
return; return;
if (channel == &card->read && if (channel == &card->read &&
channel->state == CH_STATE_UP) channel->state == CH_STATE_UP)
__qeth_issue_next_read(card); __qeth_issue_next_read(card);
iob = channel->iob; if (iob && iob->callback)
index = channel->buf_no; iob->callback(iob->channel, iob);
while (iob[index].state == BUF_STATE_PROCESSED) {
if (iob[index].callback != NULL)
iob[index].callback(channel, iob + index);
index = (index + 1) % QETH_CMD_BUFFER_NO;
}
channel->buf_no = index;
out: out:
wake_up(&card->wait_q); wake_up(&card->wait_q);
return; return;
...@@ -1870,8 +1867,8 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, ...@@ -1870,8 +1867,8 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
rc = ccw_device_start(channel->ccwdev, rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
&channel->ccw, (addr_t) iob, 0, 0); (addr_t) iob, 0, 0, QETH_TIMEOUT);
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
if (rc) { if (rc) {
...@@ -1888,7 +1885,6 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel, ...@@ -1888,7 +1885,6 @@ static int qeth_idx_activate_get_answer(struct qeth_channel *channel,
if (channel->state != CH_STATE_UP) { if (channel->state != CH_STATE_UP) {
rc = -ETIME; rc = -ETIME;
QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc); QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
qeth_clear_cmd_buffers(channel);
} else } else
rc = 0; rc = 0;
return rc; return rc;
...@@ -1942,8 +1938,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, ...@@ -1942,8 +1938,8 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0); atomic_cmpxchg(&channel->irq_pending, 0, 1) == 0);
QETH_DBF_TEXT(SETUP, 6, "noirqpnd"); QETH_DBF_TEXT(SETUP, 6, "noirqpnd");
spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags); spin_lock_irqsave(get_ccwdev_lock(channel->ccwdev), flags);
rc = ccw_device_start(channel->ccwdev, rc = ccw_device_start_timeout(channel->ccwdev, &channel->ccw,
&channel->ccw, (addr_t) iob, 0, 0); (addr_t) iob, 0, 0, QETH_TIMEOUT);
spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(channel->ccwdev), flags);
if (rc) { if (rc) {
...@@ -1964,7 +1960,6 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel, ...@@ -1964,7 +1960,6 @@ static int qeth_idx_activate_channel(struct qeth_channel *channel,
QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n", QETH_DBF_MESSAGE(2, "%s IDX activate timed out\n",
dev_name(&channel->ccwdev->dev)); dev_name(&channel->ccwdev->dev));
QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME); QETH_DBF_TEXT_(SETUP, 2, "2err%d", -ETIME);
qeth_clear_cmd_buffers(channel);
return -ETIME; return -ETIME;
} }
return qeth_idx_activate_get_answer(channel, idx_reply_cb); return qeth_idx_activate_get_answer(channel, idx_reply_cb);
...@@ -2166,8 +2161,8 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2166,8 +2161,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
QETH_CARD_TEXT(card, 6, "noirqpnd"); QETH_CARD_TEXT(card, 6, "noirqpnd");
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
(addr_t) iob, 0, 0); (addr_t) iob, 0, 0, event_timeout);
spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
if (rc) { if (rc) {
QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: " QETH_DBF_MESSAGE(2, "%s qeth_send_control_data: "
...@@ -2199,8 +2194,6 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2199,8 +2194,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
} }
} }
if (reply->rc == -EIO)
goto error;
rc = reply->rc; rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return rc;
...@@ -2211,10 +2204,6 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2211,10 +2204,6 @@ int qeth_send_control_data(struct qeth_card *card, int len,
list_del_init(&reply->list); list_del_init(&reply->list);
spin_unlock_irqrestore(&reply->card->lock, flags); spin_unlock_irqrestore(&reply->card->lock, flags);
atomic_inc(&reply->received); atomic_inc(&reply->received);
error:
atomic_set(&card->write.irq_pending, 0);
qeth_release_buffer(iob->channel, iob);
card->write.buf_no = (card->write.buf_no + 1) % QETH_CMD_BUFFER_NO;
rc = reply->rc; rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return rc;
...@@ -3033,28 +3022,23 @@ static int qeth_send_startlan(struct qeth_card *card) ...@@ -3033,28 +3022,23 @@ static int qeth_send_startlan(struct qeth_card *card)
return rc; return rc;
} }
static int qeth_default_setadapterparms_cb(struct qeth_card *card, static int qeth_setadpparms_inspect_rc(struct qeth_ipa_cmd *cmd)
struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; if (!cmd->hdr.return_code)
QETH_CARD_TEXT(card, 4, "defadpcb");
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code == 0)
cmd->hdr.return_code = cmd->hdr.return_code =
cmd->data.setadapterparms.hdr.return_code; cmd->data.setadapterparms.hdr.return_code;
return 0; return cmd->hdr.return_code;
} }
static int qeth_query_setadapterparms_cb(struct qeth_card *card, static int qeth_query_setadapterparms_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data) struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
QETH_CARD_TEXT(card, 3, "quyadpcb"); QETH_CARD_TEXT(card, 3, "quyadpcb");
if (qeth_setadpparms_inspect_rc(cmd))
return 0;
cmd = (struct qeth_ipa_cmd *) data;
if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) { if (cmd->data.setadapterparms.data.query_cmds_supp.lan_type & 0x7f) {
card->info.link_type = card->info.link_type =
cmd->data.setadapterparms.data.query_cmds_supp.lan_type; cmd->data.setadapterparms.data.query_cmds_supp.lan_type;
...@@ -3062,7 +3046,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card, ...@@ -3062,7 +3046,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
} }
card->options.adp.supported_funcs = card->options.adp.supported_funcs =
cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds; cmd->data.setadapterparms.data.query_cmds_supp.supported_cmds;
return qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd); return 0;
} }
static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card, static struct qeth_cmd_buffer *qeth_get_adapter_cmd(struct qeth_card *card,
...@@ -3154,22 +3138,20 @@ EXPORT_SYMBOL_GPL(qeth_query_ipassists); ...@@ -3154,22 +3138,20 @@ EXPORT_SYMBOL_GPL(qeth_query_ipassists);
static int qeth_query_switch_attributes_cb(struct qeth_card *card, static int qeth_query_switch_attributes_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data) struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct qeth_switch_info *sw_info;
struct qeth_query_switch_attributes *attrs; struct qeth_query_switch_attributes *attrs;
struct qeth_switch_info *sw_info;
QETH_CARD_TEXT(card, 2, "qswiatcb"); QETH_CARD_TEXT(card, 2, "qswiatcb");
cmd = (struct qeth_ipa_cmd *) data; if (qeth_setadpparms_inspect_rc(cmd))
sw_info = (struct qeth_switch_info *)reply->param; return 0;
if (cmd->data.setadapterparms.hdr.return_code == 0) {
attrs = &cmd->data.setadapterparms.data.query_switch_attributes;
sw_info->capabilities = attrs->capabilities;
sw_info->settings = attrs->settings;
QETH_CARD_TEXT_(card, 2, "%04x%04x", sw_info->capabilities,
sw_info->settings);
}
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
sw_info = (struct qeth_switch_info *)reply->param;
attrs = &cmd->data.setadapterparms.data.query_switch_attributes;
sw_info->capabilities = attrs->capabilities;
sw_info->settings = attrs->settings;
QETH_CARD_TEXT_(card, 2, "%04x%04x", sw_info->capabilities,
sw_info->settings);
return 0; return 0;
} }
...@@ -4207,16 +4189,13 @@ EXPORT_SYMBOL_GPL(qeth_do_send_packet); ...@@ -4207,16 +4189,13 @@ EXPORT_SYMBOL_GPL(qeth_do_send_packet);
static int qeth_setadp_promisc_mode_cb(struct qeth_card *card, static int qeth_setadp_promisc_mode_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data) struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct qeth_ipacmd_setadpparms *setparms; struct qeth_ipacmd_setadpparms *setparms;
QETH_CARD_TEXT(card, 4, "prmadpcb"); QETH_CARD_TEXT(card, 4, "prmadpcb");
cmd = (struct qeth_ipa_cmd *) data;
setparms = &(cmd->data.setadapterparms); setparms = &(cmd->data.setadapterparms);
if (qeth_setadpparms_inspect_rc(cmd)) {
qeth_default_setadapterparms_cb(card, reply, (unsigned long)cmd);
if (cmd->hdr.return_code) {
QETH_CARD_TEXT_(card, 4, "prmrc%x", cmd->hdr.return_code); QETH_CARD_TEXT_(card, 4, "prmrc%x", cmd->hdr.return_code);
setparms->data.mode = SET_PROMISC_MODE_OFF; setparms->data.mode = SET_PROMISC_MODE_OFF;
} }
...@@ -4286,18 +4265,18 @@ EXPORT_SYMBOL_GPL(qeth_get_stats); ...@@ -4286,18 +4265,18 @@ EXPORT_SYMBOL_GPL(qeth_get_stats);
static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card, static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data) struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
QETH_CARD_TEXT(card, 4, "chgmaccb"); QETH_CARD_TEXT(card, 4, "chgmaccb");
if (qeth_setadpparms_inspect_rc(cmd))
return 0;
cmd = (struct qeth_ipa_cmd *) data;
if (!card->options.layer2 || if (!card->options.layer2 ||
!(card->info.mac_bits & QETH_LAYER2_MAC_READ)) { !(card->info.mac_bits & QETH_LAYER2_MAC_READ)) {
ether_addr_copy(card->dev->dev_addr, ether_addr_copy(card->dev->dev_addr,
cmd->data.setadapterparms.data.change_addr.addr); cmd->data.setadapterparms.data.change_addr.addr);
card->info.mac_bits |= QETH_LAYER2_MAC_READ; card->info.mac_bits |= QETH_LAYER2_MAC_READ;
} }
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
return 0; return 0;
} }
...@@ -4328,13 +4307,15 @@ EXPORT_SYMBOL_GPL(qeth_setadpparms_change_macaddr); ...@@ -4328,13 +4307,15 @@ EXPORT_SYMBOL_GPL(qeth_setadpparms_change_macaddr);
static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card, static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data) struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct qeth_set_access_ctrl *access_ctrl_req; struct qeth_set_access_ctrl *access_ctrl_req;
int fallback = *(int *)reply->param; int fallback = *(int *)reply->param;
QETH_CARD_TEXT(card, 4, "setaccb"); QETH_CARD_TEXT(card, 4, "setaccb");
if (cmd->hdr.return_code)
return 0;
qeth_setadpparms_inspect_rc(cmd);
cmd = (struct qeth_ipa_cmd *) data;
access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
QETH_DBF_TEXT_(SETUP, 2, "setaccb"); QETH_DBF_TEXT_(SETUP, 2, "setaccb");
QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name); QETH_DBF_TEXT_(SETUP, 2, "%s", card->gdev->dev.kobj.name);
...@@ -4407,7 +4388,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card, ...@@ -4407,7 +4388,6 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
card->options.isolation = card->options.prev_isolation; card->options.isolation = card->options.prev_isolation;
break; break;
} }
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd);
return 0; return 0;
} }
...@@ -4695,14 +4675,15 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata) ...@@ -4695,14 +4675,15 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
static int qeth_setadpparms_query_oat_cb(struct qeth_card *card, static int qeth_setadpparms_query_oat_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data) struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
struct qeth_qoat_priv *priv; struct qeth_qoat_priv *priv;
char *resdata; char *resdata;
int resdatalen; int resdatalen;
QETH_CARD_TEXT(card, 3, "qoatcb"); QETH_CARD_TEXT(card, 3, "qoatcb");
if (qeth_setadpparms_inspect_rc(cmd))
return 0;
cmd = (struct qeth_ipa_cmd *)data;
priv = (struct qeth_qoat_priv *)reply->param; priv = (struct qeth_qoat_priv *)reply->param;
resdatalen = cmd->data.setadapterparms.hdr.cmdlength; resdatalen = cmd->data.setadapterparms.hdr.cmdlength;
resdata = (char *)data + 28; resdata = (char *)data + 28;
...@@ -4796,21 +4777,18 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata) ...@@ -4796,21 +4777,18 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata)
static int qeth_query_card_info_cb(struct qeth_card *card, static int qeth_query_card_info_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data) struct qeth_reply *reply, unsigned long data)
{ {
struct qeth_ipa_cmd *cmd; struct carrier_info *carrier_info = (struct carrier_info *)reply->param;
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
struct qeth_query_card_info *card_info; struct qeth_query_card_info *card_info;
struct carrier_info *carrier_info;
QETH_CARD_TEXT(card, 2, "qcrdincb"); QETH_CARD_TEXT(card, 2, "qcrdincb");
carrier_info = (struct carrier_info *)reply->param; if (qeth_setadpparms_inspect_rc(cmd))
cmd = (struct qeth_ipa_cmd *)data; return 0;
card_info = &cmd->data.setadapterparms.data.card_info;
if (cmd->data.setadapterparms.hdr.return_code == 0) {
carrier_info->card_type = card_info->card_type;
carrier_info->port_mode = card_info->port_mode;
carrier_info->port_speed = card_info->port_speed;
}
qeth_default_setadapterparms_cb(card, reply, (unsigned long) cmd); card_info = &cmd->data.setadapterparms.data.card_info;
carrier_info->card_type = card_info->card_type;
carrier_info->port_mode = card_info->port_mode;
carrier_info->port_speed = card_info->port_speed;
return 0; return 0;
} }
...@@ -4857,7 +4835,7 @@ int qeth_vm_request_mac(struct qeth_card *card) ...@@ -4857,7 +4835,7 @@ int qeth_vm_request_mac(struct qeth_card *card)
goto out; goto out;
} }
ccw_device_get_id(CARD_DDEV(card), &id); ccw_device_get_id(CARD_RDEV(card), &id);
request->resp_buf_len = sizeof(*response); request->resp_buf_len = sizeof(*response);
request->resp_version = DIAG26C_VERSION2; request->resp_version = DIAG26C_VERSION2;
request->op_code = DIAG26C_GET_MAC; request->op_code = DIAG26C_GET_MAC;
...@@ -6563,10 +6541,14 @@ static int __init qeth_core_init(void) ...@@ -6563,10 +6541,14 @@ static int __init qeth_core_init(void)
mutex_init(&qeth_mod_mutex); mutex_init(&qeth_mod_mutex);
qeth_wq = create_singlethread_workqueue("qeth_wq"); qeth_wq = create_singlethread_workqueue("qeth_wq");
if (!qeth_wq) {
rc = -ENOMEM;
goto out_err;
}
rc = qeth_register_dbf_views(); rc = qeth_register_dbf_views();
if (rc) if (rc)
goto out_err; goto dbf_err;
qeth_core_root_dev = root_device_register("qeth"); qeth_core_root_dev = root_device_register("qeth");
rc = PTR_ERR_OR_ZERO(qeth_core_root_dev); rc = PTR_ERR_OR_ZERO(qeth_core_root_dev);
if (rc) if (rc)
...@@ -6603,6 +6585,8 @@ static int __init qeth_core_init(void) ...@@ -6603,6 +6585,8 @@ static int __init qeth_core_init(void)
root_device_unregister(qeth_core_root_dev); root_device_unregister(qeth_core_root_dev);
register_err: register_err:
qeth_unregister_dbf_views(); qeth_unregister_dbf_views();
dbf_err:
destroy_workqueue(qeth_wq);
out_err: out_err:
pr_err("Initializing the qeth device driver failed\n"); pr_err("Initializing the qeth device driver failed\n");
return rc; return rc;
......
...@@ -35,6 +35,18 @@ extern unsigned char IPA_PDU_HEADER[]; ...@@ -35,6 +35,18 @@ extern unsigned char IPA_PDU_HEADER[];
#define QETH_HALT_CHANNEL_PARM -11 #define QETH_HALT_CHANNEL_PARM -11
#define QETH_RCD_PARM -12 #define QETH_RCD_PARM -12
static inline bool qeth_intparm_is_iob(unsigned long intparm)
{
switch (intparm) {
case QETH_CLEAR_CHANNEL_PARM:
case QETH_HALT_CHANNEL_PARM:
case QETH_RCD_PARM:
case 0:
return false;
}
return true;
}
/*****************************************************************************/ /*****************************************************************************/
/* IP Assist related definitions */ /* IP Assist related definitions */
/*****************************************************************************/ /*****************************************************************************/
......
...@@ -121,13 +121,10 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) ...@@ -121,13 +121,10 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
QETH_CARD_TEXT(card, 2, "L2Setmac"); QETH_CARD_TEXT(card, 2, "L2Setmac");
rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC); rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_SETVMAC);
if (rc == 0) { if (rc == 0) {
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
ether_addr_copy(card->dev->dev_addr, mac);
dev_info(&card->gdev->dev, dev_info(&card->gdev->dev,
"MAC address %pM successfully registered on device %s\n", "MAC address %pM successfully registered on device %s\n",
card->dev->dev_addr, card->dev->name); mac, card->dev->name);
} else { } else {
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
switch (rc) { switch (rc) {
case -EEXIST: case -EEXIST:
dev_warn(&card->gdev->dev, dev_warn(&card->gdev->dev,
...@@ -142,19 +139,6 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) ...@@ -142,19 +139,6 @@ static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
return rc; return rc;
} }
static int qeth_l2_send_delmac(struct qeth_card *card, __u8 *mac)
{
int rc;
QETH_CARD_TEXT(card, 2, "L2Delmac");
if (!(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
return 0;
rc = qeth_l2_send_setdelmac(card, mac, IPA_CMD_DELVMAC);
if (rc == 0)
card->info.mac_bits &= ~QETH_LAYER2_MAC_REGISTERED;
return rc;
}
static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac) static int qeth_l2_write_mac(struct qeth_card *card, u8 *mac)
{ {
enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ? enum qeth_ipa_cmds cmd = is_multicast_ether_addr_64bits(mac) ?
...@@ -519,6 +503,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) ...@@ -519,6 +503,7 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
{ {
struct sockaddr *addr = p; struct sockaddr *addr = p;
struct qeth_card *card = dev->ml_priv; struct qeth_card *card = dev->ml_priv;
u8 old_addr[ETH_ALEN];
int rc = 0; int rc = 0;
QETH_CARD_TEXT(card, 3, "setmac"); QETH_CARD_TEXT(card, 3, "setmac");
...@@ -530,14 +515,35 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p) ...@@ -530,14 +515,35 @@ static int qeth_l2_set_mac_address(struct net_device *dev, void *p)
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN); QETH_CARD_HEX(card, 3, addr->sa_data, ETH_ALEN);
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) { if (qeth_wait_for_threads(card, QETH_RECOVER_THREAD)) {
QETH_CARD_TEXT(card, 3, "setmcREC"); QETH_CARD_TEXT(card, 3, "setmcREC");
return -ERESTARTSYS; return -ERESTARTSYS;
} }
rc = qeth_l2_send_delmac(card, &card->dev->dev_addr[0]);
if (!rc || (rc == -ENOENT)) if (!qeth_card_hw_is_reachable(card)) {
rc = qeth_l2_send_setmac(card, addr->sa_data); ether_addr_copy(dev->dev_addr, addr->sa_data);
return rc ? -EINVAL : 0; return 0;
}
/* don't register the same address twice */
if (ether_addr_equal_64bits(dev->dev_addr, addr->sa_data) &&
(card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED))
return 0;
/* add the new address, switch over, drop the old */
rc = qeth_l2_send_setmac(card, addr->sa_data);
if (rc)
return rc;
ether_addr_copy(old_addr, dev->dev_addr);
ether_addr_copy(dev->dev_addr, addr->sa_data);
if (card->info.mac_bits & QETH_LAYER2_MAC_REGISTERED)
qeth_l2_remove_mac(card, old_addr);
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
return 0;
} }
static void qeth_promisc_to_bridge(struct qeth_card *card) static void qeth_promisc_to_bridge(struct qeth_card *card)
...@@ -1067,8 +1073,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) ...@@ -1067,8 +1073,9 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
goto out_remove; goto out_remove;
} }
if (card->info.type != QETH_CARD_TYPE_OSN) if (card->info.type != QETH_CARD_TYPE_OSN &&
qeth_l2_send_setmac(card, &card->dev->dev_addr[0]); !qeth_l2_send_setmac(card, card->dev->dev_addr))
card->info.mac_bits |= QETH_LAYER2_MAC_REGISTERED;
if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) { if (qeth_is_diagass_supported(card, QETH_DIAGS_CMD_TRAP)) {
if (card->info.hwtrap && if (card->info.hwtrap &&
...@@ -1338,8 +1345,8 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len, ...@@ -1338,8 +1345,8 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
qeth_prepare_control_data(card, len, iob); qeth_prepare_control_data(card, len, iob);
QETH_CARD_TEXT(card, 6, "osnoirqp"); QETH_CARD_TEXT(card, 6, "osnoirqp");
spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags); spin_lock_irqsave(get_ccwdev_lock(card->write.ccwdev), flags);
rc = ccw_device_start(card->write.ccwdev, &card->write.ccw, rc = ccw_device_start_timeout(CARD_WDEV(card), &card->write.ccw,
(addr_t) iob, 0, 0); (addr_t) iob, 0, 0, QETH_IPA_TIMEOUT);
spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags); spin_unlock_irqrestore(get_ccwdev_lock(card->write.ccwdev), flags);
if (rc) { if (rc) {
QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: " QETH_DBF_MESSAGE(2, "qeth_osn_send_control_data: "
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment