Commit 8a1343c5 authored by David S. Miller's avatar David S. Miller

Merge branch 's390-qeth-next'

Julian Wiedmann says:

====================
s390/qeth: updates 2019-02-12

please apply one more round of qeth patches to net-next.
This series targets the driver's control paths. It primarily brings improvements
to the error handling for sent cmds and received responses, along with the
usual cleanup and consolidation efforts.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a263f99c 742d4d40
...@@ -595,8 +595,8 @@ struct qeth_channel; ...@@ -595,8 +595,8 @@ struct qeth_channel;
struct qeth_cmd_buffer { struct qeth_cmd_buffer {
enum qeth_cmd_buffer_state state; enum qeth_cmd_buffer_state state;
struct qeth_channel *channel; struct qeth_channel *channel;
struct qeth_reply *reply;
unsigned char *data; unsigned char *data;
int rc;
void (*callback)(struct qeth_card *card, struct qeth_channel *channel, void (*callback)(struct qeth_card *card, struct qeth_channel *channel,
struct qeth_cmd_buffer *iob); struct qeth_cmd_buffer *iob);
}; };
...@@ -1000,13 +1000,11 @@ void qeth_tx_timeout(struct net_device *); ...@@ -1000,13 +1000,11 @@ void qeth_tx_timeout(struct net_device *);
void qeth_prepare_control_data(struct qeth_card *, int, void qeth_prepare_control_data(struct qeth_card *, int,
struct qeth_cmd_buffer *); struct qeth_cmd_buffer *);
void qeth_release_buffer(struct qeth_channel *, struct qeth_cmd_buffer *); void qeth_release_buffer(struct qeth_channel *, struct qeth_cmd_buffer *);
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob); void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 cmd_length);
struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *); struct qeth_cmd_buffer *qeth_wait_for_buffer(struct qeth_channel *);
int qeth_query_switch_attributes(struct qeth_card *card, int qeth_query_switch_attributes(struct qeth_card *card,
struct qeth_switch_info *sw_info); struct qeth_switch_info *sw_info);
int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
void *reply_param);
unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset); unsigned int qeth_count_elements(struct sk_buff *skb, unsigned int data_offset);
int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue, int qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
struct sk_buff *skb, struct qeth_hdr *hdr, struct sk_buff *skb, struct qeth_hdr *hdr,
......
...@@ -566,6 +566,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card) ...@@ -566,6 +566,7 @@ static struct qeth_reply *qeth_alloc_reply(struct qeth_card *card)
if (reply) { if (reply) {
refcount_set(&reply->refcnt, 1); refcount_set(&reply->refcnt, 1);
atomic_set(&reply->received, 0); atomic_set(&reply->received, 0);
init_waitqueue_head(&reply->wait_q);
} }
return reply; return reply;
} }
...@@ -581,6 +582,26 @@ static void qeth_put_reply(struct qeth_reply *reply) ...@@ -581,6 +582,26 @@ static void qeth_put_reply(struct qeth_reply *reply)
kfree(reply); kfree(reply);
} }
static void qeth_enqueue_reply(struct qeth_card *card, struct qeth_reply *reply)
{
spin_lock_irq(&card->lock);
list_add_tail(&reply->list, &card->cmd_waiter_list);
spin_unlock_irq(&card->lock);
}
static void qeth_dequeue_reply(struct qeth_card *card, struct qeth_reply *reply)
{
spin_lock_irq(&card->lock);
list_del(&reply->list);
spin_unlock_irq(&card->lock);
}
static void qeth_notify_reply(struct qeth_reply *reply)
{
atomic_inc(&reply->received);
wake_up(&reply->wait_q);
}
static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc, static void qeth_issue_ipa_msg(struct qeth_ipa_cmd *cmd, int rc,
struct qeth_card *card) struct qeth_card *card)
{ {
...@@ -657,19 +678,15 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, ...@@ -657,19 +678,15 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
void qeth_clear_ipacmd_list(struct qeth_card *card) void qeth_clear_ipacmd_list(struct qeth_card *card)
{ {
struct qeth_reply *reply, *r; struct qeth_reply *reply;
unsigned long flags; unsigned long flags;
QETH_CARD_TEXT(card, 4, "clipalst"); QETH_CARD_TEXT(card, 4, "clipalst");
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { list_for_each_entry(reply, &card->cmd_waiter_list, list) {
qeth_get_reply(reply);
reply->rc = -EIO; reply->rc = -EIO;
atomic_inc(&reply->received); qeth_notify_reply(reply);
list_del_init(&reply->list);
wake_up(&reply->wait_q);
qeth_put_reply(reply);
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
} }
...@@ -726,7 +743,10 @@ void qeth_release_buffer(struct qeth_channel *channel, ...@@ -726,7 +743,10 @@ void qeth_release_buffer(struct qeth_channel *channel,
spin_lock_irqsave(&channel->iob_lock, flags); spin_lock_irqsave(&channel->iob_lock, flags);
iob->state = BUF_STATE_FREE; iob->state = BUF_STATE_FREE;
iob->callback = qeth_send_control_data_cb; iob->callback = qeth_send_control_data_cb;
iob->rc = 0; if (iob->reply) {
qeth_put_reply(iob->reply);
iob->reply = NULL;
}
spin_unlock_irqrestore(&channel->iob_lock, flags); spin_unlock_irqrestore(&channel->iob_lock, flags);
wake_up(&channel->wait_q); wake_up(&channel->wait_q);
} }
...@@ -739,6 +759,17 @@ static void qeth_release_buffer_cb(struct qeth_card *card, ...@@ -739,6 +759,17 @@ static void qeth_release_buffer_cb(struct qeth_card *card,
qeth_release_buffer(channel, iob); qeth_release_buffer(channel, iob);
} }
static void qeth_cancel_cmd(struct qeth_cmd_buffer *iob, int rc)
{
struct qeth_reply *reply = iob->reply;
if (reply) {
reply->rc = rc;
qeth_notify_reply(reply);
}
qeth_release_buffer(iob->channel, iob);
}
static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *channel) static struct qeth_cmd_buffer *qeth_get_buffer(struct qeth_channel *channel)
{ {
struct qeth_cmd_buffer *buffer = NULL; struct qeth_cmd_buffer *buffer = NULL;
...@@ -774,9 +805,9 @@ static void qeth_send_control_data_cb(struct qeth_card *card, ...@@ -774,9 +805,9 @@ static void qeth_send_control_data_cb(struct qeth_card *card,
struct qeth_cmd_buffer *iob) struct qeth_cmd_buffer *iob)
{ {
struct qeth_ipa_cmd *cmd = NULL; struct qeth_ipa_cmd *cmd = NULL;
struct qeth_reply *reply, *r; struct qeth_reply *reply = NULL;
struct qeth_reply *r;
unsigned long flags; unsigned long flags;
int keep_reply;
int rc = 0; int rc = 0;
QETH_CARD_TEXT(card, 4, "sndctlcb"); QETH_CARD_TEXT(card, 4, "sndctlcb");
...@@ -808,44 +839,40 @@ static void qeth_send_control_data_cb(struct qeth_card *card, ...@@ -808,44 +839,40 @@ static void qeth_send_control_data_cb(struct qeth_card *card,
goto out; goto out;
} }
/* match against pending cmd requests */
spin_lock_irqsave(&card->lock, flags); spin_lock_irqsave(&card->lock, flags);
list_for_each_entry_safe(reply, r, &card->cmd_waiter_list, list) { list_for_each_entry(r, &card->cmd_waiter_list, list) {
if ((reply->seqno == QETH_IDX_COMMAND_SEQNO) || if ((r->seqno == QETH_IDX_COMMAND_SEQNO) ||
((cmd) && (reply->seqno == cmd->hdr.seqno))) { (cmd && (r->seqno == cmd->hdr.seqno))) {
reply = r;
/* take the object outside the lock */
qeth_get_reply(reply); qeth_get_reply(reply);
list_del_init(&reply->list); break;
spin_unlock_irqrestore(&card->lock, flags);
keep_reply = 0;
if (reply->callback != NULL) {
if (cmd) {
reply->offset = (__u16)((char *)cmd -
(char *)iob->data);
keep_reply = reply->callback(card,
reply,
(unsigned long)cmd);
} else
keep_reply = reply->callback(card,
reply,
(unsigned long)iob);
}
if (cmd)
reply->rc = (u16) cmd->hdr.return_code;
else if (iob->rc)
reply->rc = iob->rc;
if (keep_reply) {
spin_lock_irqsave(&card->lock, flags);
list_add_tail(&reply->list,
&card->cmd_waiter_list);
spin_unlock_irqrestore(&card->lock, flags);
} else {
atomic_inc(&reply->received);
wake_up(&reply->wait_q);
}
qeth_put_reply(reply);
goto out;
} }
} }
spin_unlock_irqrestore(&card->lock, flags); spin_unlock_irqrestore(&card->lock, flags);
if (!reply)
goto out;
if (!reply->callback) {
rc = 0;
} else {
if (cmd) {
reply->offset = (u16)((char *)cmd - (char *)iob->data);
rc = reply->callback(card, reply, (unsigned long)cmd);
} else {
rc = reply->callback(card, reply, (unsigned long)iob);
}
}
if (rc <= 0) {
reply->rc = rc;
qeth_notify_reply(reply);
}
qeth_put_reply(reply);
out: out:
memcpy(&card->seqno.pdu_hdr_ack, memcpy(&card->seqno.pdu_hdr_ack,
QETH_PDU_HEADER_SEQ_NO(iob->data), QETH_PDU_HEADER_SEQ_NO(iob->data),
...@@ -976,9 +1003,8 @@ static int qeth_get_problem(struct qeth_card *card, struct ccw_device *cdev, ...@@ -976,9 +1003,8 @@ static int qeth_get_problem(struct qeth_card *card, struct ccw_device *cdev,
return 0; return 0;
} }
static long qeth_check_irb_error(struct qeth_card *card, static int qeth_check_irb_error(struct qeth_card *card, struct ccw_device *cdev,
struct ccw_device *cdev, unsigned long intparm, unsigned long intparm, struct irb *irb)
struct irb *irb)
{ {
if (!IS_ERR(irb)) if (!IS_ERR(irb))
return 0; return 0;
...@@ -989,7 +1015,7 @@ static long qeth_check_irb_error(struct qeth_card *card, ...@@ -989,7 +1015,7 @@ static long qeth_check_irb_error(struct qeth_card *card,
CCW_DEVID(cdev)); CCW_DEVID(cdev));
QETH_CARD_TEXT(card, 2, "ckirberr"); QETH_CARD_TEXT(card, 2, "ckirberr");
QETH_CARD_TEXT_(card, 2, " rc%d", -EIO); QETH_CARD_TEXT_(card, 2, " rc%d", -EIO);
break; return -EIO;
case -ETIMEDOUT: case -ETIMEDOUT:
dev_warn(&cdev->dev, "A hardware operation timed out" dev_warn(&cdev->dev, "A hardware operation timed out"
" on the device\n"); " on the device\n");
...@@ -1001,14 +1027,14 @@ static long qeth_check_irb_error(struct qeth_card *card, ...@@ -1001,14 +1027,14 @@ static long qeth_check_irb_error(struct qeth_card *card,
wake_up(&card->wait_q); wake_up(&card->wait_q);
} }
} }
break; return -ETIMEDOUT;
default: default:
QETH_DBF_MESSAGE(2, "unknown error %ld on channel %x\n", QETH_DBF_MESSAGE(2, "unknown error %ld on channel %x\n",
PTR_ERR(irb), CCW_DEVID(cdev)); PTR_ERR(irb), CCW_DEVID(cdev));
QETH_CARD_TEXT(card, 2, "ckirberr"); QETH_CARD_TEXT(card, 2, "ckirberr");
QETH_CARD_TEXT(card, 2, " rc???"); QETH_CARD_TEXT(card, 2, " rc???");
return PTR_ERR(irb);
} }
return PTR_ERR(irb);
} }
static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
...@@ -1043,10 +1069,11 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -1043,10 +1069,11 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
if (qeth_intparm_is_iob(intparm)) if (qeth_intparm_is_iob(intparm))
iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm); iob = (struct qeth_cmd_buffer *) __va((addr_t)intparm);
if (qeth_check_irb_error(card, cdev, intparm, irb)) { rc = qeth_check_irb_error(card, cdev, intparm, irb);
if (rc) {
/* IO was terminated, free its resources. */ /* IO was terminated, free its resources. */
if (iob) if (iob)
qeth_release_buffer(iob->channel, iob); qeth_cancel_cmd(iob, rc);
atomic_set(&channel->irq_pending, 0); atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q); wake_up(&card->wait_q);
return; return;
...@@ -1102,7 +1129,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, ...@@ -1102,7 +1129,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
if (rc) { if (rc) {
card->read_or_write_problem = 1; card->read_or_write_problem = 1;
if (iob) if (iob)
qeth_release_buffer(iob->channel, iob); qeth_cancel_cmd(iob, rc);
qeth_clear_ipacmd_list(card); qeth_clear_ipacmd_list(card);
qeth_schedule_recovery(card); qeth_schedule_recovery(card);
goto out; goto out;
...@@ -1264,7 +1291,6 @@ static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers) ...@@ -1264,7 +1291,6 @@ static int qeth_setup_channel(struct qeth_channel *channel, bool alloc_buffers)
channel->iob[cnt].state = BUF_STATE_FREE; channel->iob[cnt].state = BUF_STATE_FREE;
channel->iob[cnt].channel = channel; channel->iob[cnt].channel = channel;
channel->iob[cnt].callback = qeth_send_control_data_cb; channel->iob[cnt].callback = qeth_send_control_data_cb;
channel->iob[cnt].rc = 0;
} }
if (cnt < QETH_CMD_BUFFER_NO) { if (cnt < QETH_CMD_BUFFER_NO) {
qeth_clean_channel(channel); qeth_clean_channel(channel);
...@@ -1991,7 +2017,7 @@ void qeth_prepare_control_data(struct qeth_card *card, int len, ...@@ -1991,7 +2017,7 @@ void qeth_prepare_control_data(struct qeth_card *card, int len,
card->seqno.pdu_hdr++; card->seqno.pdu_hdr++;
memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data), memcpy(QETH_PDU_HEADER_ACK_SEQ_NO(iob->data),
&card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH); &card->seqno.pdu_hdr_ack, QETH_SEQ_NO_LENGTH);
QETH_DBF_HEX(CTRL, 2, iob->data, QETH_DBF_CTRL_LEN); QETH_DBF_HEX(CTRL, 2, iob->data, min(len, QETH_DBF_CTRL_LEN));
} }
EXPORT_SYMBOL_GPL(qeth_prepare_control_data); EXPORT_SYMBOL_GPL(qeth_prepare_control_data);
...@@ -2008,24 +2034,22 @@ EXPORT_SYMBOL_GPL(qeth_prepare_control_data); ...@@ -2008,24 +2034,22 @@ EXPORT_SYMBOL_GPL(qeth_prepare_control_data);
* for the IPA commands. * for the IPA commands.
* @reply_param: private pointer passed to the callback * @reply_param: private pointer passed to the callback
* *
* Returns the value of the `return_code' field of the response
* block returned from the hardware, or other error indication.
* Value of zero indicates successful execution of the command.
*
* Callback function gets called one or more times, with cb_cmd * Callback function gets called one or more times, with cb_cmd
* pointing to the response returned by the hardware. Callback * pointing to the response returned by the hardware. Callback
* function must return non-zero if more reply blocks are expected, * function must return
* and zero if the last or only reply block is received. Callback * > 0 if more reply blocks are expected,
* function can get the value of the reply_param pointer from the * 0 if the last or only reply block is received, and
* < 0 on error.
* Callback function can get the value of the reply_param pointer from the
* field 'param' of the structure qeth_reply. * field 'param' of the structure qeth_reply.
*/ */
int qeth_send_control_data(struct qeth_card *card, int len, static int qeth_send_control_data(struct qeth_card *card, int len,
struct qeth_cmd_buffer *iob, struct qeth_cmd_buffer *iob,
int (*reply_cb)(struct qeth_card *cb_card, int (*reply_cb)(struct qeth_card *cb_card,
struct qeth_reply *cb_reply, struct qeth_reply *cb_reply,
unsigned long cb_cmd), unsigned long cb_cmd),
void *reply_param) void *reply_param)
{ {
struct qeth_channel *channel = iob->channel; struct qeth_channel *channel = iob->channel;
int rc; int rc;
...@@ -2047,7 +2071,9 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2047,7 +2071,9 @@ int qeth_send_control_data(struct qeth_card *card, int len,
reply->callback = reply_cb; reply->callback = reply_cb;
reply->param = reply_param; reply->param = reply_param;
init_waitqueue_head(&reply->wait_q); /* pairs with qeth_release_buffer(): */
qeth_get_reply(reply);
iob->reply = reply;
while (atomic_cmpxchg(&channel->irq_pending, 0, 1)) ; while (atomic_cmpxchg(&channel->irq_pending, 0, 1)) ;
...@@ -2062,9 +2088,7 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2062,9 +2088,7 @@ int qeth_send_control_data(struct qeth_card *card, int len,
} }
qeth_prepare_control_data(card, len, iob); qeth_prepare_control_data(card, len, iob);
spin_lock_irq(&card->lock); qeth_enqueue_reply(card, reply);
list_add_tail(&reply->list, &card->cmd_waiter_list);
spin_unlock_irq(&card->lock);
timeout = jiffies + event_timeout; timeout = jiffies + event_timeout;
...@@ -2077,10 +2101,8 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2077,10 +2101,8 @@ int qeth_send_control_data(struct qeth_card *card, int len,
QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n", QETH_DBF_MESSAGE(2, "qeth_send_control_data on device %x: ccw_device_start rc = %i\n",
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
QETH_CARD_TEXT_(card, 2, " err%d", rc); QETH_CARD_TEXT_(card, 2, " err%d", rc);
spin_lock_irq(&card->lock); qeth_dequeue_reply(card, reply);
list_del_init(&reply->list);
qeth_put_reply(reply); qeth_put_reply(reply);
spin_unlock_irq(&card->lock);
qeth_release_buffer(channel, iob); qeth_release_buffer(channel, iob);
atomic_set(&channel->irq_pending, 0); atomic_set(&channel->irq_pending, 0);
wake_up(&card->wait_q); wake_up(&card->wait_q);
...@@ -2102,21 +2124,16 @@ int qeth_send_control_data(struct qeth_card *card, int len, ...@@ -2102,21 +2124,16 @@ int qeth_send_control_data(struct qeth_card *card, int len,
} }
} }
qeth_dequeue_reply(card, reply);
rc = reply->rc; rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return rc;
time_err: time_err:
reply->rc = -ETIME; qeth_dequeue_reply(card, reply);
spin_lock_irq(&card->lock);
list_del_init(&reply->list);
spin_unlock_irq(&card->lock);
atomic_inc(&reply->received);
rc = reply->rc;
qeth_put_reply(reply); qeth_put_reply(reply);
return rc; return -ETIME;
} }
EXPORT_SYMBOL_GPL(qeth_send_control_data);
static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply, static int qeth_cm_enable_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data) unsigned long data)
...@@ -2321,9 +2338,8 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply, ...@@ -2321,9 +2338,8 @@ static int qeth_ulp_setup_cb(struct qeth_card *card, struct qeth_reply *reply,
QETH_DBF_TEXT(SETUP, 2, "olmlimit"); QETH_DBF_TEXT(SETUP, 2, "olmlimit");
dev_err(&card->gdev->dev, "A connection could not be " dev_err(&card->gdev->dev, "A connection could not be "
"established because of an OLM limit\n"); "established because of an OLM limit\n");
iob->rc = -EMLINK; return -EMLINK;
} }
QETH_DBF_TEXT_(SETUP, 2, " rc%d", iob->rc);
return 0; return 0;
} }
...@@ -2816,14 +2832,20 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card, ...@@ -2816,14 +2832,20 @@ static void qeth_fill_ipacmd_header(struct qeth_card *card,
cmd->hdr.prot_version = prot; cmd->hdr.prot_version = prot;
} }
void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob) void qeth_prepare_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
u16 cmd_length)
{ {
u16 total_length = IPA_PDU_HEADER_SIZE + cmd_length;
u8 prot_type = qeth_mpc_select_prot_type(card); u8 prot_type = qeth_mpc_select_prot_type(card);
memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE); memcpy(iob->data, IPA_PDU_HEADER, IPA_PDU_HEADER_SIZE);
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &total_length, 2);
memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1); memcpy(QETH_IPA_CMD_PROT_TYPE(iob->data), &prot_type, 1);
memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &cmd_length, 2);
memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &cmd_length, 2);
memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data), memcpy(QETH_IPA_CMD_DEST_ADDR(iob->data),
&card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH); &card->token.ulp_connection_r, QETH_MPC_TOKEN_LENGTH);
memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &cmd_length, 2);
} }
EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd); EXPORT_SYMBOL_GPL(qeth_prepare_ipa_cmd);
...@@ -2834,7 +2856,7 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card, ...@@ -2834,7 +2856,7 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card,
iob = qeth_get_buffer(&card->write); iob = qeth_get_buffer(&card->write);
if (iob) { if (iob) {
qeth_prepare_ipa_cmd(card, iob); qeth_prepare_ipa_cmd(card, iob, sizeof(struct qeth_ipa_cmd));
qeth_fill_ipacmd_header(card, __ipa_cmd(iob), ipacmd, prot); qeth_fill_ipacmd_header(card, __ipa_cmd(iob), ipacmd, prot);
} else { } else {
dev_warn(&card->gdev->dev, dev_warn(&card->gdev->dev,
...@@ -2847,6 +2869,14 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card, ...@@ -2847,6 +2869,14 @@ struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *card,
} }
EXPORT_SYMBOL_GPL(qeth_get_ipacmd_buffer); EXPORT_SYMBOL_GPL(qeth_get_ipacmd_buffer);
static int qeth_send_ipa_cmd_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
return (cmd->hdr.return_code) ? -EIO : 0;
}
/** /**
* qeth_send_ipa_cmd() - send an IPA command * qeth_send_ipa_cmd() - send an IPA command
* *
...@@ -2858,11 +2888,15 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, ...@@ -2858,11 +2888,15 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
unsigned long), unsigned long),
void *reply_param) void *reply_param)
{ {
u16 length;
int rc; int rc;
QETH_CARD_TEXT(card, 4, "sendipa"); QETH_CARD_TEXT(card, 4, "sendipa");
rc = qeth_send_control_data(card, IPA_CMD_LENGTH,
iob, reply_cb, reply_param); if (reply_cb == NULL)
reply_cb = qeth_send_ipa_cmd_cb;
memcpy(&length, QETH_IPA_PDU_LEN_TOTAL(iob->data), 2);
rc = qeth_send_control_data(card, length, iob, reply_cb, reply_param);
if (rc == -ETIME) { if (rc == -ETIME) {
qeth_clear_ipacmd_list(card); qeth_clear_ipacmd_list(card);
qeth_schedule_recovery(card); qeth_schedule_recovery(card);
...@@ -2871,9 +2905,19 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob, ...@@ -2871,9 +2905,19 @@ int qeth_send_ipa_cmd(struct qeth_card *card, struct qeth_cmd_buffer *iob,
} }
EXPORT_SYMBOL_GPL(qeth_send_ipa_cmd); EXPORT_SYMBOL_GPL(qeth_send_ipa_cmd);
static int qeth_send_startlan_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
if (cmd->hdr.return_code == IPA_RC_LAN_OFFLINE)
return -ENETDOWN;
return (cmd->hdr.return_code) ? -EIO : 0;
}
static int qeth_send_startlan(struct qeth_card *card) static int qeth_send_startlan(struct qeth_card *card)
{ {
int rc;
struct qeth_cmd_buffer *iob; struct qeth_cmd_buffer *iob;
QETH_DBF_TEXT(SETUP, 2, "strtlan"); QETH_DBF_TEXT(SETUP, 2, "strtlan");
...@@ -2881,8 +2925,7 @@ static int qeth_send_startlan(struct qeth_card *card) ...@@ -2881,8 +2925,7 @@ static int qeth_send_startlan(struct qeth_card *card)
iob = qeth_get_ipacmd_buffer(card, IPA_CMD_STARTLAN, 0); iob = qeth_get_ipacmd_buffer(card, IPA_CMD_STARTLAN, 0);
if (!iob) if (!iob)
return -ENOMEM; return -ENOMEM;
rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); return qeth_send_ipa_cmd(card, iob, qeth_send_startlan_cb, NULL);
return rc;
} }
static int qeth_setadpparms_inspect_rc(struct qeth_ipa_cmd *cmd) static int qeth_setadpparms_inspect_rc(struct qeth_ipa_cmd *cmd)
...@@ -2900,7 +2943,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card, ...@@ -2900,7 +2943,7 @@ static int qeth_query_setadapterparms_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 3, "quyadpcb"); QETH_CARD_TEXT(card, 3, "quyadpcb");
if (qeth_setadpparms_inspect_rc(cmd)) if (qeth_setadpparms_inspect_rc(cmd))
return 0; return -EIO;
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 =
...@@ -2955,19 +2998,18 @@ static int qeth_query_ipassists_cb(struct qeth_card *card, ...@@ -2955,19 +2998,18 @@ static int qeth_query_ipassists_cb(struct qeth_card *card,
cmd = (struct qeth_ipa_cmd *) data; cmd = (struct qeth_ipa_cmd *) data;
switch (cmd->hdr.return_code) { switch (cmd->hdr.return_code) {
case IPA_RC_SUCCESS:
break;
case IPA_RC_NOTSUPP: case IPA_RC_NOTSUPP:
case IPA_RC_L2_UNSUPPORTED_CMD: case IPA_RC_L2_UNSUPPORTED_CMD:
QETH_DBF_TEXT(SETUP, 2, "ipaunsup"); QETH_DBF_TEXT(SETUP, 2, "ipaunsup");
card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS; card->options.ipa4.supported_funcs |= IPA_SETADAPTERPARMS;
card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS; card->options.ipa6.supported_funcs |= IPA_SETADAPTERPARMS;
return 0; return -EOPNOTSUPP;
default: default:
if (cmd->hdr.return_code) { QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Unhandled rc=%#x\n",
QETH_DBF_MESSAGE(1, "IPA_CMD_QIPASSIST on device %x: Unhandled rc=%#x\n", CARD_DEVID(card), cmd->hdr.return_code);
CARD_DEVID(card), return -EIO;
cmd->hdr.return_code);
return 0;
}
} }
if (cmd->hdr.prot_version == QETH_PROT_IPV4) { if (cmd->hdr.prot_version == QETH_PROT_IPV4) {
...@@ -3005,7 +3047,7 @@ static int qeth_query_switch_attributes_cb(struct qeth_card *card, ...@@ -3005,7 +3047,7 @@ static int qeth_query_switch_attributes_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 2, "qswiatcb"); QETH_CARD_TEXT(card, 2, "qswiatcb");
if (qeth_setadpparms_inspect_rc(cmd)) if (qeth_setadpparms_inspect_rc(cmd))
return 0; return -EIO;
sw_info = (struct qeth_switch_info *)reply->param; sw_info = (struct qeth_switch_info *)reply->param;
attrs = &cmd->data.setadapterparms.data.query_switch_attributes; attrs = &cmd->data.setadapterparms.data.query_switch_attributes;
...@@ -3037,15 +3079,15 @@ int qeth_query_switch_attributes(struct qeth_card *card, ...@@ -3037,15 +3079,15 @@ int qeth_query_switch_attributes(struct qeth_card *card,
static int qeth_query_setdiagass_cb(struct qeth_card *card, static int qeth_query_setdiagass_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;
__u16 rc; u16 rc = cmd->hdr.return_code;
cmd = (struct qeth_ipa_cmd *)data; if (rc) {
rc = cmd->hdr.return_code;
if (rc)
QETH_CARD_TEXT_(card, 2, "diagq:%x", rc); QETH_CARD_TEXT_(card, 2, "diagq:%x", rc);
else return -EIO;
card->info.diagass_support = cmd->data.diagass.ext; }
card->info.diagass_support = cmd->data.diagass.ext;
return 0; return 0;
} }
...@@ -3092,13 +3134,13 @@ static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid) ...@@ -3092,13 +3134,13 @@ static void qeth_get_trap_id(struct qeth_card *card, struct qeth_trap_id *tid)
static int qeth_hw_trap_cb(struct qeth_card *card, static int qeth_hw_trap_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;
__u16 rc; u16 rc = cmd->hdr.return_code;
cmd = (struct qeth_ipa_cmd *)data; if (rc) {
rc = cmd->hdr.return_code;
if (rc)
QETH_CARD_TEXT_(card, 2, "trapc:%x", rc); QETH_CARD_TEXT_(card, 2, "trapc:%x", rc);
return -EIO;
}
return 0; return 0;
} }
...@@ -4157,7 +4199,7 @@ static int qeth_setadp_promisc_mode_cb(struct qeth_card *card, ...@@ -4157,7 +4199,7 @@ static int qeth_setadp_promisc_mode_cb(struct qeth_card *card,
setparms->data.mode = SET_PROMISC_MODE_OFF; setparms->data.mode = SET_PROMISC_MODE_OFF;
} }
card->info.promisc_mode = setparms->data.mode; card->info.promisc_mode = setparms->data.mode;
return 0; return (cmd->hdr.return_code) ? -EIO : 0;
} }
void qeth_setadp_promisc_mode(struct qeth_card *card) void qeth_setadp_promisc_mode(struct qeth_card *card)
...@@ -4209,12 +4251,15 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card, ...@@ -4209,12 +4251,15 @@ static int qeth_setadpparms_change_macaddr_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "chgmaccb"); QETH_CARD_TEXT(card, 4, "chgmaccb");
if (qeth_setadpparms_inspect_rc(cmd)) if (qeth_setadpparms_inspect_rc(cmd))
return 0; return -EIO;
adp_cmd = &cmd->data.setadapterparms; adp_cmd = &cmd->data.setadapterparms;
if (!is_valid_ether_addr(adp_cmd->data.change_addr.addr))
return -EADDRNOTAVAIL;
if (IS_LAYER2(card) && IS_OSD(card) && !IS_VM_NIC(card) && if (IS_LAYER2(card) && IS_OSD(card) && !IS_VM_NIC(card) &&
!(adp_cmd->hdr.flags & QETH_SETADP_FLAGS_VIRTUAL_MAC)) !(adp_cmd->hdr.flags & QETH_SETADP_FLAGS_VIRTUAL_MAC))
return 0; return -EADDRNOTAVAIL;
ether_addr_copy(card->dev->dev_addr, adp_cmd->data.change_addr.addr); ether_addr_copy(card->dev->dev_addr, adp_cmd->data.change_addr.addr);
return 0; return 0;
...@@ -4253,7 +4298,7 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card, ...@@ -4253,7 +4298,7 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 4, "setaccb"); QETH_CARD_TEXT(card, 4, "setaccb");
if (cmd->hdr.return_code) if (cmd->hdr.return_code)
return 0; return -EIO;
qeth_setadpparms_inspect_rc(cmd); qeth_setadpparms_inspect_rc(cmd);
access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl; access_ctrl_req = &cmd->data.setadapterparms.data.set_access_ctrl;
...@@ -4327,7 +4372,7 @@ static int qeth_setadpparms_set_access_ctrl_cb(struct qeth_card *card, ...@@ -4327,7 +4372,7 @@ 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;
} }
return 0; return (cmd->hdr.return_code) ? -EIO : 0;
} }
static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card, static int qeth_setadpparms_set_access_ctrl(struct qeth_card *card,
...@@ -4461,27 +4506,6 @@ static int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum) ...@@ -4461,27 +4506,6 @@ static int qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
return rc; return rc;
} }
static int qeth_send_ipa_snmp_cmd(struct qeth_card *card,
struct qeth_cmd_buffer *iob, int len,
int (*reply_cb)(struct qeth_card *, struct qeth_reply *,
unsigned long),
void *reply_param)
{
u16 s1, s2;
QETH_CARD_TEXT(card, 4, "sendsnmp");
/* adjust PDU length fields in IPA_PDU_HEADER */
s1 = (u32) IPA_PDU_HEADER_SIZE + len;
s2 = (u32) len;
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);
memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);
return qeth_send_control_data(card, IPA_PDU_HEADER_SIZE + len, iob,
reply_cb, reply_param);
}
static int qeth_snmp_command_cb(struct qeth_card *card, static int qeth_snmp_command_cb(struct qeth_card *card,
struct qeth_reply *reply, unsigned long sdata) struct qeth_reply *reply, unsigned long sdata)
{ {
...@@ -4499,13 +4523,13 @@ static int qeth_snmp_command_cb(struct qeth_card *card, ...@@ -4499,13 +4523,13 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
if (cmd->hdr.return_code) { if (cmd->hdr.return_code) {
QETH_CARD_TEXT_(card, 4, "scer1%x", cmd->hdr.return_code); QETH_CARD_TEXT_(card, 4, "scer1%x", cmd->hdr.return_code);
return 0; return -EIO;
} }
if (cmd->data.setadapterparms.hdr.return_code) { if (cmd->data.setadapterparms.hdr.return_code) {
cmd->hdr.return_code = cmd->hdr.return_code =
cmd->data.setadapterparms.hdr.return_code; cmd->data.setadapterparms.hdr.return_code;
QETH_CARD_TEXT_(card, 4, "scer2%x", cmd->hdr.return_code); QETH_CARD_TEXT_(card, 4, "scer2%x", cmd->hdr.return_code);
return 0; return -EIO;
} }
data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data)); data_len = *((__u16 *)QETH_IPA_PDU_LEN_PDU1(data));
if (cmd->data.setadapterparms.hdr.seq_no == 1) { if (cmd->data.setadapterparms.hdr.seq_no == 1) {
...@@ -4520,9 +4544,8 @@ static int qeth_snmp_command_cb(struct qeth_card *card, ...@@ -4520,9 +4544,8 @@ static int qeth_snmp_command_cb(struct qeth_card *card,
/* check if there is enough room in userspace */ /* check if there is enough room in userspace */
if ((qinfo->udata_len - qinfo->udata_offset) < data_len) { if ((qinfo->udata_len - qinfo->udata_offset) < data_len) {
QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOMEM); QETH_CARD_TEXT_(card, 4, "scer3%i", -ENOSPC);
cmd->hdr.return_code = IPA_RC_ENOMEM; return -ENOSPC;
return 0;
} }
QETH_CARD_TEXT_(card, 4, "snore%i", QETH_CARD_TEXT_(card, 4, "snore%i",
cmd->data.setadapterparms.hdr.used_total); cmd->data.setadapterparms.hdr.used_total);
...@@ -4587,10 +4610,13 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata) ...@@ -4587,10 +4610,13 @@ static int qeth_snmp_command(struct qeth_card *card, char __user *udata)
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
} }
/* for large requests, fix-up the length fields: */
qeth_prepare_ipa_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len);
cmd = __ipa_cmd(iob); cmd = __ipa_cmd(iob);
memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len); memcpy(&cmd->data.setadapterparms.data.snmp, &ureq->cmd, req_len);
rc = qeth_send_ipa_snmp_cmd(card, iob, QETH_SETADP_BASE_LEN + req_len, rc = qeth_send_ipa_cmd(card, iob, qeth_snmp_command_cb, &qinfo);
qeth_snmp_command_cb, (void *)&qinfo);
if (rc) if (rc)
QETH_DBF_MESSAGE(2, "SNMP command failed on device %x: (%#x)\n", QETH_DBF_MESSAGE(2, "SNMP command failed on device %x: (%#x)\n",
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
...@@ -4614,16 +4640,14 @@ static int qeth_setadpparms_query_oat_cb(struct qeth_card *card, ...@@ -4614,16 +4640,14 @@ static int qeth_setadpparms_query_oat_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 3, "qoatcb"); QETH_CARD_TEXT(card, 3, "qoatcb");
if (qeth_setadpparms_inspect_rc(cmd)) if (qeth_setadpparms_inspect_rc(cmd))
return 0; return -EIO;
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;
if (resdatalen > (priv->buffer_len - priv->response_len)) { if (resdatalen > (priv->buffer_len - priv->response_len))
cmd->hdr.return_code = IPA_RC_FFFF; return -ENOSPC;
return 0;
}
memcpy((priv->buffer + priv->response_len), resdata, memcpy((priv->buffer + priv->response_len), resdata,
resdatalen); resdatalen);
...@@ -4696,9 +4720,7 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata) ...@@ -4696,9 +4720,7 @@ static int qeth_query_oat_command(struct qeth_card *card, char __user *udata)
if (copy_to_user(udata, &oat_data, if (copy_to_user(udata, &oat_data,
sizeof(struct qeth_query_oat_data))) sizeof(struct qeth_query_oat_data)))
rc = -EFAULT; rc = -EFAULT;
} else }
if (rc == IPA_RC_FFFF)
rc = -EFAULT;
out_free: out_free:
vfree(priv.buffer); vfree(priv.buffer);
...@@ -4715,7 +4737,7 @@ static int qeth_query_card_info_cb(struct qeth_card *card, ...@@ -4715,7 +4737,7 @@ static int qeth_query_card_info_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 2, "qcrdincb"); QETH_CARD_TEXT(card, 2, "qcrdincb");
if (qeth_setadpparms_inspect_rc(cmd)) if (qeth_setadpparms_inspect_rc(cmd))
return 0; return -EIO;
card_info = &cmd->data.setadapterparms.data.card_info; card_info = &cmd->data.setadapterparms.data.card_info;
carrier_info->card_type = card_info->card_type; carrier_info->card_type = card_info->card_type;
...@@ -5117,12 +5139,10 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok) ...@@ -5117,12 +5139,10 @@ int qeth_core_hardsetup_card(struct qeth_card *card, bool *carrier_ok)
rc = qeth_send_startlan(card); rc = qeth_send_startlan(card);
if (rc) { if (rc) {
QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc); QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);
if (rc == IPA_RC_LAN_OFFLINE) { if (rc == -ENETDOWN) {
dev_warn(&card->gdev->dev, dev_warn(&card->gdev->dev, "The LAN is offline\n");
"The LAN is offline\n");
*carrier_ok = false; *carrier_ok = false;
} else { } else {
rc = -ENODEV;
goto out; goto out;
} }
} else { } else {
...@@ -5392,7 +5412,7 @@ static int qeth_setassparms_get_caps_cb(struct qeth_card *card, ...@@ -5392,7 +5412,7 @@ static int qeth_setassparms_get_caps_cb(struct qeth_card *card,
struct qeth_ipa_caps *caps = reply->param; struct qeth_ipa_caps *caps = reply->param;
if (qeth_setassparms_inspect_rc(cmd)) if (qeth_setassparms_inspect_rc(cmd))
return 0; return -EIO;
caps->supported = cmd->data.setassparms.data.caps.supported; caps->supported = cmd->data.setassparms.data.caps.supported;
caps->enabled = cmd->data.setassparms.data.caps.enabled; caps->enabled = cmd->data.setassparms.data.caps.enabled;
...@@ -5402,18 +5422,18 @@ static int qeth_setassparms_get_caps_cb(struct qeth_card *card, ...@@ -5402,18 +5422,18 @@ static int qeth_setassparms_get_caps_cb(struct qeth_card *card,
int qeth_setassparms_cb(struct qeth_card *card, int qeth_setassparms_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, "defadpcb"); QETH_CARD_TEXT(card, 4, "defadpcb");
cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code)
if (cmd->hdr.return_code == 0) { return -EIO;
cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
if (cmd->hdr.prot_version == QETH_PROT_IPV4) cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled; if (cmd->hdr.prot_version == QETH_PROT_IPV4)
if (cmd->hdr.prot_version == QETH_PROT_IPV6) card->options.ipa4.enabled_funcs = cmd->hdr.ipa_enabled;
card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled; if (cmd->hdr.prot_version == QETH_PROT_IPV6)
} card->options.ipa6.enabled_funcs = cmd->hdr.ipa_enabled;
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(qeth_setassparms_cb); EXPORT_SYMBOL_GPL(qeth_setassparms_cb);
...@@ -6279,120 +6299,91 @@ int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev, ...@@ -6279,120 +6299,91 @@ int qeth_core_ethtool_get_link_ksettings(struct net_device *netdev,
} }
EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_link_ksettings); EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_link_ksettings);
/* Callback to handle checksum offload command reply from OSA card. static int qeth_start_csum_cb(struct qeth_card *card, struct qeth_reply *reply,
* Verify that required features have been enabled on the card. unsigned long data)
* Return error in hdr->return_code as this value is checked by caller.
*
* Always returns zero to indicate no further messages from the OSA card.
*/
static int qeth_ipa_checksum_run_cmd_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{ {
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct qeth_checksum_cmd *chksum_cb = u32 *features = reply->param;
(struct qeth_checksum_cmd *)reply->param;
QETH_CARD_TEXT(card, 4, "chkdoccb");
if (qeth_setassparms_inspect_rc(cmd)) if (qeth_setassparms_inspect_rc(cmd))
return 0; return -EIO;
memset(chksum_cb, 0, sizeof(*chksum_cb)); *features = cmd->data.setassparms.data.flags_32bit;
if (cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_START) {
chksum_cb->supported =
cmd->data.setassparms.data.chksum.supported;
QETH_CARD_TEXT_(card, 3, "strt:%x", chksum_cb->supported);
}
if (cmd->data.setassparms.hdr.command_code == IPA_CMD_ASS_ENABLE) {
chksum_cb->supported =
cmd->data.setassparms.data.chksum.supported;
chksum_cb->enabled =
cmd->data.setassparms.data.chksum.enabled;
QETH_CARD_TEXT_(card, 3, "supp:%x", chksum_cb->supported);
QETH_CARD_TEXT_(card, 3, "enab:%x", chksum_cb->enabled);
}
return 0; return 0;
} }
/* Send command to OSA card and check results. */ static int qeth_set_csum_off(struct qeth_card *card, enum qeth_ipa_funcs cstype,
static int qeth_ipa_checksum_run_cmd(struct qeth_card *card, enum qeth_prot_versions prot)
enum qeth_ipa_funcs ipa_func,
__u16 cmd_code, long data,
struct qeth_checksum_cmd *chksum_cb,
enum qeth_prot_versions prot)
{ {
struct qeth_cmd_buffer *iob; return qeth_send_simple_setassparms_prot(card, cstype,
IPA_CMD_ASS_STOP, 0, prot);
QETH_CARD_TEXT(card, 4, "chkdocmd");
iob = qeth_get_setassparms_cmd(card, ipa_func, cmd_code,
sizeof(__u32), prot);
if (!iob)
return -ENOMEM;
__ipa_cmd(iob)->data.setassparms.data.flags_32bit = (__u32) data;
return qeth_send_ipa_cmd(card, iob, qeth_ipa_checksum_run_cmd_cb,
chksum_cb);
} }
static int qeth_send_checksum_on(struct qeth_card *card, int cstype, static int qeth_set_csum_on(struct qeth_card *card, enum qeth_ipa_funcs cstype,
enum qeth_prot_versions prot) enum qeth_prot_versions prot)
{ {
u32 required_features = QETH_IPA_CHECKSUM_UDP | QETH_IPA_CHECKSUM_TCP; u32 required_features = QETH_IPA_CHECKSUM_UDP | QETH_IPA_CHECKSUM_TCP;
struct qeth_checksum_cmd chksum_cb; struct qeth_cmd_buffer *iob;
struct qeth_ipa_caps caps;
u32 features;
int rc; int rc;
if (prot == QETH_PROT_IPV4) /* some L3 HW requires combined L3+L4 csum offload: */
if (IS_LAYER3(card) && prot == QETH_PROT_IPV4 &&
cstype == IPA_OUTBOUND_CHECKSUM)
required_features |= QETH_IPA_CHECKSUM_IP_HDR; required_features |= QETH_IPA_CHECKSUM_IP_HDR;
rc = qeth_ipa_checksum_run_cmd(card, cstype, IPA_CMD_ASS_START, 0,
&chksum_cb, prot); iob = qeth_get_setassparms_cmd(card, cstype, IPA_CMD_ASS_START, 0,
if (!rc) { prot);
if ((required_features & chksum_cb.supported) != if (!iob)
required_features) return -ENOMEM;
rc = -EIO;
else if (!(QETH_IPA_CHECKSUM_LP2LP & chksum_cb.supported) && rc = qeth_send_ipa_cmd(card, iob, qeth_start_csum_cb, &features);
cstype == IPA_INBOUND_CHECKSUM) if (rc)
dev_warn(&card->gdev->dev,
"Hardware checksumming is performed only if %s and its peer use different OSA Express 3 ports\n",
QETH_CARD_IFNAME(card));
}
if (rc) {
qeth_send_simple_setassparms_prot(card, cstype,
IPA_CMD_ASS_STOP, 0, prot);
dev_warn(&card->gdev->dev,
"Starting HW IPv%d checksumming for %s failed, using SW checksumming\n",
prot, QETH_CARD_IFNAME(card));
return rc; return rc;
if ((required_features & features) != required_features) {
qeth_set_csum_off(card, cstype, prot);
return -EOPNOTSUPP;
} }
rc = qeth_ipa_checksum_run_cmd(card, cstype, IPA_CMD_ASS_ENABLE,
chksum_cb.supported, &chksum_cb, iob = qeth_get_setassparms_cmd(card, cstype, IPA_CMD_ASS_ENABLE, 4,
prot); prot);
if (!rc) { if (!iob) {
if ((required_features & chksum_cb.enabled) != qeth_set_csum_off(card, cstype, prot);
required_features) return -ENOMEM;
rc = -EIO;
} }
if (features & QETH_IPA_CHECKSUM_LP2LP)
required_features |= QETH_IPA_CHECKSUM_LP2LP;
__ipa_cmd(iob)->data.setassparms.data.flags_32bit = required_features;
rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_get_caps_cb, &caps);
if (rc) { if (rc) {
qeth_send_simple_setassparms_prot(card, cstype, qeth_set_csum_off(card, cstype, prot);
IPA_CMD_ASS_STOP, 0, prot);
dev_warn(&card->gdev->dev,
"Enabling HW IPv%d checksumming for %s failed, using SW checksumming\n",
prot, QETH_CARD_IFNAME(card));
return rc; return rc;
} }
if (!qeth_ipa_caps_supported(&caps, required_features) ||
!qeth_ipa_caps_enabled(&caps, required_features)) {
qeth_set_csum_off(card, cstype, prot);
return -EOPNOTSUPP;
}
dev_info(&card->gdev->dev, "HW Checksumming (%sbound IPv%d) enabled\n", dev_info(&card->gdev->dev, "HW Checksumming (%sbound IPv%d) enabled\n",
cstype == IPA_INBOUND_CHECKSUM ? "in" : "out", prot); cstype == IPA_INBOUND_CHECKSUM ? "in" : "out", prot);
if (!qeth_ipa_caps_enabled(&caps, QETH_IPA_CHECKSUM_LP2LP) &&
cstype == IPA_OUTBOUND_CHECKSUM)
dev_warn(&card->gdev->dev,
"Hardware checksumming is performed only if %s and its peer use different OSA Express 3 ports\n",
QETH_CARD_IFNAME(card));
return 0; return 0;
} }
static int qeth_set_ipa_csum(struct qeth_card *card, bool on, int cstype, static int qeth_set_ipa_csum(struct qeth_card *card, bool on, int cstype,
enum qeth_prot_versions prot) enum qeth_prot_versions prot)
{ {
int rc = (on) ? qeth_send_checksum_on(card, cstype, prot) return on ? qeth_set_csum_on(card, cstype, prot) :
: qeth_send_simple_setassparms_prot(card, cstype, qeth_set_csum_off(card, cstype, prot);
IPA_CMD_ASS_STOP, 0,
prot);
return rc ? -EIO : 0;
} }
static int qeth_start_tso_cb(struct qeth_card *card, struct qeth_reply *reply, static int qeth_start_tso_cb(struct qeth_card *card, struct qeth_reply *reply,
...@@ -6402,7 +6393,7 @@ static int qeth_start_tso_cb(struct qeth_card *card, struct qeth_reply *reply, ...@@ -6402,7 +6393,7 @@ static int qeth_start_tso_cb(struct qeth_card *card, struct qeth_reply *reply,
struct qeth_tso_start_data *tso_data = reply->param; struct qeth_tso_start_data *tso_data = reply->param;
if (qeth_setassparms_inspect_rc(cmd)) if (qeth_setassparms_inspect_rc(cmd))
return 0; return -EIO;
tso_data->mss = cmd->data.setassparms.data.tso.mss; tso_data->mss = cmd->data.setassparms.data.tso.mss;
tso_data->supported = cmd->data.setassparms.data.tso.supported; tso_data->supported = cmd->data.setassparms.data.tso.supported;
...@@ -6468,10 +6459,7 @@ static int qeth_set_tso_on(struct qeth_card *card, ...@@ -6468,10 +6459,7 @@ static int qeth_set_tso_on(struct qeth_card *card,
static int qeth_set_ipa_tso(struct qeth_card *card, bool on, static int qeth_set_ipa_tso(struct qeth_card *card, bool on,
enum qeth_prot_versions prot) enum qeth_prot_versions prot)
{ {
int rc = on ? qeth_set_tso_on(card, prot) : return on ? qeth_set_tso_on(card, prot) : qeth_set_tso_off(card, prot);
qeth_set_tso_off(card, prot);
return rc ? -EIO : 0;
} }
static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on) static int qeth_set_ipa_rx_csum(struct qeth_card *card, bool on)
......
...@@ -125,24 +125,13 @@ unsigned char DM_ACT[] = { ...@@ -125,24 +125,13 @@ unsigned char DM_ACT[] = {
unsigned char IPA_PDU_HEADER[] = { unsigned char IPA_PDU_HEADER[] = {
0x00, 0xe0, 0x00, 0x00, 0x77, 0x77, 0x77, 0x77, 0x00, 0xe0, 0x00, 0x00, 0x77, 0x77, 0x77, 0x77,
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00,
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd)) / 256,
(IPA_PDU_HEADER_SIZE+sizeof(struct qeth_ipa_cmd)) % 256,
0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0xc1, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00,
sizeof(struct qeth_ipa_cmd) / 256, 0x00, 0x00, 0x00, 0x05, 0x77, 0x77, 0x77, 0x77,
sizeof(struct qeth_ipa_cmd) % 256,
0x00,
sizeof(struct qeth_ipa_cmd) / 256,
sizeof(struct qeth_ipa_cmd) % 256,
0x05,
0x77, 0x77, 0x77, 0x77,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
sizeof(struct qeth_ipa_cmd) / 256,
sizeof(struct qeth_ipa_cmd) % 256,
0x00, 0x00, 0x00, 0x40,
}; };
struct ipa_rc_msg { struct ipa_rc_msg {
...@@ -212,12 +201,10 @@ static const struct ipa_rc_msg qeth_ipa_rc_msg[] = { ...@@ -212,12 +201,10 @@ static const struct ipa_rc_msg qeth_ipa_rc_msg[] = {
{IPA_RC_LAN_OFFLINE, "STRTLAN_LAN_DISABLED - LAN offline"}, {IPA_RC_LAN_OFFLINE, "STRTLAN_LAN_DISABLED - LAN offline"},
{IPA_RC_VEPA_TO_VEB_TRANSITION, "Adj. switch disabled port mode RR"}, {IPA_RC_VEPA_TO_VEB_TRANSITION, "Adj. switch disabled port mode RR"},
{IPA_RC_INVALID_IP_VERSION2, "Invalid IP version"}, {IPA_RC_INVALID_IP_VERSION2, "Invalid IP version"},
{IPA_RC_ENOMEM, "Memory problem"}, /* default for qeth_get_ipa_msg(): */
{IPA_RC_FFFF, "Unknown Error"} {IPA_RC_FFFF, "Unknown Error"}
}; };
const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc) const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc)
{ {
int x; int x;
......
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
extern unsigned char IPA_PDU_HEADER[]; extern unsigned char IPA_PDU_HEADER[];
#define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer + 0x2c) #define QETH_IPA_CMD_DEST_ADDR(buffer) (buffer + 0x2c)
#define IPA_CMD_LENGTH (IPA_PDU_HEADER_SIZE + sizeof(struct qeth_ipa_cmd))
#define QETH_SEQ_NO_LENGTH 4 #define QETH_SEQ_NO_LENGTH 4
#define QETH_MPC_TOKEN_LENGTH 4 #define QETH_MPC_TOKEN_LENGTH 4
#define QETH_MCL_LENGTH 4 #define QETH_MCL_LENGTH 4
...@@ -231,7 +229,6 @@ enum qeth_ipa_return_codes { ...@@ -231,7 +229,6 @@ enum qeth_ipa_return_codes {
IPA_RC_LAN_OFFLINE = 0xe080, IPA_RC_LAN_OFFLINE = 0xe080,
IPA_RC_VEPA_TO_VEB_TRANSITION = 0xe090, IPA_RC_VEPA_TO_VEB_TRANSITION = 0xe090,
IPA_RC_INVALID_IP_VERSION2 = 0xf001, IPA_RC_INVALID_IP_VERSION2 = 0xf001,
IPA_RC_ENOMEM = 0xfffe,
IPA_RC_FFFF = 0xffff IPA_RC_FFFF = 0xffff
}; };
/* for VNIC Characteristics */ /* for VNIC Characteristics */
...@@ -419,12 +416,6 @@ enum qeth_ipa_checksum_bits { ...@@ -419,12 +416,6 @@ enum qeth_ipa_checksum_bits {
QETH_IPA_CHECKSUM_LP2LP = 0x0020 QETH_IPA_CHECKSUM_LP2LP = 0x0020
}; };
/* IPA Assist checksum offload reply layout. */
struct qeth_checksum_cmd {
__u32 supported;
__u32 enabled;
} __packed;
enum qeth_ipa_large_send_caps { enum qeth_ipa_large_send_caps {
QETH_IPA_LARGE_SEND_TCP = 0x00000001, QETH_IPA_LARGE_SEND_TCP = 0x00000001,
}; };
...@@ -440,7 +431,6 @@ struct qeth_ipacmd_setassparms { ...@@ -440,7 +431,6 @@ struct qeth_ipacmd_setassparms {
union { union {
__u32 flags_32bit; __u32 flags_32bit;
struct qeth_ipa_caps caps; struct qeth_ipa_caps caps;
struct qeth_checksum_cmd chksum;
struct qeth_arp_cache_entry arp_entry; struct qeth_arp_cache_entry arp_entry;
struct qeth_arp_query_data query_arp; struct qeth_arp_query_data query_arp;
struct qeth_tso_start_data tso; struct qeth_tso_start_data tso;
...@@ -834,15 +824,10 @@ enum qeth_ipa_arp_return_codes { ...@@ -834,15 +824,10 @@ enum qeth_ipa_arp_return_codes {
extern const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc); extern const char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
extern const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd); extern const char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);
#define QETH_SETASS_BASE_LEN (IPA_PDU_HEADER_SIZE + \
sizeof(struct qeth_ipacmd_hdr) + \
sizeof(struct qeth_ipacmd_setassparms_hdr))
#define QETH_SETADP_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \ #define QETH_SETADP_BASE_LEN (sizeof(struct qeth_ipacmd_hdr) + \
sizeof(struct qeth_ipacmd_setadpparms_hdr)) sizeof(struct qeth_ipacmd_setadpparms_hdr))
#define QETH_SNMP_SETADP_CMDLENGTH 16 #define QETH_SNMP_SETADP_CMDLENGTH 16
#define QETH_ARP_DATA_SIZE 3968
#define QETH_ARP_CMD_LEN (QETH_ARP_DATA_SIZE + 8)
/* Helper functions */ /* Helper functions */
#define IS_IPA_REPLY(cmd) ((cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) || \ #define IS_IPA_REPLY(cmd) ((cmd->hdr.initiator == IPA_CMD_INITIATOR_HOST) || \
(cmd->hdr.initiator == IPA_CMD_INITIATOR_OSA_REPLY)) (cmd->hdr.initiator == IPA_CMD_INITIATOR_OSA_REPLY))
......
...@@ -35,7 +35,7 @@ static void qeth_l2_vnicc_init(struct qeth_card *card); ...@@ -35,7 +35,7 @@ static void qeth_l2_vnicc_init(struct qeth_card *card);
static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc, static bool qeth_l2_vnicc_recover_timeout(struct qeth_card *card, u32 vnicc,
u32 *timeout); u32 *timeout);
static int qeth_setdelmac_makerc(struct qeth_card *card, int retcode) static int qeth_l2_setdelmac_makerc(struct qeth_card *card, u16 retcode)
{ {
int rc; int rc;
...@@ -62,9 +62,6 @@ static int qeth_setdelmac_makerc(struct qeth_card *card, int retcode) ...@@ -62,9 +62,6 @@ static int qeth_setdelmac_makerc(struct qeth_card *card, int retcode)
case IPA_RC_L2_MAC_NOT_FOUND: case IPA_RC_L2_MAC_NOT_FOUND:
rc = -ENOENT; rc = -ENOENT;
break; break;
case -ENOMEM:
rc = -ENOMEM;
break;
default: default:
rc = -EIO; rc = -EIO;
break; break;
...@@ -72,6 +69,15 @@ static int qeth_setdelmac_makerc(struct qeth_card *card, int retcode) ...@@ -72,6 +69,15 @@ static int qeth_setdelmac_makerc(struct qeth_card *card, int retcode)
return rc; return rc;
} }
static int qeth_l2_send_setdelmac_cb(struct qeth_card *card,
struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
return qeth_l2_setdelmac_makerc(card, cmd->hdr.return_code);
}
static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
enum qeth_ipa_cmds ipacmd) enum qeth_ipa_cmds ipacmd)
{ {
...@@ -85,8 +91,7 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac, ...@@ -85,8 +91,7 @@ static int qeth_l2_send_setdelmac(struct qeth_card *card, __u8 *mac,
cmd = __ipa_cmd(iob); cmd = __ipa_cmd(iob);
cmd->data.setdelmac.mac_length = ETH_ALEN; cmd->data.setdelmac.mac_length = ETH_ALEN;
ether_addr_copy(cmd->data.setdelmac.mac, mac); ether_addr_copy(cmd->data.setdelmac.mac, mac);
return qeth_setdelmac_makerc(card, qeth_send_ipa_cmd(card, iob, return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelmac_cb, NULL);
NULL, NULL));
} }
static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac) static int qeth_l2_send_setmac(struct qeth_card *card, __u8 *mac)
...@@ -205,7 +210,7 @@ static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr, ...@@ -205,7 +210,7 @@ static void qeth_l2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
} }
} }
static int qeth_setdelvlan_makerc(struct qeth_card *card, int retcode) static int qeth_l2_setdelvlan_makerc(struct qeth_card *card, u16 retcode)
{ {
if (retcode) if (retcode)
QETH_CARD_TEXT_(card, 2, "err%04x", retcode); QETH_CARD_TEXT_(card, 2, "err%04x", retcode);
...@@ -221,8 +226,6 @@ static int qeth_setdelvlan_makerc(struct qeth_card *card, int retcode) ...@@ -221,8 +226,6 @@ static int qeth_setdelvlan_makerc(struct qeth_card *card, int retcode)
return -ENOENT; return -ENOENT;
case IPA_RC_L2_VLAN_ID_NOT_ALLOWED: case IPA_RC_L2_VLAN_ID_NOT_ALLOWED:
return -EPERM; return -EPERM;
case -ENOMEM:
return -ENOMEM;
default: default:
return -EIO; return -EIO;
} }
...@@ -240,9 +243,8 @@ static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card, ...@@ -240,9 +243,8 @@ static int qeth_l2_send_setdelvlan_cb(struct qeth_card *card,
cmd->data.setdelvlan.vlan_id, cmd->data.setdelvlan.vlan_id,
CARD_DEVID(card), cmd->hdr.return_code); CARD_DEVID(card), cmd->hdr.return_code);
QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command); QETH_CARD_TEXT_(card, 2, "L2VL%4x", cmd->hdr.command);
QETH_CARD_TEXT_(card, 2, "err%d", cmd->hdr.return_code);
} }
return 0; return qeth_l2_setdelvlan_makerc(card, cmd->hdr.return_code);
} }
static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i, static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
...@@ -257,8 +259,7 @@ static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i, ...@@ -257,8 +259,7 @@ static int qeth_l2_send_setdelvlan(struct qeth_card *card, __u16 i,
return -ENOMEM; return -ENOMEM;
cmd = __ipa_cmd(iob); cmd = __ipa_cmd(iob);
cmd->data.setdelvlan.vlan_id = i; cmd->data.setdelvlan.vlan_id = i;
return qeth_setdelvlan_makerc(card, qeth_send_ipa_cmd(card, iob, return qeth_send_ipa_cmd(card, iob, qeth_l2_send_setdelvlan_cb, NULL);
qeth_l2_send_setdelvlan_cb, NULL));
} }
static int qeth_l2_vlan_rx_add_vid(struct net_device *dev, static int qeth_l2_vlan_rx_add_vid(struct net_device *dev,
...@@ -393,7 +394,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card) ...@@ -393,7 +394,7 @@ static int qeth_l2_request_initial_mac(struct qeth_card *card)
if (!IS_OSN(card)) { if (!IS_OSN(card)) {
rc = qeth_setadpparms_change_macaddr(card); rc = qeth_setadpparms_change_macaddr(card);
if (!rc && is_valid_ether_addr(card->dev->dev_addr)) if (!rc)
goto out; goto out;
QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n", QETH_DBF_MESSAGE(2, "READ_MAC Assist failed on device %x: %#x\n",
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
...@@ -1124,20 +1125,14 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len, ...@@ -1124,20 +1125,14 @@ static int qeth_osn_send_control_data(struct qeth_card *card, int len,
} }
static int qeth_osn_send_ipa_cmd(struct qeth_card *card, static int qeth_osn_send_ipa_cmd(struct qeth_card *card,
struct qeth_cmd_buffer *iob, int data_len) struct qeth_cmd_buffer *iob)
{ {
u16 s1, s2; u16 length;
QETH_CARD_TEXT(card, 4, "osndipa"); QETH_CARD_TEXT(card, 4, "osndipa");
qeth_prepare_ipa_cmd(card, iob); memcpy(&length, QETH_IPA_PDU_LEN_TOTAL(iob->data), 2);
s1 = (u16)(IPA_PDU_HEADER_SIZE + data_len); return qeth_osn_send_control_data(card, length, iob);
s2 = (u16)data_len;
memcpy(QETH_IPA_PDU_LEN_TOTAL(iob->data), &s1, 2);
memcpy(QETH_IPA_PDU_LEN_PDU1(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU2(iob->data), &s2, 2);
memcpy(QETH_IPA_PDU_LEN_PDU3(iob->data), &s2, 2);
return qeth_osn_send_control_data(card, s1, iob);
} }
int qeth_osn_assist(struct net_device *dev, void *data, int data_len) int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
...@@ -1154,8 +1149,9 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len) ...@@ -1154,8 +1149,9 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
if (!qeth_card_hw_is_reachable(card)) if (!qeth_card_hw_is_reachable(card))
return -ENODEV; return -ENODEV;
iob = qeth_wait_for_buffer(&card->write); iob = qeth_wait_for_buffer(&card->write);
qeth_prepare_ipa_cmd(card, iob, (u16) data_len);
memcpy(__ipa_cmd(iob), data, data_len); memcpy(__ipa_cmd(iob), data, data_len);
return qeth_osn_send_ipa_cmd(card, iob, data_len); return qeth_osn_send_ipa_cmd(card, iob);
} }
EXPORT_SYMBOL(qeth_osn_assist); EXPORT_SYMBOL(qeth_osn_assist);
...@@ -1412,8 +1408,6 @@ static void qeth_bridge_host_event(struct qeth_card *card, ...@@ -1412,8 +1408,6 @@ static void qeth_bridge_host_event(struct qeth_card *card,
/* SETBRIDGEPORT support; sending commands */ /* SETBRIDGEPORT support; sending commands */
struct _qeth_sbp_cbctl { struct _qeth_sbp_cbctl {
u16 ipa_rc;
u16 cmd_rc;
union { union {
u32 supported; u32 supported;
struct { struct {
...@@ -1423,23 +1417,21 @@ struct _qeth_sbp_cbctl { ...@@ -1423,23 +1417,21 @@ struct _qeth_sbp_cbctl {
} data; } data;
}; };
/**
* qeth_bridgeport_makerc() - derive "traditional" error from hardware codes.
* @card: qeth_card structure pointer, for debug messages.
* @cbctl: state structure with hardware return codes.
* @setcmd: IPA command code
*
* Returns negative errno-compatible error indication or 0 on success.
*/
static int qeth_bridgeport_makerc(struct qeth_card *card, static int qeth_bridgeport_makerc(struct qeth_card *card,
struct _qeth_sbp_cbctl *cbctl, enum qeth_ipa_sbp_cmd setcmd) struct qeth_ipa_cmd *cmd)
{ {
struct qeth_ipacmd_setbridgeport *sbp = &cmd->data.sbp;
enum qeth_ipa_sbp_cmd setcmd = sbp->hdr.command_code;
u16 ipa_rc = cmd->hdr.return_code;
u16 sbp_rc = sbp->hdr.return_code;
int rc; int rc;
int is_iqd = (card->info.type == QETH_CARD_TYPE_IQD);
if ((is_iqd && (cbctl->ipa_rc == IPA_RC_SUCCESS)) || if (ipa_rc == IPA_RC_SUCCESS && sbp_rc == IPA_RC_SUCCESS)
(!is_iqd && (cbctl->ipa_rc == cbctl->cmd_rc))) return 0;
switch (cbctl->cmd_rc) {
if ((IS_IQD(card) && ipa_rc == IPA_RC_SUCCESS) ||
(!IS_IQD(card) && ipa_rc == sbp_rc)) {
switch (sbp_rc) {
case IPA_RC_SUCCESS: case IPA_RC_SUCCESS:
rc = 0; rc = 0;
break; break;
...@@ -1503,8 +1495,8 @@ static int qeth_bridgeport_makerc(struct qeth_card *card, ...@@ -1503,8 +1495,8 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
default: default:
rc = -EIO; rc = -EIO;
} }
else } else {
switch (cbctl->ipa_rc) { switch (ipa_rc) {
case IPA_RC_NOTSUPP: case IPA_RC_NOTSUPP:
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
break; break;
...@@ -1514,10 +1506,11 @@ static int qeth_bridgeport_makerc(struct qeth_card *card, ...@@ -1514,10 +1506,11 @@ static int qeth_bridgeport_makerc(struct qeth_card *card,
default: default:
rc = -EIO; rc = -EIO;
} }
}
if (rc) { if (rc) {
QETH_CARD_TEXT_(card, 2, "SBPi%04x", cbctl->ipa_rc); QETH_CARD_TEXT_(card, 2, "SBPi%04x", ipa_rc);
QETH_CARD_TEXT_(card, 2, "SBPc%04x", cbctl->cmd_rc); QETH_CARD_TEXT_(card, 2, "SBPc%04x", sbp_rc);
} }
return rc; return rc;
} }
...@@ -1549,15 +1542,15 @@ static int qeth_bridgeport_query_support_cb(struct qeth_card *card, ...@@ -1549,15 +1542,15 @@ static int qeth_bridgeport_query_support_cb(struct qeth_card *card,
{ {
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
int rc;
QETH_CARD_TEXT(card, 2, "brqsupcb"); QETH_CARD_TEXT(card, 2, "brqsupcb");
cbctl->ipa_rc = cmd->hdr.return_code; rc = qeth_bridgeport_makerc(card, cmd);
cbctl->cmd_rc = cmd->data.sbp.hdr.return_code; if (rc)
if ((cbctl->ipa_rc == 0) && (cbctl->cmd_rc == 0)) { return rc;
cbctl->data.supported =
cmd->data.sbp.data.query_cmds_supp.supported_cmds; cbctl->data.supported =
} else { cmd->data.sbp.data.query_cmds_supp.supported_cmds;
cbctl->data.supported = 0;
}
return 0; return 0;
} }
...@@ -1578,12 +1571,11 @@ static void qeth_bridgeport_query_support(struct qeth_card *card) ...@@ -1578,12 +1571,11 @@ static void qeth_bridgeport_query_support(struct qeth_card *card)
sizeof(struct qeth_sbp_query_cmds_supp)); sizeof(struct qeth_sbp_query_cmds_supp));
if (!iob) if (!iob)
return; return;
if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb, if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb,
(void *)&cbctl) || &cbctl)) {
qeth_bridgeport_makerc(card, &cbctl,
IPA_SBP_QUERY_COMMANDS_SUPPORTED)) {
/* non-zero makerc signifies failure, and produce messages */
card->options.sbp.role = QETH_SBP_ROLE_NONE; card->options.sbp.role = QETH_SBP_ROLE_NONE;
card->options.sbp.supported_funcs = 0;
return; return;
} }
card->options.sbp.supported_funcs = cbctl.data.supported; card->options.sbp.supported_funcs = cbctl.data.supported;
...@@ -1595,16 +1587,16 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card, ...@@ -1595,16 +1587,16 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
struct qeth_sbp_query_ports *qports = &cmd->data.sbp.data.query_ports; struct qeth_sbp_query_ports *qports = &cmd->data.sbp.data.query_ports;
struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
int rc;
QETH_CARD_TEXT(card, 2, "brqprtcb"); QETH_CARD_TEXT(card, 2, "brqprtcb");
cbctl->ipa_rc = cmd->hdr.return_code; rc = qeth_bridgeport_makerc(card, cmd);
cbctl->cmd_rc = cmd->data.sbp.hdr.return_code; if (rc)
if ((cbctl->ipa_rc != 0) || (cbctl->cmd_rc != 0)) return rc;
return 0;
if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) { if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) {
cbctl->cmd_rc = 0xffff;
QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length); QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length);
return 0; return -EINVAL;
} }
/* first entry contains the state of the local port */ /* first entry contains the state of the local port */
if (qports->num_entries > 0) { if (qports->num_entries > 0) {
...@@ -1629,7 +1621,6 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card, ...@@ -1629,7 +1621,6 @@ static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
int qeth_bridgeport_query_ports(struct qeth_card *card, int qeth_bridgeport_query_ports(struct qeth_card *card,
enum qeth_sbp_roles *role, enum qeth_sbp_states *state) enum qeth_sbp_roles *role, enum qeth_sbp_states *state)
{ {
int rc = 0;
struct qeth_cmd_buffer *iob; struct qeth_cmd_buffer *iob;
struct _qeth_sbp_cbctl cbctl = { struct _qeth_sbp_cbctl cbctl = {
.data = { .data = {
...@@ -1646,22 +1637,18 @@ int qeth_bridgeport_query_ports(struct qeth_card *card, ...@@ -1646,22 +1637,18 @@ int qeth_bridgeport_query_ports(struct qeth_card *card,
iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_BRIDGE_PORTS, 0); iob = qeth_sbp_build_cmd(card, IPA_SBP_QUERY_BRIDGE_PORTS, 0);
if (!iob) if (!iob)
return -ENOMEM; return -ENOMEM;
rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb,
(void *)&cbctl); return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb,
if (rc < 0) &cbctl);
return rc;
return qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS);
} }
static int qeth_bridgeport_set_cb(struct qeth_card *card, static int qeth_bridgeport_set_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 *)data; struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data;
struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param;
QETH_CARD_TEXT(card, 2, "brsetrcb"); QETH_CARD_TEXT(card, 2, "brsetrcb");
cbctl->ipa_rc = cmd->hdr.return_code; return qeth_bridgeport_makerc(card, cmd);
cbctl->cmd_rc = cmd->data.sbp.hdr.return_code;
return 0;
} }
/** /**
...@@ -1673,10 +1660,8 @@ static int qeth_bridgeport_set_cb(struct qeth_card *card, ...@@ -1673,10 +1660,8 @@ static int qeth_bridgeport_set_cb(struct qeth_card *card,
*/ */
int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role) int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
{ {
int rc = 0;
int cmdlength; int cmdlength;
struct qeth_cmd_buffer *iob; struct qeth_cmd_buffer *iob;
struct _qeth_sbp_cbctl cbctl;
enum qeth_ipa_sbp_cmd setcmd; enum qeth_ipa_sbp_cmd setcmd;
QETH_CARD_TEXT(card, 2, "brsetrol"); QETH_CARD_TEXT(card, 2, "brsetrol");
...@@ -1701,11 +1686,8 @@ int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role) ...@@ -1701,11 +1686,8 @@ int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role)
iob = qeth_sbp_build_cmd(card, setcmd, cmdlength); iob = qeth_sbp_build_cmd(card, setcmd, cmdlength);
if (!iob) if (!iob)
return -ENOMEM; return -ENOMEM;
rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb,
(void *)&cbctl); return qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb, NULL);
if (rc < 0)
return rc;
return qeth_bridgeport_makerc(card, &cbctl, setcmd);
} }
/** /**
...@@ -1809,7 +1791,7 @@ static bool qeth_bridgeport_is_in_use(struct qeth_card *card) ...@@ -1809,7 +1791,7 @@ static bool qeth_bridgeport_is_in_use(struct qeth_card *card)
/* VNIC Characteristics support */ /* VNIC Characteristics support */
/* handle VNICC IPA command return codes; convert to error codes */ /* handle VNICC IPA command return codes; convert to error codes */
static int qeth_l2_vnicc_makerc(struct qeth_card *card, int ipa_rc) static int qeth_l2_vnicc_makerc(struct qeth_card *card, u16 ipa_rc)
{ {
int rc; int rc;
...@@ -1867,7 +1849,7 @@ static int qeth_l2_vnicc_request_cb(struct qeth_card *card, ...@@ -1867,7 +1849,7 @@ static int qeth_l2_vnicc_request_cb(struct qeth_card *card,
QETH_CARD_TEXT(card, 2, "vniccrcb"); QETH_CARD_TEXT(card, 2, "vniccrcb");
if (cmd->hdr.return_code) if (cmd->hdr.return_code)
return 0; return qeth_l2_vnicc_makerc(card, cmd->hdr.return_code);
/* return results to caller */ /* return results to caller */
card->options.vnicc.sup_chars = rep->hdr.sup; card->options.vnicc.sup_chars = rep->hdr.sup;
card->options.vnicc.cur_chars = rep->hdr.cur; card->options.vnicc.cur_chars = rep->hdr.cur;
...@@ -1888,7 +1870,6 @@ static int qeth_l2_vnicc_request(struct qeth_card *card, ...@@ -1888,7 +1870,6 @@ static int qeth_l2_vnicc_request(struct qeth_card *card,
struct qeth_ipacmd_vnicc *req; struct qeth_ipacmd_vnicc *req;
struct qeth_cmd_buffer *iob; struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd;
int rc;
QETH_CARD_TEXT(card, 2, "vniccreq"); QETH_CARD_TEXT(card, 2, "vniccreq");
...@@ -1931,10 +1912,7 @@ static int qeth_l2_vnicc_request(struct qeth_card *card, ...@@ -1931,10 +1912,7 @@ static int qeth_l2_vnicc_request(struct qeth_card *card,
} }
/* send request */ /* send request */
rc = qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, return qeth_send_ipa_cmd(card, iob, qeth_l2_vnicc_request_cb, cbctl);
(void *) cbctl);
return qeth_l2_vnicc_makerc(card, rc);
} }
/* VNICC query VNIC characteristics request */ /* VNICC query VNIC characteristics request */
......
...@@ -253,8 +253,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr) ...@@ -253,8 +253,7 @@ static int qeth_l3_add_ip(struct qeth_card *card, struct qeth_ipaddr *tmp_addr)
} else } else
rc = qeth_l3_register_addr_entry(card, addr); rc = qeth_l3_register_addr_entry(card, addr);
if (!rc || (rc == IPA_RC_DUPLICATE_IP_ADDRESS) || if (!rc || rc == -EADDRINUSE || rc == -ENETDOWN) {
(rc == IPA_RC_LAN_OFFLINE)) {
addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING; addr->disp_flag = QETH_DISP_ADDR_DO_NOTHING;
if (addr->ref_counter < 1) { if (addr->ref_counter < 1) {
qeth_l3_deregister_addr_entry(card, addr); qeth_l3_deregister_addr_entry(card, addr);
...@@ -338,10 +337,28 @@ static void qeth_l3_recover_ip(struct qeth_card *card) ...@@ -338,10 +337,28 @@ static void qeth_l3_recover_ip(struct qeth_card *card)
} }
static int qeth_l3_setdelip_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
switch (cmd->hdr.return_code) {
case IPA_RC_SUCCESS:
return 0;
case IPA_RC_DUPLICATE_IP_ADDRESS:
return -EADDRINUSE;
case IPA_RC_MC_ADDR_NOT_FOUND:
return -ENOENT;
case IPA_RC_LAN_OFFLINE:
return -ENETDOWN;
default:
return -EIO;
}
}
static int qeth_l3_send_setdelmc(struct qeth_card *card, static int qeth_l3_send_setdelmc(struct qeth_card *card,
struct qeth_ipaddr *addr, int ipacmd) struct qeth_ipaddr *addr, int ipacmd)
{ {
int rc;
struct qeth_cmd_buffer *iob; struct qeth_cmd_buffer *iob;
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd;
...@@ -358,9 +375,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card, ...@@ -358,9 +375,7 @@ static int qeth_l3_send_setdelmc(struct qeth_card *card,
else else
memcpy(&cmd->data.setdelipm.ip4, &addr->u.a4.addr, 4); memcpy(&cmd->data.setdelipm.ip4, &addr->u.a4.addr, 4);
rc = qeth_send_ipa_cmd(card, iob, NULL, NULL); return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
return rc;
} }
static void qeth_l3_fill_netmask(u8 *netmask, unsigned int len) static void qeth_l3_fill_netmask(u8 *netmask, unsigned int len)
...@@ -422,7 +437,7 @@ static int qeth_l3_send_setdelip(struct qeth_card *card, ...@@ -422,7 +437,7 @@ static int qeth_l3_send_setdelip(struct qeth_card *card,
cmd->data.setdelip4.flags = flags; cmd->data.setdelip4.flags = flags;
} }
return qeth_send_ipa_cmd(card, iob, NULL, NULL); return qeth_send_ipa_cmd(card, iob, qeth_l3_setdelip_cb, NULL);
} }
static int qeth_l3_send_setrouting(struct qeth_card *card, static int qeth_l3_send_setrouting(struct qeth_card *card,
...@@ -942,12 +957,13 @@ static int qeth_l3_start_ipassists(struct qeth_card *card) ...@@ -942,12 +957,13 @@ static int qeth_l3_start_ipassists(struct qeth_card *card)
static int qeth_l3_iqd_read_initial_mac_cb(struct qeth_card *card, static int qeth_l3_iqd_read_initial_mac_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;
cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code)
if (cmd->hdr.return_code == 0) return -EIO;
ether_addr_copy(card->dev->dev_addr,
cmd->data.create_destroy_addr.unique_id); ether_addr_copy(card->dev->dev_addr,
cmd->data.create_destroy_addr.unique_id);
return 0; return 0;
} }
...@@ -975,19 +991,18 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card) ...@@ -975,19 +991,18 @@ static int qeth_l3_iqd_read_initial_mac(struct qeth_card *card)
static int qeth_l3_get_unique_id_cb(struct qeth_card *card, static int qeth_l3_get_unique_id_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;
cmd = (struct qeth_ipa_cmd *) data; if (cmd->hdr.return_code == 0) {
if (cmd->hdr.return_code == 0)
card->info.unique_id = *((__u16 *) card->info.unique_id = *((__u16 *)
&cmd->data.create_destroy_addr.unique_id[6]); &cmd->data.create_destroy_addr.unique_id[6]);
else { return 0;
card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
UNIQUE_ID_NOT_BY_CARD;
dev_warn(&card->gdev->dev, "The network adapter failed to "
"generate a unique ID\n");
} }
return 0;
card->info.unique_id = UNIQUE_ID_IF_CREATE_ADDR_FAILED |
UNIQUE_ID_NOT_BY_CARD;
dev_warn(&card->gdev->dev, "The network adapter failed to generate a unique ID\n");
return -EIO;
} }
static int qeth_l3_get_unique_id(struct qeth_card *card) static int qeth_l3_get_unique_id(struct qeth_card *card)
...@@ -1070,7 +1085,7 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply, ...@@ -1070,7 +1085,7 @@ qeth_diags_trace_cb(struct qeth_card *card, struct qeth_reply *reply,
cmd->data.diagass.action, CARD_DEVID(card)); cmd->data.diagass.action, CARD_DEVID(card));
} }
return 0; return rc ? -EIO : 0;
} }
static int static int
...@@ -1481,14 +1496,14 @@ static void qeth_l3_set_rx_mode(struct net_device *dev) ...@@ -1481,14 +1496,14 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
switch (addr->disp_flag) { switch (addr->disp_flag) {
case QETH_DISP_ADDR_DELETE: case QETH_DISP_ADDR_DELETE:
rc = qeth_l3_deregister_addr_entry(card, addr); rc = qeth_l3_deregister_addr_entry(card, addr);
if (!rc || rc == IPA_RC_MC_ADDR_NOT_FOUND) { if (!rc || rc == -ENOENT) {
hash_del(&addr->hnode); hash_del(&addr->hnode);
kfree(addr); kfree(addr);
} }
break; break;
case QETH_DISP_ADDR_ADD: case QETH_DISP_ADDR_ADD:
rc = qeth_l3_register_addr_entry(card, addr); rc = qeth_l3_register_addr_entry(card, addr);
if (rc && rc != IPA_RC_LAN_OFFLINE) { if (rc && rc != -ENETDOWN) {
hash_del(&addr->hnode); hash_del(&addr->hnode);
kfree(addr); kfree(addr);
break; break;
...@@ -1509,7 +1524,7 @@ static void qeth_l3_set_rx_mode(struct net_device *dev) ...@@ -1509,7 +1524,7 @@ static void qeth_l3_set_rx_mode(struct net_device *dev)
qeth_l3_handle_promisc_mode(card); qeth_l3_handle_promisc_mode(card);
} }
static int qeth_l3_arp_makerc(int rc) static int qeth_l3_arp_makerc(u16 rc)
{ {
switch (rc) { switch (rc) {
case IPA_RC_SUCCESS: case IPA_RC_SUCCESS:
...@@ -1526,8 +1541,18 @@ static int qeth_l3_arp_makerc(int rc) ...@@ -1526,8 +1541,18 @@ static int qeth_l3_arp_makerc(int rc)
} }
} }
static int qeth_l3_arp_cmd_cb(struct qeth_card *card, struct qeth_reply *reply,
unsigned long data)
{
struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data;
qeth_setassparms_cb(card, reply, data);
return qeth_l3_arp_makerc(cmd->hdr.return_code);
}
static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries) static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
{ {
struct qeth_cmd_buffer *iob;
int rc; int rc;
QETH_CARD_TEXT(card, 3, "arpstnoe"); QETH_CARD_TEXT(card, 3, "arpstnoe");
...@@ -1542,13 +1567,19 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries) ...@@ -1542,13 +1567,19 @@ static int qeth_l3_arp_set_no_entries(struct qeth_card *card, int no_entries)
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_SET_NO_ENTRIES, iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
no_entries); IPA_CMD_ASS_ARP_SET_NO_ENTRIES, 4,
QETH_PROT_IPV4);
if (!iob)
return -ENOMEM;
__ipa_cmd(iob)->data.setassparms.data.flags_32bit = (u32) no_entries;
rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
if (rc) if (rc)
QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on device %x: %#x\n", QETH_DBF_MESSAGE(2, "Could not set number of ARP entries on device %x: %#x\n",
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
return qeth_l3_arp_makerc(rc); return rc;
} }
static __u32 get_arp_entry_size(struct qeth_card *card, static __u32 get_arp_entry_size(struct qeth_card *card,
...@@ -1599,7 +1630,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card, ...@@ -1599,7 +1630,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
struct qeth_ipa_cmd *cmd; struct qeth_ipa_cmd *cmd;
struct qeth_arp_query_data *qdata; struct qeth_arp_query_data *qdata;
struct qeth_arp_query_info *qinfo; struct qeth_arp_query_info *qinfo;
int i;
int e; int e;
int entrybytes_done; int entrybytes_done;
int stripped_bytes; int stripped_bytes;
...@@ -1613,13 +1643,13 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card, ...@@ -1613,13 +1643,13 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
if (cmd->hdr.return_code) { if (cmd->hdr.return_code) {
QETH_CARD_TEXT(card, 4, "arpcberr"); QETH_CARD_TEXT(card, 4, "arpcberr");
QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code); QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
return 0; return qeth_l3_arp_makerc(cmd->hdr.return_code);
} }
if (cmd->data.setassparms.hdr.return_code) { if (cmd->data.setassparms.hdr.return_code) {
cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code; cmd->hdr.return_code = cmd->data.setassparms.hdr.return_code;
QETH_CARD_TEXT(card, 4, "setaperr"); QETH_CARD_TEXT(card, 4, "setaperr");
QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code); QETH_CARD_TEXT_(card, 4, "%i", cmd->hdr.return_code);
return 0; return qeth_l3_arp_makerc(cmd->hdr.return_code);
} }
qdata = &cmd->data.setassparms.data.query_arp; qdata = &cmd->data.setassparms.data.query_arp;
QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries); QETH_CARD_TEXT_(card, 4, "anoen%i", qdata->no_entries);
...@@ -1646,9 +1676,9 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card, ...@@ -1646,9 +1676,9 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
break; break;
if ((qinfo->udata_len - qinfo->udata_offset) < esize) { if ((qinfo->udata_len - qinfo->udata_offset) < esize) {
QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOMEM); QETH_CARD_TEXT_(card, 4, "qaer3%i", -ENOSPC);
cmd->hdr.return_code = IPA_RC_ENOMEM; memset(qinfo->udata, 0, 4);
goto out_error; return -ENOSPC;
} }
memcpy(qinfo->udata + qinfo->udata_offset, memcpy(qinfo->udata + qinfo->udata_offset,
...@@ -1671,10 +1701,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card, ...@@ -1671,10 +1701,6 @@ static int qeth_l3_arp_query_cb(struct qeth_card *card,
memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2); memcpy(qinfo->udata + QETH_QARP_MASK_OFFSET, &qdata->reply_bits, 2);
QETH_CARD_TEXT_(card, 4, "rc%i", 0); QETH_CARD_TEXT_(card, 4, "rc%i", 0);
return 0; return 0;
out_error:
i = 0;
memcpy(qinfo->udata, &i, 4);
return 0;
} }
static int qeth_l3_query_arp_cache_info(struct qeth_card *card, static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
...@@ -1696,13 +1722,11 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card, ...@@ -1696,13 +1722,11 @@ static int qeth_l3_query_arp_cache_info(struct qeth_card *card,
return -ENOMEM; return -ENOMEM;
cmd = __ipa_cmd(iob); cmd = __ipa_cmd(iob);
cmd->data.setassparms.data.query_arp.request_bits = 0x000F; cmd->data.setassparms.data.query_arp.request_bits = 0x000F;
rc = qeth_send_control_data(card, rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_query_cb, qinfo);
QETH_SETASS_BASE_LEN + QETH_ARP_CMD_LEN,
iob, qeth_l3_arp_query_cb, qinfo);
if (rc) if (rc)
QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n", QETH_DBF_MESSAGE(2, "Error while querying ARP cache on device %x: %#x\n",
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
return qeth_l3_arp_makerc(rc); return rc;
} }
static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata) static int qeth_l3_arp_query(struct qeth_card *card, char __user *udata)
...@@ -1784,16 +1808,16 @@ static int qeth_l3_arp_modify_entry(struct qeth_card *card, ...@@ -1784,16 +1808,16 @@ static int qeth_l3_arp_modify_entry(struct qeth_card *card,
cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry; cmd_entry = &__ipa_cmd(iob)->data.setassparms.data.arp_entry;
ether_addr_copy(cmd_entry->macaddr, entry->macaddr); ether_addr_copy(cmd_entry->macaddr, entry->macaddr);
memcpy(cmd_entry->ipaddr, entry->ipaddr, 4); memcpy(cmd_entry->ipaddr, entry->ipaddr, 4);
rc = qeth_send_ipa_cmd(card, iob, qeth_setassparms_cb, NULL); rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
if (rc) if (rc)
QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n", QETH_DBF_MESSAGE(2, "Could not modify (cmd: %#x) ARP entry on device %x: %#x\n",
arp_cmd, CARD_DEVID(card), rc); arp_cmd, CARD_DEVID(card), rc);
return rc;
return qeth_l3_arp_makerc(rc);
} }
static int qeth_l3_arp_flush_cache(struct qeth_card *card) static int qeth_l3_arp_flush_cache(struct qeth_card *card)
{ {
struct qeth_cmd_buffer *iob;
int rc; int rc;
QETH_CARD_TEXT(card, 3, "arpflush"); QETH_CARD_TEXT(card, 3, "arpflush");
...@@ -1808,12 +1832,18 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card) ...@@ -1808,12 +1832,18 @@ static int qeth_l3_arp_flush_cache(struct qeth_card *card)
if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) { if (!qeth_is_supported(card, IPA_ARP_PROCESSING)) {
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
rc = qeth_send_simple_setassparms(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_FLUSH_CACHE, 0); iob = qeth_get_setassparms_cmd(card, IPA_ARP_PROCESSING,
IPA_CMD_ASS_ARP_FLUSH_CACHE, 0,
QETH_PROT_IPV4);
if (!iob)
return -ENOMEM;
rc = qeth_send_ipa_cmd(card, iob, qeth_l3_arp_cmd_cb, NULL);
if (rc) if (rc)
QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n", QETH_DBF_MESSAGE(2, "Could not flush ARP cache on device %x: %#x\n",
CARD_DEVID(card), rc); CARD_DEVID(card), rc);
return qeth_l3_arp_makerc(rc); return rc;
} }
static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
......
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