- Implement primal Configuration ROM parser.
- Support multiple LUNs for SBP-II.
This commit is contained in:
parent
f54846c3ec
commit
b018dcd1b8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=108503
@ -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
254
sys/dev/firewire/fwcrom.c
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user