fwcontrol.c revision 136845
1/*
2 * Copyright (C) 2002
3 * 	Hidetoshi Shimokawa. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *
16 *	This product includes software developed by Hidetoshi Shimokawa.
17 *
18 * 4. Neither the name of the author nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * $FreeBSD: head/usr.sbin/fwcontrol/fwcontrol.c 136845 2004-10-23 23:28:08Z simokawa $
35 */
36
37#include <sys/param.h>
38#include <sys/malloc.h>
39#include <sys/socket.h>
40#include <sys/ioctl.h>
41#include <sys/errno.h>
42#include <sys/eui64.h>
43#include <dev/firewire/firewire.h>
44#include <dev/firewire/iec13213.h>
45#include <dev/firewire/fwphyreg.h>
46
47#include <netinet/in.h>
48#include <fcntl.h>
49#include <stdio.h>
50#include <err.h>
51#include <stdlib.h>
52#include <string.h>
53#include <unistd.h>
54
55extern int dvrecv(int, char *, char, int);
56extern int dvsend(int, char *, char, int);
57
58static void
59usage(void)
60{
61	fprintf(stderr,
62		"fwcontrol [-u bus_num] [-rt] [-g gap_count] [-o node] "
63		    "[-b pri_req] [-c node] [-d node] [-l file] "
64		    "[-R file] [-S file]\n"
65		"\t-u: specify bus number\n"
66		"\t-g: broadcast gap_count by phy_config packet\n"
67		"\t-o: send link-on packet to the node\n"
68		"\t-s: write RESET_START register on the node\n"
69		"\t-b: set PRIORITY_BUDGET register on all supported nodes\n"
70		"\t-c: read configuration ROM\n"
71		"\t-r: bus reset\n"
72		"\t-t: read topology map\n"
73		"\t-d: hex dump of configuration ROM\n"
74		"\t-l: load and parse hex dump file of configuration ROM\n"
75		"\t-R: Receive DV stream\n"
76		"\t-S: Send DV stream\n");
77	exit(0);
78}
79
80static void
81fweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui)
82{
83	*(u_int32_t*)&(eui->octet[0]) = htonl(fweui->hi);
84	*(u_int32_t*)&(eui->octet[4]) = htonl(fweui->lo);
85}
86
87static struct fw_devlstreq *
88get_dev(int fd)
89{
90	struct fw_devlstreq *data;
91
92	data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq));
93	if (data == NULL)
94		err(1, "malloc");
95	if( ioctl(fd, FW_GDEVLST, data) < 0) {
96       			err(1, "ioctl");
97	}
98	return data;
99}
100
101static int
102str2node(int fd, const char *nodestr)
103{
104	struct eui64 eui, tmpeui;
105	struct fw_devlstreq *data;
106	char *endptr;
107	int i, node;
108
109	if (nodestr == '\0')
110		return (-1);
111
112	/*
113	 * Deal with classic node specifications.
114	 */
115	node = strtol(nodestr, &endptr, 0);
116	if (*endptr == '\0')
117		goto gotnode;
118
119	/*
120	 * Try to get an eui and match it against available nodes.
121	 */
122	if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0)
123		return (-1);
124
125	data = get_dev(fd);
126
127	for (i = 0; i < data->info_len; i++) {
128		fweui2eui64(&data->dev[i].eui, &tmpeui);
129		if (memcmp(&eui, &tmpeui, sizeof(struct eui64)) == 0) {
130			node = data->dev[i].dst;
131			goto gotnode;
132		}
133	}
134	if (i >= data->info_len)
135		return (-1);
136
137gotnode:
138	if (node < 0 || node > 63)
139		return (-1);
140	else
141		return (node);
142}
143
144static void
145list_dev(int fd)
146{
147	struct fw_devlstreq *data;
148	struct fw_devinfo *devinfo;
149	struct eui64 eui;
150	char addr[EUI64_SIZ];
151	int i;
152
153	data = get_dev(fd);
154	printf("%d devices (info_len=%d)\n", data->n, data->info_len);
155	printf("node           EUI64          status\n");
156	for (i = 0; i < data->info_len; i++) {
157		devinfo = &data->dev[i];
158		fweui2eui64(&devinfo->eui, &eui);
159		eui64_ntoa(&eui, addr, sizeof(addr));
160		printf("%4d  %s %6d\n",
161			(devinfo->status || i == 0) ? devinfo->dst : -1,
162			addr,
163			devinfo->status
164		);
165	}
166	free((void *)data);
167}
168
169static u_int32_t
170read_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int32_t data)
171{
172        struct fw_asyreq *asyreq;
173	u_int32_t *qld, res;
174
175        asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
176	asyreq->req.len = 16;
177#if 0
178	asyreq->req.type = FWASREQNODE;
179	asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node;
180#else
181	asyreq->req.type = FWASREQEUI;
182	asyreq->req.dst.eui = eui;
183#endif
184	asyreq->pkt.mode.rreqq.tlrt = 0;
185	if (read)
186		asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ;
187	else
188		asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ;
189
190	asyreq->pkt.mode.rreqq.dest_hi = 0xffff;
191	asyreq->pkt.mode.rreqq.dest_lo = addr_lo;
192
193	qld = (u_int32_t *)&asyreq->pkt;
194	if (!read)
195		asyreq->pkt.mode.wreqq.data = data;
196
197	if (ioctl(fd, FW_ASYREQ, asyreq) < 0) {
198       		err(1, "ioctl");
199	}
200	res = qld[3];
201	free(asyreq);
202	if (read)
203		return ntohl(res);
204	else
205		return 0;
206}
207
208static void
209send_phy_config(int fd, int root_node, int gap_count)
210{
211        struct fw_asyreq *asyreq;
212
213	asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12);
214	asyreq->req.len = 12;
215	asyreq->req.type = FWASREQNODE;
216	asyreq->pkt.mode.ld[0] = 0;
217	asyreq->pkt.mode.ld[1] = 0;
218	asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
219	if (root_node >= 0)
220		asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23;
221	if (gap_count >= 0)
222		asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16;
223	asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
224
225	printf("send phy_config root_node=%d gap_count=%d\n",
226						root_node, gap_count);
227
228	if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
229       		err(1, "ioctl");
230	free(asyreq);
231}
232
233static void
234send_link_on(int fd, int node)
235{
236        struct fw_asyreq *asyreq;
237
238	asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12);
239	asyreq->req.len = 12;
240	asyreq->req.type = FWASREQNODE;
241	asyreq->pkt.mode.common.tcode = FWTCODE_PHY;
242	asyreq->pkt.mode.ld[1] |= (1 << 30) | ((node & 0x3f) << 24);
243	asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1];
244
245	if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
246       		err(1, "ioctl");
247	free(asyreq);
248}
249
250static void
251reset_start(int fd, int node)
252{
253        struct fw_asyreq *asyreq;
254
255	asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16);
256	asyreq->req.len = 16;
257	asyreq->req.type = FWASREQNODE;
258	asyreq->pkt.mode.wreqq.dst = FWLOCALBUS | (node & 0x3f);
259	asyreq->pkt.mode.wreqq.tlrt = 0;
260	asyreq->pkt.mode.wreqq.tcode = FWTCODE_WREQQ;
261
262	asyreq->pkt.mode.wreqq.dest_hi = 0xffff;
263	asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START;
264
265	asyreq->pkt.mode.wreqq.data = htonl(0x1);
266
267	if (ioctl(fd, FW_ASYREQ, asyreq) < 0)
268       		err(1, "ioctl");
269	free(asyreq);
270}
271
272static void
273set_pri_req(int fd, int pri_req)
274{
275	struct fw_devlstreq *data;
276	struct fw_devinfo *devinfo;
277	struct eui64 eui;
278	char addr[EUI64_SIZ];
279	u_int32_t max, reg, old;
280	int i;
281
282	data = get_dev(fd);
283#define BUGET_REG 0xf0000218
284	for (i = 0; i < data->info_len; i++) {
285		devinfo = &data->dev[i];
286		if (!devinfo->status)
287			continue;
288		reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0);
289		fweui2eui64(&devinfo->eui, &eui);
290		eui64_ntoa(&eui, addr, sizeof(addr));
291		printf("%d %s, %08x",
292			devinfo->dst, addr, reg);
293		if (reg > 0 && pri_req >= 0) {
294			old = (reg & 0x3f);
295			max = (reg & 0x3f00) >> 8;
296			if (pri_req > max)
297				pri_req =  max;
298			printf(" 0x%x -> 0x%x\n", old, pri_req);
299			read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req);
300		} else {
301			printf("\n");
302		}
303	}
304	free((void *)data);
305}
306
307static void
308parse_bus_info_block(u_int32_t *p, int info_len)
309{
310	int i;
311	char addr[EUI64_SIZ];
312	struct bus_info *bi;
313	struct eui64 eui;
314
315	bi = (struct bus_info *)p;
316	fweui2eui64(&bi->eui64, &eui);
317	eui64_ntoa(&eui, addr, sizeof(addr));
318	printf("bus_name: 0x%04x\n"
319		"irmc:%d cmc:%d isc:%d bmc:%d pmc:%d\n"
320		"cyc_clk_acc:%d max_rec:%d max_rom:%d\n"
321		"generation:%d link_spd:%d\n"
322		"EUI64: %s\n",
323		bi->bus_name,
324		bi->irmc, bi->cmc, bi->isc, bi->bmc, bi->pmc,
325		bi->cyc_clk_acc, bi->max_rec, bi->max_rom,
326		bi->generation, bi->link_spd,
327		addr);
328}
329
330static int
331get_crom(int fd, int node, void *crom_buf, int len)
332{
333	struct fw_crom_buf buf;
334	int i, error;
335	struct fw_devlstreq *data;
336
337	data = get_dev(fd);
338
339	for (i = 0; i < data->info_len; i++) {
340		if (data->dev[i].dst == node && data->dev[i].eui.lo != 0)
341			break;
342	}
343	if (i == data->info_len)
344		errx(1, "no such node %d.", node);
345	else
346		buf.eui = data->dev[i].eui;
347	free((void *)data);
348
349	buf.len = len;
350	buf.ptr = crom_buf;
351	bzero(crom_buf, len);
352	if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) {
353       		err(1, "ioctl");
354	}
355
356	return error;
357}
358
359static void
360show_crom(u_int32_t *crom_buf)
361{
362	int i;
363	struct crom_context cc;
364	char *desc, info[256];
365	static char *key_types = "ICLD";
366	struct csrreg *reg;
367	struct csrdirectory *dir;
368	struct csrhdr *hdr;
369	u_int16_t crc;
370
371	printf("first quad: 0x%08x ", *crom_buf);
372	if (crom_buf[0] == 0) {
373		printf("(Invalid Configuration ROM)\n");
374		return;
375	}
376	hdr = (struct csrhdr *)crom_buf;
377	if (hdr->info_len == 1) {
378		/* minimum ROM */
379		struct csrreg *reg;
380		reg = (struct csrreg *)hdr;
381		printf("verndor ID: 0x%06x\n",  reg->val);
382		return;
383	}
384	printf("info_len=%d crc_len=%d crc=0x%04x",
385		hdr->info_len, hdr->crc_len, hdr->crc);
386	crc = crom_crc(crom_buf+1, hdr->crc_len);
387	if (crc == hdr->crc)
388		printf("(OK)\n");
389	else
390		printf("(NG)\n");
391	parse_bus_info_block(crom_buf+1, hdr->info_len);
392
393	crom_init_context(&cc, crom_buf);
394	dir = cc.stack[0].dir;
395	if (!dir) {
396		printf("no root directory - giving up\n");
397		return;
398	}
399	printf("root_directory: len=0x%04x(%d) crc=0x%04x",
400			dir->crc_len, dir->crc_len, dir->crc);
401	crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len);
402	if (crc == dir->crc)
403		printf("(OK)\n");
404	else
405		printf("(NG)\n");
406	if (dir->crc_len < 1)
407		return;
408	while (cc.depth >= 0) {
409		desc = crom_desc(&cc, info, sizeof(info));
410		reg = crom_get(&cc);
411		for (i = 0; i < cc.depth; i++)
412			printf("\t");
413		printf("%02x(%c:%02x) %06x %s: %s\n",
414			reg->key,
415			key_types[(reg->key & CSRTYPE_MASK)>>6],
416			reg->key & CSRKEY_MASK, reg->val,
417			desc, info);
418		crom_next(&cc);
419	}
420}
421
422#define DUMP_FORMAT	"%08x %08x %08x %08x %08x %08x %08x %08x\n"
423
424static void
425dump_crom(u_int32_t *p)
426{
427	int len=1024, i;
428
429	for (i = 0; i < len/(4*8); i ++) {
430		printf(DUMP_FORMAT,
431			p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
432		p += 8;
433	}
434}
435
436static void
437load_crom(char *filename, u_int32_t *p)
438{
439	FILE *file;
440	int len=1024, i;
441
442	if ((file = fopen(filename, "r")) == NULL)
443		err(1, "load_crom");
444	for (i = 0; i < len/(4*8); i ++) {
445		fscanf(file, DUMP_FORMAT,
446			p, p+1, p+2, p+3, p+4, p+5, p+6, p+7);
447		p += 8;
448	}
449}
450
451static void
452show_topology_map(int fd)
453{
454	struct fw_topology_map *tmap;
455	union fw_self_id sid;
456	int i;
457	static char *port_status[] = {" ", "-", "P", "C"};
458	static char *pwr_class[] = {" 0W", "15W", "30W", "45W",
459					"-1W", "-2W", "-5W", "-9W"};
460	static char *speed[] = {"S100", "S200", "S400", "S800"};
461	tmap = malloc(sizeof(struct fw_topology_map));
462	if (tmap == NULL)
463		return;
464	if (ioctl(fd, FW_GTPMAP, tmap) < 0) {
465       		err(1, "ioctl");
466	}
467	printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n",
468		tmap->crc_len, tmap->generation,
469		tmap->node_count, tmap->self_id_count);
470	printf("id link gap_cnt speed delay cIRM power port0 port1 port2"
471		" ini more\n");
472	for (i = 0; i < tmap->crc_len - 2; i++) {
473		sid = tmap->self_id[i];
474		if (sid.p0.sequel) {
475			printf("%02d sequel packet\n", sid.p0.phy_id);
476			continue;
477		}
478		printf("%02d   %2d      %2d  %4s     %d    %d   %3s"
479				"     %s     %s     %s   %d    %d\n",
480			sid.p0.phy_id,
481			sid.p0.link_active,
482			sid.p0.gap_count,
483			speed[sid.p0.phy_speed],
484			sid.p0.phy_delay,
485			sid.p0.contender,
486			pwr_class[sid.p0.power_class],
487			port_status[sid.p0.port0],
488			port_status[sid.p0.port1],
489			port_status[sid.p0.port2],
490			sid.p0.initiated_reset,
491			sid.p0.more_packets
492		);
493	}
494	free(tmap);
495}
496
497static void
498read_phy_registers(int fd, u_int8_t *buf, int offset, int len)
499{
500	struct fw_reg_req_t reg;
501	int i;
502
503	for (i = 0; i < len; i++) {
504		reg.addr = offset + i;
505		if (ioctl(fd, FWOHCI_RDPHYREG, &reg) < 0)
506       			err(1, "ioctl");
507		buf[i] = (u_int8_t) reg.data;
508		printf("0x%02x ",  reg.data);
509	}
510	printf("\n");
511}
512
513static void
514read_phy_page(int fd, u_int8_t *buf, int page, int port)
515{
516	struct fw_reg_req_t reg;
517
518	reg.addr = 0x7;
519	reg.data = ((page & 7) << 5) | (port & 0xf);
520	if (ioctl(fd, FWOHCI_WRPHYREG, &reg) < 0)
521       		err(1, "ioctl");
522	read_phy_registers(fd, buf, 8, 8);
523}
524
525static void
526dump_phy_registers(int fd)
527{
528	struct phyreg_base b;
529	struct phyreg_page0 p;
530	struct phyreg_page1 v;
531	int i;
532
533	printf("=== base register ===\n");
534	read_phy_registers(fd, (u_int8_t *)&b, 0, 8);
535	printf(
536	    "Physical_ID:%d  R:%d  CPS:%d\n"
537	    "RHB:%d  IBR:%d  Gap_Count:%d\n"
538	    "Extended:%d Num_Ports:%d\n"
539	    "PHY_Speed:%d Delay:%d\n"
540	    "LCtrl:%d C:%d Jitter:%d Pwr_Class:%d\n"
541	    "WDIE:%d ISBR:%d CTOI:%d CPSI:%d STOI:%d PEI:%d EAA:%d EMC:%d\n"
542	    "Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n"
543	    "Page_Select:%d Port_Select%d\n",
544	    b.phy_id, b.r, b.cps,
545	    b.rhb, b.ibr, b.gap_count,
546	    b.extended, b.num_ports,
547	    b.phy_speed, b.delay,
548	    b.lctrl, b.c, b.jitter, b.pwr_class,
549	    b.wdie, b.isbr, b.ctoi, b.cpsi, b.stoi, b.pei, b.eaa, b.emc,
550	    b.legacy_spd, b.blink, b.bridge,
551	    b.page_select, b.port_select
552	);
553
554	for (i = 0; i < b.num_ports; i ++) {
555		printf("\n=== page 0 port %d ===\n", i);
556		read_phy_page(fd, (u_int8_t *)&p, 0, i);
557		printf(
558		    "Astat:%d BStat:%d Ch:%d Con:%d RXOK:%d Dis:%d\n"
559		    "Negotiated_speed:%d PIE:%d Fault:%d Stanby_fault:%d Disscrm:%d B_Only:%d\n"
560		    "DC_connected:%d Max_port_speed:%d LPP:%d Cable_speed:%d\n"
561		    "Connection_unreliable:%d Beta_mode:%d\n"
562		    "Port_error:0x%x\n"
563		    "Loop_disable:%d In_standby:%d Hard_disable:%d\n",
564		    p.astat, p.bstat, p.ch, p.con, p.rxok, p.dis,
565		    p.negotiated_speed, p.pie, p.fault, p.stanby_fault, p.disscrm, p.b_only,
566		    p.dc_connected, p.max_port_speed, p.lpp, p.cable_speed,
567		    p.connection_unreliable, p.beta_mode,
568		    p.port_error,
569		    p.loop_disable, p.in_standby, p.hard_disable
570		);
571	}
572	printf("\n=== page 1 ===\n");
573	read_phy_page(fd, (u_int8_t *)&v, 1, 0);
574	printf(
575	    "Compliance:%d\n"
576	    "Vendor_ID:0x%06x\n"
577	    "Product_ID:0x%06x\n",
578	    v.compliance,
579	    (v.vendor_id[0] << 16) | (v.vendor_id[1] << 8) | v.vendor_id[2],
580	    (v.product_id[0] << 16) | (v.product_id[1] << 8) | v.product_id[2]
581	);
582}
583
584static void
585open_dev(int *fd, char *devbase)
586{
587	char devname[256];
588	int i;
589
590	if (*fd < 0) {
591		for (i = 0; i < 4; i++) {
592			snprintf(devname, sizeof(devname), "%s.%d", devbase, i);
593			if ((*fd = open(devname, O_RDWR)) >= 0)
594				break;
595		}
596		if (*fd < 0)
597			err(1, "open");
598
599	}
600}
601
602int
603sysctl_set_int(char *name, int val)
604{
605	if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0)
606		err(1, "sysctl %s failed.", name);
607}
608
609int
610main(int argc, char **argv)
611{
612	u_int32_t crom_buf[1024/4];
613	char devbase[1024] = "/dev/fw0";
614	int fd, i, tmp, ch, len=1024;
615	struct fw_eui64 eui;
616	struct eui64 target;
617
618	fd = -1;
619
620	if (argc < 2) {
621		open_dev(&fd, devbase);
622		list_dev(fd);
623	}
624
625	while ((ch = getopt(argc, argv, "g:m:o:s:b:prtc:d:l:u:R:S:")) != -1)
626		switch(ch) {
627		case 'b':
628			tmp = strtol(optarg, NULL, 0);
629			open_dev(&fd, devbase);
630			set_pri_req(fd, tmp);
631			break;
632		case 'c':
633			open_dev(&fd, devbase);
634			tmp = str2node(fd, optarg);
635			get_crom(fd, tmp, crom_buf, len);
636			show_crom(crom_buf);
637			break;
638		case 'd':
639			open_dev(&fd, devbase);
640			tmp = str2node(fd, optarg);
641			get_crom(fd, tmp, crom_buf, len);
642			dump_crom(crom_buf);
643			break;
644		case 'g':
645			tmp = strtol(optarg, NULL, 0);
646			open_dev(&fd, devbase);
647			send_phy_config(fd, -1, tmp);
648			break;
649		case 'l':
650			load_crom(optarg, crom_buf);
651			show_crom(crom_buf);
652			break;
653		case 'm':
654		       if (eui64_hostton(optarg, &target) != 0 &&
655			   eui64_aton(optarg, &target) != 0)
656				errx(1, "invalid target: %s", optarg);
657			eui.hi = ntohl(*(u_int32_t*)&(target.octet[0]));
658			eui.lo = ntohl(*(u_int32_t*)&(target.octet[4]));
659			sysctl_set_int("hw.firewire.fwmem.eui64_hi", eui.hi);
660			sysctl_set_int("hw.firewire.fwmem.eui64_lo", eui.lo);
661			break;
662		case 'o':
663			open_dev(&fd, devbase);
664			tmp = str2node(fd, optarg);
665			send_link_on(fd, tmp);
666			break;
667		case 'p':
668			open_dev(&fd, devbase);
669			dump_phy_registers(fd);
670			break;
671		case 'r':
672			open_dev(&fd, devbase);
673			if(ioctl(fd, FW_IBUSRST, &tmp) < 0)
674                       		err(1, "ioctl");
675			break;
676		case 's':
677			open_dev(&fd, devbase);
678			tmp = str2node(fd, optarg);
679			reset_start(fd, tmp);
680			break;
681		case 't':
682			open_dev(&fd, devbase);
683			show_topology_map(fd);
684			break;
685		case 'u':
686			tmp = strtol(optarg, NULL, 0);
687			snprintf(devbase, sizeof(devbase), "/dev/fw%d",  tmp);
688			if (fd > 0) {
689				close(fd);
690				fd = -1;
691			}
692			if (argc == optind) {
693				open_dev(&fd, devbase);
694				list_dev(fd);
695			}
696			break;
697#define TAG	(1<<6)
698#define CHANNEL	63
699		case 'R':
700			open_dev(&fd, devbase);
701			dvrecv(fd, optarg, TAG | CHANNEL, -1);
702			break;
703		case 'S':
704			open_dev(&fd, devbase);
705			dvsend(fd, optarg, TAG | CHANNEL, -1);
706			break;
707		default:
708			usage();
709		}
710	return 0;
711}
712