From b018dcd1b897755de577b6a32e5ea73d7918e857 Mon Sep 17 00:00:00 2001 From: Hidetoshi Shimokawa Date: Tue, 31 Dec 2002 10:28:49 +0000 Subject: [PATCH] - Implement primal Configuration ROM parser. - Support multiple LUNs for SBP-II. --- sys/conf/files | 5 +- sys/dev/firewire/fwcrom.c | 254 +++++++++++++++++++++++++ sys/dev/firewire/sbp.c | 52 +++-- sys/modules/firewire/firewire/Makefile | 2 +- 4 files changed, 295 insertions(+), 18 deletions(-) create mode 100644 sys/dev/firewire/fwcrom.c diff --git a/sys/conf/files b/sys/conf/files index 5a560286b21d..484f5f714bff 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -384,10 +384,11 @@ dev/fe/if_fe.c optional fe dev/fe/if_fe_pccard.c optional fe card dev/fe/if_fe_pccard.c optional fe pccard dev/firewire/firewire.c optional firewire +dev/firewire/fwcrom.c optional firewire +dev/firewire/fwdev.c optional firewire +dev/firewire/fwmem.c optional firewire dev/firewire/fwohci.c optional firewire dev/firewire/fwohci_pci.c optional firewire pci -dev/firewire/fwmem.c optional firewire -dev/firewire/fwdev.c optional firewire dev/firewire/if_fwe.c optional fwe dev/firewire/sbp.c optional sbp dev/fxp/if_fxp.c optional fxp diff --git a/sys/dev/firewire/fwcrom.c b/sys/dev/firewire/fwcrom.c new file mode 100644 index 000000000000..34e16746dc76 --- /dev/null +++ b/sys/dev/firewire/fwcrom.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2002 + * Hidetoshi Shimokawa. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * + * This product includes software developed by Hidetoshi Shimokawa. + * + * 4. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#ifdef _KERNEL +#include +#include +#else +#include +#include +#include +#include +#include +#include +#endif + +void +crom_init_context(struct crom_context *cc, u_int32_t *p) +{ + struct csrhdr *hdr; + + hdr = (struct csrhdr *)p; + if (hdr->info_len == 1) { + /* minimum ROM */ + cc->depth = -1; + } + p += 1 + hdr->info_len; + cc->depth = 0; + cc->stack[0].dir = (struct csrdirectory *)p; + cc->stack[0].index = 0; +} + +struct csrreg * +crom_get(struct crom_context *cc) +{ + struct crom_ptr *ptr; + + ptr = &cc->stack[cc->depth]; + return (&ptr->dir->entry[ptr->index]); +} + +void +crom_next(struct crom_context *cc) +{ + struct crom_ptr *ptr; + struct csrreg *reg; + + if (cc->depth < 0) + return; + reg = crom_get(cc); + if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { + cc->depth ++; + if (cc->depth > CROM_MAX_DEPTH) { + printf("crom_next: too deep\n"); + cc->depth --; + goto again; + } + cc->stack[cc->depth].dir = (struct csrdirectory *) + (reg + reg->val); + cc->stack[cc->depth].index = 0; + return; + } +again: + ptr = &cc->stack[cc->depth]; + ptr->index ++; + if (ptr->index < ptr->dir->crc_len) + return; + if (cc->depth > 0) { + cc->depth--; + goto again; + } + /* no more data */ + cc->depth = -1; +} + + +struct csrreg * +crom_search_key(struct crom_context *cc, u_int8_t key) +{ + struct csrreg *reg; + + while(cc->depth >= 0) { + reg = crom_get(cc); + if (reg->key == key) + return reg; + crom_next(cc); + } + return NULL; +} + +void +crom_parse_text(struct crom_context *cc, char *buf, int len) +{ + struct csrreg *reg; + struct csrtext *textleaf; + u_int32_t *bp; + int i, qlen; + static char *nullstr = "(null)"; + + reg = crom_get(cc); + if (reg->key != CROM_TEXTLEAF) { + strncpy(buf, nullstr, len); + return; + } + textleaf = (struct csrtext *)(reg + reg->val); + + /* XXX should check spec and type */ + + bp = (u_int32_t *)&buf[0]; + qlen = textleaf->crc_len - 2; + if (len < qlen * 4) + qlen = len/4; + for (i = 0; i < qlen; i ++) + *bp++ = ntohl(textleaf->text[i]); + /* make sure to terminate the string */ + if (len <= qlen * 4) + buf[len - 1] = 0; + else + buf[qlen * 4] = 0; +} + +u_int16_t +crom_crc(u_int32_t *ptr, int len) +{ + int i, shift; + u_int32_t data, sum, crc = 0; + + for (i = 0; i < len; i++) { + data = ptr[i]; + for (shift = 28; shift >= 0; shift -= 4) { + sum = ((crc >> 12) ^ (data >> shift)) & 0xf; + crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; + } + crc &= 0xffff; + } + return((u_int16_t) crc); +} + +#ifndef _KERNEL +char * +crom_desc(struct crom_context *cc, char *buf, int len) +{ + struct csrreg *reg; + struct csrdirectory *dir; + char *desc; + + reg = crom_get(cc); + switch (reg->key & CSRTYPE_MASK) { + case CSRTYPE_I: + snprintf(buf, len, "%d", reg->val); + break; + case CSRTYPE_L: + case CSRTYPE_C: + snprintf(buf, len, "offset=0x%04x(%d)", reg->val, reg->val); + break; + case CSRTYPE_D: + dir = (struct csrdirectory *) (reg + reg->val); + snprintf(buf, len, "len=0x%04x(%d) crc=0x%04x", + dir->crc_len, dir->crc_len, dir->crc); + } + switch (reg->key) { + case 0x03: + desc = "module_vendor_ID"; + break; + case 0x04: + desc = "hardware_version"; + break; + case 0x0c: + desc = "node_capabilities"; + break; + case 0x12: + desc = "unit_spec_ID"; + break; + case 0x13: + desc = "unit_sw_version"; + break; + case 0x14: + desc = "logical_unit_number"; + break; + case 0x17: + desc = "model_ID"; + break; + case 0x38: + desc = "command_set_spec_ID"; + break; + case 0x39: + desc = "command_set"; + break; + case 0x3a: + desc = "unit_characteristics"; + break; + case 0x3b: + desc = "command_set_revision"; + break; + case 0x3c: + desc = "firmware_revision"; + break; + case 0x3d: + desc = "reconnect_timeout"; + break; + case 0x54: + desc = "management_agent"; + break; + case 0x81: + desc = "text_leaf"; + crom_parse_text(cc, buf, len); + break; + case 0xd1: + desc = "unit_directory"; + break; + case 0xd4: + desc = "logical_unit_directory"; + break; + default: + desc = "unknown"; + } + return desc; +} +#endif diff --git a/sys/dev/firewire/sbp.c b/sys/dev/firewire/sbp.c index 6ddb863c95a5..2317e99ce81d 100644 --- a/sys/dev/firewire/sbp.c +++ b/sys/dev/firewire/sbp.c @@ -253,8 +253,9 @@ struct sbp_dev{ #define SBP_DEV_ATTACHED 5 /* in operation */ #define SBP_DEV_DEAD 6 /* unavailable unit */ #define SBP_DEV_RETRY 7 /* unavailable unit */ - int status; - int lun_id; + u_int8_t status; + u_int8_t type; + u_int16_t lun_id; struct cam_path *path; struct sbp_target *target; struct sbp_login_res login; @@ -388,7 +389,6 @@ END_DEBUG static void sbp_show_sdev_info(struct sbp_dev *sdev, int new) { - int lun; struct fw_device *fwdev; printf("%s:%d:%d ", @@ -400,11 +400,10 @@ sbp_show_sdev_info(struct sbp_dev *sdev, int new) return; } fwdev = sdev->target->fwdev; - lun = getcsrdata(fwdev, 0x14); printf("ordered:%d type:%d EUI:%08x%08x node:%d " "speed:%d maxrec:%d", - (lun & 0x00400000) >> 22, - (lun & 0x001f0000) >> 16, + (sdev->type & 0x40) >> 6, + (sdev->type & 0x1f), fwdev->eui.hi, fwdev->eui.lo, fwdev->dst, @@ -422,9 +421,11 @@ sbp_show_sdev_info(struct sbp_dev *sdev, int new) static struct sbp_target * sbp_alloc_target(struct sbp_softc *sbp, struct fw_device *fwdev) { - int i, lun; + int i, maxlun, lun; struct sbp_target *target; struct sbp_dev *sdev; + struct crom_context cc; + struct csrreg *reg; SBP_DEBUG(1) printf("sbp_alloc_target\n"); @@ -448,10 +449,24 @@ END_DEBUG } target->mgm_hi = 0xffff; target->mgm_lo = 0xf0000000 | target->mgm_lo << 2; - /* XXX should probe all luns */ /* XXX num_lun may be changed. realloc luns? */ - lun = getcsrdata(target->fwdev, 0x14) & 0xff; - target->num_lun = lun + 1; + crom_init_context(&cc, target->fwdev->csrrom); + /* XXX shoud parse appropriate unit directories only */ + maxlun = -1; + while (cc.depth >= 0) { + reg = crom_search_key(&cc, CROM_LUN); + if (reg == NULL) + break; + lun = reg->val & 0xff; + printf("lun %d found\n", lun); + if (maxlun < lun) + maxlun = lun; + crom_next(&cc); + } + target->num_lun = maxlun + 1; + if (maxlun < 0) { + printf("no lun found!\n"); + } target->luns = (struct sbp_dev *) malloc( sizeof(struct sbp_dev) * target->num_lun, M_SBP, M_NOWAIT | M_ZERO); @@ -460,10 +475,17 @@ END_DEBUG sdev->lun_id = i; sdev->target = target; STAILQ_INIT(&sdev->ocbs); - if (i == lun) - sdev->status = SBP_DEV_RESET; - else - sdev->status = SBP_DEV_DEAD; + sdev->status = SBP_DEV_DEAD; + } + crom_init_context(&cc, target->fwdev->csrrom); + while (cc.depth >= 0) { + reg = crom_search_key(&cc, CROM_LUN); + if (reg == NULL) + break; + lun = reg->val & 0xff; + target->luns[lun].status = SBP_DEV_RESET; + target->luns[lun].type = (reg->val & 0x0f00) >> 16; + crom_next(&cc); } return target; } @@ -1097,7 +1119,7 @@ END_DEBUG fp->mode.wreqb.dest_lo = htonl(sdev->target->mgm_lo); fp->mode.wreqb.len = htons(8); fp->mode.wreqb.extcode = 0; - fp->mode.wreqb.payload[0] = htonl(((sdev->target->sbp->fd.fc->nodeid | FWLOCALBUS )<< 16)); + fp->mode.wreqb.payload[0] = htonl(nid << 16); fp->mode.wreqb.payload[1] = htonl(vtophys(&ocb->orb[0])); sbp_enqueue_ocb(sdev, ocb); diff --git a/sys/modules/firewire/firewire/Makefile b/sys/modules/firewire/firewire/Makefile index aaa75983afa3..01771f76e9ab 100644 --- a/sys/modules/firewire/firewire/Makefile +++ b/sys/modules/firewire/firewire/Makefile @@ -9,7 +9,7 @@ SRCS = bus_if.h device_if.h pci_if.h \ firewire.c firewire.h firewire_phy.h firewirebusreg.h firewirereg.h \ fwohci.c fwohci_pci.c fwohcireg.h fwohcivar.h \ iec13213.h iec68113.h \ - fwmem.c fwmem.h fwdev.c + fwcrom.c fwdev.c fwmem.c fwmem.h EXPORT_SYMS= YES