#include <ql_apps.h>
#include <ql_api.h>
#include <ql_debug.h>
#include <ql_ioctl.h>
#include <ql_xioctl.h>
#ifndef FC_HBA_PORTSPEED_8GBIT
#define FC_HBA_PORTSPEED_8GBIT 16
#endif
static uint32_t ql_get_basedev_len(ql_adapter_state_t *, uint32_t *,
uint32_t *);
static ql_adapter_state_t *ql_search_basedev(ql_adapter_state_t *, uint32_t);
static struct ql_known_models {
uint16_t ssid;
uint16_t ssvid;
char model[256];
char model_description[256];
} models[] = {
{
0x2, 0x1077, "QLA2200", "QLogic PCI to 1Gb FC, Single Channel"
}, {
0x9, 0x1077, "QLA2300", "QLogic PCI to 2Gb FC, Single Channel"
}, {
0x4082, 0x1077, "375-3019-xx", "X6799A"
}, {
0x4083, 0x1077, "375-3030-xx", "X6727A"
}, {
0x4084, 0x1077, "375-0118-xx", "X6748A"
}, {
0x4085, 0x1077, "375-3048-xx", "X6757A"
}, {
0x100, 0x1077, "QLA2340",
"QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
}, {
0x101, 0x1077, "QLA2342",
"QLogic 133MHz PCI-X to 2Gb FC, Dual Channel"
}, {
0x102, 0x1077, "QLA2344",
"QLogic 133MHz PCI-X to 2Gb FC, Quad Channel"
}, {
0x103, 0x1077, "QCP2342", "QLogic cPCI to 2Gb FC, Dual Channel"
}, {
0x104, 0x1077, "QSB2340", "QLogic SBUS to 2Gb FC, Single Channel"
}, {
0x105, 0x1077, "QSB2342", "QLogic SBUS to 2Gb FC, Dual Channel"
}, {
0x0106, 0x1077, "375-3102-xx", "SG-XPCI1FC-QF2 (X6767A)"
}, {
0x109, 0x1077, "QCP2340", "QLogic cPCI to 2Gb FC, Single Channel"
}, {
0x010A, 0x1077, "375-3108-xx", "SG-XPCI2FC-QF2 (X6768A)"
}, {
0x115, 0x1077, "QLA2360",
"QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
}, {
0x116, 0x1077, "QLA2362",
"QLogic 133MHz PCI-X to 2Gb FC, Dual Channel"
}, {
0x117, 0x1077, "QLE2360",
"QLogic PCI-Express to 2Gb FC, Single Channel"
}, {
0x118, 0x1077, "QLE2362",
"QLogic PCI Express to 2Gb FC, Dual Channel"
}, {
0x119, 0x1077, "QLA200",
"QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
}, {
0x11c, 0x1077, "QLA200P",
"QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
}, {
0x12f, 0x1077, "QLA210",
"QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
}, {
0x130, 0x1077, "EMC250-051-900",
"QLogic 133MHz PCI-X to 2Gb FC, Single Channel"
}, {
0x132, 0x1077, "375-32X3-01", "SG-PCI1FC-QLC"
}, {
0x13e, 0x1077, "QLE210",
"QLogic PCI Express 2Gb FC, Single Channel"
}, {
0x149, 0x1077, "QLA2340",
"SUN - 133MHz PCI-X to 2Gb FC, Single Channel"
}, {
0x100, 0x0e11, "QLA2340-HP", "PCIX to 2Gb FC, Single Channel"
}, {
0x101, 0x0e11, "QLA2342-HP", "PCIX to 2Gb FC, Dual Channel"
}, {
0x103, 0x0e11, "QLA2312-HP",
"HP Bladed Server Balcony Card - HP BalcnL"
}, {
0x104, 0x0e11, "QLA2312-HP", "HP Bladed Server - HP MezzF"
}, {
0x105, 0x0e11, "QLA2312-HP", "HP Bladed Server - HP BalcnL"
}, {
0x106, 0x0e11, "QLA2312-HP", "HP Bladed Server - HP BalcnF"
}, {
0x107, 0x0e11, "QLA2312-HP", "HP Bladed Server"
}, {
0x108, 0x0e11, "QLA2312-HP", "HP Bladed Server"
}, {
0x27d, 0x1014, "IBM-FCEC",
"IBM eServer Blade Center FC Expansion Card"
}, {
0x2fb, 0x1014, "IBM-FCEC",
"IBM eServer Blade Center FC SFF Expansion Card"
}, {
0x34ba, 0x8086, "Intel SBFCM",
"Intel Server FC Expansion Card SBFCM"
}, {
0x34a0, 0x8086, "Intel SBEFCM",
"Intel Server SFF FC Expansion Card SBFCM"
}, {
0x1051, 0x1734, "FCI/O-CARD2Gb/s",
"FSC-Quanta FC I/O-Card 2GBit/s"
}, {
0x18a, 0x1028, "FCI/O-CARD2Gb/s", "Dell Glacier Blade Server"
}, {
0, 0, 0, 0, 0, 0
} };
void
ql_populate_hba_fru_details(ql_adapter_state_t *ha,
fc_fca_port_info_t *port_info)
{
fca_port_attrs_t *attrs = &port_info->pi_attrs;
uint16_t chip = ha->device_id;
uint16_t model = ha->subsys_id;
uint16_t ssdevid = ha->subven_id;
size_t vlen;
int32_t i;
QL_PRINT_3(ha, "started\n");
attrs = &port_info->pi_attrs;
(void) snprintf(attrs->manufacturer, FCHBA_MANUFACTURER_LEN,
"QLogic Corp.");
(void) snprintf(attrs->driver_name, FCHBA_DRIVER_NAME_LEN,
"%s", QL_NAME);
(void) snprintf(attrs->driver_version, FCHBA_DRIVER_VERSION_LEN,
"%s", ha->adapter_stats->revlvl.qlddv);
if ((i = ql_vpd_lookup(ha, (uint8_t *)VPD_TAG_SN, (uint8_t *)
attrs->serial_number, FCHBA_SERIAL_NUMBER_LEN)) == -1) {
attrs->serial_number[0] = '\0';
}
attrs->hardware_version[0] = '\0';
(void) snprintf(attrs->firmware_version, FCHBA_FIRMWARE_VERSION_LEN,
"%02d.%02d.%02d", ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version);
if (ha->fcache != NULL) {
uint32_t types = FTYPE_BIOS|FTYPE_FCODE|FTYPE_EFI;
ql_fcache_t *fptr = ha->fcache;
int8_t *orv = &*attrs->option_rom_version;
while ((fptr != NULL) && (types != 0)) {
if ((fptr = ql_get_fbuf(ha->fcache, types)) != NULL) {
switch (fptr->type) {
case FTYPE_FCODE:
(void) snprintf(orv,
FCHBA_OPTION_ROM_VERSION_LEN,
"%s fcode: %s;", orv, fptr->verstr);
break;
case FTYPE_BIOS:
(void) snprintf(orv,
FCHBA_OPTION_ROM_VERSION_LEN,
"%s BIOS: %s;", orv, fptr->verstr);
break;
case FTYPE_EFI:
(void) snprintf(orv,
FCHBA_OPTION_ROM_VERSION_LEN,
"%s EFI: %s;", orv, fptr->verstr);
break;
default:
EL(ha, "ignoring ftype: %xh\n",
fptr->type);
break;
}
types &= ~(fptr->type);
}
}
}
if (strlen(attrs->option_rom_version) == 0) {
int rval = -1;
uint32_t i = 0;
caddr_t fcode_ver_buf = NULL;
if (CFG_IST(ha, CFG_CTRL_22XX)) {
rval = ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version",
(caddr_t)&fcode_ver_buf, (int32_t *)&i);
}
(void) snprintf(attrs->option_rom_version,
FCHBA_OPTION_ROM_VERSION_LEN, "%s",
(rval == DDI_PROP_SUCCESS ? fcode_ver_buf :
"No boot image detected"));
if (fcode_ver_buf != NULL) {
kmem_free(fcode_ver_buf, (size_t)i);
}
}
attrs->vendor_specific_id = ha->adapter_features;
attrs->max_frame_size = ha->loginparams.common_service.rx_bufsize;
attrs->supported_cos = 0x10000000;
switch (chip & 0xFF00) {
case 0x2000:
attrs->supported_speed = chip == 0x2071 ?
FC_HBA_PORTSPEED_32GBIT : FC_HBA_PORTSPEED_16GBIT;
break;
case 0x2200:
attrs->supported_speed = chip == 0x2261 ?
FC_HBA_PORTSPEED_16GBIT : FC_HBA_PORTSPEED_1GBIT;
break;
case 0x2300:
attrs->supported_speed = FC_HBA_PORTSPEED_2GBIT |
FC_HBA_PORTSPEED_1GBIT;
break;
case 0x2400:
case 0x8400:
attrs->supported_speed = FC_HBA_PORTSPEED_4GBIT |
FC_HBA_PORTSPEED_2GBIT | FC_HBA_PORTSPEED_1GBIT;
break;
case 0x8000:
attrs->supported_speed = FC_HBA_PORTSPEED_10GBIT;
break;
case 0x2500:
attrs->supported_speed = FC_HBA_PORTSPEED_8GBIT |
FC_HBA_PORTSPEED_4GBIT | FC_HBA_PORTSPEED_2GBIT |
FC_HBA_PORTSPEED_1GBIT;
switch (ha->sfp_stat) {
case 2:
case 4:
attrs->supported_speed &= ~FC_HBA_PORTSPEED_8GBIT;
break;
case 3:
case 5:
attrs->supported_speed &= ~FC_HBA_PORTSPEED_1GBIT;
break;
default:
EL(ha, "sfp_stat: %xh\n", ha->sfp_stat);
break;
}
break;
case 0x5400:
if (model == 0x13e) {
attrs->supported_speed = FC_HBA_PORTSPEED_2GBIT;
} else {
attrs->supported_speed = FC_HBA_PORTSPEED_4GBIT;
}
break;
case 0x6300:
attrs->supported_speed = FC_HBA_PORTSPEED_2GBIT;
break;
default:
attrs->supported_speed = FC_HBA_PORTSPEED_UNKNOWN;
break;
}
attrs->hba_fru_details.low = 0x514C6F6769630000;
if (ha->fru_hba_index == 0) {
EL(ha, "unable to generate high_fru details from "
"device path: %s\n", ha->devpath);
attrs->hba_fru_details.low = 0;
attrs->hba_fru_details.high = 0;
attrs->hba_fru_details.port_index = 0;
} else {
attrs->hba_fru_details.high = ha->fru_hba_index;
attrs->hba_fru_details.port_index = ha->fru_port_index;
}
switch (chip & 0xFF00) {
case 0x2200:
case 0x2300:
case 0x6300:
for (i = 0; models[i].ssid; i++) {
if ((model == models[i].ssid) &&
(ssdevid == models[i].ssvid)) {
break;
}
}
if (models[i].ssid) {
(void) snprintf(attrs->model, FCHBA_MODEL_LEN, "%s",
models[i].model);
(void) snprintf(attrs->model_description,
FCHBA_MODEL_DESCRIPTION_LEN, "%s",
models[i].model_description);
} else {
(void) snprintf(attrs->model, FCHBA_MODEL_LEN,
"%x", chip);
(void) snprintf(attrs->model_description,
FCHBA_MODEL_DESCRIPTION_LEN, "%x", chip);
}
if (models[i].ssid == 0x10a && ha->adapInfo[10] ==
(uint8_t)0x36) {
(void) snprintf(attrs->model, FCHBA_MODEL_LEN, "%s",
"375-3363-xx");
(void) snprintf(attrs->model_description,
FCHBA_MODEL_DESCRIPTION_LEN, "%s",
"SG-XPCI2FC-QF2-Z");
}
break;
case 0x2400:
case 0x2500:
case 0x5400:
case 0x8400:
case 0x8000:
default:
if ((i = ql_vpd_lookup(ha, (uint8_t *)VPD_TAG_PN,
(uint8_t *)attrs->model, FCHBA_MODEL_LEN)) >= 0) {
(void) ql_vpd_lookup(ha, (uint8_t *)VPD_TAG_PRODID,
(uint8_t *)attrs->model_description,
FCHBA_MODEL_DESCRIPTION_LEN);
} else {
(void) snprintf(attrs->model, FCHBA_MODEL_LEN,
"%x", chip);
(void) snprintf(attrs->model_description,
FCHBA_MODEL_DESCRIPTION_LEN, "%x", chip);
}
break;
}
vlen = (strlen(utsname.nodename) > FCHBA_SYMB_NAME_LEN ?
FCHBA_SYMB_NAME_LEN : strlen(utsname.nodename));
(void) snprintf((int8_t *)attrs->sym_node_name, vlen, "%s",
utsname.nodename);
vlen = (strlen(QL_NAME) + 9 > FCHBA_SYMB_NAME_LEN ?
FCHBA_SYMB_NAME_LEN : strlen(QL_NAME) + 9);
(void) snprintf((int8_t *)attrs->sym_port_name, vlen,
"%s(%d,%d)", QL_NAME, ha->instance, ha->vp_index);
QL_PRINT_3(ha, "done\n");
}
void
ql_setup_fruinfo(ql_adapter_state_t *ha)
{
uint32_t mybasedev_len;
ql_adapter_state_t *base_ha = NULL;
QL_PRINT_3(ha, "started\n");
if (ql_get_basedev_len(ha, &mybasedev_len, &ha->fru_port_index) == 0) {
base_ha = ql_search_basedev(ha, mybasedev_len);
if (base_ha != NULL && base_ha->fru_hba_index != 0) {
ha->fru_hba_index = base_ha->fru_hba_index;
ha->fru_port_index = base_ha->fru_port_index + 1;
} else {
ha->fru_hba_index = ql_gfru_hba_index++;
ha->fru_port_index = 0;
}
} else {
ha->fru_hba_index = 0;
ha->fru_port_index = 0;
}
QL_PRINT_3(ha, "done\n");
}
static uint32_t
ql_get_basedev_len(ql_adapter_state_t *ha, uint32_t *basedev_len,
uint32_t *port_index)
{
int32_t dev_off;
int32_t port_off;
int8_t *devstr;
QL_PRINT_3(ha, "started\n");
if (ha->devpath == NULL) {
return ((uint32_t)-1);
}
dev_off = (int32_t)(strlen(ha->devpath) - 1);
port_off = -1;
while ((dev_off >= 0) && (ha->devpath[dev_off] != '@')) {
if (ha->devpath[dev_off] == ',') {
port_off = dev_off + 1;
}
dev_off--;
}
if (dev_off < 0) {
EL(ha, "Invalid device path '%s'. Cannot get basedev\n",
ha->devpath);
return ((uint32_t)-1);
}
if (port_off == -1) {
*port_index = 0;
*basedev_len = (uint32_t)strlen(ha->devpath);
} else {
devstr = ha->devpath + port_off;
*port_index = stoi(&devstr);
if (*port_index == 0) {
EL(ha, "Invalid device path '%s'. Cannot get "
"port_index\n", ha->devpath);
return ((uint32_t)-1);
}
*basedev_len = (uint32_t)(port_off - 1);
}
QL_PRINT_3(ha, "done\n");
return (0);
}
static ql_adapter_state_t *
ql_search_basedev(ql_adapter_state_t *myha, uint32_t mybasedev_len)
{
ql_link_t *link;
ql_adapter_state_t *ha;
uint32_t basedev_len, port_index;
QL_PRINT_3(myha, "started\n", myha->instance);
for (link = ql_hba.first; link != NULL; link = link->next) {
ha = link->base_address;
if (ha == NULL) {
EL(myha, "null ha link detected!\n");
return (NULL);
}
if (ha == myha) {
continue;
}
if (ql_get_basedev_len(ha, &basedev_len, &port_index) != 0) {
if (ha->devpath == NULL) {
EL(myha, "Device path NULL. Unable to get "
"the basedev\n");
} else {
EL(myha, "Invalid device path '%s'. Cannot "
"get the hba index and port index\n",
ha->devpath);
}
continue;
}
if ((basedev_len == mybasedev_len) && (strncmp(myha->devpath,
ha->devpath, basedev_len) == 0)) {
QL_PRINT_3(myha, "found, done\n",
myha->instance);
return (ha);
}
}
QL_PRINT_3(myha, "not found, done\n", myha->instance);
return (NULL);
}