fwcontrol.c revision 136845
1108441Ssimokawa/* 2108441Ssimokawa * Copyright (C) 2002 3108441Ssimokawa * Hidetoshi Shimokawa. All rights reserved. 4108441Ssimokawa * 5108441Ssimokawa * Redistribution and use in source and binary forms, with or without 6108441Ssimokawa * modification, are permitted provided that the following conditions 7108441Ssimokawa * are met: 8108441Ssimokawa * 1. Redistributions of source code must retain the above copyright 9108441Ssimokawa * notice, this list of conditions and the following disclaimer. 10108441Ssimokawa * 2. Redistributions in binary form must reproduce the above copyright 11108441Ssimokawa * notice, this list of conditions and the following disclaimer in the 12108441Ssimokawa * documentation and/or other materials provided with the distribution. 13108441Ssimokawa * 3. All advertising materials mentioning features or use of this software 14108441Ssimokawa * must display the following acknowledgement: 15108441Ssimokawa * 16108441Ssimokawa * This product includes software developed by Hidetoshi Shimokawa. 17108441Ssimokawa * 18108441Ssimokawa * 4. Neither the name of the author nor the names of its contributors 19108441Ssimokawa * may be used to endorse or promote products derived from this software 20108441Ssimokawa * without specific prior written permission. 21108441Ssimokawa * 22108441Ssimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23108441Ssimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24108441Ssimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25108441Ssimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26108441Ssimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27108441Ssimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28108441Ssimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29108441Ssimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30108441Ssimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31108441Ssimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32108441Ssimokawa * SUCH DAMAGE. 33108441Ssimokawa * 34108441Ssimokawa * $FreeBSD: head/usr.sbin/fwcontrol/fwcontrol.c 136845 2004-10-23 23:28:08Z simokawa $ 35108441Ssimokawa */ 36108441Ssimokawa 37108441Ssimokawa#include <sys/param.h> 38108441Ssimokawa#include <sys/malloc.h> 39108441Ssimokawa#include <sys/socket.h> 40108441Ssimokawa#include <sys/ioctl.h> 41108441Ssimokawa#include <sys/errno.h> 42129760Sbrooks#include <sys/eui64.h> 43108441Ssimokawa#include <dev/firewire/firewire.h> 44108441Ssimokawa#include <dev/firewire/iec13213.h> 45120432Ssimokawa#include <dev/firewire/fwphyreg.h> 46108441Ssimokawa 47108441Ssimokawa#include <netinet/in.h> 48108441Ssimokawa#include <fcntl.h> 49108441Ssimokawa#include <stdio.h> 50108441Ssimokawa#include <err.h> 51108441Ssimokawa#include <stdlib.h> 52108441Ssimokawa#include <string.h> 53108441Ssimokawa#include <unistd.h> 54108441Ssimokawa 55109737Ssimokawaextern int dvrecv(int, char *, char, int); 56109737Ssimokawaextern int dvsend(int, char *, char, int); 57109737Ssimokawa 58108657Ssimokawastatic void 59108441Ssimokawausage(void) 60108441Ssimokawa{ 61109787Ssimokawa fprintf(stderr, 62118457Ssimokawa "fwcontrol [-u bus_num] [-rt] [-g gap_count] [-o node] " 63118457Ssimokawa "[-b pri_req] [-c node] [-d node] [-l file] " 64118457Ssimokawa "[-R file] [-S file]\n" 65118457Ssimokawa "\t-u: specify bus number\n" 66114217Ssimokawa "\t-g: broadcast gap_count by phy_config packet\n" 67114217Ssimokawa "\t-o: send link-on packet to the node\n" 68114217Ssimokawa "\t-s: write RESET_START register on the node\n" 69114217Ssimokawa "\t-b: set PRIORITY_BUDGET register on all supported nodes\n" 70114217Ssimokawa "\t-c: read configuration ROM\n" 71114217Ssimokawa "\t-r: bus reset\n" 72114217Ssimokawa "\t-t: read topology map\n" 73114217Ssimokawa "\t-d: hex dump of configuration ROM\n" 74114217Ssimokawa "\t-l: load and parse hex dump file of configuration ROM\n" 75114217Ssimokawa "\t-R: Receive DV stream\n" 76114217Ssimokawa "\t-S: Send DV stream\n"); 77108441Ssimokawa exit(0); 78108441Ssimokawa} 79108441Ssimokawa 80129760Sbrooksstatic void 81129760Sbrooksfweui2eui64(const struct fw_eui64 *fweui, struct eui64 *eui) 82129760Sbrooks{ 83129760Sbrooks *(u_int32_t*)&(eui->octet[0]) = htonl(fweui->hi); 84129760Sbrooks *(u_int32_t*)&(eui->octet[4]) = htonl(fweui->lo); 85129760Sbrooks} 86129760Sbrooks 87109814Ssimokawastatic struct fw_devlstreq * 88109814Ssimokawaget_dev(int fd) 89108441Ssimokawa{ 90109814Ssimokawa struct fw_devlstreq *data; 91109814Ssimokawa 92109814Ssimokawa data = (struct fw_devlstreq *)malloc(sizeof(struct fw_devlstreq)); 93109814Ssimokawa if (data == NULL) 94109814Ssimokawa err(1, "malloc"); 95108441Ssimokawa if( ioctl(fd, FW_GDEVLST, data) < 0) { 96108441Ssimokawa err(1, "ioctl"); 97108441Ssimokawa } 98109814Ssimokawa return data; 99108441Ssimokawa} 100108441Ssimokawa 101129760Sbrooksstatic int 102129760Sbrooksstr2node(int fd, const char *nodestr) 103129760Sbrooks{ 104129760Sbrooks struct eui64 eui, tmpeui; 105129760Sbrooks struct fw_devlstreq *data; 106129760Sbrooks char *endptr; 107129760Sbrooks int i, node; 108129760Sbrooks 109129760Sbrooks if (nodestr == '\0') 110129760Sbrooks return (-1); 111129760Sbrooks 112129760Sbrooks /* 113129760Sbrooks * Deal with classic node specifications. 114129760Sbrooks */ 115129760Sbrooks node = strtol(nodestr, &endptr, 0); 116129760Sbrooks if (*endptr == '\0') 117129760Sbrooks goto gotnode; 118129760Sbrooks 119129760Sbrooks /* 120129760Sbrooks * Try to get an eui and match it against available nodes. 121129760Sbrooks */ 122129760Sbrooks if (eui64_hostton(nodestr, &eui) != 0 && eui64_aton(nodestr, &eui) != 0) 123129760Sbrooks return (-1); 124129760Sbrooks 125129760Sbrooks data = get_dev(fd); 126129760Sbrooks 127129760Sbrooks for (i = 0; i < data->info_len; i++) { 128129760Sbrooks fweui2eui64(&data->dev[i].eui, &tmpeui); 129129760Sbrooks if (memcmp(&eui, &tmpeui, sizeof(struct eui64)) == 0) { 130129760Sbrooks node = data->dev[i].dst; 131129760Sbrooks goto gotnode; 132129760Sbrooks } 133129760Sbrooks } 134129760Sbrooks if (i >= data->info_len) 135129760Sbrooks return (-1); 136129760Sbrooks 137129760Sbrooksgotnode: 138129760Sbrooks if (node < 0 || node > 63) 139129760Sbrooks return (-1); 140129760Sbrooks else 141129760Sbrooks return (node); 142129760Sbrooks} 143129760Sbrooks 144108657Ssimokawastatic void 145108441Ssimokawalist_dev(int fd) 146108441Ssimokawa{ 147109814Ssimokawa struct fw_devlstreq *data; 148109814Ssimokawa struct fw_devinfo *devinfo; 149129760Sbrooks struct eui64 eui; 150129760Sbrooks char addr[EUI64_SIZ]; 151108441Ssimokawa int i; 152108441Ssimokawa 153109814Ssimokawa data = get_dev(fd); 154109814Ssimokawa printf("%d devices (info_len=%d)\n", data->n, data->info_len); 155129760Sbrooks printf("node EUI64 status\n"); 156109814Ssimokawa for (i = 0; i < data->info_len; i++) { 157109814Ssimokawa devinfo = &data->dev[i]; 158129760Sbrooks fweui2eui64(&devinfo->eui, &eui); 159129760Sbrooks eui64_ntoa(&eui, addr, sizeof(addr)); 160129760Sbrooks printf("%4d %s %6d\n", 161110578Ssimokawa (devinfo->status || i == 0) ? devinfo->dst : -1, 162129760Sbrooks addr, 163109814Ssimokawa devinfo->status 164108441Ssimokawa ); 165108441Ssimokawa } 166109814Ssimokawa free((void *)data); 167108441Ssimokawa} 168108441Ssimokawa 169108657Ssimokawastatic u_int32_t 170108441Ssimokawaread_write_quad(int fd, struct fw_eui64 eui, u_int32_t addr_lo, int read, u_int32_t data) 171108441Ssimokawa{ 172108441Ssimokawa struct fw_asyreq *asyreq; 173108441Ssimokawa u_int32_t *qld, res; 174108441Ssimokawa 175108441Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16); 176108441Ssimokawa asyreq->req.len = 16; 177114217Ssimokawa#if 0 178114217Ssimokawa asyreq->req.type = FWASREQNODE; 179114217Ssimokawa asyreq->pkt.mode.rreqq.dst = FWLOCALBUS | node; 180114217Ssimokawa#else 181108441Ssimokawa asyreq->req.type = FWASREQEUI; 182108441Ssimokawa asyreq->req.dst.eui = eui; 183108441Ssimokawa#endif 184108441Ssimokawa asyreq->pkt.mode.rreqq.tlrt = 0; 185108441Ssimokawa if (read) 186108441Ssimokawa asyreq->pkt.mode.rreqq.tcode = FWTCODE_RREQQ; 187108441Ssimokawa else 188108441Ssimokawa asyreq->pkt.mode.rreqq.tcode = FWTCODE_WREQQ; 189108441Ssimokawa 190113584Ssimokawa asyreq->pkt.mode.rreqq.dest_hi = 0xffff; 191113584Ssimokawa asyreq->pkt.mode.rreqq.dest_lo = addr_lo; 192108441Ssimokawa 193108441Ssimokawa qld = (u_int32_t *)&asyreq->pkt; 194108441Ssimokawa if (!read) 195108441Ssimokawa asyreq->pkt.mode.wreqq.data = data; 196108441Ssimokawa 197108441Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) { 198108441Ssimokawa err(1, "ioctl"); 199108441Ssimokawa } 200108441Ssimokawa res = qld[3]; 201108441Ssimokawa free(asyreq); 202108441Ssimokawa if (read) 203108441Ssimokawa return ntohl(res); 204108441Ssimokawa else 205108441Ssimokawa return 0; 206108441Ssimokawa} 207108657Ssimokawa 208108657Ssimokawastatic void 209108441Ssimokawasend_phy_config(int fd, int root_node, int gap_count) 210108441Ssimokawa{ 211108441Ssimokawa struct fw_asyreq *asyreq; 212108441Ssimokawa 213108441Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12); 214108441Ssimokawa asyreq->req.len = 12; 215108441Ssimokawa asyreq->req.type = FWASREQNODE; 216108441Ssimokawa asyreq->pkt.mode.ld[0] = 0; 217108441Ssimokawa asyreq->pkt.mode.ld[1] = 0; 218108441Ssimokawa asyreq->pkt.mode.common.tcode = FWTCODE_PHY; 219108441Ssimokawa if (root_node >= 0) 220113584Ssimokawa asyreq->pkt.mode.ld[1] |= (root_node & 0x3f) << 24 | 1 << 23; 221108441Ssimokawa if (gap_count >= 0) 222113584Ssimokawa asyreq->pkt.mode.ld[1] |= 1 << 22 | (gap_count & 0x3f) << 16; 223108441Ssimokawa asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1]; 224108441Ssimokawa 225108441Ssimokawa printf("send phy_config root_node=%d gap_count=%d\n", 226108441Ssimokawa root_node, gap_count); 227108441Ssimokawa 228114274Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 229108441Ssimokawa err(1, "ioctl"); 230114274Ssimokawa free(asyreq); 231108441Ssimokawa} 232108441Ssimokawa 233108657Ssimokawastatic void 234114217Ssimokawasend_link_on(int fd, int node) 235114217Ssimokawa{ 236114217Ssimokawa struct fw_asyreq *asyreq; 237114217Ssimokawa 238114217Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 12); 239114217Ssimokawa asyreq->req.len = 12; 240114217Ssimokawa asyreq->req.type = FWASREQNODE; 241114217Ssimokawa asyreq->pkt.mode.common.tcode = FWTCODE_PHY; 242114217Ssimokawa asyreq->pkt.mode.ld[1] |= (1 << 30) | ((node & 0x3f) << 24); 243114217Ssimokawa asyreq->pkt.mode.ld[2] = ~asyreq->pkt.mode.ld[1]; 244114217Ssimokawa 245114274Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 246114217Ssimokawa err(1, "ioctl"); 247114274Ssimokawa free(asyreq); 248114217Ssimokawa} 249114217Ssimokawa 250114217Ssimokawastatic void 251114217Ssimokawareset_start(int fd, int node) 252114217Ssimokawa{ 253114217Ssimokawa struct fw_asyreq *asyreq; 254114217Ssimokawa 255114217Ssimokawa asyreq = (struct fw_asyreq *)malloc(sizeof(struct fw_asyreq_t) + 16); 256114217Ssimokawa asyreq->req.len = 16; 257114217Ssimokawa asyreq->req.type = FWASREQNODE; 258114217Ssimokawa asyreq->pkt.mode.wreqq.dst = FWLOCALBUS | (node & 0x3f); 259114217Ssimokawa asyreq->pkt.mode.wreqq.tlrt = 0; 260114217Ssimokawa asyreq->pkt.mode.wreqq.tcode = FWTCODE_WREQQ; 261114217Ssimokawa 262114217Ssimokawa asyreq->pkt.mode.wreqq.dest_hi = 0xffff; 263114217Ssimokawa asyreq->pkt.mode.wreqq.dest_lo = 0xf0000000 | RESET_START; 264114217Ssimokawa 265114217Ssimokawa asyreq->pkt.mode.wreqq.data = htonl(0x1); 266114217Ssimokawa 267114274Ssimokawa if (ioctl(fd, FW_ASYREQ, asyreq) < 0) 268114217Ssimokawa err(1, "ioctl"); 269114274Ssimokawa free(asyreq); 270114217Ssimokawa} 271114217Ssimokawa 272114217Ssimokawastatic void 273108441Ssimokawaset_pri_req(int fd, int pri_req) 274108441Ssimokawa{ 275109814Ssimokawa struct fw_devlstreq *data; 276109814Ssimokawa struct fw_devinfo *devinfo; 277129760Sbrooks struct eui64 eui; 278129760Sbrooks char addr[EUI64_SIZ]; 279108441Ssimokawa u_int32_t max, reg, old; 280108441Ssimokawa int i; 281108441Ssimokawa 282109814Ssimokawa data = get_dev(fd); 283108441Ssimokawa#define BUGET_REG 0xf0000218 284109814Ssimokawa for (i = 0; i < data->info_len; i++) { 285109814Ssimokawa devinfo = &data->dev[i]; 286109814Ssimokawa if (!devinfo->status) 287108441Ssimokawa continue; 288109814Ssimokawa reg = read_write_quad(fd, devinfo->eui, BUGET_REG, 1, 0); 289129760Sbrooks fweui2eui64(&devinfo->eui, &eui); 290129760Sbrooks eui64_ntoa(&eui, addr, sizeof(addr)); 291129760Sbrooks printf("%d %s, %08x", 292129760Sbrooks devinfo->dst, addr, reg); 293108441Ssimokawa if (reg > 0 && pri_req >= 0) { 294108441Ssimokawa old = (reg & 0x3f); 295108441Ssimokawa max = (reg & 0x3f00) >> 8; 296108441Ssimokawa if (pri_req > max) 297108441Ssimokawa pri_req = max; 298108441Ssimokawa printf(" 0x%x -> 0x%x\n", old, pri_req); 299109814Ssimokawa read_write_quad(fd, devinfo->eui, BUGET_REG, 0, pri_req); 300108441Ssimokawa } else { 301108441Ssimokawa printf("\n"); 302108441Ssimokawa } 303108441Ssimokawa } 304109814Ssimokawa free((void *)data); 305108441Ssimokawa} 306108441Ssimokawa 307108657Ssimokawastatic void 308108657Ssimokawaparse_bus_info_block(u_int32_t *p, int info_len) 309108441Ssimokawa{ 310108441Ssimokawa int i; 311129760Sbrooks char addr[EUI64_SIZ]; 312116141Ssimokawa struct bus_info *bi; 313129760Sbrooks struct eui64 eui; 314108441Ssimokawa 315116141Ssimokawa bi = (struct bus_info *)p; 316129760Sbrooks fweui2eui64(&bi->eui64, &eui); 317129760Sbrooks eui64_ntoa(&eui, addr, sizeof(addr)); 318116141Ssimokawa printf("bus_name: 0x%04x\n" 319116141Ssimokawa "irmc:%d cmc:%d isc:%d bmc:%d pmc:%d\n" 320116141Ssimokawa "cyc_clk_acc:%d max_rec:%d max_rom:%d\n" 321116141Ssimokawa "generation:%d link_spd:%d\n" 322129760Sbrooks "EUI64: %s\n", 323116141Ssimokawa bi->bus_name, 324116141Ssimokawa bi->irmc, bi->cmc, bi->isc, bi->bmc, bi->pmc, 325116141Ssimokawa bi->cyc_clk_acc, bi->max_rec, bi->max_rom, 326116141Ssimokawa bi->generation, bi->link_spd, 327129760Sbrooks addr); 328108441Ssimokawa} 329108441Ssimokawa 330108657Ssimokawastatic int 331108441Ssimokawaget_crom(int fd, int node, void *crom_buf, int len) 332108441Ssimokawa{ 333108441Ssimokawa struct fw_crom_buf buf; 334109991Ssimokawa int i, error; 335109814Ssimokawa struct fw_devlstreq *data; 336108441Ssimokawa 337109814Ssimokawa data = get_dev(fd); 338108441Ssimokawa 339109814Ssimokawa for (i = 0; i < data->info_len; i++) { 340109814Ssimokawa if (data->dev[i].dst == node && data->dev[i].eui.lo != 0) 341108441Ssimokawa break; 342108441Ssimokawa } 343109814Ssimokawa if (i == data->info_len) 344109814Ssimokawa errx(1, "no such node %d.", node); 345109814Ssimokawa else 346109814Ssimokawa buf.eui = data->dev[i].eui; 347109814Ssimokawa free((void *)data); 348108441Ssimokawa 349108441Ssimokawa buf.len = len; 350108441Ssimokawa buf.ptr = crom_buf; 351117474Ssimokawa bzero(crom_buf, len); 352108441Ssimokawa if ((error = ioctl(fd, FW_GCROM, &buf)) < 0) { 353108441Ssimokawa err(1, "ioctl"); 354108441Ssimokawa } 355109814Ssimokawa 356108441Ssimokawa return error; 357108441Ssimokawa} 358108441Ssimokawa 359108657Ssimokawastatic void 360108441Ssimokawashow_crom(u_int32_t *crom_buf) 361108441Ssimokawa{ 362108441Ssimokawa int i; 363108441Ssimokawa struct crom_context cc; 364108441Ssimokawa char *desc, info[256]; 365108441Ssimokawa static char *key_types = "ICLD"; 366108441Ssimokawa struct csrreg *reg; 367108441Ssimokawa struct csrdirectory *dir; 368108441Ssimokawa struct csrhdr *hdr; 369113584Ssimokawa u_int16_t crc; 370108441Ssimokawa 371113584Ssimokawa printf("first quad: 0x%08x ", *crom_buf); 372136845Ssimokawa if (crom_buf[0] == 0) { 373136845Ssimokawa printf("(Invalid Configuration ROM)\n"); 374136845Ssimokawa return; 375136845Ssimokawa } 376108441Ssimokawa hdr = (struct csrhdr *)crom_buf; 377108441Ssimokawa if (hdr->info_len == 1) { 378108441Ssimokawa /* minimum ROM */ 379108441Ssimokawa struct csrreg *reg; 380108441Ssimokawa reg = (struct csrreg *)hdr; 381108441Ssimokawa printf("verndor ID: 0x%06x\n", reg->val); 382108441Ssimokawa return; 383108441Ssimokawa } 384113584Ssimokawa printf("info_len=%d crc_len=%d crc=0x%04x", 385113584Ssimokawa hdr->info_len, hdr->crc_len, hdr->crc); 386113584Ssimokawa crc = crom_crc(crom_buf+1, hdr->crc_len); 387113584Ssimokawa if (crc == hdr->crc) 388113584Ssimokawa printf("(OK)\n"); 389113584Ssimokawa else 390113584Ssimokawa printf("(NG)\n"); 391108441Ssimokawa parse_bus_info_block(crom_buf+1, hdr->info_len); 392108441Ssimokawa 393108441Ssimokawa crom_init_context(&cc, crom_buf); 394108441Ssimokawa dir = cc.stack[0].dir; 395129604Sdfr if (!dir) { 396129604Sdfr printf("no root directory - giving up\n"); 397129604Sdfr return; 398129604Sdfr } 399113584Ssimokawa printf("root_directory: len=0x%04x(%d) crc=0x%04x", 400108441Ssimokawa dir->crc_len, dir->crc_len, dir->crc); 401113584Ssimokawa crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); 402113584Ssimokawa if (crc == dir->crc) 403113584Ssimokawa printf("(OK)\n"); 404113584Ssimokawa else 405113584Ssimokawa printf("(NG)\n"); 406108657Ssimokawa if (dir->crc_len < 1) 407108657Ssimokawa return; 408108441Ssimokawa while (cc.depth >= 0) { 409108441Ssimokawa desc = crom_desc(&cc, info, sizeof(info)); 410108441Ssimokawa reg = crom_get(&cc); 411108441Ssimokawa for (i = 0; i < cc.depth; i++) 412108441Ssimokawa printf("\t"); 413108441Ssimokawa printf("%02x(%c:%02x) %06x %s: %s\n", 414108441Ssimokawa reg->key, 415108441Ssimokawa key_types[(reg->key & CSRTYPE_MASK)>>6], 416108441Ssimokawa reg->key & CSRKEY_MASK, reg->val, 417108441Ssimokawa desc, info); 418108441Ssimokawa crom_next(&cc); 419108441Ssimokawa } 420108441Ssimokawa} 421108441Ssimokawa 422108441Ssimokawa#define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 423108441Ssimokawa 424108657Ssimokawastatic void 425108441Ssimokawadump_crom(u_int32_t *p) 426108441Ssimokawa{ 427108441Ssimokawa int len=1024, i; 428108441Ssimokawa 429108441Ssimokawa for (i = 0; i < len/(4*8); i ++) { 430108441Ssimokawa printf(DUMP_FORMAT, 431108441Ssimokawa p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 432108441Ssimokawa p += 8; 433108441Ssimokawa } 434108441Ssimokawa} 435108441Ssimokawa 436108657Ssimokawastatic void 437108441Ssimokawaload_crom(char *filename, u_int32_t *p) 438108441Ssimokawa{ 439108441Ssimokawa FILE *file; 440108441Ssimokawa int len=1024, i; 441108441Ssimokawa 442108441Ssimokawa if ((file = fopen(filename, "r")) == NULL) 443108441Ssimokawa err(1, "load_crom"); 444108441Ssimokawa for (i = 0; i < len/(4*8); i ++) { 445108441Ssimokawa fscanf(file, DUMP_FORMAT, 446108441Ssimokawa p, p+1, p+2, p+3, p+4, p+5, p+6, p+7); 447108441Ssimokawa p += 8; 448108441Ssimokawa } 449108441Ssimokawa} 450108441Ssimokawa 451108441Ssimokawastatic void 452108441Ssimokawashow_topology_map(int fd) 453108441Ssimokawa{ 454108441Ssimokawa struct fw_topology_map *tmap; 455108441Ssimokawa union fw_self_id sid; 456108441Ssimokawa int i; 457108441Ssimokawa static char *port_status[] = {" ", "-", "P", "C"}; 458108441Ssimokawa static char *pwr_class[] = {" 0W", "15W", "30W", "45W", 459108441Ssimokawa "-1W", "-2W", "-5W", "-9W"}; 460108441Ssimokawa static char *speed[] = {"S100", "S200", "S400", "S800"}; 461108441Ssimokawa tmap = malloc(sizeof(struct fw_topology_map)); 462108441Ssimokawa if (tmap == NULL) 463108441Ssimokawa return; 464108441Ssimokawa if (ioctl(fd, FW_GTPMAP, tmap) < 0) { 465108441Ssimokawa err(1, "ioctl"); 466108441Ssimokawa } 467108441Ssimokawa printf("crc_len: %d generation:%d node_count:%d sid_count:%d\n", 468108441Ssimokawa tmap->crc_len, tmap->generation, 469108441Ssimokawa tmap->node_count, tmap->self_id_count); 470108441Ssimokawa printf("id link gap_cnt speed delay cIRM power port0 port1 port2" 471108441Ssimokawa " ini more\n"); 472108441Ssimokawa for (i = 0; i < tmap->crc_len - 2; i++) { 473108441Ssimokawa sid = tmap->self_id[i]; 474108441Ssimokawa if (sid.p0.sequel) { 475108441Ssimokawa printf("%02d sequel packet\n", sid.p0.phy_id); 476108441Ssimokawa continue; 477108441Ssimokawa } 478110070Ssimokawa printf("%02d %2d %2d %4s %d %d %3s" 479108441Ssimokawa " %s %s %s %d %d\n", 480108441Ssimokawa sid.p0.phy_id, 481108441Ssimokawa sid.p0.link_active, 482108441Ssimokawa sid.p0.gap_count, 483108441Ssimokawa speed[sid.p0.phy_speed], 484108441Ssimokawa sid.p0.phy_delay, 485108441Ssimokawa sid.p0.contender, 486108441Ssimokawa pwr_class[sid.p0.power_class], 487108441Ssimokawa port_status[sid.p0.port0], 488108441Ssimokawa port_status[sid.p0.port1], 489108441Ssimokawa port_status[sid.p0.port2], 490108441Ssimokawa sid.p0.initiated_reset, 491108441Ssimokawa sid.p0.more_packets 492108441Ssimokawa ); 493108441Ssimokawa } 494108441Ssimokawa free(tmap); 495108441Ssimokawa} 496108441Ssimokawa 497118457Ssimokawastatic void 498120432Ssimokawaread_phy_registers(int fd, u_int8_t *buf, int offset, int len) 499120432Ssimokawa{ 500120432Ssimokawa struct fw_reg_req_t reg; 501120432Ssimokawa int i; 502120432Ssimokawa 503120432Ssimokawa for (i = 0; i < len; i++) { 504120432Ssimokawa reg.addr = offset + i; 505120432Ssimokawa if (ioctl(fd, FWOHCI_RDPHYREG, ®) < 0) 506120432Ssimokawa err(1, "ioctl"); 507120432Ssimokawa buf[i] = (u_int8_t) reg.data; 508120432Ssimokawa printf("0x%02x ", reg.data); 509120432Ssimokawa } 510120432Ssimokawa printf("\n"); 511120432Ssimokawa} 512120432Ssimokawa 513120432Ssimokawastatic void 514120432Ssimokawaread_phy_page(int fd, u_int8_t *buf, int page, int port) 515120432Ssimokawa{ 516120432Ssimokawa struct fw_reg_req_t reg; 517120432Ssimokawa 518120432Ssimokawa reg.addr = 0x7; 519120432Ssimokawa reg.data = ((page & 7) << 5) | (port & 0xf); 520120432Ssimokawa if (ioctl(fd, FWOHCI_WRPHYREG, ®) < 0) 521120432Ssimokawa err(1, "ioctl"); 522120432Ssimokawa read_phy_registers(fd, buf, 8, 8); 523120432Ssimokawa} 524120432Ssimokawa 525120432Ssimokawastatic void 526120432Ssimokawadump_phy_registers(int fd) 527120432Ssimokawa{ 528120432Ssimokawa struct phyreg_base b; 529120432Ssimokawa struct phyreg_page0 p; 530120432Ssimokawa struct phyreg_page1 v; 531120432Ssimokawa int i; 532120432Ssimokawa 533120432Ssimokawa printf("=== base register ===\n"); 534120432Ssimokawa read_phy_registers(fd, (u_int8_t *)&b, 0, 8); 535120432Ssimokawa printf( 536120432Ssimokawa "Physical_ID:%d R:%d CPS:%d\n" 537120432Ssimokawa "RHB:%d IBR:%d Gap_Count:%d\n" 538120432Ssimokawa "Extended:%d Num_Ports:%d\n" 539120432Ssimokawa "PHY_Speed:%d Delay:%d\n" 540120432Ssimokawa "LCtrl:%d C:%d Jitter:%d Pwr_Class:%d\n" 541120432Ssimokawa "WDIE:%d ISBR:%d CTOI:%d CPSI:%d STOI:%d PEI:%d EAA:%d EMC:%d\n" 542120432Ssimokawa "Max_Legacy_SPD:%d BLINK:%d Bridge:%d\n" 543120432Ssimokawa "Page_Select:%d Port_Select%d\n", 544120432Ssimokawa b.phy_id, b.r, b.cps, 545120432Ssimokawa b.rhb, b.ibr, b.gap_count, 546120432Ssimokawa b.extended, b.num_ports, 547120432Ssimokawa b.phy_speed, b.delay, 548120432Ssimokawa b.lctrl, b.c, b.jitter, b.pwr_class, 549120432Ssimokawa b.wdie, b.isbr, b.ctoi, b.cpsi, b.stoi, b.pei, b.eaa, b.emc, 550120432Ssimokawa b.legacy_spd, b.blink, b.bridge, 551120432Ssimokawa b.page_select, b.port_select 552120432Ssimokawa ); 553120432Ssimokawa 554120432Ssimokawa for (i = 0; i < b.num_ports; i ++) { 555120432Ssimokawa printf("\n=== page 0 port %d ===\n", i); 556120432Ssimokawa read_phy_page(fd, (u_int8_t *)&p, 0, i); 557120432Ssimokawa printf( 558120432Ssimokawa "Astat:%d BStat:%d Ch:%d Con:%d RXOK:%d Dis:%d\n" 559120432Ssimokawa "Negotiated_speed:%d PIE:%d Fault:%d Stanby_fault:%d Disscrm:%d B_Only:%d\n" 560120432Ssimokawa "DC_connected:%d Max_port_speed:%d LPP:%d Cable_speed:%d\n" 561120432Ssimokawa "Connection_unreliable:%d Beta_mode:%d\n" 562120432Ssimokawa "Port_error:0x%x\n" 563120432Ssimokawa "Loop_disable:%d In_standby:%d Hard_disable:%d\n", 564120432Ssimokawa p.astat, p.bstat, p.ch, p.con, p.rxok, p.dis, 565120432Ssimokawa p.negotiated_speed, p.pie, p.fault, p.stanby_fault, p.disscrm, p.b_only, 566120432Ssimokawa p.dc_connected, p.max_port_speed, p.lpp, p.cable_speed, 567120432Ssimokawa p.connection_unreliable, p.beta_mode, 568120432Ssimokawa p.port_error, 569120432Ssimokawa p.loop_disable, p.in_standby, p.hard_disable 570120432Ssimokawa ); 571120432Ssimokawa } 572120432Ssimokawa printf("\n=== page 1 ===\n"); 573120432Ssimokawa read_phy_page(fd, (u_int8_t *)&v, 1, 0); 574120432Ssimokawa printf( 575120432Ssimokawa "Compliance:%d\n" 576120432Ssimokawa "Vendor_ID:0x%06x\n" 577120432Ssimokawa "Product_ID:0x%06x\n", 578120432Ssimokawa v.compliance, 579120432Ssimokawa (v.vendor_id[0] << 16) | (v.vendor_id[1] << 8) | v.vendor_id[2], 580120432Ssimokawa (v.product_id[0] << 16) | (v.product_id[1] << 8) | v.product_id[2] 581120432Ssimokawa ); 582120432Ssimokawa} 583120432Ssimokawa 584120432Ssimokawastatic void 585118457Ssimokawaopen_dev(int *fd, char *devbase) 586118457Ssimokawa{ 587118457Ssimokawa char devname[256]; 588118457Ssimokawa int i; 589118457Ssimokawa 590118457Ssimokawa if (*fd < 0) { 591118457Ssimokawa for (i = 0; i < 4; i++) { 592118457Ssimokawa snprintf(devname, sizeof(devname), "%s.%d", devbase, i); 593118457Ssimokawa if ((*fd = open(devname, O_RDWR)) >= 0) 594118457Ssimokawa break; 595118457Ssimokawa } 596118457Ssimokawa if (*fd < 0) 597118457Ssimokawa err(1, "open"); 598118457Ssimokawa 599118457Ssimokawa } 600118457Ssimokawa} 601118457Ssimokawa 602108441Ssimokawaint 603136845Ssimokawasysctl_set_int(char *name, int val) 604136845Ssimokawa{ 605136845Ssimokawa if (sysctlbyname(name, NULL, NULL, &val, sizeof(int)) < 0) 606136845Ssimokawa err(1, "sysctl %s failed.", name); 607136845Ssimokawa} 608136845Ssimokawa 609136845Ssimokawaint 610108441Ssimokawamain(int argc, char **argv) 611108441Ssimokawa{ 612108441Ssimokawa u_int32_t crom_buf[1024/4]; 613118457Ssimokawa char devbase[1024] = "/dev/fw0"; 614109991Ssimokawa int fd, i, tmp, ch, len=1024; 615136845Ssimokawa struct fw_eui64 eui; 616136845Ssimokawa struct eui64 target; 617108441Ssimokawa 618118457Ssimokawa fd = -1; 619108441Ssimokawa 620108441Ssimokawa if (argc < 2) { 621118457Ssimokawa open_dev(&fd, devbase); 622108441Ssimokawa list_dev(fd); 623108441Ssimokawa } 624108441Ssimokawa 625136845Ssimokawa while ((ch = getopt(argc, argv, "g:m:o:s:b:prtc:d:l:u:R:S:")) != -1) 626108441Ssimokawa switch(ch) { 627108441Ssimokawa case 'b': 628108441Ssimokawa tmp = strtol(optarg, NULL, 0); 629118457Ssimokawa open_dev(&fd, devbase); 630108441Ssimokawa set_pri_req(fd, tmp); 631108441Ssimokawa break; 632108441Ssimokawa case 'c': 633118457Ssimokawa open_dev(&fd, devbase); 634129760Sbrooks tmp = str2node(fd, optarg); 635108441Ssimokawa get_crom(fd, tmp, crom_buf, len); 636108441Ssimokawa show_crom(crom_buf); 637108441Ssimokawa break; 638108441Ssimokawa case 'd': 639118457Ssimokawa open_dev(&fd, devbase); 640129760Sbrooks tmp = str2node(fd, optarg); 641108441Ssimokawa get_crom(fd, tmp, crom_buf, len); 642108441Ssimokawa dump_crom(crom_buf); 643108441Ssimokawa break; 644118457Ssimokawa case 'g': 645118457Ssimokawa tmp = strtol(optarg, NULL, 0); 646118457Ssimokawa open_dev(&fd, devbase); 647118457Ssimokawa send_phy_config(fd, -1, tmp); 648118457Ssimokawa break; 649108441Ssimokawa case 'l': 650108441Ssimokawa load_crom(optarg, crom_buf); 651108441Ssimokawa show_crom(crom_buf); 652108441Ssimokawa break; 653136845Ssimokawa case 'm': 654136845Ssimokawa if (eui64_hostton(optarg, &target) != 0 && 655136845Ssimokawa eui64_aton(optarg, &target) != 0) 656136845Ssimokawa errx(1, "invalid target: %s", optarg); 657136845Ssimokawa eui.hi = ntohl(*(u_int32_t*)&(target.octet[0])); 658136845Ssimokawa eui.lo = ntohl(*(u_int32_t*)&(target.octet[4])); 659136845Ssimokawa sysctl_set_int("hw.firewire.fwmem.eui64_hi", eui.hi); 660136845Ssimokawa sysctl_set_int("hw.firewire.fwmem.eui64_lo", eui.lo); 661136845Ssimokawa break; 662118457Ssimokawa case 'o': 663118457Ssimokawa open_dev(&fd, devbase); 664129760Sbrooks tmp = str2node(fd, optarg); 665118457Ssimokawa send_link_on(fd, tmp); 666118457Ssimokawa break; 667120432Ssimokawa case 'p': 668120432Ssimokawa open_dev(&fd, devbase); 669120432Ssimokawa dump_phy_registers(fd); 670120432Ssimokawa break; 671118457Ssimokawa case 'r': 672118457Ssimokawa open_dev(&fd, devbase); 673118457Ssimokawa if(ioctl(fd, FW_IBUSRST, &tmp) < 0) 674118457Ssimokawa err(1, "ioctl"); 675118457Ssimokawa break; 676118457Ssimokawa case 's': 677118457Ssimokawa open_dev(&fd, devbase); 678129760Sbrooks tmp = str2node(fd, optarg); 679118457Ssimokawa reset_start(fd, tmp); 680118457Ssimokawa break; 681118457Ssimokawa case 't': 682118457Ssimokawa open_dev(&fd, devbase); 683118457Ssimokawa show_topology_map(fd); 684118457Ssimokawa break; 685118457Ssimokawa case 'u': 686118457Ssimokawa tmp = strtol(optarg, NULL, 0); 687118457Ssimokawa snprintf(devbase, sizeof(devbase), "/dev/fw%d", tmp); 688118457Ssimokawa if (fd > 0) { 689118457Ssimokawa close(fd); 690118457Ssimokawa fd = -1; 691118457Ssimokawa } 692118457Ssimokawa if (argc == optind) { 693118457Ssimokawa open_dev(&fd, devbase); 694118457Ssimokawa list_dev(fd); 695118457Ssimokawa } 696118457Ssimokawa break; 697109737Ssimokawa#define TAG (1<<6) 698109737Ssimokawa#define CHANNEL 63 699109737Ssimokawa case 'R': 700118457Ssimokawa open_dev(&fd, devbase); 701109737Ssimokawa dvrecv(fd, optarg, TAG | CHANNEL, -1); 702109737Ssimokawa break; 703109737Ssimokawa case 'S': 704118457Ssimokawa open_dev(&fd, devbase); 705109737Ssimokawa dvsend(fd, optarg, TAG | CHANNEL, -1); 706109737Ssimokawa break; 707108441Ssimokawa default: 708108441Ssimokawa usage(); 709108441Ssimokawa } 710108441Ssimokawa return 0; 711108441Ssimokawa} 712