xref: /aosp_15_r20/external/ethtool/netlink/module-eeprom.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski  * module-eeprom.c - netlink implementation of module eeprom get command
3*1b481fc3SMaciej Żenczykowski  *
4*1b481fc3SMaciej Żenczykowski  * ethtool -m <dev>
5*1b481fc3SMaciej Żenczykowski  */
6*1b481fc3SMaciej Żenczykowski 
7*1b481fc3SMaciej Żenczykowski #include <errno.h>
8*1b481fc3SMaciej Żenczykowski #include <string.h>
9*1b481fc3SMaciej Żenczykowski #include <stdio.h>
10*1b481fc3SMaciej Żenczykowski #include <stddef.h>
11*1b481fc3SMaciej Żenczykowski 
12*1b481fc3SMaciej Żenczykowski #include "../sff-common.h"
13*1b481fc3SMaciej Żenczykowski #include "../qsfp.h"
14*1b481fc3SMaciej Żenczykowski #include "../cmis.h"
15*1b481fc3SMaciej Żenczykowski #include "../internal.h"
16*1b481fc3SMaciej Żenczykowski #include "../common.h"
17*1b481fc3SMaciej Żenczykowski #include "../list.h"
18*1b481fc3SMaciej Żenczykowski #include "netlink.h"
19*1b481fc3SMaciej Żenczykowski #include "parser.h"
20*1b481fc3SMaciej Żenczykowski 
21*1b481fc3SMaciej Żenczykowski #define ETH_I2C_ADDRESS_LOW	0x50
22*1b481fc3SMaciej Żenczykowski #define ETH_I2C_MAX_ADDRESS	0x7F
23*1b481fc3SMaciej Żenczykowski 
24*1b481fc3SMaciej Żenczykowski struct cmd_params {
25*1b481fc3SMaciej Żenczykowski 	u8 dump_hex;
26*1b481fc3SMaciej Żenczykowski 	u8 dump_raw;
27*1b481fc3SMaciej Żenczykowski 	u32 offset;
28*1b481fc3SMaciej Żenczykowski 	u32 length;
29*1b481fc3SMaciej Żenczykowski 	u32 page;
30*1b481fc3SMaciej Żenczykowski 	u32 bank;
31*1b481fc3SMaciej Żenczykowski 	u32 i2c_address;
32*1b481fc3SMaciej Żenczykowski };
33*1b481fc3SMaciej Żenczykowski 
34*1b481fc3SMaciej Żenczykowski static const struct param_parser getmodule_params[] = {
35*1b481fc3SMaciej Żenczykowski 	{
36*1b481fc3SMaciej Żenczykowski 		.arg		= "hex",
37*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_u8bool,
38*1b481fc3SMaciej Żenczykowski 		.dest_offset	= offsetof(struct cmd_params, dump_hex),
39*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
40*1b481fc3SMaciej Żenczykowski 	},
41*1b481fc3SMaciej Żenczykowski 	{
42*1b481fc3SMaciej Żenczykowski 		.arg		= "raw",
43*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_u8bool,
44*1b481fc3SMaciej Żenczykowski 		.dest_offset	= offsetof(struct cmd_params, dump_raw),
45*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
46*1b481fc3SMaciej Żenczykowski 	},
47*1b481fc3SMaciej Żenczykowski 	{
48*1b481fc3SMaciej Żenczykowski 		.arg		= "offset",
49*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u32,
50*1b481fc3SMaciej Żenczykowski 		.dest_offset	= offsetof(struct cmd_params, offset),
51*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
52*1b481fc3SMaciej Żenczykowski 	},
53*1b481fc3SMaciej Żenczykowski 	{
54*1b481fc3SMaciej Żenczykowski 		.arg		= "length",
55*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u32,
56*1b481fc3SMaciej Żenczykowski 		.dest_offset	= offsetof(struct cmd_params, length),
57*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
58*1b481fc3SMaciej Żenczykowski 	},
59*1b481fc3SMaciej Żenczykowski 	{
60*1b481fc3SMaciej Żenczykowski 		.arg		= "page",
61*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u32,
62*1b481fc3SMaciej Żenczykowski 		.dest_offset	= offsetof(struct cmd_params, page),
63*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
64*1b481fc3SMaciej Żenczykowski 	},
65*1b481fc3SMaciej Żenczykowski 	{
66*1b481fc3SMaciej Żenczykowski 		.arg		= "bank",
67*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u32,
68*1b481fc3SMaciej Żenczykowski 		.dest_offset	= offsetof(struct cmd_params, bank),
69*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
70*1b481fc3SMaciej Żenczykowski 	},
71*1b481fc3SMaciej Żenczykowski 	{
72*1b481fc3SMaciej Żenczykowski 		.arg		= "i2c",
73*1b481fc3SMaciej Żenczykowski 		.handler	= nl_parse_direct_u32,
74*1b481fc3SMaciej Żenczykowski 		.dest_offset	= offsetof(struct cmd_params, i2c_address),
75*1b481fc3SMaciej Żenczykowski 		.min_argc	= 1,
76*1b481fc3SMaciej Żenczykowski 	},
77*1b481fc3SMaciej Żenczykowski 	{}
78*1b481fc3SMaciej Żenczykowski };
79*1b481fc3SMaciej Żenczykowski 
80*1b481fc3SMaciej Żenczykowski static struct list_head eeprom_page_list = LIST_HEAD_INIT(eeprom_page_list);
81*1b481fc3SMaciej Żenczykowski 
82*1b481fc3SMaciej Żenczykowski struct eeprom_page_entry {
83*1b481fc3SMaciej Żenczykowski 	struct list_head list;	/* Member of eeprom_page_list */
84*1b481fc3SMaciej Żenczykowski 	void *data;
85*1b481fc3SMaciej Żenczykowski };
86*1b481fc3SMaciej Żenczykowski 
eeprom_page_list_add(void * data)87*1b481fc3SMaciej Żenczykowski static int eeprom_page_list_add(void *data)
88*1b481fc3SMaciej Żenczykowski {
89*1b481fc3SMaciej Żenczykowski 	struct eeprom_page_entry *entry;
90*1b481fc3SMaciej Żenczykowski 
91*1b481fc3SMaciej Żenczykowski 	entry = malloc(sizeof(*entry));
92*1b481fc3SMaciej Żenczykowski 	if (!entry)
93*1b481fc3SMaciej Żenczykowski 		return -ENOMEM;
94*1b481fc3SMaciej Żenczykowski 
95*1b481fc3SMaciej Żenczykowski 	entry->data = data;
96*1b481fc3SMaciej Żenczykowski 	list_add(&entry->list, &eeprom_page_list);
97*1b481fc3SMaciej Żenczykowski 
98*1b481fc3SMaciej Żenczykowski 	return 0;
99*1b481fc3SMaciej Żenczykowski }
100*1b481fc3SMaciej Żenczykowski 
eeprom_page_list_flush(void)101*1b481fc3SMaciej Żenczykowski static void eeprom_page_list_flush(void)
102*1b481fc3SMaciej Żenczykowski {
103*1b481fc3SMaciej Żenczykowski 	struct eeprom_page_entry *entry;
104*1b481fc3SMaciej Żenczykowski 	struct list_head *head, *next;
105*1b481fc3SMaciej Żenczykowski 
106*1b481fc3SMaciej Żenczykowski 	list_for_each_safe(head, next, &eeprom_page_list) {
107*1b481fc3SMaciej Żenczykowski 		entry = (struct eeprom_page_entry *) head;
108*1b481fc3SMaciej Żenczykowski 		free(entry->data);
109*1b481fc3SMaciej Żenczykowski 		list_del(head);
110*1b481fc3SMaciej Żenczykowski 		free(entry);
111*1b481fc3SMaciej Żenczykowski 	}
112*1b481fc3SMaciej Żenczykowski }
113*1b481fc3SMaciej Żenczykowski 
get_eeprom_page_reply_cb(const struct nlmsghdr * nlhdr,void * data)114*1b481fc3SMaciej Żenczykowski static int get_eeprom_page_reply_cb(const struct nlmsghdr *nlhdr, void *data)
115*1b481fc3SMaciej Żenczykowski {
116*1b481fc3SMaciej Żenczykowski 	const struct nlattr *tb[ETHTOOL_A_MODULE_EEPROM_DATA + 1] = {};
117*1b481fc3SMaciej Żenczykowski 	struct ethtool_module_eeprom *request = data;
118*1b481fc3SMaciej Żenczykowski 	DECLARE_ATTR_TB_INFO(tb);
119*1b481fc3SMaciej Żenczykowski 	u8 *eeprom_data;
120*1b481fc3SMaciej Żenczykowski 	int ret;
121*1b481fc3SMaciej Żenczykowski 
122*1b481fc3SMaciej Żenczykowski 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
123*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
124*1b481fc3SMaciej Żenczykowski 		return ret;
125*1b481fc3SMaciej Żenczykowski 
126*1b481fc3SMaciej Żenczykowski 	if (!tb[ETHTOOL_A_MODULE_EEPROM_DATA])
127*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
128*1b481fc3SMaciej Żenczykowski 
129*1b481fc3SMaciej Żenczykowski 	eeprom_data = mnl_attr_get_payload(tb[ETHTOOL_A_MODULE_EEPROM_DATA]);
130*1b481fc3SMaciej Żenczykowski 	request->data = malloc(request->length);
131*1b481fc3SMaciej Żenczykowski 	if (!request->data)
132*1b481fc3SMaciej Żenczykowski 		return MNL_CB_ERROR;
133*1b481fc3SMaciej Żenczykowski 	memcpy(request->data, eeprom_data, request->length);
134*1b481fc3SMaciej Żenczykowski 
135*1b481fc3SMaciej Żenczykowski 	ret = eeprom_page_list_add(request->data);
136*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
137*1b481fc3SMaciej Żenczykowski 		goto err_list_add;
138*1b481fc3SMaciej Żenczykowski 
139*1b481fc3SMaciej Żenczykowski 	return MNL_CB_OK;
140*1b481fc3SMaciej Żenczykowski 
141*1b481fc3SMaciej Żenczykowski err_list_add:
142*1b481fc3SMaciej Żenczykowski 	free(request->data);
143*1b481fc3SMaciej Żenczykowski 	return MNL_CB_ERROR;
144*1b481fc3SMaciej Żenczykowski }
145*1b481fc3SMaciej Żenczykowski 
nl_get_eeprom_page(struct cmd_context * ctx,struct ethtool_module_eeprom * request)146*1b481fc3SMaciej Żenczykowski int nl_get_eeprom_page(struct cmd_context *ctx,
147*1b481fc3SMaciej Żenczykowski 		       struct ethtool_module_eeprom *request)
148*1b481fc3SMaciej Żenczykowski {
149*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = ctx->nlctx;
150*1b481fc3SMaciej Żenczykowski 	struct nl_socket *nlsock;
151*1b481fc3SMaciej Żenczykowski 	struct nl_msg_buff *msg;
152*1b481fc3SMaciej Żenczykowski 	int ret;
153*1b481fc3SMaciej Żenczykowski 
154*1b481fc3SMaciej Żenczykowski 	if (!request || request->i2c_address > ETH_I2C_MAX_ADDRESS)
155*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
156*1b481fc3SMaciej Żenczykowski 
157*1b481fc3SMaciej Żenczykowski 	nlsock = nlctx->ethnl_socket;
158*1b481fc3SMaciej Żenczykowski 	msg = &nlsock->msgbuff;
159*1b481fc3SMaciej Żenczykowski 
160*1b481fc3SMaciej Żenczykowski 	ret = nlsock_prep_get_request(nlsock, ETHTOOL_MSG_MODULE_EEPROM_GET,
161*1b481fc3SMaciej Żenczykowski 				      ETHTOOL_A_MODULE_EEPROM_HEADER, 0);
162*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
163*1b481fc3SMaciej Żenczykowski 		return ret;
164*1b481fc3SMaciej Żenczykowski 
165*1b481fc3SMaciej Żenczykowski 	if (ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_LENGTH,
166*1b481fc3SMaciej Żenczykowski 			   request->length) ||
167*1b481fc3SMaciej Żenczykowski 	    ethnla_put_u32(msg, ETHTOOL_A_MODULE_EEPROM_OFFSET,
168*1b481fc3SMaciej Żenczykowski 			   request->offset) ||
169*1b481fc3SMaciej Żenczykowski 	    ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_PAGE,
170*1b481fc3SMaciej Żenczykowski 			  request->page) ||
171*1b481fc3SMaciej Żenczykowski 	    ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_BANK,
172*1b481fc3SMaciej Żenczykowski 			  request->bank) ||
173*1b481fc3SMaciej Żenczykowski 	    ethnla_put_u8(msg, ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS,
174*1b481fc3SMaciej Żenczykowski 			  request->i2c_address))
175*1b481fc3SMaciej Żenczykowski 		return -EMSGSIZE;
176*1b481fc3SMaciej Żenczykowski 
177*1b481fc3SMaciej Żenczykowski 	ret = nlsock_sendmsg(nlsock, NULL);
178*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
179*1b481fc3SMaciej Żenczykowski 		return ret;
180*1b481fc3SMaciej Żenczykowski 	return nlsock_process_reply(nlsock, get_eeprom_page_reply_cb,
181*1b481fc3SMaciej Żenczykowski 				    (void *)request);
182*1b481fc3SMaciej Żenczykowski }
183*1b481fc3SMaciej Żenczykowski 
eeprom_dump_hex(struct cmd_context * ctx)184*1b481fc3SMaciej Żenczykowski static int eeprom_dump_hex(struct cmd_context *ctx)
185*1b481fc3SMaciej Żenczykowski {
186*1b481fc3SMaciej Żenczykowski 	struct ethtool_module_eeprom request = {
187*1b481fc3SMaciej Żenczykowski 		.length = 128,
188*1b481fc3SMaciej Żenczykowski 		.i2c_address = ETH_I2C_ADDRESS_LOW,
189*1b481fc3SMaciej Żenczykowski 	};
190*1b481fc3SMaciej Żenczykowski 	int ret;
191*1b481fc3SMaciej Żenczykowski 
192*1b481fc3SMaciej Żenczykowski 	ret = nl_get_eeprom_page(ctx, &request);
193*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
194*1b481fc3SMaciej Żenczykowski 		return ret;
195*1b481fc3SMaciej Żenczykowski 
196*1b481fc3SMaciej Żenczykowski 	dump_hex(stdout, request.data, request.length, request.offset);
197*1b481fc3SMaciej Żenczykowski 
198*1b481fc3SMaciej Żenczykowski 	return 0;
199*1b481fc3SMaciej Żenczykowski }
200*1b481fc3SMaciej Żenczykowski 
eeprom_parse(struct cmd_context * ctx)201*1b481fc3SMaciej Żenczykowski static int eeprom_parse(struct cmd_context *ctx)
202*1b481fc3SMaciej Żenczykowski {
203*1b481fc3SMaciej Żenczykowski 	struct ethtool_module_eeprom request = {
204*1b481fc3SMaciej Żenczykowski 		.length = 1,
205*1b481fc3SMaciej Żenczykowski 		.i2c_address = ETH_I2C_ADDRESS_LOW,
206*1b481fc3SMaciej Żenczykowski 	};
207*1b481fc3SMaciej Żenczykowski 	int ret;
208*1b481fc3SMaciej Żenczykowski 
209*1b481fc3SMaciej Żenczykowski 	/* Fetch the SFF-8024 Identifier Value. For all supported standards, it
210*1b481fc3SMaciej Żenczykowski 	 * is located at I2C address 0x50, byte 0. See section 4.1 in SFF-8024,
211*1b481fc3SMaciej Żenczykowski 	 * revision 4.9.
212*1b481fc3SMaciej Żenczykowski 	 */
213*1b481fc3SMaciej Żenczykowski 	ret = nl_get_eeprom_page(ctx, &request);
214*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
215*1b481fc3SMaciej Żenczykowski 		return ret;
216*1b481fc3SMaciej Żenczykowski 
217*1b481fc3SMaciej Żenczykowski 	switch (request.data[0]) {
218*1b481fc3SMaciej Żenczykowski #ifdef ETHTOOL_ENABLE_PRETTY_DUMP
219*1b481fc3SMaciej Żenczykowski 	case SFF8024_ID_SFP:
220*1b481fc3SMaciej Żenczykowski 		return sff8079_show_all_nl(ctx);
221*1b481fc3SMaciej Żenczykowski 	case SFF8024_ID_QSFP:
222*1b481fc3SMaciej Żenczykowski 	case SFF8024_ID_QSFP28:
223*1b481fc3SMaciej Żenczykowski 	case SFF8024_ID_QSFP_PLUS:
224*1b481fc3SMaciej Żenczykowski 		return sff8636_show_all_nl(ctx);
225*1b481fc3SMaciej Żenczykowski 	case SFF8024_ID_QSFP_DD:
226*1b481fc3SMaciej Żenczykowski 	case SFF8024_ID_OSFP:
227*1b481fc3SMaciej Żenczykowski 	case SFF8024_ID_DSFP:
228*1b481fc3SMaciej Żenczykowski 		return cmis_show_all_nl(ctx);
229*1b481fc3SMaciej Żenczykowski #endif
230*1b481fc3SMaciej Żenczykowski 	default:
231*1b481fc3SMaciej Żenczykowski 		/* If we cannot recognize the memory map, default to dumping
232*1b481fc3SMaciej Żenczykowski 		 * the first 128 bytes in hex.
233*1b481fc3SMaciej Żenczykowski 		 */
234*1b481fc3SMaciej Żenczykowski 		return eeprom_dump_hex(ctx);
235*1b481fc3SMaciej Żenczykowski 	}
236*1b481fc3SMaciej Żenczykowski }
237*1b481fc3SMaciej Żenczykowski 
nl_getmodule(struct cmd_context * ctx)238*1b481fc3SMaciej Żenczykowski int nl_getmodule(struct cmd_context *ctx)
239*1b481fc3SMaciej Żenczykowski {
240*1b481fc3SMaciej Żenczykowski 	struct cmd_params getmodule_cmd_params = {};
241*1b481fc3SMaciej Żenczykowski 	struct ethtool_module_eeprom request = {0};
242*1b481fc3SMaciej Żenczykowski 	struct nl_context *nlctx = ctx->nlctx;
243*1b481fc3SMaciej Żenczykowski 	int ret;
244*1b481fc3SMaciej Żenczykowski 
245*1b481fc3SMaciej Żenczykowski 	if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_EEPROM_GET, false))
246*1b481fc3SMaciej Żenczykowski 		return -EOPNOTSUPP;
247*1b481fc3SMaciej Żenczykowski 
248*1b481fc3SMaciej Żenczykowski 	nlctx->cmd = "-m";
249*1b481fc3SMaciej Żenczykowski 	nlctx->argp = ctx->argp;
250*1b481fc3SMaciej Żenczykowski 	nlctx->argc = ctx->argc;
251*1b481fc3SMaciej Żenczykowski 	nlctx->devname = ctx->devname;
252*1b481fc3SMaciej Żenczykowski 	ret = nl_parser(nlctx, getmodule_params, &getmodule_cmd_params, PARSER_GROUP_NONE, NULL);
253*1b481fc3SMaciej Żenczykowski 	if (ret < 0)
254*1b481fc3SMaciej Żenczykowski 		return ret;
255*1b481fc3SMaciej Żenczykowski 
256*1b481fc3SMaciej Żenczykowski 	if (getmodule_cmd_params.dump_hex && getmodule_cmd_params.dump_raw) {
257*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "Hex and raw dump cannot be specified together\n");
258*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
259*1b481fc3SMaciej Żenczykowski 	}
260*1b481fc3SMaciej Żenczykowski 
261*1b481fc3SMaciej Żenczykowski 	/* When complete hex/raw dump of the EEPROM is requested, fallback to
262*1b481fc3SMaciej Żenczykowski 	 * ioctl. Netlink can only request specific pages.
263*1b481fc3SMaciej Żenczykowski 	 */
264*1b481fc3SMaciej Żenczykowski 	if ((getmodule_cmd_params.dump_hex || getmodule_cmd_params.dump_raw) &&
265*1b481fc3SMaciej Żenczykowski 	    !getmodule_cmd_params.page && !getmodule_cmd_params.bank &&
266*1b481fc3SMaciej Żenczykowski 	    !getmodule_cmd_params.i2c_address) {
267*1b481fc3SMaciej Żenczykowski 		nlctx->ioctl_fallback = true;
268*1b481fc3SMaciej Żenczykowski 		return -EOPNOTSUPP;
269*1b481fc3SMaciej Żenczykowski 	}
270*1b481fc3SMaciej Żenczykowski 
271*1b481fc3SMaciej Żenczykowski #ifdef ETHTOOL_ENABLE_PRETTY_DUMP
272*1b481fc3SMaciej Żenczykowski 	if (getmodule_cmd_params.page || getmodule_cmd_params.bank ||
273*1b481fc3SMaciej Żenczykowski 	    getmodule_cmd_params.offset || getmodule_cmd_params.length)
274*1b481fc3SMaciej Żenczykowski #endif
275*1b481fc3SMaciej Żenczykowski 		getmodule_cmd_params.dump_hex = true;
276*1b481fc3SMaciej Żenczykowski 
277*1b481fc3SMaciej Żenczykowski 	request.offset = getmodule_cmd_params.offset;
278*1b481fc3SMaciej Żenczykowski 	request.length = getmodule_cmd_params.length ?: 128;
279*1b481fc3SMaciej Żenczykowski 	request.page = getmodule_cmd_params.page;
280*1b481fc3SMaciej Żenczykowski 	request.bank = getmodule_cmd_params.bank;
281*1b481fc3SMaciej Żenczykowski 	request.i2c_address = getmodule_cmd_params.i2c_address ?: ETH_I2C_ADDRESS_LOW;
282*1b481fc3SMaciej Żenczykowski 
283*1b481fc3SMaciej Żenczykowski 	if (request.page && !request.offset)
284*1b481fc3SMaciej Żenczykowski 		request.offset = 128;
285*1b481fc3SMaciej Żenczykowski 
286*1b481fc3SMaciej Żenczykowski 	if (getmodule_cmd_params.dump_hex || getmodule_cmd_params.dump_raw) {
287*1b481fc3SMaciej Żenczykowski 		ret = nl_get_eeprom_page(ctx, &request);
288*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
289*1b481fc3SMaciej Żenczykowski 			goto cleanup;
290*1b481fc3SMaciej Żenczykowski 
291*1b481fc3SMaciej Żenczykowski 		if (getmodule_cmd_params.dump_raw)
292*1b481fc3SMaciej Żenczykowski 			fwrite(request.data, 1, request.length, stdout);
293*1b481fc3SMaciej Żenczykowski 		else
294*1b481fc3SMaciej Żenczykowski 			dump_hex(stdout, request.data, request.length,
295*1b481fc3SMaciej Żenczykowski 				 request.offset);
296*1b481fc3SMaciej Żenczykowski 	} else {
297*1b481fc3SMaciej Żenczykowski 		ret = eeprom_parse(ctx);
298*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
299*1b481fc3SMaciej Żenczykowski 			goto cleanup;
300*1b481fc3SMaciej Żenczykowski 	}
301*1b481fc3SMaciej Żenczykowski 
302*1b481fc3SMaciej Żenczykowski cleanup:
303*1b481fc3SMaciej Żenczykowski 	eeprom_page_list_flush();
304*1b481fc3SMaciej Żenczykowski 	return ret;
305*1b481fc3SMaciej Żenczykowski }
306