- Implement primal Configuration ROM parser.

- Support multiple LUNs for SBP-II.
This commit is contained in:
Hidetoshi Shimokawa 2002-12-31 10:28:49 +00:00
parent f54846c3ec
commit b018dcd1b8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=108503
4 changed files with 295 additions and 18 deletions

View File

@ -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

254
sys/dev/firewire/fwcrom.c Normal file
View File

@ -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 <sys/param.h>
#include <dev/firewire/firewire.h>
#include <dev/firewire/iec13213.h>
#ifdef _KERNEL
#include <sys/systm.h>
#include <sys/kernel.h>
#else
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <err.h>
#include <stdlib.h>
#include <string.h>
#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

View File

@ -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);

View File

@ -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