xref: /freebsd-src/usr.sbin/fwcontrol/fwcontrol.c (revision 9494dfe1b3faf5c48abaa9be4ec87e4669963942)
1df57947fSPedro F. Giffuni /*-
2df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni  *
4a7a73b95SHidetoshi Shimokawa  * Copyright (C) 2002
5a7a73b95SHidetoshi Shimokawa  * 	Hidetoshi Shimokawa. All rights reserved.
6a7a73b95SHidetoshi Shimokawa  *
7a7a73b95SHidetoshi Shimokawa  * Redistribution and use in source and binary forms, with or without
8a7a73b95SHidetoshi Shimokawa  * modification, are permitted provided that the following conditions
9a7a73b95SHidetoshi Shimokawa  * are met:
10a7a73b95SHidetoshi Shimokawa  * 1. Redistributions of source code must retain the above copyright
11a7a73b95SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer.
12a7a73b95SHidetoshi Shimokawa  * 2. Redistributions in binary form must reproduce the above copyright
13a7a73b95SHidetoshi Shimokawa  *    notice, this list of conditions and the following disclaimer in the
14a7a73b95SHidetoshi Shimokawa  *    documentation and/or other materials provided with the distribution.
15a7a73b95SHidetoshi Shimokawa  * 3. All advertising materials mentioning features or use of this software
16a7a73b95SHidetoshi Shimokawa  *    must display the following acknowledgement:
17a7a73b95SHidetoshi Shimokawa  *
18a7a73b95SHidetoshi Shimokawa  *	This product includes software developed by Hidetoshi Shimokawa.
19a7a73b95SHidetoshi Shimokawa  *
20a7a73b95SHidetoshi Shimokawa  * 4. Neither the name of the author nor the names of its contributors
21a7a73b95SHidetoshi Shimokawa  *    may be used to endorse or promote products derived from this software
22a7a73b95SHidetoshi Shimokawa  *    without specific prior written permission.
23a7a73b95SHidetoshi Shimokawa  *
24a7a73b95SHidetoshi Shimokawa  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25a7a73b95SHidetoshi Shimokawa  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26a7a73b95SHidetoshi Shimokawa  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27a7a73b95SHidetoshi Shimokawa  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28a7a73b95SHidetoshi Shimokawa  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29a7a73b95SHidetoshi Shimokawa  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30a7a73b95SHidetoshi Shimokawa  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31a7a73b95SHidetoshi Shimokawa  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32a7a73b95SHidetoshi Shimokawa  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33a7a73b95SHidetoshi Shimokawa  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34a7a73b95SHidetoshi Shimokawa  * SUCH DAMAGE.
35a7a73b95SHidetoshi Shimokawa  */
36a7a73b95SHidetoshi Shimokawa 
37c1de48a3SSean Bruno #if defined(__FreeBSD__)
383fe9d89aSPhilippe Charnier #include <sys/cdefs.h>
39c1de48a3SSean Bruno #endif
403fe9d89aSPhilippe Charnier 
41a7a73b95SHidetoshi Shimokawa #include <sys/param.h>
42a7a73b95SHidetoshi Shimokawa #include <sys/malloc.h>
433fe9d89aSPhilippe Charnier #include <sys/types.h>
443fe9d89aSPhilippe Charnier #include <sys/sysctl.h>
45a7a73b95SHidetoshi Shimokawa #include <sys/socket.h>
46a7a73b95SHidetoshi Shimokawa #include <sys/ioctl.h>
47a7a73b95SHidetoshi Shimokawa #include <sys/errno.h>
48c1de48a3SSean Bruno #if defined(__FreeBSD__)
49cb5df0b2SBrooks Davis #include <sys/eui64.h>
50a7a73b95SHidetoshi Shimokawa #include <dev/firewire/firewire.h>
51a7a73b95SHidetoshi Shimokawa #include <dev/firewire/iec13213.h>
52a8587980SHidetoshi Shimokawa #include <dev/firewire/fwphyreg.h>
536d815a7dSWarner Losh #include <dev/firewire/iec68113.h>
54c1de48a3SSean Bruno #elif defined(__NetBSD__)
55c1de48a3SSean Bruno #include "eui64.h"
56c1de48a3SSean Bruno #include <dev/ieee1394/firewire.h>
57c1de48a3SSean Bruno #include <dev/ieee1394/iec13213.h>
58c1de48a3SSean Bruno #include <dev/ieee1394/fwphyreg.h>
59c1de48a3SSean Bruno #include <dev/ieee1394/iec68113.h>
60c1de48a3SSean Bruno #else
61c1de48a3SSean Bruno #warning "You need to add support for your OS"
62c1de48a3SSean Bruno #endif
63c1de48a3SSean Bruno 
64a7a73b95SHidetoshi Shimokawa 
65a7a73b95SHidetoshi Shimokawa #include <netinet/in.h>
66a7a73b95SHidetoshi Shimokawa #include <fcntl.h>
67a7a73b95SHidetoshi Shimokawa #include <stdio.h>
68a7a73b95SHidetoshi Shimokawa #include <err.h>
69a7a73b95SHidetoshi Shimokawa #include <stdlib.h>
70a7a73b95SHidetoshi Shimokawa #include <string.h>
716d815a7dSWarner Losh #include <sysexits.h>
72a7a73b95SHidetoshi Shimokawa #include <unistd.h>
737f1b527cSSean Bruno #include <stdint.h>
747f1b527cSSean Bruno #include <stdbool.h>
756d815a7dSWarner Losh #include "fwmethods.h"
76a7a73b95SHidetoshi Shimokawa 
776d815a7dSWarner Losh static void sysctl_set_int(const char *, int);
783fe9d89aSPhilippe Charnier 
797ddbf617SHidetoshi Shimokawa static void
80a7a73b95SHidetoshi Shimokawa usage(void)
81a7a73b95SHidetoshi Shimokawa {
828604e72aSHidetoshi Shimokawa 	fprintf(stderr,
83c1de48a3SSean Bruno 		"%s [-u bus_num] [-prt] [-c node] [-d node] [-o node] [-s node]\n"
847f1b527cSSean Bruno 		"\t  [-l file] [-g gap_count] [-f force_root ] [-b pri_req]\n"
857f1b527cSSean Bruno 		"\t  [-M mode] [-R filename] [-S filename] [-m EUI64 | hostname]\n"
86abd538f2SHidetoshi Shimokawa 		"\t-u: specify bus number\n"
877f1b527cSSean Bruno 		"\t-p: Display current PHY register settings\n"
88d1f7bcb5SHidetoshi Shimokawa 		"\t-r: bus reset\n"
89d1f7bcb5SHidetoshi Shimokawa 		"\t-t: read topology map\n"
907f1b527cSSean Bruno 		"\t-c: read configuration ROM\n"
91d1f7bcb5SHidetoshi Shimokawa 		"\t-d: hex dump of configuration ROM\n"
927f1b527cSSean Bruno 		"\t-o: send link-on packet to the node\n"
937f1b527cSSean Bruno 		"\t-s: write RESET_START register on the node\n"
94d1f7bcb5SHidetoshi Shimokawa 		"\t-l: load and parse hex dump file of configuration ROM\n"
95c1de48a3SSean Bruno 		"\t-g: set gap count\n"
96c1de48a3SSean Bruno 		"\t-f: force root node\n"
977f1b527cSSean Bruno 		"\t-b: set PRIORITY_BUDGET register on all supported nodes\n"
987f1b527cSSean Bruno 		"\t-M: specify dv or mpeg\n"
996d815a7dSWarner Losh 		"\t-R: Receive DV or MPEG TS stream\n"
100f6248231SHidetoshi Shimokawa 		"\t-S: Send DV stream\n"
101c1de48a3SSean Bruno 		"\t-m: set fwmem target\n"
102c1de48a3SSean Bruno 		, getprogname() );
103c1de48a3SSean Bruno 	fprintf(stderr, "\n");
104a7a73b95SHidetoshi Shimokawa }
105a7a73b95SHidetoshi Shimokawa 
106cb5df0b2SBrooks Davis static void
107cb5df0b2SBrooks Davis fweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui)
108cb5df0b2SBrooks Davis {
109cb5df0b2SBrooks Davis 	*(u_int32_t*)&(eui->octet[0]) = htonl(fweui->hi);
110cb5df0b2SBrooks Davis 	*(u_int32_t*)&(eui->octet[4]) = htonl(fweui->lo);
111cb5df0b2SBrooks Davis }
112cb5df0b2SBrooks Davis 
1137f1b527cSSean Bruno static void
1147f1b527cSSean Bruno get_dev(int fd, struct fw_devlstreq *data)
115a7a73b95SHidetoshi Shimokawa {
116c547b896SHidetoshi Shimokawa 	if (data == NULL)
1177f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s: data malloc", __func__);
118a7a73b95SHidetoshi Shimokawa 	if( ioctl(fd, FW_GDEVLST, data) < 0) {
1197f1b527cSSean Bruno        			err(EX_IOERR, "%s: ioctl", __func__);
120a7a73b95SHidetoshi Shimokawa 	}
121a7a73b95SHidetoshi Shimokawa }
122a7a73b95SHidetoshi Shimokawa 
123cb5df0b2SBrooks Davis static int
124cb5df0b2SBrooks Davis str2node(int fd, const char *nodestr)
125cb5df0b2SBrooks Davis {
126cb5df0b2SBrooks Davis 	struct eui64 eui, tmpeui;
127cb5df0b2SBrooks Davis 	struct fw_devlstreq *data;
128cb5df0b2SBrooks Davis 	char *endptr;
129cb5df0b2SBrooks Davis 	int i, node;
130cb5df0b2SBrooks Davis 
131f1897613SBrooks Davis 	if (nodestr == NULL || *nodestr == '\0')
132cb5df0b2SBrooks Davis 		return (-1);
133cb5df0b2SBrooks Davis 
134cb5df0b2SBrooks Davis 	/*
135cb5df0b2SBrooks Davis 	 * Deal with classic node specifications.
136cb5df0b2SBrooks Davis 	 */
137cb5df0b2SBrooks Davis 	node = strtol(nodestr, &endptr, 0);
138cb5df0b2SBrooks Davis 	if (*endptr == '\0')
139cb5df0b2SBrooks Davis 		goto gotnode;
140cb5df0b2SBrooks Davis 
141cb5df0b2SBrooks Davis 	/*
142cb5df0b2SBrooks Davis 	 * Try to get an eui and match it against available nodes.
143cb5df0b2SBrooks Davis 	 */
144cb5df0b2SBrooks Davis 	if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0)
145cb5df0b2SBrooks Davis 		return (-1);
146cb5df0b2SBrooks Davis 
1477f1b527cSSean Bruno 	data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
1487f1b527cSSean Bruno 	if (data == NULL)
1497f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s: data malloc", __func__);
1507f1b527cSSean Bruno 	get_dev(fd,data);
151cb5df0b2SBrooks Davis 
152cb5df0b2SBrooks Davis 	for (i = 0; i < data->info_len; i++) {
153cb5df0b2SBrooks Davis 		fweui2eui64(&data->dev[i].eui, &tmpeui);
154cb5df0b2SBrooks Davis 		if (memcmp(&eui, &tmpeui, sizeof(struct eui64)) == 0) {
155cb5df0b2SBrooks Davis 			node = data->dev[i].dst;
1567f1b527cSSean Bruno 			free(data);
157cb5df0b2SBrooks Davis 			goto gotnode;
158cb5df0b2SBrooks Davis 		}
159cb5df0b2SBrooks Davis 	}
1607f1b527cSSean Bruno 	if (i >= data->info_len) {
1617f1b527cSSean Bruno 		if (data != NULL)
1627f1b527cSSean Bruno 			free(data);
163cb5df0b2SBrooks Davis 		return (-1);
1647f1b527cSSean Bruno 	}
165cb5df0b2SBrooks Davis 
166cb5df0b2SBrooks Davis gotnode:
167cb5df0b2SBrooks Davis 	if (node < 0 || node > 63)
168cb5df0b2SBrooks Davis 		return (-1);
169cb5df0b2SBrooks Davis 	else
170cb5df0b2SBrooks Davis 		return (node);
171cb5df0b2SBrooks Davis }
172cb5df0b2SBrooks Davis 
1737ddbf617SHidetoshi Shimokawa static void
174a7a73b95SHidetoshi Shimokawa list_dev(int fd)
175a7a73b95SHidetoshi Shimokawa {
176c547b896SHidetoshi Shimokawa 	struct fw_devlstreq *data;
177c547b896SHidetoshi Shimokawa 	struct fw_devinfo *devinfo;
178cb5df0b2SBrooks Davis 	struct eui64 eui;
179302176c7SHidetoshi Shimokawa 	char addr[EUI64_SIZ], hostname[40];
180a7a73b95SHidetoshi Shimokawa 	int i;
181a7a73b95SHidetoshi Shimokawa 
1827f1b527cSSean Bruno 	data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
1837f1b527cSSean Bruno 	if (data == NULL)
1847f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:data malloc", __func__);
1857f1b527cSSean Bruno 	get_dev(fd, data);
186c547b896SHidetoshi Shimokawa 	printf("%d devices (info_len=%d)\n", data->n, data->info_len);
187302176c7SHidetoshi Shimokawa 	printf("node           EUI64          status    hostname\n");
188c547b896SHidetoshi Shimokawa 	for (i = 0; i < data->info_len; i++) {
189c547b896SHidetoshi Shimokawa 		devinfo = &data->dev[i];
190cb5df0b2SBrooks Davis 		fweui2eui64(&devinfo->eui, &eui);
191cb5df0b2SBrooks Davis 		eui64_ntoa(&eui, addr, sizeof(addr));
192302176c7SHidetoshi Shimokawa 	        if (eui64_ntohost(hostname, sizeof(hostname), &eui))
193302176c7SHidetoshi Shimokawa 			hostname[0] = 0;
194302176c7SHidetoshi Shimokawa 		printf("%4d  %s %6d    %s\n",
195e6aaafcdSHidetoshi Shimokawa 			(devinfo->status || i == 0) ? devinfo->dst : -1,
196cb5df0b2SBrooks Davis 			addr,
197302176c7SHidetoshi Shimokawa 			devinfo->status,
198302176c7SHidetoshi Shimokawa 			hostname
199a7a73b95SHidetoshi Shimokawa 		);
200a7a73b95SHidetoshi Shimokawa 	}
201c547b896SHidetoshi Shimokawa 	free((void *)data);
202a7a73b95SHidetoshi Shimokawa }
203a7a73b95SHidetoshi Shimokawa 
2047ddbf617SHidetoshi Shimokawa static u_int32_t
2053fe9d89aSPhilippe Charnier read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int readmode, u_int32_t data)
206a7a73b95SHidetoshi Shimokawa {
207a7a73b95SHidetoshi Shimokawa         struct fw_asyreq *asyreq;
208a7a73b95SHidetoshi Shimokawa 	u_int32_t *qld, res;
209a7a73b95SHidetoshi Shimokawa 
210*9494dfe1SJohn Baldwin 	asyreq = malloc(sizeof(*asyreq));
2117f1b527cSSean Bruno 	if (asyreq == NULL)
2127f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:asyreq malloc", __func__);
213a7a73b95SHidetoshi Shimokawa 	asyreq->req.len = 16;
214d1f7bcb5SHidetoshi Shimokawa #if 0
215d1f7bcb5SHidetoshi Shimokawa 	asyreq->req.type = FWASREQNODE;
216d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node;
217d1f7bcb5SHidetoshi Shimokawa #else
218a7a73b95SHidetoshi Shimokawa 	asyreq->req.type = FWASREQEUI;
219a7a73b95SHidetoshi Shimokawa 	asyreq->req.dst.eui = eui;
220a7a73b95SHidetoshi Shimokawa #endif
221a7a73b95SHidetoshi Shimokawa 	asyreq->pkt.mode.rreqq.tlrt = 0;
2223fe9d89aSPhilippe Charnier 	if (readmode)
223a7a73b95SHidetoshi Shimokawa 		asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ;
224a7a73b95SHidetoshi Shimokawa 	else
225a7a73b95SHidetoshi Shimokawa 		asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
226a7a73b95SHidetoshi Shimokawa 
22777ee030bSHidetoshi Shimokawa 	asyreq->pkt.mode.rreqq.dest_hi = 0xffff;
22877ee030bSHidetoshi Shimokawa 	asyreq->pkt.mode.rreqq.dest_lo = addr_lo;
229a7a73b95SHidetoshi Shimokawa 
230a7a73b95SHidetoshi Shimokawa 	qld = (u_int32_t *)&asyreq->pkt;
2313fe9d89aSPhilippe Charnier 	if (!readmode)
232302176c7SHidetoshi Shimokawa 		asyreq->pkt.mode.wreqq.data = htonl(data);
233a7a73b95SHidetoshi Shimokawa 
234a7a73b95SHidetoshi Shimokawa 	if (ioctl(fd, FW_ASYREQ, asyreq) < 0) {
2357f1b527cSSean Bruno        		err(EX_IOERR, "%s: ioctl", __func__);
236a7a73b95SHidetoshi Shimokawa 	}
237a7a73b95SHidetoshi Shimokawa 	res = qld[3];
238a7a73b95SHidetoshi Shimokawa 	free(asyreq);
2393fe9d89aSPhilippe Charnier 	if (readmode)
240a7a73b95SHidetoshi Shimokawa 		return ntohl(res);
241a7a73b95SHidetoshi Shimokawa 	else
242a7a73b95SHidetoshi Shimokawa 		return 0;
243a7a73b95SHidetoshi Shimokawa }
2447ddbf617SHidetoshi Shimokawa 
2457f1b527cSSean Bruno /*
2467f1b527cSSean Bruno  * Send a PHY Config Packet
2477f1b527cSSean Bruno  * ieee 1394a-2005 4.3.4.3
2487f1b527cSSean Bruno  *
2497f1b527cSSean Bruno  * Message ID   Root ID    R  T   Gap Count
2507f1b527cSSean Bruno  * 00(2 bits)   (6 bits)   1  1   (6 bits)
2517f1b527cSSean Bruno  *
2527f1b527cSSean Bruno  * if "R" is set, then Root ID will be the next
2537f1b527cSSean Bruno  * root node upon the next bus reset.
2547f1b527cSSean Bruno  * if "T" is set, then Gap Count will be the
2557f1b527cSSean Bruno  * value that all nodes use for their Gap Count
2567f1b527cSSean Bruno  * if "R" and "T" are not set, then this message
2577f1b527cSSean Bruno  * is either ignored or interpreted as an extended
2587f1b527cSSean Bruno  * PHY config Packet as per 1394a-2005 4.3.4.4
2597f1b527cSSean Bruno  */
2607ddbf617SHidetoshi Shimokawa static void
261a7a73b95SHidetoshi Shimokawa send_phy_config(int fd, int root_node, int gap_count)
262a7a73b95SHidetoshi Shimokawa {
263a7a73b95SHidetoshi Shimokawa         struct fw_asyreq *asyreq;
264a7a73b95SHidetoshi Shimokawa 
265*9494dfe1SJohn Baldwin 	asyreq = malloc(sizeof(*asyreq));
2667f1b527cSSean Bruno 	if (asyreq == NULL)
2677f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:asyreq malloc", __func__);
268a7a73b95SHidetoshi Shimokawa 	asyreq->req.len = 12;
269a7a73b95SHidetoshi Shimokawa 	asyreq->req.type = FWASREQNODE;
270a7a73b95SHidetoshi Shimokawa 	asyreq->pkt.mode.ld[0] = 0;
271a7a73b95SHidetoshi Shimokawa 	asyreq->pkt.mode.ld[1] = 0;
272a7a73b95SHidetoshi Shimokawa 	asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
273a7a73b95SHidetoshi Shimokawa 	if (root_node >= 0)
2747f1b527cSSean Bruno 		asyreq->pkt.mode.ld[1] |= ((root_node << 24) | (1 << 23));
275a7a73b95SHidetoshi Shimokawa 	if (gap_count >= 0)
2767f1b527cSSean Bruno 		asyreq->pkt.mode.ld[1] |= ((1 << 22) | (gap_count << 16));
277a7a73b95SHidetoshi Shimokawa 	asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
278a7a73b95SHidetoshi Shimokawa 
279a7a73b95SHidetoshi Shimokawa 	printf("send phy_config root_node=%d gap_count=%d\n",
280a7a73b95SHidetoshi Shimokawa 						root_node, gap_count);
281a7a73b95SHidetoshi Shimokawa 
2825193feb6SHidetoshi Shimokawa 	if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
2837f1b527cSSean Bruno        		err(EX_IOERR, "%s: ioctl", __func__);
2845193feb6SHidetoshi Shimokawa 	free(asyreq);
285a7a73b95SHidetoshi Shimokawa }
286a7a73b95SHidetoshi Shimokawa 
2877ddbf617SHidetoshi Shimokawa static void
2887f1b527cSSean Bruno link_on(int fd, int node)
289d1f7bcb5SHidetoshi Shimokawa {
290d1f7bcb5SHidetoshi Shimokawa         struct fw_asyreq *asyreq;
291d1f7bcb5SHidetoshi Shimokawa 
292*9494dfe1SJohn Baldwin 	asyreq = malloc(sizeof(*asyreq));
2937f1b527cSSean Bruno 	if (asyreq == NULL)
2947f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:asyreq malloc", __func__);
295d1f7bcb5SHidetoshi Shimokawa 	asyreq->req.len = 12;
296d1f7bcb5SHidetoshi Shimokawa 	asyreq->req.type = FWASREQNODE;
297d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
298d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.ld[1] |= (1 << 30) | ((node & 0x3f) << 24);
299d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
300d1f7bcb5SHidetoshi Shimokawa 
3015193feb6SHidetoshi Shimokawa 	if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
3027f1b527cSSean Bruno        		err(EX_IOERR, "%s: ioctl", __func__);
3035193feb6SHidetoshi Shimokawa 	free(asyreq);
304d1f7bcb5SHidetoshi Shimokawa }
305d1f7bcb5SHidetoshi Shimokawa 
306d1f7bcb5SHidetoshi Shimokawa static void
307d1f7bcb5SHidetoshi Shimokawa reset_start(int fd, int node)
308d1f7bcb5SHidetoshi Shimokawa {
309d1f7bcb5SHidetoshi Shimokawa         struct fw_asyreq *asyreq;
310d1f7bcb5SHidetoshi Shimokawa 
311*9494dfe1SJohn Baldwin 	asyreq = malloc(sizeof(*asyreq));
3127f1b527cSSean Bruno 	if (asyreq == NULL)
3137f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:asyreq malloc", __func__);
314d1f7bcb5SHidetoshi Shimokawa 	asyreq->req.len = 16;
315d1f7bcb5SHidetoshi Shimokawa 	asyreq->req.type = FWASREQNODE;
316d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.wreqq.dst = FWLOCALBUS | (node & 0x3f);
317d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.wreqq.tlrt = 0;
318d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.wreqq.tcode = FWTCODE_WREQQ;
319d1f7bcb5SHidetoshi Shimokawa 
320d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.wreqq.dest_hi = 0xffff;
321d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
322d1f7bcb5SHidetoshi Shimokawa 
323d1f7bcb5SHidetoshi Shimokawa 	asyreq->pkt.mode.wreqq.data = htonl(0x1);
324d1f7bcb5SHidetoshi Shimokawa 
3255193feb6SHidetoshi Shimokawa 	if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
3267f1b527cSSean Bruno        		err(EX_IOERR, "%s: ioctl", __func__);
3275193feb6SHidetoshi Shimokawa 	free(asyreq);
328d1f7bcb5SHidetoshi Shimokawa }
329d1f7bcb5SHidetoshi Shimokawa 
330d1f7bcb5SHidetoshi Shimokawa static void
3316d815a7dSWarner Losh set_pri_req(int fd, u_int32_t pri_req)
332a7a73b95SHidetoshi Shimokawa {
333c547b896SHidetoshi Shimokawa 	struct fw_devlstreq *data;
334c547b896SHidetoshi Shimokawa 	struct fw_devinfo *devinfo;
335cb5df0b2SBrooks Davis 	struct eui64 eui;
336cb5df0b2SBrooks Davis 	char addr[EUI64_SIZ];
337a7a73b95SHidetoshi Shimokawa 	u_int32_t max, reg, old;
338a7a73b95SHidetoshi Shimokawa 	int i;
339a7a73b95SHidetoshi Shimokawa 
3407f1b527cSSean Bruno 	data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
3417f1b527cSSean Bruno 	if (data == NULL)
3427f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:data malloc", __func__);
3437f1b527cSSean Bruno 	get_dev(fd, data);
344a7a73b95SHidetoshi Shimokawa #define BUGET_REG 0xf0000218
345c547b896SHidetoshi Shimokawa 	for (i = 0; i < data->info_len; i++) {
346c547b896SHidetoshi Shimokawa 		devinfo = &data->dev[i];
347c547b896SHidetoshi Shimokawa 		if (!devinfo->status)
348a7a73b95SHidetoshi Shimokawa 			continue;
349c547b896SHidetoshi Shimokawa 		reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0);
350cb5df0b2SBrooks Davis 		fweui2eui64(&devinfo->eui, &eui);
351cb5df0b2SBrooks Davis 		eui64_ntoa(&eui, addr, sizeof(addr));
352cb5df0b2SBrooks Davis 		printf("%d %s, %08x",
353cb5df0b2SBrooks Davis 			devinfo->dst, addr, reg);
3546d815a7dSWarner Losh 		if (reg > 0) {
355a7a73b95SHidetoshi Shimokawa 			old = (reg & 0x3f);
356a7a73b95SHidetoshi Shimokawa 			max = (reg & 0x3f00) >> 8;
357a7a73b95SHidetoshi Shimokawa 			if (pri_req > max)
358a7a73b95SHidetoshi Shimokawa 				pri_req =  max;
359a7a73b95SHidetoshi Shimokawa 			printf(" 0x%x -> 0x%x\n", old, pri_req);
360c547b896SHidetoshi Shimokawa 			read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req);
361a7a73b95SHidetoshi Shimokawa 		} else {
362a7a73b95SHidetoshi Shimokawa 			printf("\n");
363a7a73b95SHidetoshi Shimokawa 		}
364a7a73b95SHidetoshi Shimokawa 	}
365c547b896SHidetoshi Shimokawa 	free((void *)data);
366a7a73b95SHidetoshi Shimokawa }
367a7a73b95SHidetoshi Shimokawa 
3687ddbf617SHidetoshi Shimokawa static void
3696d815a7dSWarner Losh parse_bus_info_block(u_int32_t *p)
370a7a73b95SHidetoshi Shimokawa {
371cb5df0b2SBrooks Davis 	char addr[EUI64_SIZ];
372c6747f0fSHidetoshi Shimokawa 	struct bus_info *bi;
373cb5df0b2SBrooks Davis 	struct eui64 eui;
374a7a73b95SHidetoshi Shimokawa 
375c6747f0fSHidetoshi Shimokawa 	bi = (struct bus_info *)p;
376cb5df0b2SBrooks Davis 	fweui2eui64(&bi->eui64, &eui);
377cb5df0b2SBrooks Davis 	eui64_ntoa(&eui, addr, sizeof(addr));
378c6747f0fSHidetoshi Shimokawa 	printf("bus_name: 0x%04x\n"
379c6747f0fSHidetoshi Shimokawa 		"irmc:%d cmc:%d isc:%d bmc:%d pmc:%d\n"
380c6747f0fSHidetoshi Shimokawa 		"cyc_clk_acc:%d max_rec:%d max_rom:%d\n"
381c6747f0fSHidetoshi Shimokawa 		"generation:%d link_spd:%d\n"
382cb5df0b2SBrooks Davis 		"EUI64: %s\n",
383c6747f0fSHidetoshi Shimokawa 		bi->bus_name,
384c6747f0fSHidetoshi Shimokawa 		bi->irmc, bi->cmc, bi->isc, bi->bmc, bi->pmc,
385c6747f0fSHidetoshi Shimokawa 		bi->cyc_clk_acc, bi->max_rec, bi->max_rom,
386c6747f0fSHidetoshi Shimokawa 		bi->generation, bi->link_spd,
387cb5df0b2SBrooks Davis 		addr);
388a7a73b95SHidetoshi Shimokawa }
389a7a73b95SHidetoshi Shimokawa 
3907ddbf617SHidetoshi Shimokawa static int
391a7a73b95SHidetoshi Shimokawa get_crom(int fd, int node, void *crom_buf, int len)
392a7a73b95SHidetoshi Shimokawa {
393a7a73b95SHidetoshi Shimokawa 	struct fw_crom_buf buf;
394013490c5SHidetoshi Shimokawa 	int i, error;
395c547b896SHidetoshi Shimokawa 	struct fw_devlstreq *data;
396a7a73b95SHidetoshi Shimokawa 
3977f1b527cSSean Bruno 	data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
3987f1b527cSSean Bruno 	if (data == NULL)
3997f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:data malloc", __func__);
4007f1b527cSSean Bruno 	get_dev(fd, data);
401a7a73b95SHidetoshi Shimokawa 
402c547b896SHidetoshi Shimokawa 	for (i = 0; i < data->info_len; i++) {
403c547b896SHidetoshi Shimokawa 		if (data->dev[i].dst == node && data->dev[i].eui.lo != 0)
404a7a73b95SHidetoshi Shimokawa 			break;
405a7a73b95SHidetoshi Shimokawa 	}
406c547b896SHidetoshi Shimokawa 	if (i == data->info_len)
407c547b896SHidetoshi Shimokawa 		errx(1, "no such node %d.", node);
408c547b896SHidetoshi Shimokawa 	else
409c547b896SHidetoshi Shimokawa 		buf.eui = data->dev[i].eui;
410c547b896SHidetoshi Shimokawa 	free((void *)data);
411a7a73b95SHidetoshi Shimokawa 
412a7a73b95SHidetoshi Shimokawa 	buf.len = len;
413a7a73b95SHidetoshi Shimokawa 	buf.ptr = crom_buf;
414cf00a0daSHidetoshi Shimokawa 	bzero(crom_buf, len);
415a7a73b95SHidetoshi Shimokawa 	if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) {
4167f1b527cSSean Bruno        		err(EX_IOERR, "%s: ioctl", __func__);
417a7a73b95SHidetoshi Shimokawa 	}
418c547b896SHidetoshi Shimokawa 
419a7a73b95SHidetoshi Shimokawa 	return error;
420a7a73b95SHidetoshi Shimokawa }
421a7a73b95SHidetoshi Shimokawa 
4227ddbf617SHidetoshi Shimokawa static void
423a7a73b95SHidetoshi Shimokawa show_crom(u_int32_t *crom_buf)
424a7a73b95SHidetoshi Shimokawa {
425a7a73b95SHidetoshi Shimokawa 	int i;
426a7a73b95SHidetoshi Shimokawa 	struct crom_context cc;
427a7a73b95SHidetoshi Shimokawa 	char *desc, info[256];
4283fe9d89aSPhilippe Charnier 	static const char *key_types = "ICLD";
429a7a73b95SHidetoshi Shimokawa 	struct csrreg *reg;
430a7a73b95SHidetoshi Shimokawa 	struct csrdirectory *dir;
431a7a73b95SHidetoshi Shimokawa 	struct csrhdr *hdr;
43277ee030bSHidetoshi Shimokawa 	u_int16_t crc;
433a7a73b95SHidetoshi Shimokawa 
43477ee030bSHidetoshi Shimokawa 	printf("first quad: 0x%08x ", *crom_buf);
4351be7387cSHidetoshi Shimokawa 	if (crom_buf[0] == 0) {
4361be7387cSHidetoshi Shimokawa 		printf("(Invalid Configuration ROM)\n");
4371be7387cSHidetoshi Shimokawa 		return;
4381be7387cSHidetoshi Shimokawa 	}
439a7a73b95SHidetoshi Shimokawa 	hdr = (struct csrhdr *)crom_buf;
440a7a73b95SHidetoshi Shimokawa 	if (hdr->info_len == 1) {
441a7a73b95SHidetoshi Shimokawa 		/* minimum ROM */
442a7a73b95SHidetoshi Shimokawa 		reg = (struct csrreg *)hdr;
443a7a73b95SHidetoshi Shimokawa 		printf("verndor ID: 0x%06x\n",  reg->val);
444a7a73b95SHidetoshi Shimokawa 		return;
445a7a73b95SHidetoshi Shimokawa 	}
44677ee030bSHidetoshi Shimokawa 	printf("info_len=%d crc_len=%d crc=0x%04x",
44777ee030bSHidetoshi Shimokawa 		hdr->info_len, hdr->crc_len, hdr->crc);
44877ee030bSHidetoshi Shimokawa 	crc = crom_crc(crom_buf+1, hdr->crc_len);
44977ee030bSHidetoshi Shimokawa 	if (crc == hdr->crc)
45077ee030bSHidetoshi Shimokawa 		printf("(OK)\n");
45177ee030bSHidetoshi Shimokawa 	else
45277ee030bSHidetoshi Shimokawa 		printf("(NG)\n");
4536d815a7dSWarner Losh 	parse_bus_info_block(crom_buf+1);
454a7a73b95SHidetoshi Shimokawa 
455a7a73b95SHidetoshi Shimokawa 	crom_init_context(&cc, crom_buf);
456a7a73b95SHidetoshi Shimokawa 	dir = cc.stack[0].dir;
4573d7b1b41SDoug Rabson 	if (!dir) {
4583d7b1b41SDoug Rabson 		printf("no root directory - giving up\n");
4593d7b1b41SDoug Rabson 		return;
4603d7b1b41SDoug Rabson 	}
46177ee030bSHidetoshi Shimokawa 	printf("root_directory: len=0x%04x(%d) crc=0x%04x",
462a7a73b95SHidetoshi Shimokawa 			dir->crc_len, dir->crc_len, dir->crc);
46377ee030bSHidetoshi Shimokawa 	crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
46477ee030bSHidetoshi Shimokawa 	if (crc == dir->crc)
46577ee030bSHidetoshi Shimokawa 		printf("(OK)\n");
46677ee030bSHidetoshi Shimokawa 	else
46777ee030bSHidetoshi Shimokawa 		printf("(NG)\n");
4687ddbf617SHidetoshi Shimokawa 	if (dir->crc_len < 1)
4697ddbf617SHidetoshi Shimokawa 		return;
470a7a73b95SHidetoshi Shimokawa 	while (cc.depth >= 0) {
471a7a73b95SHidetoshi Shimokawa 		desc = crom_desc(&cc, info, sizeof(info));
472a7a73b95SHidetoshi Shimokawa 		reg = crom_get(&cc);
473a7a73b95SHidetoshi Shimokawa 		for (i = 0; i < cc.depth; i++)
474a7a73b95SHidetoshi Shimokawa 			printf("\t");
475a7a73b95SHidetoshi Shimokawa 		printf("%02x(%c:%02x) %06x %s: %s\n",
476a7a73b95SHidetoshi Shimokawa 			reg->key,
477a7a73b95SHidetoshi Shimokawa 			key_types[(reg->key & CSRTYPE_MASK)>>6],
478a7a73b95SHidetoshi Shimokawa 			reg->key & CSRKEY_MASK, reg->val,
479a7a73b95SHidetoshi Shimokawa 			desc, info);
480a7a73b95SHidetoshi Shimokawa 		crom_next(&cc);
481a7a73b95SHidetoshi Shimokawa 	}
482a7a73b95SHidetoshi Shimokawa }
483a7a73b95SHidetoshi Shimokawa 
484a7a73b95SHidetoshi Shimokawa #define DUMP_FORMAT	"%08x %08x %08x %08x %08x %08x %08x %08x\n"
485a7a73b95SHidetoshi Shimokawa 
4867ddbf617SHidetoshi Shimokawa static void
487a7a73b95SHidetoshi Shimokawa dump_crom(u_int32_t *p)
488a7a73b95SHidetoshi Shimokawa {
489a7a73b95SHidetoshi Shimokawa 	int len=1024, i;
490a7a73b95SHidetoshi Shimokawa 
491a7a73b95SHidetoshi Shimokawa 	for (i = 0; i < len/(4*8); i ++) {
492a7a73b95SHidetoshi Shimokawa 		printf(DUMP_FORMAT,
493a7a73b95SHidetoshi Shimokawa 			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
494a7a73b95SHidetoshi Shimokawa 		p += 8;
495a7a73b95SHidetoshi Shimokawa 	}
496a7a73b95SHidetoshi Shimokawa }
497a7a73b95SHidetoshi Shimokawa 
4987ddbf617SHidetoshi Shimokawa static void
499a7a73b95SHidetoshi Shimokawa load_crom(char *filename, u_int32_t *p)
500a7a73b95SHidetoshi Shimokawa {
501a7a73b95SHidetoshi Shimokawa 	FILE *file;
502a7a73b95SHidetoshi Shimokawa 	int len=1024, i;
503a7a73b95SHidetoshi Shimokawa 
504a7a73b95SHidetoshi Shimokawa 	if ((file = fopen(filename, "r")) == NULL)
505c1de48a3SSean Bruno 	  err(1, "load_crom %s", filename);
506a7a73b95SHidetoshi Shimokawa 	for (i = 0; i < len/(4*8); i ++) {
507a7a73b95SHidetoshi Shimokawa 		fscanf(file, DUMP_FORMAT,
508a7a73b95SHidetoshi Shimokawa 			p, p+1, p+2, p+3, p+4, p+5, p+6, p+7);
509a7a73b95SHidetoshi Shimokawa 		p += 8;
510a7a73b95SHidetoshi Shimokawa 	}
511f55df2a2SKevin Lo 	fclose(file);
512a7a73b95SHidetoshi Shimokawa }
513a7a73b95SHidetoshi Shimokawa 
514a7a73b95SHidetoshi Shimokawa static void
515a7a73b95SHidetoshi Shimokawa show_topology_map(int fd)
516a7a73b95SHidetoshi Shimokawa {
517a7a73b95SHidetoshi Shimokawa 	struct fw_topology_map *tmap;
518a7a73b95SHidetoshi Shimokawa 	union fw_self_id sid;
519a7a73b95SHidetoshi Shimokawa 	int i;
5203fe9d89aSPhilippe Charnier 	static const char *port_status[] = {" ", "-", "P", "C"};
5213fe9d89aSPhilippe Charnier 	static const char *pwr_class[] = {" 0W", "15W", "30W", "45W",
522a7a73b95SHidetoshi Shimokawa 					"-1W", "-2W", "-5W", "-9W"};
5233fe9d89aSPhilippe Charnier 	static const char *speed[] = {"S100", "S200", "S400", "S800"};
524a7a73b95SHidetoshi Shimokawa 	tmap = malloc(sizeof(struct fw_topology_map));
525a7a73b95SHidetoshi Shimokawa 	if (tmap == NULL)
5267f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:tmap malloc", __func__);
527a7a73b95SHidetoshi Shimokawa 	if (ioctl(fd, FW_GTPMAP, tmap) < 0) {
5287f1b527cSSean Bruno        		err(EX_IOERR, "%s: ioctl", __func__);
529a7a73b95SHidetoshi Shimokawa 	}
530a7a73b95SHidetoshi Shimokawa 	printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n",
531a7a73b95SHidetoshi Shimokawa 		tmap->crc_len, tmap->generation,
532a7a73b95SHidetoshi Shimokawa 		tmap->node_count, tmap->self_id_count);
533a7a73b95SHidetoshi Shimokawa 	printf("id link gap_cnt speed delay cIRM power port0 port1 port2"
534a7a73b95SHidetoshi Shimokawa 		" ini more\n");
535a7a73b95SHidetoshi Shimokawa 	for (i = 0; i < tmap->crc_len - 2; i++) {
536a7a73b95SHidetoshi Shimokawa 		sid = tmap->self_id[i];
537a7a73b95SHidetoshi Shimokawa 		if (sid.p0.sequel) {
538a7a73b95SHidetoshi Shimokawa 			printf("%02d sequel packet\n", sid.p0.phy_id);
539a7a73b95SHidetoshi Shimokawa 			continue;
540a7a73b95SHidetoshi Shimokawa 		}
541cde9186fSSean Bruno 		printf("%02d   %2d      %2d  %4s     %d   %3s"
542a7a73b95SHidetoshi Shimokawa 				"     %s     %s     %s   %d    %d\n",
543a7a73b95SHidetoshi Shimokawa 			sid.p0.phy_id,
544a7a73b95SHidetoshi Shimokawa 			sid.p0.link_active,
545a7a73b95SHidetoshi Shimokawa 			sid.p0.gap_count,
546a7a73b95SHidetoshi Shimokawa 			speed[sid.p0.phy_speed],
547a7a73b95SHidetoshi Shimokawa 			sid.p0.contender,
548a7a73b95SHidetoshi Shimokawa 			pwr_class[sid.p0.power_class],
549a7a73b95SHidetoshi Shimokawa 			port_status[sid.p0.port0],
550a7a73b95SHidetoshi Shimokawa 			port_status[sid.p0.port1],
551a7a73b95SHidetoshi Shimokawa 			port_status[sid.p0.port2],
552a7a73b95SHidetoshi Shimokawa 			sid.p0.initiated_reset,
553a7a73b95SHidetoshi Shimokawa 			sid.p0.more_packets
554a7a73b95SHidetoshi Shimokawa 		);
555a7a73b95SHidetoshi Shimokawa 	}
556a7a73b95SHidetoshi Shimokawa 	free(tmap);
557a7a73b95SHidetoshi Shimokawa }
558a7a73b95SHidetoshi Shimokawa 
559abd538f2SHidetoshi Shimokawa static void
560a8587980SHidetoshi Shimokawa read_phy_registers(int fd, u_int8_t *buf, int offset, int len)
561a8587980SHidetoshi Shimokawa {
562a8587980SHidetoshi Shimokawa 	struct fw_reg_req_t reg;
563a8587980SHidetoshi Shimokawa 	int i;
564a8587980SHidetoshi Shimokawa 
565a8587980SHidetoshi Shimokawa 	for (i = 0; i < len; i++) {
566a8587980SHidetoshi Shimokawa 		reg.addr = offset + i;
567a8587980SHidetoshi Shimokawa 		if (ioctl(fd, FWOHCI_RDPHYREG, &reg) < 0)
5687f1b527cSSean Bruno        			err(EX_IOERR, "%s: ioctl", __func__);
569a8587980SHidetoshi Shimokawa 		buf[i] = (u_int8_t) reg.data;
570a8587980SHidetoshi Shimokawa 		printf("0x%02x ",  reg.data);
571a8587980SHidetoshi Shimokawa 	}
572a8587980SHidetoshi Shimokawa 	printf("\n");
573a8587980SHidetoshi Shimokawa }
574a8587980SHidetoshi Shimokawa 
575a8587980SHidetoshi Shimokawa static void
576a8587980SHidetoshi Shimokawa read_phy_page(int fd, u_int8_t *buf, int page, int port)
577a8587980SHidetoshi Shimokawa {
578a8587980SHidetoshi Shimokawa 	struct fw_reg_req_t reg;
579a8587980SHidetoshi Shimokawa 
580a8587980SHidetoshi Shimokawa 	reg.addr = 0x7;
581a8587980SHidetoshi Shimokawa 	reg.data = ((page & 7) << 5) | (port & 0xf);
582a8587980SHidetoshi Shimokawa 	if (ioctl(fd, FWOHCI_WRPHYREG, &reg) < 0)
5837f1b527cSSean Bruno        		err(EX_IOERR, "%s: ioctl", __func__);
584a8587980SHidetoshi Shimokawa 	read_phy_registers(fd, buf, 8, 8);
585a8587980SHidetoshi Shimokawa }
586a8587980SHidetoshi Shimokawa 
587a8587980SHidetoshi Shimokawa static void
588a8587980SHidetoshi Shimokawa dump_phy_registers(int fd)
589a8587980SHidetoshi Shimokawa {
590a8587980SHidetoshi Shimokawa 	struct phyreg_base b;
591a8587980SHidetoshi Shimokawa 	struct phyreg_page0 p;
592a8587980SHidetoshi Shimokawa 	struct phyreg_page1 v;
593a8587980SHidetoshi Shimokawa 	int i;
594a8587980SHidetoshi Shimokawa 
595a8587980SHidetoshi Shimokawa 	printf("=== base register ===\n");
596a8587980SHidetoshi Shimokawa 	read_phy_registers(fd, (u_int8_t *)&b, 0, 8);
597a8587980SHidetoshi Shimokawa 	printf(
598a8587980SHidetoshi Shimokawa 	    "Physical_ID:%d  R:%d  CPS:%d\n"
599a8587980SHidetoshi Shimokawa 	    "RHB:%d  IBR:%d  Gap_Count:%d\n"
600a8587980SHidetoshi Shimokawa 	    "Extended:%d Num_Ports:%d\n"
601a8587980SHidetoshi Shimokawa 	    "PHY_Speed:%d Delay:%d\n"
602a8587980SHidetoshi Shimokawa 	    "LCtrl:%d C:%d Jitter:%d Pwr_Class:%d\n"
603a8587980SHidetoshi Shimokawa 	    "WDIE:%d ISBR:%d CTOI:%d CPSI:%d STOI:%d PEI:%d EAA:%d EMC:%d\n"
604a8587980SHidetoshi Shimokawa 	    "Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n"
605a8587980SHidetoshi Shimokawa 	    "Page_Select:%d Port_Select%d\n",
606a8587980SHidetoshi Shimokawa 	    b.phy_id, b.r, b.cps,
607a8587980SHidetoshi Shimokawa 	    b.rhb, b.ibr, b.gap_count,
608a8587980SHidetoshi Shimokawa 	    b.extended, b.num_ports,
609a8587980SHidetoshi Shimokawa 	    b.phy_speed, b.delay,
610a8587980SHidetoshi Shimokawa 	    b.lctrl, b.c, b.jitter, b.pwr_class,
611a8587980SHidetoshi Shimokawa 	    b.wdie, b.isbr, b.ctoi, b.cpsi, b.stoi, b.pei, b.eaa, b.emc,
612a8587980SHidetoshi Shimokawa 	    b.legacy_spd, b.blink, b.bridge,
613a8587980SHidetoshi Shimokawa 	    b.page_select, b.port_select
614a8587980SHidetoshi Shimokawa 	);
615a8587980SHidetoshi Shimokawa 
616a8587980SHidetoshi Shimokawa 	for (i = 0; i < b.num_ports; i ++) {
617a8587980SHidetoshi Shimokawa 		printf("\n=== page 0 port %d ===\n", i);
618a8587980SHidetoshi Shimokawa 		read_phy_page(fd, (u_int8_t *)&p, 0, i);
619a8587980SHidetoshi Shimokawa 		printf(
620a8587980SHidetoshi Shimokawa 		    "Astat:%d BStat:%d Ch:%d Con:%d RXOK:%d Dis:%d\n"
621a8587980SHidetoshi Shimokawa 		    "Negotiated_speed:%d PIE:%d Fault:%d Stanby_fault:%d Disscrm:%d B_Only:%d\n"
622a8587980SHidetoshi Shimokawa 		    "DC_connected:%d Max_port_speed:%d LPP:%d Cable_speed:%d\n"
623a8587980SHidetoshi Shimokawa 		    "Connection_unreliable:%d Beta_mode:%d\n"
624a8587980SHidetoshi Shimokawa 		    "Port_error:0x%x\n"
625a8587980SHidetoshi Shimokawa 		    "Loop_disable:%d In_standby:%d Hard_disable:%d\n",
626a8587980SHidetoshi Shimokawa 		    p.astat, p.bstat, p.ch, p.con, p.rxok, p.dis,
627a8587980SHidetoshi Shimokawa 		    p.negotiated_speed, p.pie, p.fault, p.stanby_fault, p.disscrm, p.b_only,
628a8587980SHidetoshi Shimokawa 		    p.dc_connected, p.max_port_speed, p.lpp, p.cable_speed,
629a8587980SHidetoshi Shimokawa 		    p.connection_unreliable, p.beta_mode,
630a8587980SHidetoshi Shimokawa 		    p.port_error,
631a8587980SHidetoshi Shimokawa 		    p.loop_disable, p.in_standby, p.hard_disable
632a8587980SHidetoshi Shimokawa 		);
633a8587980SHidetoshi Shimokawa 	}
634a8587980SHidetoshi Shimokawa 	printf("\n=== page 1 ===\n");
635a8587980SHidetoshi Shimokawa 	read_phy_page(fd, (u_int8_t *)&v, 1, 0);
636a8587980SHidetoshi Shimokawa 	printf(
637a8587980SHidetoshi Shimokawa 	    "Compliance:%d\n"
638a8587980SHidetoshi Shimokawa 	    "Vendor_ID:0x%06x\n"
639a8587980SHidetoshi Shimokawa 	    "Product_ID:0x%06x\n",
640a8587980SHidetoshi Shimokawa 	    v.compliance,
641a8587980SHidetoshi Shimokawa 	    (v.vendor_id[0] << 16) | (v.vendor_id[1] << 8) | v.vendor_id[2],
642a8587980SHidetoshi Shimokawa 	    (v.product_id[0] << 16) | (v.product_id[1] << 8) | v.product_id[2]
643a8587980SHidetoshi Shimokawa 	);
644a8587980SHidetoshi Shimokawa }
645a8587980SHidetoshi Shimokawa 
6467f1b527cSSean Bruno static int
6477f1b527cSSean Bruno open_dev(int *fd, char *devname)
648abd538f2SHidetoshi Shimokawa {
649abd538f2SHidetoshi Shimokawa 	if (*fd < 0) {
6507f1b527cSSean Bruno 		*fd = open(devname, O_RDWR);
651abd538f2SHidetoshi Shimokawa 		if (*fd < 0)
6527f1b527cSSean Bruno 			return(-1);
653abd538f2SHidetoshi Shimokawa 
654abd538f2SHidetoshi Shimokawa 	}
6557f1b527cSSean Bruno 	return(0);
656abd538f2SHidetoshi Shimokawa }
657abd538f2SHidetoshi Shimokawa 
6586d815a7dSWarner Losh static void
6593fe9d89aSPhilippe Charnier sysctl_set_int(const char *name, int val)
6601be7387cSHidetoshi Shimokawa {
6611be7387cSHidetoshi Shimokawa 	if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0)
6621be7387cSHidetoshi Shimokawa 		err(1, "sysctl %s failed.", name);
6631be7387cSHidetoshi Shimokawa }
6641be7387cSHidetoshi Shimokawa 
6656d815a7dSWarner Losh static fwmethod *
6666d815a7dSWarner Losh detect_recv_fn(int fd, char ich)
6676d815a7dSWarner Losh {
6686d815a7dSWarner Losh 	char *buf;
6696d815a7dSWarner Losh 	struct fw_isochreq isoreq;
6706d815a7dSWarner Losh 	struct fw_isobufreq bufreq;
6716d815a7dSWarner Losh 	int len;
6726d815a7dSWarner Losh 	u_int32_t *ptr;
6736d815a7dSWarner Losh 	struct ciphdr *ciph;
6746d815a7dSWarner Losh 	fwmethod *retfn;
6757f1b527cSSean Bruno #define RECV_NUM_PACKET 16
6767f1b527cSSean Bruno #define RECV_PACKET_SZ  1024
6776d815a7dSWarner Losh 
6786d815a7dSWarner Losh 	bufreq.rx.nchunk = 8;
6797f1b527cSSean Bruno 	bufreq.rx.npacket = RECV_NUM_PACKET;
6807f1b527cSSean Bruno 	bufreq.rx.psize = RECV_PACKET_SZ;
6816d815a7dSWarner Losh 	bufreq.tx.nchunk = 0;
6826d815a7dSWarner Losh 	bufreq.tx.npacket = 0;
6836d815a7dSWarner Losh 	bufreq.tx.psize = 0;
6846d815a7dSWarner Losh 
6856d815a7dSWarner Losh 	if (ioctl(fd, FW_SSTBUF, &bufreq) < 0)
6867f1b527cSSean Bruno 		err(EX_IOERR, "%s: ioctl FW_SSTBUF", __func__);
6876d815a7dSWarner Losh 
6886d815a7dSWarner Losh 	isoreq.ch = ich & 0x3f;
6896d815a7dSWarner Losh 	isoreq.tag = (ich >> 6) & 3;
6906d815a7dSWarner Losh 
6916d815a7dSWarner Losh 	if (ioctl(fd, FW_SRSTREAM, &isoreq) < 0)
6927f1b527cSSean Bruno 		err(EX_IOERR, "%s: ioctl FW_SRSTREAM", __func__);
6936d815a7dSWarner Losh 
6947f1b527cSSean Bruno 	buf = (char *)malloc(RECV_NUM_PACKET * RECV_PACKET_SZ);
6957f1b527cSSean Bruno 	if (buf == NULL)
6967f1b527cSSean Bruno 		err(EX_SOFTWARE, "%s:buf malloc", __func__);
6977f1b527cSSean Bruno 	/*
6987f1b527cSSean Bruno 	 * fwdev.c seems to return EIO on error and
6997f1b527cSSean Bruno 	 * the return value of the last uiomove
7007f1b527cSSean Bruno 	 * on success.  For now, checking that the
7017f1b527cSSean Bruno 	 * return is not less than zero should be
7027f1b527cSSean Bruno 	 * sufficient.  fwdev.c::fw_read() should
7037f1b527cSSean Bruno 	 * return the total length read, not the value
7047f1b527cSSean Bruno 	 * of the last uiomove().
7057f1b527cSSean Bruno 	 */
7067f1b527cSSean Bruno 	len = read(fd, buf, RECV_NUM_PACKET * RECV_PACKET_SZ);
7077f1b527cSSean Bruno 	if (len < 0)
708c1de48a3SSean Bruno 		err(EX_IOERR, "%s: error reading from device", __func__);
7096d815a7dSWarner Losh 	ptr = (u_int32_t *) buf;
7106d815a7dSWarner Losh 	ciph = (struct ciphdr *)(ptr + 1);
7116d815a7dSWarner Losh 
7126d815a7dSWarner Losh 	switch(ciph->fmt) {
7136d815a7dSWarner Losh 		case CIP_FMT_DVCR:
7146d815a7dSWarner Losh 			fprintf(stderr, "Detected DV format on input.\n");
7156d815a7dSWarner Losh 			retfn = dvrecv;
7166d815a7dSWarner Losh 			break;
7176d815a7dSWarner Losh 		case CIP_FMT_MPEG:
7186d815a7dSWarner Losh 			fprintf(stderr, "Detected MPEG TS format on input.\n");
7196d815a7dSWarner Losh 			retfn = mpegtsrecv;
7206d815a7dSWarner Losh 			break;
7216d815a7dSWarner Losh 		default:
7226d815a7dSWarner Losh 			errx(1, "Unsupported format for receiving: fmt=0x%x", ciph->fmt);
7236d815a7dSWarner Losh 	}
7246d815a7dSWarner Losh 	free(buf);
7256d815a7dSWarner Losh 	return retfn;
7266d815a7dSWarner Losh }
7276d815a7dSWarner Losh 
7281be7387cSHidetoshi Shimokawa int
729a7a73b95SHidetoshi Shimokawa main(int argc, char **argv)
730a7a73b95SHidetoshi Shimokawa {
7317f1b527cSSean Bruno #define MAX_BOARDS 10
732a7a73b95SHidetoshi Shimokawa 	u_int32_t crom_buf[1024/4];
7337f1b527cSSean Bruno 	u_int32_t crom_buf_hex[1024/4];
7347f1b527cSSean Bruno 	char devbase[64];
7357f1b527cSSean Bruno 	const char *device_string = "/dev/fw";
7367f1b527cSSean Bruno 	int fd = -1, ch, len=1024;
7377f1b527cSSean Bruno 	int32_t current_board = 0;
7387f1b527cSSean Bruno  /*
7397f1b527cSSean Bruno   * If !command_set, then -u will display the nodes for the board.
7407f1b527cSSean Bruno   * This emulates the previous behavior when -u is passed by itself
7417f1b527cSSean Bruno   */
7427f1b527cSSean Bruno 	bool command_set = false;
7437f1b527cSSean Bruno 	bool open_needed = false;
7446d815a7dSWarner Losh 	long tmp;
7451be7387cSHidetoshi Shimokawa 	struct fw_eui64 eui;
7461be7387cSHidetoshi Shimokawa 	struct eui64 target;
7476d815a7dSWarner Losh 	fwmethod *recvfn = NULL;
7487f1b527cSSean Bruno /*
7497f1b527cSSean Bruno  * Holders for which functions
7507f1b527cSSean Bruno  * to iterate through
7517f1b527cSSean Bruno  */
7527f1b527cSSean Bruno 	bool display_board_only = false;
7537f1b527cSSean Bruno 	bool display_crom = false;
7547f1b527cSSean Bruno 	bool send_bus_reset = false;
7557f1b527cSSean Bruno 	bool display_crom_hex = false;
7567f1b527cSSean Bruno 	bool load_crom_from_file = false;
7577f1b527cSSean Bruno 	bool set_fwmem_target = false;
7587f1b527cSSean Bruno 	bool dump_topology = false;
7597f1b527cSSean Bruno 	bool dump_phy_reg = false;
760a7a73b95SHidetoshi Shimokawa 
7617f1b527cSSean Bruno 	int32_t priority_budget = -1;
7627f1b527cSSean Bruno 	int32_t set_root_node = -1;
7637f1b527cSSean Bruno 	int32_t set_gap_count = -1;
7647f1b527cSSean Bruno 	int32_t send_link_on = -1;
7657f1b527cSSean Bruno 	int32_t send_reset_start = -1;
7667f1b527cSSean Bruno 
7677f1b527cSSean Bruno 	char *crom_string = NULL;
7687f1b527cSSean Bruno 	char *crom_string_hex = NULL;
7697f1b527cSSean Bruno 	char *recv_data = NULL;
7707f1b527cSSean Bruno 	char *send_data = NULL;
771a7a73b95SHidetoshi Shimokawa 
772a7a73b95SHidetoshi Shimokawa 	if (argc < 2) {
7737f1b527cSSean Bruno 		for (current_board = 0; current_board < MAX_BOARDS; current_board++) {
774c1de48a3SSean Bruno 			snprintf(devbase, sizeof(devbase), "%s%d.0", device_string, current_board);
7757f1b527cSSean Bruno 			if (open_dev(&fd, devbase) < 0) {
7767f1b527cSSean Bruno 				if (current_board == 0) {
7777f1b527cSSean Bruno 					usage();
778c1de48a3SSean Bruno 		  			err(EX_IOERR, "%s: Error opening firewire controller #%d %s",
779c1de48a3SSean Bruno 						      __func__, current_board, devbase);
780a7a73b95SHidetoshi Shimokawa 				}
7817f1b527cSSean Bruno 				return(EIO);
7827f1b527cSSean Bruno 			}
7837f1b527cSSean Bruno 			list_dev(fd);
784abd538f2SHidetoshi Shimokawa 			close(fd);
785abd538f2SHidetoshi Shimokawa 			fd = -1;
786abd538f2SHidetoshi Shimokawa 		}
787abd538f2SHidetoshi Shimokawa 	}
7887f1b527cSSean Bruno        /*
7897f1b527cSSean Bruno 	* Parse all command line options, then execute requested operations.
7907f1b527cSSean Bruno 	*/
7917f1b527cSSean Bruno 	while ((ch = getopt(argc, argv, "M:f:g:m:o:s:b:prtc:d:l:u:R:S:")) != -1) {
7927f1b527cSSean Bruno 		switch(ch) {
7937f1b527cSSean Bruno 		case 'b':
7947f1b527cSSean Bruno 			priority_budget = strtol(optarg, NULL, 0);
7957f1b527cSSean Bruno 			if (priority_budget < 0 || priority_budget > INT32_MAX)
796c1de48a3SSean Bruno 				errx(EX_USAGE, "%s: priority_budget out of range: %s", __func__, optarg);
7977f1b527cSSean Bruno 			command_set = true;
7987f1b527cSSean Bruno 			open_needed = true;
7997f1b527cSSean Bruno 			display_board_only = false;
800abd538f2SHidetoshi Shimokawa 			break;
8017f1b527cSSean Bruno 		case 'c':
8027f1b527cSSean Bruno 			crom_string = malloc(strlen(optarg)+1);
8037f1b527cSSean Bruno 			if (crom_string == NULL)
8047f1b527cSSean Bruno 				err(EX_SOFTWARE, "%s:crom_string malloc", __func__);
8057f1b527cSSean Bruno 			if ( (strtol(crom_string, NULL, 0) < 0) || strtol(crom_string, NULL, 0) > MAX_BOARDS)
806c1de48a3SSean Bruno 				errx(EX_USAGE, "%s:Invalid value for node", __func__);
8077f1b527cSSean Bruno 			strcpy(crom_string, optarg);
8087f1b527cSSean Bruno 			display_crom = 1;
8097f1b527cSSean Bruno 			open_needed = true;
8107f1b527cSSean Bruno 			command_set = true;
8117f1b527cSSean Bruno 			display_board_only = false;
8127f1b527cSSean Bruno 			break;
8137f1b527cSSean Bruno 		case 'd':
8147f1b527cSSean Bruno 			crom_string_hex = malloc(strlen(optarg)+1);
8157f1b527cSSean Bruno 			if (crom_string_hex == NULL)
8167f1b527cSSean Bruno 				err(EX_SOFTWARE, "%s:crom_string_hex malloc", __func__);
8177f1b527cSSean Bruno 			strcpy(crom_string_hex, optarg);
8187f1b527cSSean Bruno 			display_crom_hex = 1;
8197f1b527cSSean Bruno 			open_needed = true;
8207f1b527cSSean Bruno 			command_set = true;
8217f1b527cSSean Bruno 			display_board_only = false;
8227f1b527cSSean Bruno 			break;
8237f1b527cSSean Bruno 		case 'f':
8247f1b527cSSean Bruno #define MAX_PHY_CONFIG 0x3f
8257f1b527cSSean Bruno 			set_root_node = strtol(optarg, NULL, 0);
8267f1b527cSSean Bruno 			if ( (set_root_node < 0) || (set_root_node > MAX_PHY_CONFIG) )
827c1de48a3SSean Bruno 				errx(EX_USAGE, "%s:set_root_node out of range", __func__);
8287f1b527cSSean Bruno 			open_needed = true;
8297f1b527cSSean Bruno 			command_set = true;
8307f1b527cSSean Bruno 			display_board_only = false;
8317f1b527cSSean Bruno 			break;
8327f1b527cSSean Bruno 		case 'g':
8337f1b527cSSean Bruno 			set_gap_count = strtol(optarg, NULL, 0);
8347f1b527cSSean Bruno 			if ( (set_gap_count < 0) || (set_gap_count > MAX_PHY_CONFIG) )
835c1de48a3SSean Bruno 				errx(EX_USAGE, "%s:set_gap_count out of range", __func__);
8367f1b527cSSean Bruno 			open_needed = true;
8377f1b527cSSean Bruno 			command_set = true;
8387f1b527cSSean Bruno 			display_board_only = false;
8397f1b527cSSean Bruno 			break;
8407f1b527cSSean Bruno 		case 'l':
8417f1b527cSSean Bruno 			load_crom_from_file = 1;
8427f1b527cSSean Bruno 			load_crom(optarg, crom_buf);
8437f1b527cSSean Bruno 			command_set = true;
8447f1b527cSSean Bruno 			display_board_only = false;
8457f1b527cSSean Bruno 			break;
8467f1b527cSSean Bruno 		case 'm':
8477f1b527cSSean Bruno 			set_fwmem_target = 1;
8487f1b527cSSean Bruno 			open_needed = 0;
8497f1b527cSSean Bruno 			command_set = true;
8507f1b527cSSean Bruno 			display_board_only = false;
8517f1b527cSSean Bruno 			if (eui64_hostton(optarg, &target) != 0 &&
8527f1b527cSSean Bruno 			    eui64_aton(optarg, &target) != 0)
853c1de48a3SSean Bruno 				errx(EX_USAGE, "%s: invalid target: %s", __func__, optarg);
8547f1b527cSSean Bruno 			break;
8557f1b527cSSean Bruno 		case 'o':
8567f1b527cSSean Bruno 			send_link_on = str2node(fd, optarg);
857c1de48a3SSean Bruno 			if ( (send_link_on < 0) || (send_link_on > MAX_PHY_CONFIG) )
858c1de48a3SSean Bruno 				errx(EX_USAGE, "%s: node out of range: %s\n",__func__, optarg);
8597f1b527cSSean Bruno 			open_needed = true;
8607f1b527cSSean Bruno 			command_set = true;
8617f1b527cSSean Bruno 			display_board_only = false;
8627f1b527cSSean Bruno 			break;
8637f1b527cSSean Bruno 		case 'p':
8647f1b527cSSean Bruno 			dump_phy_reg = 1;
8657f1b527cSSean Bruno 			open_needed = true;
8667f1b527cSSean Bruno 			command_set = true;
8677f1b527cSSean Bruno 			display_board_only = false;
8687f1b527cSSean Bruno 			break;
8697f1b527cSSean Bruno 		case 'r':
8707f1b527cSSean Bruno 			send_bus_reset = 1;
8717f1b527cSSean Bruno 			open_needed = true;
8727f1b527cSSean Bruno 			command_set = true;
8737f1b527cSSean Bruno 			display_board_only = false;
8747f1b527cSSean Bruno 			break;
8757f1b527cSSean Bruno 		case 's':
8767f1b527cSSean Bruno 			send_reset_start  = str2node(fd, optarg);
877c1de48a3SSean Bruno 			if ( (send_reset_start < 0) || (send_reset_start > MAX_PHY_CONFIG) )
878c1de48a3SSean Bruno 				errx(EX_USAGE, "%s: node out of range: %s\n", __func__, optarg);
8797f1b527cSSean Bruno 			open_needed = true;
8807f1b527cSSean Bruno 			command_set = true;
8817f1b527cSSean Bruno 			display_board_only = false;
8827f1b527cSSean Bruno 			break;
8837f1b527cSSean Bruno 		case 't':
8847f1b527cSSean Bruno 			dump_topology = 1;
8857f1b527cSSean Bruno 			open_needed = true;
8867f1b527cSSean Bruno 			command_set = true;
8877f1b527cSSean Bruno 			display_board_only = false;
8887f1b527cSSean Bruno 			break;
8897f1b527cSSean Bruno 		case 'u':
8907f1b527cSSean Bruno 			if(!command_set)
8917f1b527cSSean Bruno 				display_board_only = true;
8927f1b527cSSean Bruno 			current_board = strtol(optarg, NULL, 0);
8937f1b527cSSean Bruno 			open_needed = true;
8947f1b527cSSean Bruno 			break;
8956d815a7dSWarner Losh 		case 'M':
8966d815a7dSWarner Losh 			switch (optarg[0]) {
8976d815a7dSWarner Losh 			case 'm':
8986d815a7dSWarner Losh 				recvfn = mpegtsrecv;
8996d815a7dSWarner Losh 				break;
9006d815a7dSWarner Losh 			case 'd':
9016d815a7dSWarner Losh 				recvfn = dvrecv;
9026d815a7dSWarner Losh 				break;
9036d815a7dSWarner Losh 			default:
9046d815a7dSWarner Losh 				errx(EX_USAGE, "unrecognized method: %s",
9056d815a7dSWarner Losh 				    optarg);
9066d815a7dSWarner Losh 			}
9077f1b527cSSean Bruno 			command_set = true;
9087f1b527cSSean Bruno 			display_board_only = false;
9096d815a7dSWarner Losh 			break;
910937bcaa8SHidetoshi Shimokawa 		case 'R':
9117f1b527cSSean Bruno 			recv_data = malloc(strlen(optarg)+1);
9127f1b527cSSean Bruno 			if (recv_data == NULL)
9137f1b527cSSean Bruno 				err(EX_SOFTWARE, "%s:recv_data malloc", __func__);
9147f1b527cSSean Bruno 			strcpy(recv_data, optarg);
9157f1b527cSSean Bruno 			open_needed = false;
9167f1b527cSSean Bruno 			command_set = true;
9177f1b527cSSean Bruno 			display_board_only = false;
918937bcaa8SHidetoshi Shimokawa 			break;
919937bcaa8SHidetoshi Shimokawa 		case 'S':
9207f1b527cSSean Bruno 			send_data = malloc(strlen(optarg)+1);
9217f1b527cSSean Bruno 			if (send_data == NULL)
9227f1b527cSSean Bruno 				err(EX_SOFTWARE, "%s:send_data malloc", __func__);
9237f1b527cSSean Bruno 			strcpy(send_data, optarg);
9247f1b527cSSean Bruno 			open_needed = true;
9257f1b527cSSean Bruno 			command_set = true;
9267f1b527cSSean Bruno 			display_board_only = false;
927937bcaa8SHidetoshi Shimokawa 			break;
928c1de48a3SSean Bruno 		case '?':
929a7a73b95SHidetoshi Shimokawa 		default:
930a7a73b95SHidetoshi Shimokawa 			usage();
931c1de48a3SSean Bruno 		        warnc(EINVAL, "%s: Unknown command line arguments", __func__);
9327f1b527cSSean Bruno 			return 0;
9337f1b527cSSean Bruno 		}
9347f1b527cSSean Bruno 	} /* end while */
9357f1b527cSSean Bruno 
9367f1b527cSSean Bruno        /*
937c1de48a3SSean Bruno 	* Catch the error case when the user
938c1de48a3SSean Bruno 	* executes the command with non ''-''
939c1de48a3SSean Bruno 	* delimited arguments.
940c1de48a3SSean Bruno 	* Generate the usage() display and exit.
941c1de48a3SSean Bruno 	*/
942c1de48a3SSean Bruno 	if (!command_set && !display_board_only) {
943c1de48a3SSean Bruno 		usage();
944c1de48a3SSean Bruno 		warnc(EINVAL, "%s: Unknown command line arguments", __func__);
945c1de48a3SSean Bruno 		return 0;
946c1de48a3SSean Bruno 	}
947c1de48a3SSean Bruno 
948c1de48a3SSean Bruno        /*
9497f1b527cSSean Bruno 	* If -u <bus_number> is passed, execute
9507f1b527cSSean Bruno 	* command for that card only.
9517f1b527cSSean Bruno 	*
9527f1b527cSSean Bruno 	* If -u <bus_number> is not passed, execute
9537f1b527cSSean Bruno 	* command for card 0 only.
9547f1b527cSSean Bruno 	*
9557f1b527cSSean Bruno 	*/
9567f1b527cSSean Bruno 	if(open_needed){
957c1de48a3SSean Bruno 		snprintf(devbase, sizeof(devbase), "%s%d.0", device_string, current_board);
9587f1b527cSSean Bruno 		if (open_dev(&fd, devbase) < 0) {
959c1de48a3SSean Bruno 		  err(EX_IOERR, "%s: Error opening firewire controller #%d %s", __func__, current_board, devbase);
9607f1b527cSSean Bruno 		}
9617f1b527cSSean Bruno 	}
9627f1b527cSSean Bruno 	/*
9637f1b527cSSean Bruno 	 * display the nodes on this board "-u"
9647f1b527cSSean Bruno 	 * only
9657f1b527cSSean Bruno 	 */
9667f1b527cSSean Bruno 	if (display_board_only)
9677f1b527cSSean Bruno 		list_dev(fd);
9687f1b527cSSean Bruno 
9697f1b527cSSean Bruno 	/*
9707f1b527cSSean Bruno 	 * dump_phy_reg "-p"
9717f1b527cSSean Bruno 	 */
9727f1b527cSSean Bruno 	if (dump_phy_reg)
9737f1b527cSSean Bruno 		dump_phy_registers(fd);
9747f1b527cSSean Bruno 
9757f1b527cSSean Bruno 	/*
9767f1b527cSSean Bruno 	 * send a BUS_RESET Event "-r"
9777f1b527cSSean Bruno 	 */
9787f1b527cSSean Bruno 	if (send_bus_reset) {
9797f1b527cSSean Bruno 		if(ioctl(fd, FW_IBUSRST, &tmp) < 0)
980c1de48a3SSean Bruno                		err(EX_IOERR, "%s: Ioctl of bus reset failed for %s", __func__, devbase);
9817f1b527cSSean Bruno 	}
9827f1b527cSSean Bruno 	/*
9837f1b527cSSean Bruno 	 * Print out the CROM for this node "-c"
9847f1b527cSSean Bruno 	 */
9857f1b527cSSean Bruno 	if (display_crom) {
9867f1b527cSSean Bruno 		tmp = str2node(fd, crom_string);
9877f1b527cSSean Bruno 		get_crom(fd, tmp, crom_buf, len);
9887f1b527cSSean Bruno 		show_crom(crom_buf);
9897f1b527cSSean Bruno 		free(crom_string);
9907f1b527cSSean Bruno 	}
9917f1b527cSSean Bruno 	/*
9927f1b527cSSean Bruno 	 * Hex Dump the CROM for this node "-d"
9937f1b527cSSean Bruno 	 */
9947f1b527cSSean Bruno 	if (display_crom_hex) {
9957f1b527cSSean Bruno 		tmp = str2node(fd, crom_string_hex);
9967f1b527cSSean Bruno 		get_crom(fd, tmp, crom_buf_hex, len);
9977f1b527cSSean Bruno 		dump_crom(crom_buf_hex);
9987f1b527cSSean Bruno 		free(crom_string_hex);
9997f1b527cSSean Bruno 	}
10007f1b527cSSean Bruno 	/*
10017f1b527cSSean Bruno 	 * Set Priority Budget to value for this node "-b"
10027f1b527cSSean Bruno 	 */
10037f1b527cSSean Bruno 	if (priority_budget >= 0)
10047f1b527cSSean Bruno 		set_pri_req(fd, priority_budget);
10057f1b527cSSean Bruno 
10067f1b527cSSean Bruno 	/*
10077f1b527cSSean Bruno 	 * Explicitly set the root node of this bus to value "-f"
10087f1b527cSSean Bruno 	 */
10097f1b527cSSean Bruno 	if (set_root_node >= 0)
10107f1b527cSSean Bruno 		send_phy_config(fd, set_root_node, -1);
10117f1b527cSSean Bruno 
10127f1b527cSSean Bruno 	/*
10137f1b527cSSean Bruno 	 * Set the gap count for this card/bus  "-g"
10147f1b527cSSean Bruno 	 */
10157f1b527cSSean Bruno 	if (set_gap_count >= 0)
10167f1b527cSSean Bruno 		send_phy_config(fd, -1, set_gap_count);
10177f1b527cSSean Bruno 
10187f1b527cSSean Bruno 	/*
10197f1b527cSSean Bruno 	 * Load a CROM from a file "-l"
10207f1b527cSSean Bruno 	 */
10217f1b527cSSean Bruno 	if (load_crom_from_file)
10227f1b527cSSean Bruno 		show_crom(crom_buf);
10237f1b527cSSean Bruno 	/*
10247f1b527cSSean Bruno 	 * Set the fwmem target for a node to argument "-m"
10257f1b527cSSean Bruno 	 */
10267f1b527cSSean Bruno 	if (set_fwmem_target) {
10277f1b527cSSean Bruno 		eui.hi = ntohl(*(u_int32_t*)&(target.octet[0]));
10287f1b527cSSean Bruno 		eui.lo = ntohl(*(u_int32_t*)&(target.octet[4]));
1029c1de48a3SSean Bruno #if defined(__FreeBSD__)
10307f1b527cSSean Bruno 		sysctl_set_int("hw.firewire.fwmem.eui64_hi", eui.hi);
10317f1b527cSSean Bruno 		sysctl_set_int("hw.firewire.fwmem.eui64_lo", eui.lo);
1032c1de48a3SSean Bruno #elif defined(__NetBSD__)
1033c1de48a3SSean Bruno 		sysctl_set_int("hw.fwmem.eui64_hi", eui.hi);
1034c1de48a3SSean Bruno 		sysctl_set_int("hw.fwmem.eui64_lo", eui.lo);
1035c1de48a3SSean Bruno #else
1036c1de48a3SSean Bruno #warning "You need to add support for your OS"
1037c1de48a3SSean Bruno #endif
1038c1de48a3SSean Bruno 
10397f1b527cSSean Bruno 	}
10407f1b527cSSean Bruno 
10417f1b527cSSean Bruno 	/*
10427f1b527cSSean Bruno 	 * Send a link on to this board/bus "-o"
10437f1b527cSSean Bruno 	 */
10447f1b527cSSean Bruno 	if (send_link_on >= 0)
10457f1b527cSSean Bruno 		link_on(fd, send_link_on);
10467f1b527cSSean Bruno 
10477f1b527cSSean Bruno 	/*
10487f1b527cSSean Bruno 	 * Send a reset start to this board/bus "-s"
10497f1b527cSSean Bruno 	 */
10507f1b527cSSean Bruno 	if (send_reset_start >= 0)
10517f1b527cSSean Bruno 		reset_start(fd, send_reset_start);
10527f1b527cSSean Bruno 
10537f1b527cSSean Bruno 	/*
10547f1b527cSSean Bruno 	 * Dump the node topology for this board/bus "-t"
10557f1b527cSSean Bruno 	 */
10567f1b527cSSean Bruno 	if (dump_topology)
10577f1b527cSSean Bruno 		show_topology_map(fd);
10587f1b527cSSean Bruno 
10597f1b527cSSean Bruno 	/*
10603df5ecacSUlrich Spörlein 	 * Receive data file from node "-R"
10617f1b527cSSean Bruno 	 */
10627f1b527cSSean Bruno #define TAG	(1<<6)
10637f1b527cSSean Bruno #define CHANNEL	63
10647f1b527cSSean Bruno 	if (recv_data != NULL){
10657f1b527cSSean Bruno 		if (recvfn == NULL) { /* guess... */
10667f1b527cSSean Bruno 			recvfn = detect_recv_fn(fd, TAG | CHANNEL);
10677f1b527cSSean Bruno 			close(fd);
106896747dc0SWarner Losh 			fd = -1;
10697f1b527cSSean Bruno 		}
1070c1de48a3SSean Bruno 		snprintf(devbase, sizeof(devbase), "%s%d.0", device_string, current_board);
10717f1b527cSSean Bruno 		if (open_dev(&fd, devbase) < 0)
1072c1de48a3SSean Bruno 		  err(EX_IOERR, "%s: Error opening firewire controller #%d %s in recv_data\n", __func__, current_board, devbase);
10737f1b527cSSean Bruno 		(*recvfn)(fd, recv_data, TAG | CHANNEL, -1);
10747f1b527cSSean Bruno 		free(recv_data);
10757f1b527cSSean Bruno 	}
10767f1b527cSSean Bruno 
10777f1b527cSSean Bruno 	/*
10787f1b527cSSean Bruno 	 * Send data file to node "-S"
10797f1b527cSSean Bruno 	 */
10807f1b527cSSean Bruno 	if (send_data != NULL){
10817f1b527cSSean Bruno 		dvsend(fd, send_data, TAG | CHANNEL, -1);
10827f1b527cSSean Bruno 		free(send_data);
10837f1b527cSSean Bruno 	}
10847f1b527cSSean Bruno 
10857f1b527cSSean Bruno 	if (fd > 0) {
10867f1b527cSSean Bruno 		close(fd);
10877f1b527cSSean Bruno 		fd = -1;
1088a7a73b95SHidetoshi Shimokawa 	}
1089a7a73b95SHidetoshi Shimokawa 	return 0;
1090a7a73b95SHidetoshi Shimokawa }
1091