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

Commit 76b11f8e authored by Ursula Braun's avatar Ursula Braun Committed by David S. Miller
Browse files

qeth: HiperSockets Network Traffic Analyzer



New feature to trace HiperSockets network traffic for debugging
purposes.

Signed-off-by: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarFrank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent ab8932f3
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -649,6 +649,7 @@ struct qeth_card_options {
	int performance_stats;
	int rx_sg_cb;
	enum qeth_ipa_isolation_modes isolation;
	int sniffer;
};

/*
@@ -737,6 +738,7 @@ struct qeth_card {
	struct qeth_discipline discipline;
	atomic_t force_alloc_skb;
	struct service_level qeth_service_level;
	struct qdio_ssqd_desc ssqd;
};

struct qeth_card_list_struct {
@@ -811,7 +813,8 @@ int qeth_send_ipa_cmd(struct qeth_card *, struct qeth_cmd_buffer *,
struct qeth_cmd_buffer *qeth_get_ipacmd_buffer(struct qeth_card *,
			enum qeth_ipa_cmds, enum qeth_prot_versions);
int qeth_query_setadapterparms(struct qeth_card *);
int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int, const char *);
int qeth_check_qdio_errors(struct qeth_card *, struct qdio_buffer *,
		unsigned int, const char *);
void qeth_queue_input_buffer(struct qeth_card *, int);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
		struct qdio_buffer *, struct qdio_buffer_element **, int *,
+74 −56
Original line number Diff line number Diff line
@@ -269,6 +269,7 @@ int qeth_realloc_buffer_pool(struct qeth_card *card, int bufcnt)
	card->qdio.init_pool.buf_count = bufcnt;
	return qeth_alloc_buffer_pool(card);
}
EXPORT_SYMBOL_GPL(qeth_realloc_buffer_pool);

static int qeth_issue_next_read(struct qeth_card *card)
{
@@ -350,8 +351,10 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
	if (IS_IPA(iob->data)) {
		cmd = (struct qeth_ipa_cmd *) PDU_ENCAPSULATION(iob->data);
		if (IS_IPA_REPLY(cmd)) {
			if (cmd->hdr.command < IPA_CMD_SETCCID ||
			    cmd->hdr.command > IPA_CMD_MODCCID)
			if (cmd->hdr.command != IPA_CMD_SETCCID &&
			    cmd->hdr.command != IPA_CMD_DELCCID &&
			    cmd->hdr.command != IPA_CMD_MODCCID &&
			    cmd->hdr.command != IPA_CMD_SET_DIAG_ASS)
				qeth_issue_ipa_msg(cmd,
						cmd->hdr.return_code, card);
			return cmd;
@@ -1100,11 +1103,6 @@ static int qeth_setup_card(struct qeth_card *card)
	card->thread_running_mask = 0;
	INIT_WORK(&card->kernel_thread_starter, qeth_start_kernel_thread);
	INIT_LIST_HEAD(&card->ip_list);
	card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
	if (!card->ip_tbd_list) {
		QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
		return -ENOMEM;
	}
	INIT_LIST_HEAD(card->ip_tbd_list);
	INIT_LIST_HEAD(&card->cmd_waiter_list);
	init_waitqueue_head(&card->wait_q);
@@ -1138,21 +1136,30 @@ static struct qeth_card *qeth_alloc_card(void)
	QETH_DBF_TEXT(SETUP, 2, "alloccrd");
	card = kzalloc(sizeof(struct qeth_card), GFP_DMA|GFP_KERNEL);
	if (!card)
		return NULL;
		goto out;
	QETH_DBF_HEX(SETUP, 2, &card, sizeof(void *));
	if (qeth_setup_channel(&card->read)) {
		kfree(card);
		return NULL;
	}
	if (qeth_setup_channel(&card->write)) {
		qeth_clean_channel(&card->read);
		kfree(card);
		return NULL;
	card->ip_tbd_list = kmalloc(sizeof(struct list_head), GFP_KERNEL);
	if (!card->ip_tbd_list) {
		QETH_DBF_TEXT(SETUP, 0, "iptbdnom");
		goto out_card;
	}
	if (qeth_setup_channel(&card->read))
		goto out_ip;
	if (qeth_setup_channel(&card->write))
		goto out_channel;
	card->options.layer2 = -1;
	card->qeth_service_level.seq_print = qeth_core_sl_print;
	register_service_level(&card->qeth_service_level);
	return card;

out_channel:
	qeth_clean_channel(&card->read);
out_ip:
	kfree(card->ip_tbd_list);
out_card:
	kfree(card);
out:
	return NULL;
}

static int qeth_determine_card_type(struct qeth_card *card)
@@ -2573,8 +2580,8 @@ int qeth_query_setadapterparms(struct qeth_card *card)
}
EXPORT_SYMBOL_GPL(qeth_query_setadapterparms);

int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
		const char *dbftext)
int qeth_check_qdio_errors(struct qeth_card *card, struct qdio_buffer *buf,
		unsigned int qdio_error, const char *dbftext)
{
	if (qdio_error) {
		QETH_DBF_TEXT(TRACE, 2, dbftext);
@@ -2584,6 +2591,10 @@ int qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
		QETH_DBF_TEXT_(QERR, 2, " F14=%02X",
			       buf->element[14].flags & 0xff);
		QETH_DBF_TEXT_(QERR, 2, " qerr=%X", qdio_error);
		if ((buf->element[15].flags & 0xff) == 0x12) {
			card->stats.rx_dropped++;
			return 0;
		} else
			return 1;
	}
	return 0;
@@ -2667,7 +2678,7 @@ static int qeth_handle_send_error(struct qeth_card *card,
			qdio_err = 1;
		}
	}
	qeth_check_qdio_errors(buffer->buffer, qdio_err, "qouterr");
	qeth_check_qdio_errors(card, buffer->buffer, qdio_err, "qouterr");

	if (!qdio_err)
		return QETH_SEND_ERROR_NONE;
@@ -3509,6 +3520,7 @@ void qeth_tx_timeout(struct net_device *dev)
{
	struct qeth_card *card;

	QETH_DBF_TEXT(TRACE, 4, "txtimeo");
	card = dev->ml_priv;
	card->stats.tx_errors++;
	qeth_schedule_recovery(card);
@@ -3847,9 +3859,7 @@ static int qeth_core_driver_group(const char *buf, struct device *root_dev,

int qeth_core_hardsetup_card(struct qeth_card *card)
{
	struct qdio_ssqd_desc *ssqd;
	int retries = 0;
	int mpno = 0;
	int rc;

	QETH_DBF_TEXT(SETUP, 2, "hrdsetup");
@@ -3882,31 +3892,6 @@ int qeth_core_hardsetup_card(struct qeth_card *card)
		else
			goto retry;
	}

	rc = qeth_get_unitaddr(card);
	if (rc) {
		QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
		return rc;
	}

	ssqd = kmalloc(sizeof(struct qdio_ssqd_desc), GFP_KERNEL);
	if (!ssqd) {
		rc = -ENOMEM;
		goto out;
	}
	rc = qdio_get_ssqd_desc(CARD_DDEV(card), ssqd);
	if (rc == 0)
		mpno = ssqd->pcnt;
	kfree(ssqd);

	if (mpno)
		mpno = min(mpno - 1, QETH_MAX_PORTNO);
	if (card->info.portno > mpno) {
		QETH_DBF_MESSAGE(2, "Device %s does not offer port number %d"
			"\n.", CARD_BUS_ID(card), card->info.portno);
		rc = -ENODEV;
		goto out;
	}
	qeth_init_tokens(card);
	qeth_init_func_level(card);
	rc = qeth_idx_activate_channel(&card->read, qeth_idx_read_cb);
@@ -3990,7 +3975,7 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
	struct qdio_buffer_element *element = *__element;
	int offset = *__offset;
	struct sk_buff *skb = NULL;
	int skb_len;
	int skb_len = 0;
	void *data_ptr;
	int data_len;
	int headroom = 0;
@@ -4009,20 +3994,24 @@ struct sk_buff *qeth_core_get_next_skb(struct qeth_card *card,
	*hdr = element->addr + offset;

	offset += sizeof(struct qeth_hdr);
	if (card->options.layer2) {
		if (card->info.type == QETH_CARD_TYPE_OSN) {
			skb_len = (*hdr)->hdr.osn.pdu_length;
			headroom = sizeof(struct qeth_hdr);
		} else {
	switch ((*hdr)->hdr.l2.id) {
	case QETH_HEADER_TYPE_LAYER2:
		skb_len = (*hdr)->hdr.l2.pkt_length;
		}
	} else {
		break;
	case QETH_HEADER_TYPE_LAYER3:
		skb_len = (*hdr)->hdr.l3.length;
		if ((card->info.link_type == QETH_LINK_TYPE_LANE_TR) ||
		    (card->info.link_type == QETH_LINK_TYPE_HSTR))
			headroom = TR_HLEN;
		else
			headroom = ETH_HLEN;
		break;
	case QETH_HEADER_TYPE_OSN:
		skb_len = (*hdr)->hdr.osn.pdu_length;
		headroom = sizeof(struct qeth_hdr);
		break;
	default:
		break;
	}

	if (!skb_len)
@@ -4177,6 +4166,33 @@ void qeth_core_free_discipline(struct qeth_card *card)
	card->discipline.ccwgdriver = NULL;
}

static void qeth_determine_capabilities(struct qeth_card *card)
{
	int rc;

	QETH_DBF_TEXT(SETUP, 2, "detcapab");
	rc = ccw_device_set_online(CARD_DDEV(card));
	if (rc) {
		QETH_DBF_TEXT_(SETUP, 2, "3err%d", rc);
		goto out;
	}

	rc = qeth_get_unitaddr(card);
	if (rc) {
		QETH_DBF_TEXT_(SETUP, 2, "5err%d", rc);
		goto out_offline;
	}

	rc = qdio_get_ssqd_desc(CARD_DDEV(card), &card->ssqd);
	if (rc)
		QETH_DBF_TEXT_(SETUP, 2, "6err%d", rc);

out_offline:
	ccw_device_set_offline(CARD_DDEV(card));
out:
	return;
}

static int qeth_core_probe_device(struct ccwgroup_device *gdev)
{
	struct qeth_card *card;
@@ -4242,6 +4258,8 @@ static int qeth_core_probe_device(struct ccwgroup_device *gdev)
	write_lock_irqsave(&qeth_core_card_list.rwlock, flags);
	list_add_tail(&card->list, &qeth_core_card_list.list);
	write_unlock_irqrestore(&qeth_core_card_list.rwlock, flags);

	qeth_determine_capabilities(card);
	return 0;

err_card:
+43 −1
Original line number Diff line number Diff line
@@ -156,6 +156,8 @@ enum qeth_ipa_return_codes {
	IPA_RC_IP_TABLE_FULL		= 0x0002,
	IPA_RC_UNKNOWN_ERROR		= 0x0003,
	IPA_RC_UNSUPPORTED_COMMAND	= 0x0004,
	IPA_RC_TRACE_ALREADY_ACTIVE	= 0x0005,
	IPA_RC_INVALID_FORMAT		= 0x0006,
	IPA_RC_DUP_IPV6_REMOTE		= 0x0008,
	IPA_RC_DUP_IPV6_HOME		= 0x0010,
	IPA_RC_UNREGISTERED_ADDR	= 0x0011,
@@ -196,6 +198,11 @@ enum qeth_ipa_return_codes {
	IPA_RC_INVALID_IP_VERSION2	= 0xf001,
	IPA_RC_FFFF			= 0xffff
};
/* for DELIP */
#define IPA_RC_IP_ADDRESS_NOT_DEFINED	IPA_RC_PRIMARY_ALREADY_DEFINED
/* for SET_DIAGNOSTIC_ASSIST */
#define IPA_RC_INVALID_SUBCMD		IPA_RC_IP_TABLE_FULL
#define IPA_RC_HARDWARE_AUTH_ERROR	IPA_RC_UNKNOWN_ERROR

/* IPA function flags; each flag marks availability of respective function */
enum qeth_ipa_funcs {
@@ -246,6 +253,7 @@ enum qeth_ipa_setadp_cmd {
	IPA_SETADP_SET_SNMP_CONTROL		= 0x00000200L,
	IPA_SETADP_QUERY_CARD_INFO		= 0x00000400L,
	IPA_SETADP_SET_PROMISC_MODE		= 0x00000800L,
	IPA_SETADP_SET_DIAG_ASSIST		= 0x00002000L,
	IPA_SETADP_SET_ACCESS_CONTROL		= 0x00010000L,
};
enum qeth_ipa_mac_ops {
@@ -424,6 +432,40 @@ struct qeth_create_destroy_address {
	__u8 unique_id[8];
} __attribute__ ((packed));

/* SET DIAGNOSTIC ASSIST IPA Command:	 *************************************/

enum qeth_diags_cmds {
	QETH_DIAGS_CMD_QUERY	= 0x0001,
	QETH_DIAGS_CMD_TRAP	= 0x0002,
	QETH_DIAGS_CMD_TRACE	= 0x0004,
	QETH_DIAGS_CMD_NOLOG	= 0x0008,
	QETH_DIAGS_CMD_DUMP	= 0x0010,
};

enum qeth_diags_trace_types {
	QETH_DIAGS_TYPE_HIPERSOCKET	= 0x02,
};

enum qeth_diags_trace_cmds {
	QETH_DIAGS_CMD_TRACE_ENABLE	= 0x0001,
	QETH_DIAGS_CMD_TRACE_DISABLE	= 0x0002,
	QETH_DIAGS_CMD_TRACE_MODIFY	= 0x0004,
	QETH_DIAGS_CMD_TRACE_REPLACE	= 0x0008,
	QETH_DIAGS_CMD_TRACE_QUERY	= 0x0010,
};

struct qeth_ipacmd_diagass {
	__u32  host_tod2;
	__u32:32;
	__u16  subcmd_len;
	__u16:16;
	__u32  subcmd;
	__u8   type;
	__u8   action;
	__u16  options;
	__u32:32;
} __attribute__ ((packed));

/* Header for each IPA command */
struct qeth_ipacmd_hdr {
	__u8   command;
@@ -452,6 +494,7 @@ struct qeth_ipa_cmd {
		struct qeth_create_destroy_address	create_destroy_addr;
		struct qeth_ipacmd_setadpparms		setadapterparms;
		struct qeth_set_routing			setrtg;
		struct qeth_ipacmd_diagass		diagass;
	} data;
} __attribute__ ((packed));

@@ -469,7 +512,6 @@ enum qeth_ipa_arp_return_codes {
	QETH_IPA_ARP_RC_Q_NO_DATA    = 0x0008,
};


extern char *qeth_get_ipa_msg(enum qeth_ipa_return_codes rc);
extern char *qeth_get_ipa_cmd_name(enum qeth_ipa_cmds cmd);

+5 −3
Original line number Diff line number Diff line
@@ -118,7 +118,7 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
{
	struct qeth_card *card = dev_get_drvdata(dev);
	char *tmp;
	unsigned int portno;
	unsigned int portno, limit;

	if (!card)
		return -EINVAL;
@@ -128,9 +128,11 @@ static ssize_t qeth_dev_portno_store(struct device *dev,
		return -EPERM;

	portno = simple_strtoul(buf, &tmp, 16);
	if (portno > QETH_MAX_PORTNO) {
	if (portno > QETH_MAX_PORTNO)
		return -EINVAL;
	limit = (card->ssqd.pcnt ? card->ssqd.pcnt - 1 : card->ssqd.pcnt);
	if (portno > limit)
		return -EINVAL;
	}

	card->info.portno = portno;
	return count;
+2 −1
Original line number Diff line number Diff line
@@ -769,7 +769,8 @@ static void qeth_l2_qdio_input_handler(struct ccw_device *ccwdev,
		index = i % QDIO_MAX_BUFFERS_PER_Q;
		buffer = &card->qdio.in_q->bufs[index];
		if (!(qdio_err &&
		      qeth_check_qdio_errors(buffer->buffer, qdio_err, "qinerr")))
		      qeth_check_qdio_errors(card, buffer->buffer, qdio_err,
					     "qinerr")))
			qeth_l2_process_inbound_buffer(card, buffer, index);
		/* clear buffer and give back to hardware */
		qeth_put_buffer_pool_entry(card, buffer->pool_entry);
Loading