Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b7ae122 authored by Julian Wiedmann's avatar Julian Wiedmann Committed by David S. Miller
Browse files

s390/qeth: allow cmd callbacks to return errnos



Error propagation from cmd callbacks currently works in a way where
qeth_send_control_data_cb() picks the raw HW code from the response,
and the cmd's originator later translates this into an errno.
The callback itself only returns 0 ("done") or 1 ("expect more data").

This is
1. limiting, as the only means for the callback to report an internal
error is to invent pseudo HW codes (such as IPA_RC_ENOMEM), that
the originator then needs to understand. For non-IPA callbacks, we
even provide a separate field in the IO buffer metadata (iob->rc) so
the callback can pass back a return value.
2. fragile, as the originator must take care to not translate any errno
that is returned by qeth's own IO code paths (eg -ENOMEM). Also, any
originator that forgets to translate the HW codes potentially passes
garbage back to its caller. For instance, see
commit 2aa48671 ("s390/qeth: translate SETVLAN/DELVLAN errors").

Introduce a new model where all HW error translation is done within the
callback, and the callback returns
>  0, if it expects more data (as before)
== 0, on success
<  0, with an errno

Start off with converting all callbacks to the new model that either
a) pass back pseudo HW codes, or b) have a dependency on a specific
HW error code. Also convert c) the one callback that uses iob->rc, and
d) qeth_setadpparms_change_macaddr_cb() so that it can pass back an
error back to qeth_l2_request_initial_mac() even when the cmd itself
was successful.

The old model remains supported: if the callback returns 0, we still
propagate the response's HW error code back to the originator.

Signed-off-by: default avatarJulian Wiedmann <jwi@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 54daaca7
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -597,7 +597,6 @@ struct qeth_cmd_buffer {
	struct qeth_channel *channel;
	struct qeth_channel *channel;
	struct qeth_reply *reply;
	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);
};
};
+44 −38
Original line number Original line Diff line number Diff line
@@ -747,7 +747,6 @@ void qeth_release_buffer(struct qeth_channel *channel,
		qeth_put_reply(iob->reply);
		qeth_put_reply(iob->reply);
		iob->reply = NULL;
		iob->reply = NULL;
	}
	}
	iob->rc = 0;
	spin_unlock_irqrestore(&channel->iob_lock, flags);
	spin_unlock_irqrestore(&channel->iob_lock, flags);
	wake_up(&channel->wait_q);
	wake_up(&channel->wait_q);
}
}
@@ -809,7 +808,6 @@ static void qeth_send_control_data_cb(struct qeth_card *card,
	struct qeth_reply *reply = NULL;
	struct qeth_reply *reply = NULL;
	struct qeth_reply *r;
	struct qeth_reply *r;
	unsigned long flags;
	unsigned long flags;
	int keep_reply = 0;
	int rc = 0;
	int rc = 0;


	QETH_CARD_TEXT(card, 4, "sndctlcb");
	QETH_CARD_TEXT(card, 4, "sndctlcb");
@@ -857,22 +855,27 @@ static void qeth_send_control_data_cb(struct qeth_card *card,
	if (!reply)
	if (!reply)
		goto out;
		goto out;


	if (reply->callback) {
	if (!reply->callback) {
		rc = 0;
	} else {
		if (cmd) {
		if (cmd) {
			reply->offset = (u16)((char *)cmd - (char *)iob->data);
			reply->offset = (u16)((char *)cmd - (char *)iob->data);
			keep_reply = reply->callback(card, reply,
			rc = reply->callback(card, reply, (unsigned long)cmd);
						     (unsigned long)cmd);
		} else {
		} else
			rc = reply->callback(card, reply, (unsigned long)iob);
			keep_reply = reply->callback(card, reply,
		}
						     (unsigned long)iob);
	}
	}

	if (rc <= 0) {
		if (cmd)
		if (cmd)
			reply->rc = (u16) cmd->hdr.return_code;
			reply->rc = (u16) cmd->hdr.return_code;
	else if (iob->rc)
		reply->rc = iob->rc;


	if (!keep_reply)
		/* for callbacks with proper errnos: */
		if (rc < 0)
			reply->rc = rc;
		qeth_notify_reply(reply);
		qeth_notify_reply(reply);
	}

	qeth_put_reply(reply);
	qeth_put_reply(reply);


out:
out:
@@ -1293,7 +1296,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);
@@ -2343,9 +2345,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;
}
}


@@ -2900,9 +2901,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");
@@ -2910,8 +2921,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)
@@ -4238,12 +4248,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;
@@ -4507,13 +4520,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) {
@@ -4528,9 +4541,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);
@@ -4625,16 +4637,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);
@@ -4707,9 +4717,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);
@@ -5128,12 +5136,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 {
+1 −3
Original line number Original line Diff line number Diff line
@@ -201,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;
+0 −1
Original line number Original line Diff line number Diff line
@@ -229,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 */
+1 −1
Original line number Original line Diff line number Diff line
@@ -393,7 +393,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);
Loading