#include <ql_apps.h>
#include <ql_api.h>
#include <ql_debug.h>
#include <ql_init.h>
#include <ql_iocb.h>
#include <ql_isr.h>
#include <ql_mbx.h>
#include <ql_nx.h>
#include <ql_xioctl.h>
static uint16_t ql_nvram_request(ql_adapter_state_t *, uint32_t);
static int ql_nvram_24xx_config(ql_adapter_state_t *);
static void ql_23_properties(ql_adapter_state_t *, ql_init_cb_t *);
static void ql_24xx_properties(ql_adapter_state_t *, ql_init_24xx_cb_t *);
static int ql_check_isp_firmware(ql_adapter_state_t *);
static int ql_load_flash_fw(ql_adapter_state_t *);
static int ql_configure_loop(ql_adapter_state_t *);
static int ql_configure_hba(ql_adapter_state_t *);
static int ql_configure_fabric(ql_adapter_state_t *);
static int ql_configure_device_d_id(ql_adapter_state_t *);
static void ql_update_dev(ql_adapter_state_t *, uint32_t);
static void ql_set_max_read_req(ql_adapter_state_t *);
static void ql_configure_n_port_info(ql_adapter_state_t *);
static void ql_reset_24xx_chip(ql_adapter_state_t *);
static void ql_mps_reset(ql_adapter_state_t *);
int
ql_initialize_adapter(ql_adapter_state_t *ha)
{
int rval;
class_svc_param_t *class3_param;
caddr_t msg;
la_els_logi_t *els = &ha->loginparams;
int retries = 5;
QL_PRINT_10(ha, "started cfg=0x%llx\n", ha->cfg_flags);
do {
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= TASK_DAEMON_STOP_FLG |
TASK_DAEMON_SLEEPING_FLG | TASK_DAEMON_ALIVE_FLG |
TASK_DAEMON_IDLE_CHK_FLG;
ha->task_daemon_flags |= LOOP_DOWN;
TASK_DAEMON_UNLOCK(ha);
ha->loop_down_timer = LOOP_DOWN_TIMER_OFF;
ADAPTER_STATE_LOCK(ha);
ha->flags |= ABORT_CMDS_LOOP_DOWN_TMO;
ha->flags &= ~ONLINE;
ADAPTER_STATE_UNLOCK(ha);
ha->state = FC_STATE_OFFLINE;
msg = "Loop OFFLINE";
rval = ql_pci_sbus_config(ha);
if (rval != QL_SUCCESS) {
TASK_DAEMON_LOCK(ha);
if (!(ha->task_daemon_flags & ABORT_ISP_ACTIVE)) {
EL(ha, "ql_pci_sbus_cfg, isp_abort_needed\n");
ha->task_daemon_flags |= ISP_ABORT_NEEDED;
}
TASK_DAEMON_UNLOCK(ha);
continue;
}
(void) ql_setup_fcache(ha);
ql_reset_chip(ha);
if (ha->init_ctrl_blk.cb.version == 0) {
(void) ql_nvram_config(ha);
}
if ((rval = ql_check_isp_firmware(ha)) != QL_SUCCESS) {
if (ha->dev_state != NX_DEV_READY) {
EL(ha, "dev_state not ready, isp_abort_needed_2"
"\n");
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= ISP_ABORT_NEEDED;
TASK_DAEMON_UNLOCK(ha);
break;
}
if ((rval = ql_mbx_wrap_test(ha, NULL)) == QL_SUCCESS) {
rval = ql_load_isp_firmware(ha);
}
}
if (rval == QL_SUCCESS && (rval = ql_set_cache_line(ha)) ==
QL_SUCCESS && (rval = ql_init_rings(ha)) == QL_SUCCESS) {
ql_enable_intr(ha);
(void) ql_fw_ready(ha, ha->fwwait);
if (!DRIVER_SUSPENDED(ha) &&
ha->loop_down_timer == LOOP_DOWN_TIMER_OFF) {
if (ha->topology & QL_LOOP_CONNECTION) {
ha->state = ha->state | FC_STATE_LOOP;
msg = "Loop ONLINE";
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= STATE_ONLINE;
TASK_DAEMON_UNLOCK(ha);
} else if (ha->topology & QL_P2P_CONNECTION) {
ha->state = ha->state |
FC_STATE_ONLINE;
msg = "Link ONLINE";
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= STATE_ONLINE;
TASK_DAEMON_UNLOCK(ha);
} else {
msg = "Unknown Link state";
}
}
} else {
TASK_DAEMON_LOCK(ha);
if (!(ha->task_daemon_flags & ABORT_ISP_ACTIVE)) {
EL(ha, "failed, isp_abort_needed\n");
ha->task_daemon_flags |= ISP_ABORT_NEEDED |
LOOP_DOWN;
}
TASK_DAEMON_UNLOCK(ha);
}
} while (retries-- != 0 && ha->task_daemon_flags & ISP_ABORT_NEEDED);
cmn_err(CE_NOTE, "!Qlogic %s(%d): %s", QL_NAME, ha->instance, msg);
if (!(ha->flags & INTERRUPTS_ENABLED)) {
ql_enable_intr(ha);
}
ADAPTER_STATE_LOCK(ha);
ha->flags |= ONLINE;
ADAPTER_STATE_UNLOCK(ha);
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2) &&
ha->dev_state == NX_DEV_READY) {
ql_24xx_protect_flash(ha);
}
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~(FC_STATE_CHANGE | MARKER_NEEDED |
COMMAND_WAIT_NEEDED);
TASK_DAEMON_UNLOCK(ha);
bcopy(QL_VERSION, ha->adapter_stats->revlvl.qlddv, strlen(QL_VERSION));
els->common_service.fcph_version = 0x2006;
els->common_service.btob_credit = 3;
els->common_service.cmn_features =
ha->topology & QL_N_PORT ? 0x8000 : 0x8800;
els->common_service.conc_sequences = 0xff;
els->common_service.relative_offset = 3;
els->common_service.e_d_tov = 0x07d0;
class3_param = (class_svc_param_t *)&els->class_3;
class3_param->class_valid_svc_opt = 0x8800;
class3_param->rcv_data_size = els->common_service.rx_bufsize;
class3_param->conc_sequences = 0xff;
class3_param->open_sequences_per_exch = 1;
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
int
ql_pci_sbus_config(ql_adapter_state_t *ha)
{
uint32_t timer;
uint16_t cmd, w16;
QL_PRINT_10(ha, "started\n");
if (CFG_IST(ha, CFG_SBUS_CARD)) {
w16 = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_REVISION));
EL(ha, "FPGA rev is %d.%d", (w16 & 0xf0) >> 4,
w16 & 0xf);
} else {
cmd = (uint16_t)ql_pci_config_get16(ha, PCI_CONF_COMM);
cmd = (uint16_t)(cmd | PCI_COMM_IO | PCI_COMM_MAE |
PCI_COMM_ME | PCI_COMM_PARITY_DETECT |
PCI_COMM_SERR_ENABLE);
if (ql_get_cap_ofst(ha, PCI_CAP_ID_PCIX)) {
cmd = (uint16_t)(cmd | PCI_COMM_MEMWR_INVAL);
}
if (ha->device_id == 0x2300) {
WRT16_IO_REG(ha, hccr, HC_PAUSE_RISC);
for (timer = 0; timer < 30000; timer++) {
if ((RD16_IO_REG(ha, hccr) & HC_RISC_PAUSE) !=
0) {
break;
} else {
drv_usecwait(MILLISEC);
}
}
WRT16_IO_REG(ha, ctrl_status, 0x20);
if (RD16_IO_REG(ha, fb_cmd) == 6) {
cmd = (uint16_t)(cmd & ~PCI_COMM_MEMWR_INVAL);
}
WRT16_IO_REG(ha, ctrl_status, 0x0);
WRT16_IO_REG(ha, hccr, HC_RELEASE_RISC);
for (timer = 0; timer < 30000; timer++) {
if ((RD16_IO_REG(ha, hccr) & HC_RISC_PAUSE) ==
0) {
break;
} else {
drv_usecwait(MILLISEC);
}
}
} else if (ha->device_id == 0x2312) {
if ((RD16_IO_REG(ha, ctrl_status) & ISP_FUNC_NUM_MASK)
!= 0) {
ql_pci_config_put8(ha, 0x66, 0xc2);
}
}
if (!(CFG_IST(ha, CFG_CTRL_82XX)) &&
ha->pci_max_read_req != 0) {
ql_set_max_read_req(ha);
}
ql_pci_config_put16(ha, PCI_CONF_COMM, cmd);
ql_pci_config_put8(ha, PCI_CONF_CACHE_LINESZ, 0x10);
ql_pci_config_put8(ha, PCI_CONF_LATENCY_TIMER, 0x40);
if (!CFG_IST(ha, CFG_CTRL_278083)) {
w16 = (uint16_t)ql_pci_config_get16(ha, PCI_CONF_ROM);
w16 = (uint16_t)(w16 & ~BIT_0);
ql_pci_config_put16(ha, PCI_CONF_ROM, w16);
}
}
QL_PRINT_10(ha, "done\n");
return (QL_SUCCESS);
}
static void
ql_set_max_read_req(ql_adapter_state_t *ha)
{
int ofst;
uint16_t read_req, w16;
uint16_t tmp = ha->pci_max_read_req;
QL_PRINT_3(ha, "started\n");
if ((ofst = ql_get_cap_ofst(ha, PCI_CAP_ID_PCIX))) {
ofst += PCI_PCIX_COMMAND;
QL_PRINT_10(ha, "PCI-X Command Reg = %xh\n", ofst);
if (tmp == 512 || tmp == 1024 || tmp == 2048 ||
tmp == 4096) {
tmp = (uint16_t)(tmp >> 10);
for (read_req = 0; tmp != 0; read_req++) {
tmp = (uint16_t)(tmp >> 1);
}
w16 = (uint16_t)ql_pci_config_get16(ha, ofst);
w16 = (uint16_t)(w16 & ~(BIT_3 & BIT_2));
w16 = (uint16_t)(w16 | (read_req << 2));
ql_pci_config_put16(ha, ofst, w16);
} else {
EL(ha, "invalid parameter value for "
"'pci-max-read-request': %d; using system "
"default\n", tmp);
}
} else if ((ofst = ql_get_cap_ofst(ha, PCI_CAP_ID_PCI_E))) {
ofst += PCI_PCIE_DEVICE_CONTROL;
QL_PRINT_10(ha, "PCI-E Device Control Reg = %xh\n", ofst);
if (tmp == 128 || tmp == 256 || tmp == 512 ||
tmp == 1024 || tmp == 2048 || tmp == 4096) {
tmp = (uint16_t)(tmp >> 8);
for (read_req = 0; tmp != 0; read_req++) {
tmp = (uint16_t)(tmp >> 1);
}
w16 = (uint16_t)ql_pci_config_get16(ha, ofst);
w16 = (uint16_t)(w16 & ~(BIT_14 | BIT_13 |
BIT_12));
w16 = (uint16_t)(w16 | (read_req << 12));
ql_pci_config_put16(ha, ofst, w16);
} else {
EL(ha, "invalid parameter value for "
"'pci-max-read-request': %d; using system "
"default\n", tmp);
}
}
QL_PRINT_3(ha, "done\n");
}
int
ql_nvram_config(ql_adapter_state_t *ha)
{
uint32_t cnt;
caddr_t dptr1, dptr2;
ql_init_cb_t *icb = &ha->init_ctrl_blk.cb;
ql_ip_init_cb_t *ip_icb = &ha->ip_init_ctrl_blk.cb;
nvram_t *nv = (nvram_t *)ha->req_q[0]->req_ring.bp;
uint16_t *wptr = (uint16_t *)ha->req_q[0]->req_ring.bp;
uint8_t chksum = 0;
int rval;
int idpromlen;
char idprombuf[32];
uint32_t start_addr;
la_els_logi_t *els = &ha->loginparams;
QL_PRINT_10(ha, "started\n");
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
return (ql_nvram_24xx_config(ha));
}
start_addr = 0;
if ((rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA)) ==
QL_SUCCESS) {
for (cnt = 0; cnt < sizeof (nvram_t) / 2; cnt++) {
*wptr = (uint16_t)ql_get_nvram_word(ha,
(uint32_t)(cnt + start_addr));
chksum = (uint8_t)(chksum + (uint8_t)*wptr);
chksum = (uint8_t)(chksum + (uint8_t)(*wptr >> 8));
wptr++;
}
ql_release_nvram(ha);
}
if (rval != QL_SUCCESS || chksum || nv->id[0] != 'I' ||
nv->id[1] != 'S' || nv->id[2] != 'P' || nv->id[3] != ' ' ||
nv->nvram_version < 1) {
EL(ha, "failed, rval=%xh, checksum=%xh, "
"id=%02x%02x%02x%02xh, flsz=%xh, pciconfvid=%xh, "
"nvram_version=%x\n", rval, chksum, nv->id[0], nv->id[1],
nv->id[2], nv->id[3], ha->xioctl->fdesc.flash_size,
ha->subven_id, nv->nvram_version);
if (!((CFG_IST(ha, CFG_CTRL_22XX)) &&
(ha->xioctl->fdesc.flash_size == 0))) {
cmn_err(CE_WARN, "%s(%d): NVRAM configuration failed,"
" using driver defaults.", QL_NAME, ha->instance);
}
bzero((void *)nv, sizeof (nvram_t));
nv->parameter_block_version = ICB_VERSION;
nv->firmware_options[0] = BIT_4 | BIT_3 | BIT_2 | BIT_1;
nv->firmware_options[1] = BIT_7 | BIT_5 | BIT_2;
nv->max_frame_length[1] = 4;
if (CFG_IST(ha, CFG_CTRL_2363)) {
nv->max_frame_length[1] = 8;
}
nv->max_iocb_allocation[1] = 1;
nv->execution_throttle[0] = 16;
nv->login_retry_count = 8;
idpromlen = 32;
if (ddi_getlongprop_buf(DDI_DEV_T_ANY, ha->dip,
DDI_PROP_CANSLEEP, "idprom", (caddr_t)idprombuf,
&idpromlen) != DDI_PROP_SUCCESS) {
QL_PRINT_10(ha, "Unable to read idprom "
"property\n");
cmn_err(CE_WARN, "%s(%d) : Unable to read idprom "
"property", QL_NAME, ha->instance);
nv->port_name[2] = 33;
nv->port_name[3] = 224;
nv->port_name[4] = 139;
nv->port_name[7] = (uint8_t)
(NAA_ID_IEEE_EXTENDED << 4 | ha->instance);
} else {
nv->port_name[2] = idprombuf[2];
nv->port_name[3] = idprombuf[3];
nv->port_name[4] = idprombuf[4];
nv->port_name[5] = idprombuf[5];
nv->port_name[6] = idprombuf[6];
nv->port_name[7] = idprombuf[7];
nv->port_name[0] = (uint8_t)
(NAA_ID_IEEE_EXTENDED << 4 | ha->instance);
}
if (!(CFG_IST(ha, CFG_CTRL_22XX)) &&
(ha->xioctl->fdesc.flash_size == 0)) {
cmn_err(CE_WARN, "%s(%d): Unreliable HBA NVRAM, using"
" default HBA parameters and temporary WWPN:"
" %02x%02x%02x%02x%02x%02x%02x%02x", QL_NAME,
ha->instance, nv->port_name[0], nv->port_name[1],
nv->port_name[2], nv->port_name[3],
nv->port_name[4], nv->port_name[5],
nv->port_name[6], nv->port_name[7]);
}
nv->login_timeout = 4;
if (!(CFG_IST(ha, CFG_CTRL_22XX))) {
nv->add_fw_opt[0] = (uint8_t)(nv->add_fw_opt[0] |
BIT_5);
}
nv->host_p[0] = BIT_1;
nv->host_p[1] = BIT_2;
nv->reset_delay = 5;
nv->port_down_retry_count = 8;
nv->maximum_luns_per_target[0] = 8;
rval = QL_FUNCTION_FAILED;
}
bzero((void *)icb, sizeof (ql_init_cb_t));
bzero((void *)ip_icb, sizeof (ql_ip_init_cb_t));
dptr1 = (caddr_t)icb;
dptr2 = (caddr_t)&nv->parameter_block_version;
cnt = (uint32_t)((uintptr_t)&icb->request_q_outpointer[0] -
(uintptr_t)&icb->version);
while (cnt-- != 0) {
*dptr1++ = *dptr2++;
}
dptr1 = (caddr_t)&icb->add_fw_opt[0];
cnt = (uint32_t)((uintptr_t)&icb->reserved_3[0] -
(uintptr_t)&icb->add_fw_opt[0]);
while (cnt-- != 0) {
*dptr1++ = *dptr2++;
}
ha->execution_throttle = CHAR_TO_SHORT(nv->execution_throttle[0],
nv->execution_throttle[1]);
ha->loop_reset_delay = nv->reset_delay;
ha->port_down_retry_count = nv->port_down_retry_count;
ha->maximum_luns_per_target = CHAR_TO_SHORT(
nv->maximum_luns_per_target[0], nv->maximum_luns_per_target[1]);
if (ha->maximum_luns_per_target == 0) {
ha->maximum_luns_per_target++;
}
ha->adapter_features = CHAR_TO_SHORT(nv->adapter_features[0],
nv->adapter_features[1]);
for (cnt = 0; cnt < 8; cnt++) {
if (icb->node_name[cnt] != 0) {
break;
}
}
if (cnt == 8) {
for (cnt = 0; cnt < 8; cnt++) {
icb->node_name[cnt] = icb->port_name[cnt];
}
icb->node_name[0] = (uint8_t)(icb->node_name[0] & ~BIT_0);
icb->port_name[0] = (uint8_t)(icb->node_name[0] | BIT_0);
}
ADAPTER_STATE_LOCK(ha);
ha->cfg_flags &= ~(CFG_ENABLE_FULL_LIP_LOGIN | CFG_ENABLE_TARGET_RESET |
CFG_ENABLE_LIP_RESET | CFG_LOAD_FLASH_FW | CFG_FAST_TIMEOUT |
CFG_DISABLE_RISC_CODE_LOAD | CFG_ENABLE_FWEXTTRACE |
CFG_ENABLE_FWFCETRACE | CFG_SET_CACHE_LINE_SIZE_1 | CFG_LR_SUPPORT);
if (nv->host_p[0] & BIT_4) {
ha->cfg_flags |= CFG_DISABLE_RISC_CODE_LOAD;
}
if (nv->host_p[0] & BIT_5) {
ha->cfg_flags |= CFG_SET_CACHE_LINE_SIZE_1;
}
if (nv->host_p[1] & BIT_2) {
ha->cfg_flags |= CFG_ENABLE_FULL_LIP_LOGIN;
}
if (nv->host_p[1] & BIT_3) {
ha->cfg_flags |= CFG_ENABLE_TARGET_RESET;
}
nv->adapter_features[0] & BIT_3 ?
(ha->flags |= MULTI_CHIP_ADAPTER) :
(ha->flags &= ~MULTI_CHIP_ADAPTER);
ADAPTER_STATE_UNLOCK(ha);
ql_23_properties(ha, icb);
icb->firmware_options[0] = (uint8_t)
(icb->firmware_options[0] | BIT_6 | BIT_1);
ha->cfg_flags |= CFG_ENABLE_64BIT_ADDRESSING;
if (CFG_IST(ha, CFG_SBUS_CARD | CFG_CTRL_2363)) {
icb->firmware_options[0] = (uint8_t)
(icb->firmware_options[0] & ~BIT_3);
if (CFG_IST(ha, CFG_SBUS_CARD)) {
icb->special_options[0] = (uint8_t)
(icb->special_options[0] | BIT_5);
ha->cfg_flags &= ~CFG_ENABLE_64BIT_ADDRESSING;
}
} else {
icb->firmware_options[0] = (uint8_t)
(icb->firmware_options[0] | BIT_3);
}
icb->add_fw_opt[0] = (uint8_t)(icb->add_fw_opt[0] &
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
icb->firmware_options[1] = (uint8_t)(icb->firmware_options[1] |
BIT_7 | BIT_6 | BIT_5 | BIT_2 | BIT_0);
icb->firmware_options[0] = (uint8_t)
(icb->firmware_options[0] & ~(BIT_5 | BIT_4));
icb->firmware_options[1] = (uint8_t)
(icb->firmware_options[1] & ~BIT_4);
if (CFG_IST(ha, CFG_ENABLE_FCP_2_SUPPORT)) {
icb->firmware_options[1] = (uint8_t)
(icb->firmware_options[1] | BIT_7 | BIT_6);
icb->add_fw_opt[1] = (uint8_t)
(icb->add_fw_opt[1] | BIT_5 | BIT_4);
}
icb->add_fw_opt[1] = (uint8_t)(icb->add_fw_opt[1] & ~(BIT_5 | BIT_4));
icb->special_options[0] = (uint8_t)(icb->special_options[0] | BIT_1);
if (CFG_IST(ha, CFG_CTRL_2363)) {
if ((icb->special_options[1] & 0x20) == 0) {
EL(ha, "50 ohm is not set\n");
}
}
if (CFG_IST(ha, CFG_CTRL_23XX) && nv->adapInfo[0] != 0) {
(void) snprintf((int8_t *)ha->adapInfo, 16, "%s",
nv->adapInfo);
}
ha->r_a_tov = (uint16_t)(icb->login_timeout < R_A_TOV_DEFAULT ?
R_A_TOV_DEFAULT : icb->login_timeout);
els->common_service.rx_bufsize = CHAR_TO_SHORT(
icb->max_frame_length[0], icb->max_frame_length[1]);
bcopy((void *)icb->port_name, (void *)els->nport_ww_name.raw_wwn, 8);
bcopy((void *)icb->node_name, (void *)els->node_ww_name.raw_wwn, 8);
cmn_err(CE_CONT, "!Qlogic %s(%d) WWPN=%02x%02x%02x%02x"
"%02x%02x%02x%02x : WWNN=%02x%02x%02x%02x%02x%02x%02x%02x\n",
QL_NAME, ha->instance,
els->nport_ww_name.raw_wwn[0], els->nport_ww_name.raw_wwn[1],
els->nport_ww_name.raw_wwn[2], els->nport_ww_name.raw_wwn[3],
els->nport_ww_name.raw_wwn[4], els->nport_ww_name.raw_wwn[5],
els->nport_ww_name.raw_wwn[6], els->nport_ww_name.raw_wwn[7],
els->node_ww_name.raw_wwn[0], els->node_ww_name.raw_wwn[1],
els->node_ww_name.raw_wwn[2], els->node_ww_name.raw_wwn[3],
els->node_ww_name.raw_wwn[4], els->node_ww_name.raw_wwn[5],
els->node_ww_name.raw_wwn[6], els->node_ww_name.raw_wwn[7]);
cnt = ha->req_q[0]->req_entry_cnt;
icb->request_q_length[0] = LSB(cnt);
icb->request_q_length[1] = MSB(cnt);
cnt = ha->rsp_queues[0]->rsp_entry_cnt;
icb->response_q_length[0] = LSB(cnt);
icb->response_q_length[1] = MSB(cnt);
start_addr = ha->req_q[0]->req_ring.cookie.dmac_address;
icb->request_q_address[0] = LSB(LSW(start_addr));
icb->request_q_address[1] = MSB(LSW(start_addr));
icb->request_q_address[2] = LSB(MSW(start_addr));
icb->request_q_address[3] = MSB(MSW(start_addr));
start_addr = ha->req_q[0]->req_ring.cookie.dmac_notused;
icb->request_q_address[4] = LSB(LSW(start_addr));
icb->request_q_address[5] = MSB(LSW(start_addr));
icb->request_q_address[6] = LSB(MSW(start_addr));
icb->request_q_address[7] = MSB(MSW(start_addr));
start_addr = ha->rsp_queues[0]->rsp_ring.cookie.dmac_address;
icb->response_q_address[0] = LSB(LSW(start_addr));
icb->response_q_address[1] = MSB(LSW(start_addr));
icb->response_q_address[2] = LSB(MSW(start_addr));
icb->response_q_address[3] = MSB(MSW(start_addr));
start_addr = ha->rsp_queues[0]->rsp_ring.cookie.dmac_notused;
icb->response_q_address[4] = LSB(LSW(start_addr));
icb->response_q_address[5] = MSB(LSW(start_addr));
icb->response_q_address[6] = LSB(MSW(start_addr));
icb->response_q_address[7] = MSB(MSW(start_addr));
ip_icb->version = IP_ICB_VERSION;
if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
ip_icb->ip_firmware_options[0] = (uint8_t)
(ip_icb->ip_firmware_options[0] | BIT_2 | BIT_0);
} else {
ip_icb->ip_firmware_options[0] = (uint8_t)
(ip_icb->ip_firmware_options[0] | BIT_2);
}
cnt = RCVBUF_CONTAINER_CNT;
ip_icb->queue_size[0] = LSB(cnt);
ip_icb->queue_size[1] = MSB(cnt);
start_addr = ha->rcv_ring.cookie.dmac_address;
ip_icb->queue_address[0] = LSB(LSW(start_addr));
ip_icb->queue_address[1] = MSB(LSW(start_addr));
ip_icb->queue_address[2] = LSB(MSW(start_addr));
ip_icb->queue_address[3] = MSB(MSW(start_addr));
start_addr = ha->rcv_ring.cookie.dmac_notused;
ip_icb->queue_address[4] = LSB(LSW(start_addr));
ip_icb->queue_address[5] = MSB(LSW(start_addr));
ip_icb->queue_address[6] = LSB(MSW(start_addr));
ip_icb->queue_address[7] = MSB(MSW(start_addr));
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
uint16_t
ql_get_nvram_word(ql_adapter_state_t *ha, uint32_t address)
{
uint32_t nv_cmd;
uint16_t rval;
QL_PRINT_4(ha, "started\n");
nv_cmd = address << 16;
nv_cmd = nv_cmd | NV_READ_OP;
rval = (uint16_t)ql_nvram_request(ha, nv_cmd);
QL_PRINT_4(ha, "NVRAM data = %xh\n", rval);
return (rval);
}
static uint16_t
ql_nvram_request(ql_adapter_state_t *ha, uint32_t nv_cmd)
{
uint8_t cnt;
uint16_t reg_data;
uint16_t data = 0;
nv_cmd <<= 5;
for (cnt = 0; cnt < 11; cnt++) {
if (nv_cmd & BIT_31) {
ql_nv_write(ha, NV_DATA_OUT);
} else {
ql_nv_write(ha, 0);
}
nv_cmd <<= 1;
}
for (cnt = 0; cnt < 16; cnt++) {
WRT16_IO_REG(ha, nvram, NV_SELECT + NV_CLOCK);
ql_nv_delay();
data <<= 1;
reg_data = RD16_IO_REG(ha, nvram);
if (reg_data & NV_DATA_IN) {
data = (uint16_t)(data | BIT_0);
}
WRT16_IO_REG(ha, nvram, NV_SELECT);
ql_nv_delay();
}
WRT16_IO_REG(ha, nvram, NV_DESELECT);
ql_nv_delay();
return (data);
}
void
ql_nv_write(ql_adapter_state_t *ha, uint16_t data)
{
WRT16_IO_REG(ha, nvram, (uint16_t)(data | NV_SELECT));
ql_nv_delay();
WRT16_IO_REG(ha, nvram, (uint16_t)(data | NV_SELECT | NV_CLOCK));
ql_nv_delay();
WRT16_IO_REG(ha, nvram, (uint16_t)(data | NV_SELECT));
ql_nv_delay();
}
void
ql_nv_delay(void)
{
drv_usecwait(NV_DELAY_COUNT);
}
int
ql_nvram_24xx_config(ql_adapter_state_t *ha)
{
uint32_t index, addr;
uint32_t chksum = 0, saved_chksum = 0;
uint32_t *longptr;
nvram_24xx_t nvram;
int idpromlen;
char idprombuf[32];
caddr_t src, dst;
uint16_t w1;
int rval;
nvram_24xx_t *nv = (nvram_24xx_t *)&nvram;
ql_init_24xx_cb_t *icb =
(ql_init_24xx_cb_t *)&ha->init_ctrl_blk.cb24;
ql_ip_init_24xx_cb_t *ip_icb = &ha->ip_init_ctrl_blk.cb24;
la_els_logi_t *els = &ha->loginparams;
QL_PRINT_10(ha, "started\n");
if ((rval = ql_lock_nvram(ha, &addr, LNF_NVRAM_DATA)) == QL_SUCCESS) {
longptr = (uint32_t *)nv;
chksum = saved_chksum = 0;
for (index = 0; index < sizeof (nvram_24xx_t) / 4; index++) {
rval = ql_24xx_read_flash(ha, addr++, longptr);
if (rval != QL_SUCCESS) {
EL(ha, "24xx_read_flash failed=%xh\n", rval);
break;
}
saved_chksum = chksum;
chksum += *longptr;
LITTLE_ENDIAN_32(longptr);
longptr++;
}
ql_release_nvram(ha);
}
if (rval != QL_SUCCESS || chksum || nv->id[0] != 'I' ||
nv->id[1] != 'S' || nv->id[2] != 'P' || nv->id[3] != ' ' ||
(nv->nvram_version[0] | nv->nvram_version[1]) == 0) {
cmn_err(CE_WARN, "%s(%d): NVRAM configuration failed, using "
"driver defaults.", QL_NAME, ha->instance);
EL(ha, "failed, rval=%xh, checksum=%xh, id=%c%c%c%c, "
"nvram_version=%x\n", rval, chksum, nv->id[0], nv->id[1],
nv->id[2], nv->id[3], CHAR_TO_SHORT(nv->nvram_version[0],
nv->nvram_version[1]));
saved_chksum = ~saved_chksum + 1;
(void) ql_flash_errlog(ha, FLASH_ERRLOG_NVRAM_CHKSUM_ERR, 0,
MSW(saved_chksum), LSW(saved_chksum));
bzero((void *)nv, sizeof (nvram_24xx_t));
nv->nvram_version[0] = LSB(ICB_24XX_VERSION);
nv->nvram_version[1] = MSB(ICB_24XX_VERSION);
nv->version[0] = 1;
nv->max_frame_length[1] = 8;
nv->execution_throttle[0] = 16;
nv->exchange_count[0] = 128;
nv->max_luns_per_target[0] = 8;
idpromlen = 32;
if (rval = ddi_getlongprop_buf(DDI_DEV_T_ANY, ha->dip,
DDI_PROP_CANSLEEP, "idprom", (caddr_t)idprombuf,
&idpromlen) != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "%s(%d) : Unable to read idprom "
"property, rval=%x", QL_NAME, ha->instance, rval);
nv->port_name[0] = 33;
nv->port_name[3] = 224;
nv->port_name[4] = 139;
nv->port_name[7] = (uint8_t)
(NAA_ID_IEEE_EXTENDED << 4 | ha->instance);
} else {
nv->port_name[2] = idprombuf[2];
nv->port_name[3] = idprombuf[3];
nv->port_name[4] = idprombuf[4];
nv->port_name[5] = idprombuf[5];
nv->port_name[6] = idprombuf[6];
nv->port_name[7] = idprombuf[7];
nv->port_name[0] = (uint8_t)
(NAA_ID_IEEE_EXTENDED << 4 | ha->instance);
}
cmn_err(CE_WARN, "%s(%d): Unreliable HBA NVRAM, using default "
"HBA parameters and temporary "
"WWPN: %02x%02x%02x%02x%02x%02x%02x%02x", QL_NAME,
ha->instance, nv->port_name[0], nv->port_name[1],
nv->port_name[2], nv->port_name[3], nv->port_name[4],
nv->port_name[5], nv->port_name[6], nv->port_name[7]);
nv->login_retry_count[0] = 8;
nv->firmware_options_1[0] = BIT_2 | BIT_1;
nv->firmware_options_1[1] = BIT_5;
nv->firmware_options_2[0] = BIT_5;
nv->firmware_options_2[1] = BIT_4;
nv->firmware_options_3[1] = BIT_6;
nv->host_p[0] = BIT_4 | BIT_1;
nv->host_p[1] = BIT_3 | BIT_2;
nv->reset_delay = 5;
nv->max_luns_per_target[0] = 128;
nv->port_down_retry_count[0] = 30;
nv->link_down_timeout[0] = 30;
if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
nv->firmware_options_3[2] = BIT_4;
nv->feature_mask_l[0] = 9;
nv->ext_blk.version[0] = 1;
nv->ext_blk.fcf_vlan_match = 1;
nv->ext_blk.fcf_vlan_id[0] = LSB(1002);
nv->ext_blk.fcf_vlan_id[1] = MSB(1002);
nv->fw.isp8001.e_node_mac_addr[1] = 2;
nv->fw.isp8001.e_node_mac_addr[2] = 3;
nv->fw.isp8001.e_node_mac_addr[3] = 4;
nv->fw.isp8001.e_node_mac_addr[4] = MSB(ha->instance);
nv->fw.isp8001.e_node_mac_addr[5] = LSB(ha->instance);
}
rval = QL_FUNCTION_FAILED;
}
bzero((void *)icb, sizeof (ql_init_24xx_cb_t));
dst = (caddr_t)icb;
src = (caddr_t)&nv->version;
index = (uint32_t)((uintptr_t)&icb->response_q_inpointer[0] -
(uintptr_t)icb);
while (index--) {
*dst++ = *src++;
}
icb->login_retry_count[0] = nv->login_retry_count[0];
icb->login_retry_count[1] = nv->login_retry_count[1];
icb->link_down_on_nos[0] = nv->link_down_on_nos[0];
icb->link_down_on_nos[1] = nv->link_down_on_nos[1];
dst = (caddr_t)&icb->interrupt_delay_timer;
src = (caddr_t)&nv->interrupt_delay_timer;
index = (uint32_t)((uintptr_t)&icb->qos -
(uintptr_t)&icb->interrupt_delay_timer);
while (index--) {
*dst++ = *src++;
}
ha->execution_throttle = 16;
ha->loop_reset_delay = nv->reset_delay;
ha->port_down_retry_count = CHAR_TO_SHORT(nv->port_down_retry_count[0],
nv->port_down_retry_count[1]);
ha->maximum_luns_per_target = CHAR_TO_SHORT(
nv->max_luns_per_target[0], nv->max_luns_per_target[1]);
if (ha->maximum_luns_per_target == 0) {
ha->maximum_luns_per_target++;
}
if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
dst = (caddr_t)icb->enode_mac_addr;
src = (caddr_t)nv->fw.isp8001.e_node_mac_addr;
index = sizeof (nv->fw.isp8001.e_node_mac_addr);
while (index--) {
*dst++ = *src++;
}
dst = (caddr_t)&icb->ext_blk;
src = (caddr_t)&nv->ext_blk;
index = sizeof (ql_ext_icb_8100_t);
while (index--) {
*dst++ = *src++;
}
EL(ha, "e_node_mac_addr=%02x-%02x-%02x-%02x-%02x-%02x\n",
icb->enode_mac_addr[0], icb->enode_mac_addr[1],
icb->enode_mac_addr[2], icb->enode_mac_addr[3],
icb->enode_mac_addr[4], icb->enode_mac_addr[5]);
}
for (index = 0; index < 8; index++) {
if (icb->node_name[index] != 0) {
break;
}
}
if (index == 8) {
for (index = 0; index < 8; index++) {
icb->node_name[index] = icb->port_name[index];
}
icb->node_name[0] = (uint8_t)(icb->node_name[0] & ~BIT_0);
icb->port_name[0] = (uint8_t)(icb->node_name[0] | BIT_0);
}
ADAPTER_STATE_LOCK(ha);
ha->cfg_flags &= ~(CFG_ENABLE_FULL_LIP_LOGIN | CFG_ENABLE_TARGET_RESET |
CFG_ENABLE_LIP_RESET | CFG_LOAD_FLASH_FW | CFG_FAST_TIMEOUT |
CFG_DISABLE_RISC_CODE_LOAD | CFG_ENABLE_FWEXTTRACE |
CFG_ENABLE_FWFCETRACE | CFG_SET_CACHE_LINE_SIZE_1 | CFG_LR_SUPPORT);
if (nv->host_p[1] & BIT_2) {
ha->cfg_flags |= CFG_ENABLE_FULL_LIP_LOGIN;
}
if (nv->host_p[1] & BIT_3) {
ha->cfg_flags |= CFG_ENABLE_TARGET_RESET;
}
ha->flags &= ~MULTI_CHIP_ADAPTER;
ADAPTER_STATE_UNLOCK(ha);
ql_24xx_properties(ha, icb);
if (!CFG_IST(ha, CFG_FCOE_SUPPORT)) {
icb->firmware_options_1[0] = (uint8_t)
(icb->firmware_options_1[0] | BIT_1);
icb->firmware_options_1[1] = (uint8_t)
(icb->firmware_options_1[1] | BIT_5 | BIT_2);
icb->firmware_options_3[0] = (uint8_t)
(icb->firmware_options_3[0] | BIT_1);
}
icb->firmware_options_1[0] = (uint8_t)(icb->firmware_options_1[0] &
~(BIT_5 | BIT_4));
icb->firmware_options_1[1] = (uint8_t)(icb->firmware_options_1[1] |
BIT_6);
icb->firmware_options_2[0] = (uint8_t)(icb->firmware_options_2[0] &
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
if (CFG_IST(ha, CFG_ENABLE_FCP_2_SUPPORT)) {
icb->firmware_options_2[1] = (uint8_t)
(icb->firmware_options_2[1] | BIT_4);
} else {
icb->firmware_options_2[1] = (uint8_t)
(icb->firmware_options_2[1] & ~BIT_4);
}
icb->firmware_options_3[0] = (uint8_t)(icb->firmware_options_3[0] &
~BIT_7);
w1 = CHAR_TO_SHORT(icb->login_timeout[0], icb->login_timeout[1]);
ha->r_a_tov = (uint16_t)(w1 < R_A_TOV_DEFAULT ? R_A_TOV_DEFAULT : w1);
ADAPTER_STATE_LOCK(ha);
ha->cfg_flags |= CFG_ENABLE_64BIT_ADDRESSING;
if (CFG_IST(ha, CFG_CTRL_81XX) && nv->enhanced_features[0] & BIT_0) {
ha->cfg_flags |= CFG_LR_SUPPORT;
}
ADAPTER_STATE_UNLOCK(ha);
if (ha->flags & QUEUE_SHADOW_PTRS) {
icb->firmware_options_2[3] = (uint8_t)
(icb->firmware_options_2[3] | BIT_6 | BIT_5);
} else {
icb->firmware_options_2[3] = (uint8_t)
(icb->firmware_options_2[3] | ~(BIT_6 | BIT_5));
}
if (CFG_IST(ha, CFG_CTRL_24XX)) {
ha->serdes_param[0] = CHAR_TO_SHORT(nv->fw.isp2400.swing_opt[0],
nv->fw.isp2400.swing_opt[1]);
ha->serdes_param[1] = CHAR_TO_SHORT(nv->fw.isp2400.swing_1g[0],
nv->fw.isp2400.swing_1g[1]);
ha->serdes_param[2] = CHAR_TO_SHORT(nv->fw.isp2400.swing_2g[0],
nv->fw.isp2400.swing_2g[1]);
ha->serdes_param[3] = CHAR_TO_SHORT(nv->fw.isp2400.swing_4g[0],
nv->fw.isp2400.swing_4g[1]);
}
els->common_service.rx_bufsize = CHAR_TO_SHORT(
icb->max_frame_length[0], icb->max_frame_length[1]);
bcopy((void *)icb->port_name, (void *)els->nport_ww_name.raw_wwn, 8);
bcopy((void *)icb->node_name, (void *)els->node_ww_name.raw_wwn, 8);
cmn_err(CE_CONT, "!Qlogic %s(%d) WWPN=%02x%02x%02x%02x"
"%02x%02x%02x%02x : WWNN=%02x%02x%02x%02x%02x%02x%02x%02x\n",
QL_NAME, ha->instance,
els->nport_ww_name.raw_wwn[0], els->nport_ww_name.raw_wwn[1],
els->nport_ww_name.raw_wwn[2], els->nport_ww_name.raw_wwn[3],
els->nport_ww_name.raw_wwn[4], els->nport_ww_name.raw_wwn[5],
els->nport_ww_name.raw_wwn[6], els->nport_ww_name.raw_wwn[7],
els->node_ww_name.raw_wwn[0], els->node_ww_name.raw_wwn[1],
els->node_ww_name.raw_wwn[2], els->node_ww_name.raw_wwn[3],
els->node_ww_name.raw_wwn[4], els->node_ww_name.raw_wwn[5],
els->node_ww_name.raw_wwn[6], els->node_ww_name.raw_wwn[7]);
w1 = ha->req_q[0]->req_entry_cnt;
icb->request_q_length[0] = LSB(w1);
icb->request_q_length[1] = MSB(w1);
w1 = ha->rsp_queues[0]->rsp_entry_cnt;
icb->response_q_length[0] = LSB(w1);
icb->response_q_length[1] = MSB(w1);
addr = ha->req_q[0]->req_ring.cookie.dmac_address;
icb->request_q_address[0] = LSB(LSW(addr));
icb->request_q_address[1] = MSB(LSW(addr));
icb->request_q_address[2] = LSB(MSW(addr));
icb->request_q_address[3] = MSB(MSW(addr));
addr = ha->req_q[0]->req_ring.cookie.dmac_notused;
icb->request_q_address[4] = LSB(LSW(addr));
icb->request_q_address[5] = MSB(LSW(addr));
icb->request_q_address[6] = LSB(MSW(addr));
icb->request_q_address[7] = MSB(MSW(addr));
addr = ha->rsp_queues[0]->rsp_ring.cookie.dmac_address;
icb->response_q_address[0] = LSB(LSW(addr));
icb->response_q_address[1] = MSB(LSW(addr));
icb->response_q_address[2] = LSB(MSW(addr));
icb->response_q_address[3] = MSB(MSW(addr));
addr = ha->rsp_queues[0]->rsp_ring.cookie.dmac_notused;
icb->response_q_address[4] = LSB(LSW(addr));
icb->response_q_address[5] = MSB(LSW(addr));
icb->response_q_address[6] = LSB(MSW(addr));
icb->response_q_address[7] = MSB(MSW(addr));
ip_icb->version = IP_ICB_24XX_VERSION;
ip_icb->ip_firmware_options[0] = (uint8_t)
(ip_icb->ip_firmware_options[0] | BIT_2);
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
int
ql_lock_nvram(ql_adapter_state_t *ha, uint32_t *addr, uint32_t flags)
{
int i;
QL_PRINT_3(ha, "started\n");
if ((flags & LNF_NVRAM_DATA) && (flags & LNF_VPD_DATA)) {
EL(ha, "invalid options for function");
return (QL_FUNCTION_FAILED);
}
if (ha->device_id == 0x2312 || ha->device_id == 0x2322) {
if ((flags & LNF_NVRAM_DATA) == 0) {
EL(ha, "invalid 2312/2322 option for HBA");
return (QL_FUNCTION_FAILED);
}
*addr = ha->flash_nvram_addr;
for (i = 0; i < 10000; i++) {
if ((RD16_IO_REG(ha, nvram) & 0x8000) == 0) {
WRT16_IO_REG(ha, host_to_host_sema, 1);
drv_usecwait(MILLISEC);
if (RD16_IO_REG(ha, host_to_host_sema) & 1) {
break;
}
}
drv_usecwait(MILLISEC);
}
if ((RD16_IO_REG(ha, host_to_host_sema) & 1) == 0) {
cmn_err(CE_WARN, "%s(%d): unable to get NVRAM lock",
QL_NAME, ha->instance);
return (QL_FUNCTION_FAILED);
}
} else if (CFG_IST(ha, CFG_CTRL_24XX)) {
if (flags & LNF_VPD_DATA) {
*addr = NVRAM_DATA_ADDR | ha->flash_vpd_addr;
} else if (flags & LNF_NVRAM_DATA) {
*addr = NVRAM_DATA_ADDR | ha->flash_nvram_addr;
} else {
EL(ha, "invalid 2422 option for HBA");
return (QL_FUNCTION_FAILED);
}
GLOBAL_HW_LOCK();
} else if (CFG_IST(ha, CFG_CTRL_252780818283)) {
if (flags & LNF_VPD_DATA) {
*addr = ha->flash_data_addr | ha->flash_vpd_addr;
} else if (flags & LNF_NVRAM_DATA) {
*addr = ha->flash_data_addr | ha->flash_nvram_addr;
} else {
EL(ha, "invalid 2581 option for HBA");
return (QL_FUNCTION_FAILED);
}
GLOBAL_HW_LOCK();
} else {
if ((flags & LNF_NVRAM_DATA) == 0) {
EL(ha, "invalid option for HBA");
return (QL_FUNCTION_FAILED);
}
*addr = 0;
GLOBAL_HW_LOCK();
}
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
void
ql_release_nvram(ql_adapter_state_t *ha)
{
QL_PRINT_3(ha, "started\n");
if (ha->device_id == 0x2312 || ha->device_id == 0x2322) {
WRT16_IO_REG(ha, host_to_host_sema, 0);
} else {
GLOBAL_HW_UNLOCK();
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_23_properties(ql_adapter_state_t *ha, ql_init_cb_t *icb)
{
uint32_t data, cnt;
QL_PRINT_3(ha, "started\n");
if ((data = ql_get_prop(ha, "max-frame-length")) == 0xffffffff) {
data = 2048;
}
if (data == 512 || data == 1024 || data == 2048) {
icb->max_frame_length[0] = LSB(data);
icb->max_frame_length[1] = MSB(data);
} else {
EL(ha, "invalid parameter value for 'max-frame-length': "
"%d; using nvram default of %d\n", data, CHAR_TO_SHORT(
icb->max_frame_length[0], icb->max_frame_length[1]));
}
icb->max_iocb_allocation[0] = 0;
icb->max_iocb_allocation[1] = 1;
if ((data = ql_get_prop(ha, "execution-throttle")) == 0xffffffff) {
data = 32;
}
if (data != 0 && data < 65536) {
icb->execution_throttle[0] = LSB(data);
icb->execution_throttle[1] = MSB(data);
} else {
EL(ha, "invalid parameter value for 'execution-throttle': "
"%d; using nvram default of %d\n", data, CHAR_TO_SHORT(
icb->execution_throttle[0], icb->execution_throttle[1]));
}
if ((data = ql_get_prop(ha, "login-timeout")) == 0xffffffff) {
data = 3;
}
if (data < 256) {
icb->login_timeout = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'login-timeout': "
"%d; using nvram value of %d\n", data, icb->login_timeout);
}
if ((data = ql_get_prop(ha, "login-retry-count")) == 0xffffffff) {
data = 4;
}
if (data < 256) {
icb->login_retry_count = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'login-retry-count': "
"%d; using nvram value of %d\n", data,
icb->login_retry_count);
}
data = ql_get_prop(ha, "enable-adapter-hard-loop-ID");
if (data == 0) {
icb->firmware_options[0] =
(uint8_t)(icb->firmware_options[0] & ~BIT_0);
} else if (data == 1) {
icb->firmware_options[0] =
(uint8_t)(icb->firmware_options[0] | BIT_0);
} else if (data != 0xffffffff) {
EL(ha, "invalid parameter value for "
"'enable-adapter-hard-loop-ID': %d; using nvram value "
"of %d\n", data, icb->firmware_options[0] & BIT_0 ? 1 : 0);
}
data = ql_get_prop(ha, "adapter-hard-loop-ID");
if (data < 126) {
icb->hard_address[0] = (uint8_t)data;
} else if (data != 0xffffffff) {
EL(ha, "invalid parameter value for 'adapter-hard-loop-ID': "
"%d; using nvram value of %d\n",
data, icb->hard_address[0]);
}
if ((data = ql_get_prop(ha, "enable-LIP-reset-on-bus-reset")) ==
0xffffffff) {
data = 0;
}
if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_LIP_RESET;
} else if (data == 1) {
ha->cfg_flags |= CFG_ENABLE_LIP_RESET;
} else {
EL(ha, "invalid parameter value for "
"'enable-LIP-reset-on-bus-reset': %d; using nvram value "
"of %d\n", data,
CFG_IST(ha, CFG_ENABLE_LIP_RESET) ? 1 : 0);
}
if ((data = ql_get_prop(ha, "enable-LIP-full-login-on-bus-reset")) ==
0xffffffff) {
data = 1;
}
if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_FULL_LIP_LOGIN;
} else if (data == 1) {
ha->cfg_flags |= CFG_ENABLE_FULL_LIP_LOGIN;
} else {
EL(ha, "invalid parameter value for "
"'enable-LIP-full-login-on-bus-reset': %d; using nvram "
"value of %d\n", data,
CFG_IST(ha, CFG_ENABLE_FULL_LIP_LOGIN) ? 1 : 0);
}
if ((data = ql_get_prop(ha, "enable-target-reset-on-bus-reset")) ==
0xffffffff) {
data = 0;
}
if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_TARGET_RESET;
} else if (data == 1) {
ha->cfg_flags |= CFG_ENABLE_TARGET_RESET;
} else {
EL(ha, "invalid parameter value for "
"'enable-target-reset-on-bus-reset': %d; using nvram "
"value of %d", data,
CFG_IST(ha, CFG_ENABLE_TARGET_RESET) ? 1 : 0);
}
if ((data = ql_get_prop(ha, "reset-delay")) == 0xffffffff) {
data = 5;
}
if (data != 0 && data < 256) {
ha->loop_reset_delay = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'reset-delay': %d; "
"using nvram value of %d", data, ha->loop_reset_delay);
}
if ((data = ql_get_prop(ha, "port-down-retry-count")) == 0xffffffff) {
data = 8;
}
if (data < 256) {
ha->port_down_retry_count = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'port-down-retry-count':"
" %d; using nvram value of %d\n", data,
ha->port_down_retry_count);
}
if ((data = ql_get_prop(ha, "connection-options")) == 0xffffffff) {
data = 2;
}
cnt = CFG_IST(ha, CFG_CTRL_22XX) ? 3 : 2;
if (data <= cnt) {
icb->add_fw_opt[0] = (uint8_t)(icb->add_fw_opt[0] &
~(BIT_6 | BIT_5 | BIT_4));
icb->add_fw_opt[0] = (uint8_t)(icb->add_fw_opt[0] |
(uint8_t)(data << 4));
} else {
EL(ha, "invalid parameter value for 'connection-options': "
"%d; using nvram value of %d\n", data,
(icb->add_fw_opt[0] >> 4) & 0x3);
}
if ((CFG_IST(ha, CFG_CTRL_22XX)) == 0) {
if ((data = ql_get_prop(ha, "fc-data-rate")) == 0xffffffff) {
data = 2;
}
if (data < 3) {
icb->special_options[1] = (uint8_t)
(icb->special_options[1] & 0x3f);
icb->special_options[1] = (uint8_t)
(icb->special_options[1] | (uint8_t)(data << 6));
} else {
EL(ha, "invalid parameter value for 'fc-data-rate': "
"%d; using nvram value of %d\n", data,
(icb->special_options[1] >> 6) & 0x3);
}
}
ha->ip_init_ctrl_blk.cb.cc[0] = LSB(ql_ip_buffer_count);
ha->ip_init_ctrl_blk.cb.cc[1] = MSB(ql_ip_buffer_count);
ha->ip_init_ctrl_blk.cb.low_water_mark[0] = LSB(ql_ip_low_water);
ha->ip_init_ctrl_blk.cb.low_water_mark[1] = MSB(ql_ip_low_water);
ha->ip_init_ctrl_blk.cb.fast_post_reg_count[0] =
ql_ip_fast_post_count;
ADAPTER_STATE_LOCK(ha);
ql_common_properties(ha);
ADAPTER_STATE_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
void
ql_common_properties(ql_adapter_state_t *ha)
{
uint32_t data;
QL_PRINT_10(ha, "started\n");
if ((data = ql_get_prop(ha, "extended-logging")) == 0xffffffff ||
data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_EXTENDED_LOGGING;
} else if (data == 1) {
ha->cfg_flags |= CFG_ENABLE_EXTENDED_LOGGING;
} else {
EL(ha, "invalid parameter value for 'extended-logging': %d;"
" using default value of 0\n", data);
ha->cfg_flags &= ~CFG_ENABLE_EXTENDED_LOGGING;
}
if ((data = ql_get_prop(ha, "enable-FCP-2-error-recovery")) ==
0xffffffff || data == 1) {
ha->cfg_flags |= CFG_ENABLE_FCP_2_SUPPORT;
} else if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_FCP_2_SUPPORT;
} else {
EL(ha, "invalid parameter value for "
"'enable-FCP-2-error-recovery': %d; using nvram value of "
"1\n", data);
ha->cfg_flags |= CFG_ENABLE_FCP_2_SUPPORT;
}
#ifdef QL_DEBUG_LEVEL_2
ha->cfg_flags |= CFG_ENABLE_EXTENDED_LOGGING;
#endif
if ((data = ql_get_prop(ha, "port-down-retry-delay")) == 0xffffffff) {
ha->port_down_retry_delay = PORT_RETRY_TIME;
} else if (data < 256) {
ha->port_down_retry_delay = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'port-down-retry-delay':"
" %d; using default value of %d", data, PORT_RETRY_TIME);
ha->port_down_retry_delay = PORT_RETRY_TIME;
}
if ((data = ql_get_prop(ha, "queue-full-retry-count")) == 0xffffffff) {
ha->qfull_retry_count = 16;
} else if (data < 256) {
ha->qfull_retry_count = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'queue-full-retry-count':"
" %d; using default value of 16", data);
ha->qfull_retry_count = 16;
}
if ((data = ql_get_prop(ha, "queue-full-retry-delay")) == 0xffffffff) {
ha->qfull_retry_delay = PORT_RETRY_TIME;
} else if (data < 256) {
ha->qfull_retry_delay = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'queue-full-retry-delay':"
" %d; using default value of %d", data, PORT_RETRY_TIME);
ha->qfull_retry_delay = PORT_RETRY_TIME;
}
if ((data = ql_get_prop(ha, "link-down-timeout")) == 0xffffffff) {
data = 0;
} else if (data > 255) {
EL(ha, "invalid parameter value for 'link-down-timeout': %d;"
" using nvram value of 0\n", data);
data = 0;
}
ha->loop_down_abort_time = (uint8_t)(LOOP_DOWN_TIMER_START - data);
if (ha->loop_down_abort_time == LOOP_DOWN_TIMER_START) {
ha->loop_down_abort_time--;
} else if (ha->loop_down_abort_time <= LOOP_DOWN_TIMER_END) {
ha->loop_down_abort_time = LOOP_DOWN_TIMER_END + 1;
}
if ((data = ql_get_prop(ha, "enable-link-down-error")) == 0xffffffff ||
data == 1) {
ha->cfg_flags |= CFG_ENABLE_LINK_DOWN_REPORTING;
} else if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_LINK_DOWN_REPORTING;
} else {
EL(ha, "invalid parameter value for 'link-down-error': %d;"
" using default value of 1\n", data);
}
ha->cfg_flags &= ~(CFG_DUMP_MAILBOX_TIMEOUT |
CFG_DUMP_ISP_SYSTEM_ERROR | CFG_DUMP_DRIVER_COMMAND_TIMEOUT |
CFG_DUMP_LOOP_OFFLINE_TIMEOUT);
if ((data = ql_get_prop(ha, "firmware-dump-flags")) != 0xffffffff) {
if (data & BIT_0) {
ha->cfg_flags |= CFG_DUMP_MAILBOX_TIMEOUT;
}
if (data & BIT_1) {
ha->cfg_flags |= CFG_DUMP_ISP_SYSTEM_ERROR;
}
if (data & BIT_2) {
ha->cfg_flags |= CFG_DUMP_DRIVER_COMMAND_TIMEOUT;
}
if (data & BIT_3) {
ha->cfg_flags |= CFG_DUMP_LOOP_OFFLINE_TIMEOUT;
}
}
ha->pci_max_read_req = 0;
if ((data = ql_get_prop(ha, "pci-max-read-request")) != 0xffffffff &&
data != 0) {
ha->pci_max_read_req = (uint16_t)(data);
}
if ((data = ql_get_prop(ha, "plogi_params_retry_count")) !=
0xffffffff && data != 0) {
ha->plogi_params->retry_cnt = (uint32_t)(data);
}
if ((data = ql_get_prop(ha, "plogi_params_retry_delay")) !=
0xffffffff && data != 0) {
ha->plogi_params->retry_dly_usec = (uint32_t)(data);
}
ha->fwwait = (uint8_t)(CFG_IST(ha, CFG_FCOE_SUPPORT) ? 45 : 10);
if ((data = ql_get_prop(ha, "init-loop-sync-wait")) != 0xffffffff) {
if (data > 0 && data <= 240) {
ha->fwwait = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for "
"'init-loop-sync-wait': %d; using default "
"value of %d\n", data, ha->fwwait);
}
}
ha->fm_capabilities = DDI_FM_NOT_CAPABLE;
if ((data = ql_get_prop(ha, "fm-capable")) != 0xffffffff) {
if (data == 0) {
ha->fm_capabilities = DDI_FM_NOT_CAPABLE;
} else if (data > 0xf) {
ha->fm_capabilities = 0xf;
} else {
ha->fm_capabilities = (int)(data);
}
} else {
ha->fm_capabilities = (int)(DDI_FM_EREPORT_CAPABLE
| DDI_FM_ERRCB_CAPABLE);
}
if ((data = ql_get_prop(ha, "msix-vectors")) == 0xffffffff) {
ha->mq_msix_vectors = 0;
} else if (data < 256) {
ha->mq_msix_vectors = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'msix-vectors': "
"%d; using value of %d\n", data, 0);
ha->mq_msix_vectors = 0;
}
if ((data = ql_get_prop(ha, "completion-threads")) == 0xffffffff) {
ha->completion_thds = 4;
} else if (data < 256 && data >= 1) {
ha->completion_thds = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'completion-threads':"
" %d; using default value of %d", data, 4);
ha->completion_thds = 4;
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_24xx_properties(ql_adapter_state_t *ha, ql_init_24xx_cb_t *icb)
{
uint32_t data;
QL_PRINT_10(ha, "started\n");
if ((data = ql_get_prop(ha, "max-frame-length")) == 0xffffffff) {
data = 2048;
}
if (data == 512 || data == 1024 || data == 2048 || data == 2112) {
icb->max_frame_length[0] = LSB(data);
icb->max_frame_length[1] = MSB(data);
} else {
EL(ha, "invalid parameter value for 'max-frame-length': %d;"
" using nvram default of %d\n", data, CHAR_TO_SHORT(
icb->max_frame_length[0], icb->max_frame_length[1]));
}
if ((data = ql_get_prop(ha, "execution-throttle")) == 0xffffffff) {
data = 32;
}
if (data != 0 && data < 65536) {
icb->execution_throttle[0] = LSB(data);
icb->execution_throttle[1] = MSB(data);
} else {
EL(ha, "invalid parameter value for 'execution-throttle':"
" %d; using nvram default of %d\n", data, CHAR_TO_SHORT(
icb->execution_throttle[0], icb->execution_throttle[1]));
}
if ((data = ql_get_prop(ha, "login-timeout")) == 0xffffffff) {
data = 3;
}
if (data < 65536) {
icb->login_timeout[0] = LSB(data);
icb->login_timeout[1] = MSB(data);
} else {
EL(ha, "invalid parameter value for 'login-timeout': %d; "
"using nvram value of %d\n", data, CHAR_TO_SHORT(
icb->login_timeout[0], icb->login_timeout[1]));
}
if ((data = ql_get_prop(ha, "login-retry-count")) == 0xffffffff) {
data = 4;
}
if (data < 65536) {
icb->login_retry_count[0] = LSB(data);
icb->login_retry_count[1] = MSB(data);
} else {
EL(ha, "invalid parameter value for 'login-retry-count': "
"%d; using nvram value of %d\n", data, CHAR_TO_SHORT(
icb->login_retry_count[0], icb->login_retry_count[1]));
}
data = ql_get_prop(ha, "enable-adapter-hard-loop-ID");
if (data == 0) {
icb->firmware_options_1[0] =
(uint8_t)(icb->firmware_options_1[0] & ~BIT_0);
} else if (data == 1) {
icb->firmware_options_1[0] =
(uint8_t)(icb->firmware_options_1[0] | BIT_0);
} else if (data != 0xffffffff) {
EL(ha, "invalid parameter value for "
"'enable-adapter-hard-loop-ID': %d; using nvram value "
"of %d\n", data,
icb->firmware_options_1[0] & BIT_0 ? 1 : 0);
}
data = ql_get_prop(ha, "adapter-hard-loop-ID");
if (data < 126) {
icb->hard_address[0] = LSB(data);
icb->hard_address[1] = MSB(data);
} else if (data != 0xffffffff) {
EL(ha, "invalid parameter value for 'adapter-hard-loop-ID':"
" %d; using nvram value of %d\n", data, CHAR_TO_SHORT(
icb->hard_address[0], icb->hard_address[1]));
}
if ((data = ql_get_prop(ha, "enable-LIP-reset-on-bus-reset")) ==
0xffffffff) {
data = 0;
}
if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_LIP_RESET;
} else if (data == 1) {
ha->cfg_flags |= CFG_ENABLE_LIP_RESET;
} else {
EL(ha, "invalid parameter value for "
"'enable-LIP-reset-on-bus-reset': %d; using value of 0\n",
data);
}
if ((data = ql_get_prop(ha, "enable-LIP-full-login-on-bus-reset")) ==
0xffffffff) {
data = 1;
}
if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_FULL_LIP_LOGIN;
} else if (data == 1) {
ha->cfg_flags |= CFG_ENABLE_FULL_LIP_LOGIN;
} else {
EL(ha, "invalid parameter value for "
"'enable-LIP-full-login-on-bus-reset': %d; using nvram "
"value of %d\n", data,
ha->cfg_flags & CFG_ENABLE_FULL_LIP_LOGIN ? 1 : 0);
}
if ((data = ql_get_prop(ha, "enable-target-reset-on-bus-reset")) ==
0xffffffff) {
data = 0;
}
if (data == 0) {
ha->cfg_flags &= ~CFG_ENABLE_TARGET_RESET;
} else if (data == 1) {
ha->cfg_flags |= CFG_ENABLE_TARGET_RESET;
} else {
EL(ha, "invalid parameter value for "
"'enable-target-reset-on-bus-reset': %d; using nvram "
"value of %d", data,
ha->cfg_flags & CFG_ENABLE_TARGET_RESET ? 1 : 0);
}
if ((data = ql_get_prop(ha, "reset-delay")) == 0xffffffff) {
data = 5;
}
if (data != 0 && data < 256) {
ha->loop_reset_delay = (uint8_t)data;
} else {
EL(ha, "invalid parameter value for 'reset-delay': %d; "
"using nvram value of %d", data, ha->loop_reset_delay);
}
if ((data = ql_get_prop(ha, "port-down-retry-count")) == 0xffffffff) {
data = 8;
}
if (data < 256) {
ha->port_down_retry_count = (uint16_t)data;
} else {
EL(ha, "invalid parameter value for 'port-down-retry-count':"
" %d; using nvram value of %d\n", data,
ha->port_down_retry_count);
}
if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
uint32_t conn;
if ((conn = ql_get_prop(ha, "connection-options")) ==
0xffffffff) {
conn = 2;
}
if (conn <= 2) {
icb->firmware_options_2[0] = (uint8_t)
(icb->firmware_options_2[0] &
~(BIT_6 | BIT_5 | BIT_4));
icb->firmware_options_2[0] = (uint8_t)
(icb->firmware_options_2[0] | (uint8_t)(conn << 4));
} else {
EL(ha, "invalid parameter value for 'connection-"
"options': %d; using nvram value of %d\n", conn,
(icb->firmware_options_2[0] >> 4) & 0x3);
}
conn = icb->firmware_options_2[0] >> 4 & 0x3;
if (conn == 0 && ha->max_vports > 125) {
ha->max_vports = 125;
}
if ((data = ql_get_prop(ha, "fc-data-rate")) == 0xffffffff) {
data = 2;
}
if ((CFG_IST(ha, CFG_CTRL_24XX) && data < 4) ||
(CFG_IST(ha, CFG_CTRL_25XX) && data < 5) ||
(CFG_IST(ha, CFG_CTRL_2783) && data < 6)) {
if (CFG_IST(ha, CFG_CTRL_2783) && data == 5 &&
conn == 0) {
EL(ha, "invalid parameter value for 'fc-data-"
"rate': %d; using nvram value of %d\n",
data, 2);
data = 2;
}
icb->firmware_options_3[1] = (uint8_t)
(icb->firmware_options_3[1] & 0x1f);
icb->firmware_options_3[1] = (uint8_t)
(icb->firmware_options_3[1] | (uint8_t)(data << 5));
} else {
EL(ha, "invalid parameter value for 'fc-data-rate': "
"%d; using nvram value of %d\n", data,
(icb->firmware_options_3[1] >> 5) & 0x7);
}
}
ha->ip_init_ctrl_blk.cb24.cc[0] = LSB(ql_ip_buffer_count);
ha->ip_init_ctrl_blk.cb24.cc[1] = MSB(ql_ip_buffer_count);
ha->ip_init_ctrl_blk.cb24.low_water_mark[0] = LSB(ql_ip_low_water);
ha->ip_init_ctrl_blk.cb24.low_water_mark[1] = MSB(ql_ip_low_water);
ADAPTER_STATE_LOCK(ha);
if ((data = ql_get_prop(ha, "enable-flash-load")) == 0xffffffff ||
data == 0) {
ha->cfg_flags &= ~CFG_LOAD_FLASH_FW;
} else if (data == 1) {
ha->cfg_flags |= CFG_LOAD_FLASH_FW;
} else {
EL(ha, "invalid parameter value for 'enable-flash-load': "
"%d; using default value of 0\n", data);
}
if ((data = ql_get_prop(ha, "enable-fwexttrace")) != 0xffffffff) {
if (data != 0) {
ha->cfg_flags |= CFG_ENABLE_FWEXTTRACE;
}
}
if ((data = ql_get_prop(ha, "enable-fwfcetrace")) != 0xffffffff) {
ha->cfg_flags |= CFG_ENABLE_FWFCETRACE;
ha->fwfcetraceopt = data;
}
if ((data = ql_get_prop(ha, "enable-fasttimeout")) != 0xffffffff) {
if (data != 0) {
ha->cfg_flags |= CFG_FAST_TIMEOUT;
}
}
ql_common_properties(ha);
ADAPTER_STATE_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
uint32_t
ql_get_prop(ql_adapter_state_t *ha, char *string)
{
char buf[256];
uint32_t data = 0xffffffff;
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
(void) sprintf(buf, "hba%d-vp%d-%s", ha->instance,
ha->vp_index, string);
data = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, ha->dip, 0,
buf, (int)0xffffffff);
}
if (data == 0xffffffff) {
(void) sprintf(buf, "hba%d-%s", ha->instance, string);
data = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, ha->dip,
0, buf, (int)0xffffffff);
}
if (data == 0xffffffff) {
data = (uint32_t)ddi_prop_get_int(DDI_DEV_T_ANY, ha->dip, 0,
string, (int)0xffffffff);
}
return (data);
}
static int
ql_check_isp_firmware(ql_adapter_state_t *ha)
{
int rval;
uint16_t word_count;
uint32_t byte_count;
uint32_t fw_size, *lptr;
caddr_t bufp;
uint16_t risc_address = (uint16_t)ha->risc_fw[0].addr;
QL_PRINT_10(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_82XX)) {
if ((rval = ql_8021_fw_chk(ha)) == QL_SUCCESS) {
rval = ql_start_firmware(ha);
}
} else if (CFG_IST(ha, CFG_CTRL_278083)) {
ha->dev_state = NX_DEV_READY;
if (ha->rom_status == MBS_ROM_FW_RUNNING) {
EL(ha, "ISP ROM Status = MBS_ROM_FW_RUNNING\n");
rval = QL_SUCCESS;
} else if (ha->rom_status == MBS_ROM_IDLE) {
EL(ha, "ISP ROM Status = MBS_ROM_IDLE\n");
rval = QL_FUNCTION_FAILED;
} else {
EL(ha, "ISP ROM Status, mbx0=%xh\n", ha->rom_status);
rval = QL_FUNCTION_FAILED;
}
} else if (CFG_IST(ha, CFG_DISABLE_RISC_CODE_LOAD)) {
ha->dev_state = NX_DEV_READY;
if (ha->risc_code != NULL) {
kmem_free(ha->risc_code, ha->risc_code_size);
ha->risc_code = NULL;
ha->risc_code_size = 0;
}
rval = ql_rd_risc_ram(ha, risc_address + 3,
ha->req_q[0]->req_ring.cookie.dmac_laddress, 1);
if (rval == QL_SUCCESS) {
lptr = (uint32_t *)ha->req_q[0]->req_ring.bp;
fw_size = *lptr << 1;
if ((bufp = kmem_alloc(fw_size, KM_SLEEP)) != NULL) {
ha->risc_code_size = fw_size;
ha->risc_code = bufp;
ha->fw_transfer_size = 128;
do {
if (fw_size > ha->fw_transfer_size) {
byte_count =
ha->fw_transfer_size;
} else {
byte_count = fw_size;
}
word_count =
(uint16_t)(byte_count >> 1);
rval = ql_rd_risc_ram(ha, risc_address,
ha->req_q[0]->req_ring.cookie.
dmac_laddress, word_count);
if (rval != QL_SUCCESS) {
kmem_free(ha->risc_code,
ha->risc_code_size);
ha->risc_code = NULL;
ha->risc_code_size = 0;
break;
}
(void) ddi_dma_sync(
ha->req_q[0]->req_ring.dma_handle,
0, byte_count,
DDI_DMA_SYNC_FORKERNEL);
ddi_rep_get16(
ha->req_q[0]->req_ring.acc_handle,
(uint16_t *)bufp, (uint16_t *)
ha->req_q[0]->req_ring.bp,
word_count, DDI_DEV_AUTOINCR);
risc_address += word_count;
fw_size -= byte_count;
bufp += byte_count;
} while (fw_size != 0);
}
rval = QL_FUNCTION_FAILED;
}
} else {
ha->dev_state = NX_DEV_READY;
rval = QL_FUNCTION_FAILED;
}
if (rval != QL_SUCCESS) {
EL(ha, "Load RISC code\n");
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
int
ql_load_isp_firmware(ql_adapter_state_t *vha)
{
caddr_t risc_code_address;
uint32_t risc_address, risc_code_size;
int rval = QL_FUNCTION_FAILED;
uint32_t word_count, cnt;
size_t byte_count;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_10(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_82XX)) {
rval = ql_8021_reset_fw(ha) == NX_DEV_READY ?
QL_SUCCESS : QL_FUNCTION_FAILED;
} else {
if (CFG_IST(ha, CFG_CTRL_81XX)) {
ql_mps_reset(ha);
}
if (CFG_IST(ha, CFG_LOAD_FLASH_FW)) {
QL_PRINT_10(ha, "CFG_LOAD_FLASH_FW exit\n");
return (ql_load_flash_fw(ha));
}
if (CFG_IST(ha, CFG_CTRL_27XX)) {
(void) ql_2700_get_module_dmp_template(ha);
}
for (cnt = 0; cnt < MAX_RISC_CODE_SEGMENTS &&
ha->risc_fw[cnt].code != NULL; cnt++) {
risc_code_address = ha->risc_fw[cnt].code;
risc_address = ha->risc_fw[cnt].addr;
if ((risc_address = ha->risc_fw[cnt].addr) == 0) {
continue;
}
risc_code_size = ha->risc_fw[cnt].length;
while (risc_code_size) {
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
word_count = ha->fw_transfer_size >> 2;
if (word_count > risc_code_size) {
word_count = risc_code_size;
}
byte_count = word_count << 2;
ddi_rep_put32(
ha->req_q[0]->req_ring.acc_handle,
(uint32_t *)risc_code_address,
(uint32_t *)
ha->req_q[0]->req_ring.bp,
word_count, DDI_DEV_AUTOINCR);
} else {
word_count = ha->fw_transfer_size >> 1;
if (word_count > risc_code_size) {
word_count = risc_code_size;
}
byte_count = word_count << 1;
ddi_rep_put16(
ha->req_q[0]->req_ring.acc_handle,
(uint16_t *)risc_code_address,
(uint16_t *)
ha->req_q[0]->req_ring.bp,
word_count, DDI_DEV_AUTOINCR);
}
(void) ddi_dma_sync(
ha->req_q[0]->req_ring.dma_handle,
0, byte_count, DDI_DMA_SYNC_FORDEV);
rval = ql_wrt_risc_ram(ha, risc_address,
ha->req_q[0]->req_ring.cookie.dmac_laddress,
word_count);
if (rval != QL_SUCCESS) {
EL(ha, "failed, load=%xh\n", rval);
cnt = MAX_RISC_CODE_SEGMENTS;
break;
}
risc_address += word_count;
risc_code_size -= word_count;
risc_code_address += byte_count;
}
}
}
bzero(ha->req_q[0]->req_ring.bp, ha->fw_transfer_size);
if (rval == QL_SUCCESS) {
rval = ql_start_firmware(ha);
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
static int
ql_load_flash_fw(ql_adapter_state_t *ha)
{
int rval;
uint8_t seg_cnt;
uint32_t risc_address, xfer_size, count, *bp, faddr;
uint32_t risc_code_size = 0;
QL_PRINT_10(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_278083)) {
if ((rval = ql_load_flash_image(ha)) != QL_SUCCESS) {
EL(ha, "load_flash_image status=%xh\n", rval);
} else if (CFG_IST(ha, CFG_CTRL_27XX) &&
(rval = ql_2700_get_flash_dmp_template(ha)) !=
QL_SUCCESS) {
EL(ha, "get_flash_dmp_template status=%xh\n", rval);
}
} else {
faddr = ha->flash_data_addr | ha->flash_fw_addr;
for (seg_cnt = 0; seg_cnt < 2; seg_cnt++) {
xfer_size = ha->fw_transfer_size >> 2;
do {
GLOBAL_HW_LOCK();
bp = (uint32_t *)ha->req_q[0]->req_ring.bp;
for (count = 0; count < xfer_size; count++) {
rval = ql_24xx_read_flash(ha, faddr++,
bp);
if (rval != QL_SUCCESS) {
break;
}
ql_chg_endian((uint8_t *)bp++, 4);
}
GLOBAL_HW_UNLOCK();
if (rval != QL_SUCCESS) {
EL(ha, "24xx_read_flash failed=%xh\n",
rval);
break;
}
if (risc_code_size == 0) {
bp = (uint32_t *)
ha->req_q[0]->req_ring.bp;
risc_address = bp[2];
risc_code_size = bp[3];
ha->risc_fw[seg_cnt].addr =
risc_address;
}
if (risc_code_size < xfer_size) {
faddr -= xfer_size - risc_code_size;
xfer_size = risc_code_size;
}
(void) ddi_dma_sync(
ha->req_q[0]->req_ring.dma_handle,
0, xfer_size << 2, DDI_DMA_SYNC_FORDEV);
rval = ql_wrt_risc_ram(ha, risc_address,
ha->req_q[0]->req_ring.cookie.dmac_laddress,
xfer_size);
if (rval != QL_SUCCESS) {
EL(ha, "ql_wrt_risc_ram failed=%xh\n",
rval);
break;
}
risc_address += xfer_size;
risc_code_size -= xfer_size;
} while (risc_code_size);
if (rval != QL_SUCCESS) {
break;
}
}
}
if (rval == QL_SUCCESS) {
rval = ql_start_firmware(ha);
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
int
ql_start_firmware(ql_adapter_state_t *vha)
{
int rval, rval2;
uint32_t data;
ql_mbx_data_t mr = {0};
ql_adapter_state_t *ha = vha->pha;
ql_init_24xx_cb_t *icb =
(ql_init_24xx_cb_t *)&ha->init_ctrl_blk.cb24;
QL_PRINT_10(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_82XX)) {
rval = ql_get_fw_version(ha, &mr, MAILBOX_TOV);
ha->fw_major_version = mr.mb[1];
ha->fw_minor_version = mr.mb[2];
ha->fw_subminor_version = mr.mb[3];
ha->fw_attributes = mr.mb[6];
} else if ((rval = ql_verify_checksum(ha)) == QL_SUCCESS) {
(void) ql_execute_fw(ha);
(void) ql_get_fw_version(ha, &mr, MAILBOX_TOV);
ha->fw_major_version = mr.mb[1];
ha->fw_minor_version = mr.mb[2];
ha->fw_subminor_version = mr.mb[3];
ha->fw_ext_memory_end = SHORT_TO_LONG(mr.mb[4], mr.mb[5]);
ha->fw_ext_memory_size = ((ha->fw_ext_memory_end -
0x100000) + 1) * 4;
if (CFG_IST(ha, CFG_CTRL_278083)) {
ha->fw_attributes = SHORT_TO_LONG(mr.mb[6], mr.mb[15]);
ha->phy_fw_major_version = LSB(mr.mb[13]);
ha->phy_fw_minor_version = MSB(mr.mb[14]);
ha->phy_fw_subminor_version = LSB(mr.mb[14]);
ha->fw_ext_attributes = SHORT_TO_LONG(mr.mb[16],
mr.mb[17]);
} else {
ha->fw_attributes = mr.mb[6];
ha->phy_fw_major_version = LSB(mr.mb[8]);
ha->phy_fw_minor_version = MSB(mr.mb[9]);
ha->phy_fw_subminor_version = LSB(mr.mb[9]);
ha->mpi_capability_list =
SHORT_TO_LONG(mr.mb[13], mr.mb[12]);
}
ha->mpi_fw_major_version = LSB(mr.mb[10]);
ha->mpi_fw_minor_version = MSB(mr.mb[11]);
ha->mpi_fw_subminor_version = LSB(mr.mb[11]);
if (CFG_IST(ha, CFG_CTRL_27XX)) {
ha->fw_shared_ram_start =
SHORT_TO_LONG(mr.mb[18], mr.mb[19]);
ha->fw_shared_ram_end =
SHORT_TO_LONG(mr.mb[20], mr.mb[21]);
ha->fw_ddr_ram_start =
SHORT_TO_LONG(mr.mb[22], mr.mb[23]);
ha->fw_ddr_ram_end =
SHORT_TO_LONG(mr.mb[24], mr.mb[25]);
}
if (CFG_IST(ha, CFG_FLASH_ACC_SUPPORT)) {
if ((rval2 = ql_flash_access(ha, FAC_GET_SECTOR_SIZE,
0, 0, &data)) == QL_SUCCESS) {
ha->xioctl->fdesc.block_size = data << 2;
QL_PRINT_10(ha, "fdesc.block_size="
"%xh\n",
ha->xioctl->fdesc.block_size);
} else {
EL(ha, "flash_access status=%xh\n", rval2);
}
}
if (CFG_IST(ha, CFG_CTRL_24XX) && ha->serdes_param[0] & BIT_0) {
mr.mb[1] = ha->serdes_param[0];
mr.mb[2] = ha->serdes_param[1];
mr.mb[3] = ha->serdes_param[2];
mr.mb[4] = ha->serdes_param[3];
(void) ql_serdes_param(ha, &mr);
}
}
if (CFG_IST(ha, CFG_CTRL_81XX) && ql_enable_ets) {
if (ql_get_firmware_option(ha, &mr) == QL_SUCCESS) {
mr.mb[2] = (uint16_t)
(mr.mb[2] | FO2_FCOE_512_MAX_MEM_WR_BURST);
(void) ql_set_firmware_option(ha, &mr);
}
}
if (ha->flags & MULTI_QUEUE) {
QL_PRINT_10(ha, "MULTI_QUEUE\n");
icb->msi_x_vector[0] = LSB(ha->rsp_queues[0]->msi_x_vector);
icb->msi_x_vector[1] = MSB(ha->rsp_queues[0]->msi_x_vector);
if (ha->iflags & IFLG_INTR_MSIX &&
CFG_IST(ha, CFG_NO_INTR_HSHAKE_SUP)) {
QL_PRINT_10(ha, "NO_INTR_HANDSHAKE\n");
ADAPTER_STATE_LOCK(ha);
ha->flags |= NO_INTR_HANDSHAKE;
ADAPTER_STATE_UNLOCK(ha);
icb->firmware_options_2[2] = (uint8_t)
(icb->firmware_options_2[2] & ~(BIT_6 | BIT_5));
icb->firmware_options_2[2] = (uint8_t)
(icb->firmware_options_2[2] | BIT_7);
} else {
icb->firmware_options_2[2] = (uint8_t)
(icb->firmware_options_2[2] & ~BIT_5);
icb->firmware_options_2[2] = (uint8_t)
(icb->firmware_options_2[2] | BIT_7 | BIT_6);
}
} else {
icb->firmware_options_2[2] = (uint8_t)
(icb->firmware_options_2[2] & ~(BIT_7 | BIT_5));
icb->firmware_options_2[2] = (uint8_t)
(icb->firmware_options_2[2] | BIT_6);
}
icb->firmware_options_2[3] = (uint8_t)
(icb->firmware_options_2[3] & ~(BIT_1 | BIT_0));
if (CFG_IST(ha, CFG_CTRL_22XX) ||
ql_get_resource_cnts(ha, &mr) != QL_SUCCESS) {
icb->execution_throttle[0] = 0xff;
icb->execution_throttle[1] = 0xff;
} else {
icb->execution_throttle[0] = LSB(mr.mb[6]);
icb->execution_throttle[1] = MSB(mr.mb[6]);
}
EL(ha, "icb->execution_throttle %d\n",
CHAR_TO_SHORT(icb->execution_throttle[0],
icb->execution_throttle[1]));
if (rval != QL_SUCCESS) {
ha->task_daemon_flags &= ~FIRMWARE_LOADED;
EL(ha, "failed, rval = %xh\n", rval);
} else {
ha->task_daemon_flags |= FIRMWARE_LOADED;
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
int
ql_set_cache_line(ql_adapter_state_t *ha)
{
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha->pha, CFG_SET_CACHE_LINE_SIZE_1)) {
ql_pci_config_put8(ha->pha, PCI_CONF_CACHE_LINESZ, 1);
}
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
int
ql_init_rings(ql_adapter_state_t *vha2)
{
int rval, rval2;
uint16_t index;
ql_mbx_data_t mr;
ql_adapter_state_t *ha = vha2->pha;
QL_PRINT_3(ha, "started\n");
for (index = 0; index < ha->osc_max_cnt; index++) {
ha->outstanding_cmds[index] = NULL;
}
ha->osc_index = 1;
ha->pending_cmds.first = NULL;
ha->pending_cmds.last = NULL;
ha->req_q[0]->req_ring_ptr = ha->req_q[0]->req_ring.bp;
ha->req_q[0]->req_ring_index = 0;
ha->req_q[0]->req_q_cnt = REQUEST_ENTRY_CNT - 1;
ha->rsp_queues[0]->rsp_ring_ptr = ha->rsp_queues[0]->rsp_ring.bp;
ha->rsp_queues[0]->rsp_ring_index = 0;
if (ha->flags & VP_ENABLED) {
ql_adapter_state_t *vha;
ql_init_24xx_cb_t *icb = &ha->init_ctrl_blk.cb24;
bzero(icb->vp_count,
((uintptr_t)icb + sizeof (ql_init_24xx_cb_t)) -
(uintptr_t)icb->vp_count);
icb->vp_count[0] = ha->max_vports - 1;
icb->global_vp_option[0] = BIT_1;
for (index = 0; index < ha->max_vports; index++) {
icb->vpc[index].options = VPO_TARGET_MODE_DISABLED |
VPO_INITIATOR_MODE_ENABLED;
}
for (vha = ha->vp_next; vha != NULL; vha = vha->vp_next) {
if (vha->vp_index == 0 ||
vha->vp_index >= ha->max_vports) {
continue;
}
index = (uint8_t)(vha->vp_index - 1);
bcopy(vha->loginparams.node_ww_name.raw_wwn,
icb->vpc[index].node_name, 8);
bcopy(vha->loginparams.nport_ww_name.raw_wwn,
icb->vpc[index].port_name, 8);
if (vha->flags & VP_ENABLED) {
icb->vpc[index].options = (uint8_t)
(icb->vpc[index].options | VPO_ENABLED);
}
}
}
for (index = 0; index < 2; index++) {
rval = ql_init_firmware(ha);
if (rval == QL_COMMAND_ERROR) {
EL(ha, "stopping firmware\n");
(void) ql_stop_firmware(ha);
} else {
break;
}
}
if (rval == QL_SUCCESS && CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
rval = ql_get_firmware_option(ha, &mr);
if (rval == QL_SUCCESS) {
mr.mb[1] = (uint16_t)(mr.mb[1] | BIT_9);
mr.mb[2] = 0;
mr.mb[3] = BIT_10;
rval = ql_set_firmware_option(ha, &mr);
}
}
if ((rval == QL_SUCCESS) && (CFG_IST(ha, CFG_ENABLE_FWFCETRACE))) {
if ((rval2 = ql_get_dma_mem(ha, &ha->fwfcetracebuf, FWFCESIZE,
LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN)) != QL_SUCCESS) {
EL(ha, "fcetrace buffer alloc failed: %xh\n", rval2);
} else {
if ((rval2 = ql_fw_etrace(ha, &ha->fwfcetracebuf,
FTO_FCE_TRACE_ENABLE, NULL)) != QL_SUCCESS) {
EL(ha, "fcetrace enable failed: %xh\n", rval2);
ql_free_phys(ha, &ha->fwfcetracebuf);
}
}
}
if ((rval == QL_SUCCESS) && (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE))) {
if ((rval2 = ql_get_dma_mem(ha, &ha->fwexttracebuf, FWEXTSIZE,
LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN)) != QL_SUCCESS) {
EL(ha, "exttrace buffer alloc failed: %xh\n", rval2);
} else {
if ((rval2 = ql_fw_etrace(ha, &ha->fwexttracebuf,
FTO_EXT_TRACE_ENABLE, NULL)) != QL_SUCCESS) {
EL(ha, "exttrace enable failed: %xh\n", rval2);
ql_free_phys(ha, &ha->fwexttracebuf);
}
}
}
if (rval == QL_SUCCESS && CFG_IST(ha, CFG_CTRL_MENLO)) {
ql_mbx_iocb_t *pkt;
clock_t timer;
for (timer = 3000; timer; timer--) {
if (ha->flags & MENLO_LOGIN_OPERATIONAL) {
break;
}
if (!(ha->flags & INTERRUPTS_ENABLED) ||
ddi_in_panic()) {
if (INTERRUPT_PENDING(ha)) {
(void) ql_isr((caddr_t)ha);
INTR_LOCK(ha);
ha->intr_claimed = B_TRUE;
INTR_UNLOCK(ha);
}
}
ql_delay(ha, 10000);
}
if (timer == 0) {
rval = QL_FUNCTION_TIMEOUT;
} else {
pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
if (pkt == NULL) {
EL(ha, "failed, kmem_zalloc\n");
rval = QL_MEMORY_ALLOC_FAILED;
} else {
pkt->mvfy.entry_type = VERIFY_MENLO_TYPE;
pkt->mvfy.entry_count = 1;
pkt->mvfy.options_status =
LE_16(VMF_DO_NOT_UPDATE_FW);
rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
sizeof (ql_mbx_iocb_t));
LITTLE_ENDIAN_16(&pkt->mvfy.options_status);
LITTLE_ENDIAN_16(&pkt->mvfy.failure_code);
if (rval != QL_SUCCESS ||
(pkt->mvfy.entry_status & 0x3c) != 0 ||
pkt->mvfy.options_status != CS_COMPLETE) {
EL(ha, "failed, status=%xh, es=%xh, "
"cs=%xh, fc=%xh\n", rval,
pkt->mvfy.entry_status & 0x3c,
pkt->mvfy.options_status,
pkt->mvfy.failure_code);
if (rval == QL_SUCCESS) {
rval = QL_FUNCTION_FAILED;
}
}
kmem_free(pkt, sizeof (ql_mbx_iocb_t));
}
}
}
if (rval != QL_SUCCESS) {
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~FIRMWARE_UP;
TASK_DAEMON_UNLOCK(ha);
EL(ha, "failed, rval = %xh\n", rval);
} else {
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= FIRMWARE_UP;
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
int
ql_fw_ready(ql_adapter_state_t *ha, uint8_t secs)
{
ql_mbx_data_t mr;
clock_t timer, login_wait, wait;
clock_t dly = 250000;
clock_t sec_delay = MICROSEC / dly;
int rval = QL_FUNCTION_FAILED;
uint16_t state[6] = {0};
QL_PRINT_3(ha, "started\n");
login_wait = ha->r_a_tov * 2 * sec_delay;
timer = wait = secs * sec_delay;
state[0] = 0xffff;
while (login_wait != 0 && wait != 0 &&
!(ha->task_daemon_flags & ISP_ABORT_NEEDED) &&
!(ha->flags & MPI_RESET_NEEDED)) {
rval = ql_get_firmware_state(ha, &mr);
if (rval == QL_SUCCESS) {
if (mr.mb[1] != FSTATE_READY) {
if (mr.mb[1] == FSTATE_LOSS_SYNC &&
mr.mb[4] == FSTATE_MPI_NIC_ERROR &&
CFG_IST(ha, CFG_FCOE_SUPPORT)) {
EL(ha, "mpi_nic_error, "
"isp_abort_needed\n");
ADAPTER_STATE_LOCK(ha);
ha->flags |= MPI_RESET_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
if (!(ha->task_daemon_flags &
ABORT_ISP_ACTIVE)) {
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |=
ISP_ABORT_NEEDED;
TASK_DAEMON_UNLOCK(ha);
}
}
if (mr.mb[1] != FSTATE_WAIT_LOGIN) {
timer = --wait;
} else {
timer = --login_wait;
}
rval = QL_FUNCTION_FAILED;
} else {
rval = ql_get_timeout_parameters(ha,
&ha->r_a_tov);
if (rval != QL_SUCCESS) {
EL(ha, "failed, get_timeout_param"
"=%xh\n", rval);
}
rval = ql_configure_loop(ha);
(void) ql_marker(ha, 0, 0, MK_SYNC_ALL);
if (ha->task_daemon_flags &
LOOP_RESYNC_NEEDED) {
wait--;
EL(ha, "loop trans; tdf=%xh\n",
ha->task_daemon_flags);
} else {
break;
}
}
} else {
break;
}
if (state[0] != mr.mb[1] || state[1] != mr.mb[2] ||
state[2] != mr.mb[3] || state[3] != mr.mb[4] ||
state[4] != mr.mb[5] || state[5] != mr.mb[6]) {
EL(ha, "mbx1=%xh, mbx2=%xh, mbx3=%xh, mbx4=%xh, "
"mbx5=%xh, mbx6=%xh\n", mr.mb[1], mr.mb[2],
mr.mb[3], mr.mb[4], mr.mb[5], mr.mb[6]);
state[0] = mr.mb[1];
state[1] = mr.mb[2];
state[2] = mr.mb[3];
state[3] = mr.mb[4];
state[4] = mr.mb[5];
state[5] = mr.mb[6];
}
if (timer != 0) {
if (timer % 4 == 0) {
delay(drv_usectohz(dly));
} else {
drv_usecwait(dly);
}
} else {
rval = QL_FUNCTION_TIMEOUT;
}
}
if (rval != QL_SUCCESS) {
if ((ha->task_daemon_flags & ISP_ABORT_NEEDED ||
ha->flags & MPI_RESET_NEEDED) &&
ha->task_daemon_flags & LOOP_RESYNC_NEEDED) {
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~LOOP_RESYNC_NEEDED;
TASK_DAEMON_UNLOCK(ha);
}
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_configure_loop(ql_adapter_state_t *ha)
{
int rval = QL_SUCCESS;
ql_adapter_state_t *vha;
QL_PRINT_10(ha, "started\n");
for (vha = ha; vha != NULL; vha = vha->vp_next) {
TASK_DAEMON_LOCK(ha);
if (!(vha->task_daemon_flags & LOOP_RESYNC_NEEDED) &&
vha->vp_index != 0 &&
(!(vha->flags & VP_ENABLED) ||
vha->flags & VP_ID_NOT_ACQUIRED)) {
TASK_DAEMON_UNLOCK(ha);
continue;
}
vha->task_daemon_flags &= ~LOOP_RESYNC_NEEDED;
TASK_DAEMON_UNLOCK(ha);
rval = ql_configure_hba(vha);
if (rval == QL_SUCCESS && !(ha->task_daemon_flags &
(LOOP_RESYNC_NEEDED | LOOP_DOWN))) {
rval = ql_configure_device_d_id(vha);
if (rval == QL_SUCCESS && !(ha->task_daemon_flags &
(LOOP_RESYNC_NEEDED | LOOP_DOWN))) {
(void) ql_configure_fabric(vha);
}
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
static void
ql_configure_n_port_info(ql_adapter_state_t *ha)
{
ql_tgt_t tmp_tq;
ql_tgt_t *tq;
uint8_t *cb_port_name;
ql_link_t *link;
int index, rval;
uint16_t loop_id = 0;
uint32_t found = 0;
ql_dev_id_list_t *list;
uint32_t list_size;
ql_mbx_data_t mr;
port_id_t d_id = {0, 0, 0, 0};
QL_PRINT_10(ha, "started\n");
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
link = ha->dev[index].first;
while (link != NULL) {
tq = link->base_address;
link = link->next;
if ((tq->loop_id != 0x7ff) &&
(tq->loop_id != 0x7fe)) {
if (found == 0) {
rval = ql_get_port_database(ha,
tq, PDF_NONE);
if ((rval == QL_SUCCESS) &&
(tq->master_state ==
PD_STATE_PORT_LOGGED_IN)) {
EL(ha, "nport id (%xh) "
"loop_id=%xh "
"reappeared\n",
tq->d_id.b24,
tq->loop_id);
bcopy((void *)&tq->port_name[0],
(void *)&ha->n_port->
port_name[0],
8);
bcopy((void *)&tq->node_name[0],
(void *)&ha->n_port->
node_name[0],
8);
ha->n_port->d_id.b24 =
tq->d_id.b24;
found = 1;
continue;
}
}
(void) ql_logout_fabric_port(ha, tq);
}
tq->loop_id = PORT_NO_LOOP_ID;
}
}
if (found == 1) {
QL_PRINT_10(ha, "done found\n");
return;
}
tq = &tmp_tq;
tq->d_id.b.al_pa = 0;
tq->d_id.b.area = 0;
tq->d_id.b.domain = 0;
tq->loop_id = 0x7fe;
rval = ql_get_port_database(ha, tq, PDF_NONE);
if (rval == QL_SUCCESS) {
cb_port_name = &ha->loginparams.nport_ww_name.raw_wwn[0];
if ((ql_wwn_cmp(ha, (la_wwn_t *)&tq->port_name[0],
(la_wwn_t *)cb_port_name) == 1)) {
EL(ha, "target port has N_Port login initiative\n");
} else {
EL(ha, "host port has N_Port login initiative\n");
}
bcopy((void *)&tq->port_name[0],
(void *)&ha->n_port->port_name[0], 8);
bcopy((void *)&tq->node_name[0],
(void *)&ha->n_port->node_name[0], 8);
ha->n_port->n_port_handle = 0x7fe;
}
list_size = sizeof (ql_dev_id_list_t) * DEVICE_LIST_ENTRIES;
list = (ql_dev_id_list_t *)kmem_zalloc(list_size, KM_SLEEP);
if (ql_get_id_list(ha, (caddr_t)list, list_size, &mr) ==
QL_SUCCESS) {
if (mr.mb[1] == 1) {
index = 0;
ql_dev_list(ha, list, index,
&d_id, &loop_id);
ha->n_port->n_port_handle = loop_id;
tq->loop_id = loop_id;
tq->d_id.b24 = d_id.b24;
ha->n_port->d_id.b24 = d_id.b24;
} else {
for (index = 0; index <= LAST_LOCAL_LOOP_ID;
index++) {
tq->loop_id = (uint16_t)index;
rval = ql_get_port_database(ha, tq,
PDF_NONE);
if (rval == QL_NOT_LOGGED_IN) {
if (tq->master_state ==
PD_STATE_PLOGI_PENDING) {
ha->n_port->
n_port_handle =
tq->loop_id;
ha->n_port->d_id.b24 =
tq->hard_addr.b24;
break;
}
} else if (rval == QL_SUCCESS) {
ha->n_port->n_port_handle =
tq->loop_id;
ha->n_port->d_id.b24 =
tq->hard_addr.b24;
break;
}
}
if (index > LAST_LOCAL_LOOP_ID) {
EL(ha, "P2P:exceeded last id, "
"n_port_handle = %xh\n",
ha->n_port->n_port_handle);
ha->n_port->n_port_handle = 0;
tq->loop_id = 0;
}
}
} else {
kmem_free(list, list_size);
EL(ha, "ql_get_dev_list unsuccessful\n");
return;
}
rval = ql_get_port_database(ha, tq, PDF_NONE);
if (rval == QL_NOT_LOGGED_IN) {
if (tq->master_state == PD_STATE_PLOGI_PENDING) {
bcopy((void *)&tq->port_name[0],
(void *)&ha->n_port->port_name[0], 8);
bcopy((void *)&tq->node_name[0],
(void *)&ha->n_port->node_name[0], 8);
bcopy((void *)&tq->hard_addr,
(void *)&ha->n_port->d_id,
sizeof (port_id_t));
ha->n_port->d_id.b24 = d_id.b24;
}
} else if (rval == QL_SUCCESS) {
bcopy((void *)&tq->port_name[0],
(void *)&ha->n_port->port_name[0], 8);
bcopy((void *)&tq->node_name[0],
(void *)&ha->n_port->node_name[0], 8);
bcopy((void *)&tq->hard_addr,
(void *)&ha->n_port->d_id, sizeof (port_id_t));
ha->n_port->d_id.b24 = d_id.b24;
}
kmem_free(list, list_size);
EL(ha, "d_id = %xh, nport_handle = %xh, tq->loop_id = %xh",
tq->d_id.b24, ha->n_port->n_port_handle, tq->loop_id);
}
static int
ql_configure_hba(ql_adapter_state_t *ha)
{
uint8_t *bp;
int rval;
uint32_t state;
ql_mbx_data_t mr;
QL_PRINT_10(ha, "started\n");
rval = ql_get_adapter_id(ha, &mr);
if (rval == QL_SUCCESS) {
ha->topology = (uint8_t)(ha->topology &
~(QL_N_PORT | QL_NL_PORT | QL_F_PORT | QL_FL_PORT));
ha->loop_id = mr.mb[1];
ha->d_id.b.al_pa = LSB(mr.mb[2]);
ha->d_id.b.area = MSB(mr.mb[2]);
ha->d_id.b.domain = LSB(mr.mb[3]);
ha->bbcr_initial = LSB(mr.mb[15]);
ha->bbcr_runtime = MSB(mr.mb[15]);
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~FDISC_ENABLED;
ADAPTER_STATE_UNLOCK(ha);
switch (mr.mb[6]) {
case GID_TOP_NL_PORT:
ha->topology = (uint8_t)(ha->topology | QL_NL_PORT);
ha->loop_id = mr.mb[1];
break;
case GID_TOP_FL_PORT:
ha->topology = (uint8_t)(ha->topology | QL_FL_PORT);
ha->loop_id = mr.mb[1];
break;
case GID_TOP_N_PORT:
case GID_TOP_N_PORT_NO_TGT:
ha->flags |= POINT_TO_POINT;
ha->topology = (uint8_t)(ha->topology | QL_N_PORT);
ha->loop_id = 0xffff;
if (CFG_IST(ha, CFG_N2N_SUPPORT)) {
ql_configure_n_port_info(ha);
}
break;
case GID_TOP_F_PORT:
ha->flags |= POINT_TO_POINT;
ha->topology = (uint8_t)(ha->topology | QL_F_PORT);
ha->loop_id = 0xffff;
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2) &&
mr.mb[7] & GID_FP_NPIV_SUPPORT) {
ADAPTER_STATE_LOCK(ha);
ha->flags |= FDISC_ENABLED;
ADAPTER_STATE_UNLOCK(ha);
}
if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
ha->flags |= FDISC_ENABLED;
ha->fabric_params = mr.mb[7];
ha->fcoe_vlan_id = (uint16_t)(mr.mb[9] & 0xfff);
ha->fcoe_fcf_idx = mr.mb[10];
ha->fcoe_vnport_mac[5] = MSB(mr.mb[11]);
ha->fcoe_vnport_mac[4] = LSB(mr.mb[11]);
ha->fcoe_vnport_mac[3] = MSB(mr.mb[12]);
ha->fcoe_vnport_mac[2] = LSB(mr.mb[12]);
ha->fcoe_vnport_mac[1] = MSB(mr.mb[13]);
ha->fcoe_vnport_mac[0] = LSB(mr.mb[13]);
}
break;
default:
QL_PRINT_2(ha, "UNKNOWN topology=%xh, d_id=%xh\n",
mr.mb[6], ha->d_id.b24);
rval = QL_FUNCTION_FAILED;
break;
}
if (CFG_IST(ha, CFG_CTRL_2363 | CFG_ISP_FW_TYPE_2)) {
mr.mb[1] = 0;
mr.mb[2] = 0;
rval = ql_data_rate(ha, &mr);
if (rval != QL_SUCCESS) {
EL(ha, "data_rate status=%xh\n", rval);
state = FC_STATE_FULL_SPEED;
} else {
ha->iidma_rate = mr.mb[1];
if (mr.mb[1] == IIDMA_RATE_1GB) {
state = FC_STATE_1GBIT_SPEED;
} else if (mr.mb[1] == IIDMA_RATE_2GB) {
state = FC_STATE_2GBIT_SPEED;
} else if (mr.mb[1] == IIDMA_RATE_4GB) {
state = FC_STATE_4GBIT_SPEED;
} else if (mr.mb[1] == IIDMA_RATE_8GB) {
state = FC_STATE_8GBIT_SPEED;
} else if (mr.mb[1] == IIDMA_RATE_10GB) {
state = FC_STATE_10GBIT_SPEED;
} else if (mr.mb[1] == IIDMA_RATE_16GB) {
state = FC_STATE_16GBIT_SPEED;
} else if (mr.mb[1] == IIDMA_RATE_32GB) {
state = FC_STATE_32GBIT_SPEED;
} else {
state = 0;
}
}
} else {
ha->iidma_rate = IIDMA_RATE_1GB;
state = FC_STATE_FULL_SPEED;
}
ha->state = FC_PORT_STATE_MASK(ha->state) | state;
} else if (rval == MBS_COMMAND_ERROR) {
EL(ha, "mbox cmd error, rval = %xh, mr.mb[1]=%hx\n",
rval, mr.mb[1]);
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
bp = ha->loginparams.nport_ww_name.raw_wwn;
EL(ha, "topology=%xh, hba port id=%xh, "
"wwpn=%02x%02x%02x%02x%02x%02x%02x%02xh\n",
ha->topology, ha->d_id.b24, bp[0], bp[1],
bp[2], bp[3], bp[4], bp[5], bp[6], bp[7]);
}
return (rval);
}
static int
ql_configure_device_d_id(ql_adapter_state_t *ha)
{
port_id_t d_id;
ql_link_t *link;
int rval;
int loop;
ql_tgt_t *tq;
ql_dev_id_list_t *list;
uint32_t list_size;
uint16_t index, loop_id;
ql_mbx_data_t mr;
uint8_t retries = MAX_DEVICE_LOST_RETRY;
QL_PRINT_10(ha, "started\n");
list_size = sizeof (ql_dev_id_list_t) * DEVICE_LIST_ENTRIES;
list = kmem_zalloc(list_size, KM_SLEEP);
if (list == NULL) {
rval = QL_MEMORY_ALLOC_FAILED;
EL(ha, "failed, rval = %xh\n", rval);
return (rval);
}
do {
rval = ql_get_id_list(ha, (caddr_t)list, list_size, &mr);
if (rval != QL_SUCCESS) {
kmem_free(list, list_size);
EL(ha, "failed, rval = %xh\n", rval);
return (rval);
}
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
for (link = ha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
if (VALID_DEVICE_ID(ha, tq->loop_id)) {
DEVICE_QUEUE_LOCK(tq);
if (!(tq->flags & TQF_PLOGI_PROGRS) &&
!(ha->topology & QL_N_PORT)) {
tq->loop_id = (uint16_t)
(tq->loop_id |
PORT_LOST_ID);
}
if ((ha->topology & QL_NL_PORT) &&
(tq->flags & TQF_FABRIC_DEVICE)) {
tq->loop_id = (uint16_t)
(tq->loop_id |
PORT_LOST_ID);
}
DEVICE_QUEUE_UNLOCK(tq);
}
}
}
for (index = 0; index < mr.mb[1]; index++) {
ql_dev_list(ha, list, index, &d_id, &loop_id);
if (VALID_DEVICE_ID(ha, loop_id)) {
ADAPTER_STATE_LOCK(ha);
tq = ql_dev_init(ha, d_id, loop_id);
ADAPTER_STATE_UNLOCK(ha);
if (tq != NULL) {
tq->loop_id = loop_id;
if (ha->topology & QL_F_PORT ||
d_id.b.domain !=
ha->d_id.b.domain ||
d_id.b.area != ha->d_id.b.area) {
tq->flags |= TQF_FABRIC_DEVICE;
}
if (ql_get_port_database(ha, tq,
PDF_NONE) == QL_SUCCESS) {
tq->loop_id = (uint16_t)
(tq->loop_id &
~PORT_LOST_ID);
}
}
}
}
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2) &&
ha->topology & QL_FABRIC_CONNECTION) {
d_id.b24 = FS_FABRIC_F_PORT;
ADAPTER_STATE_LOCK(ha);
tq = ql_dev_init(ha, d_id, FL_PORT_24XX_HDL);
ADAPTER_STATE_UNLOCK(ha);
if (tq != NULL) {
tq->flags |= TQF_FABRIC_DEVICE;
(void) ql_get_port_database(ha, tq, PDF_NONE);
}
d_id.b24 = FS_NAME_SERVER;
ADAPTER_STATE_LOCK(ha);
tq = ql_dev_init(ha, d_id, SNS_24XX_HDL);
ADAPTER_STATE_UNLOCK(ha);
if (tq != NULL) {
tq->flags |= TQF_FABRIC_DEVICE;
if (ha->vp_index != 0) {
(void) ql_login_fport(ha, tq,
SNS_24XX_HDL, LFF_NONE, NULL);
}
(void) ql_get_port_database(ha, tq, PDF_NONE);
}
}
d_id.b24 = FS_BROADCAST;
ADAPTER_STATE_LOCK(ha);
(void) ql_dev_init(ha, d_id, (uint16_t)
(CFG_IST(ha, CFG_ISP_FW_TYPE_2) ? BROADCAST_24XX_HDL :
IP_BROADCAST_LOOP_ID));
ADAPTER_STATE_UNLOCK(ha);
loop = FALSE;
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
ql_update_dev(ha, index);
}
if ((ha->topology & QL_NL_PORT) && (mr.mb[1] != 0)) {
loop = FALSE;
} else if (mr.mb[1] == 0 && !(ha->topology & QL_F_PORT)) {
loop = TRUE;
}
if (loop == TRUE) {
drv_usecwait(1000000);
}
} while (retries-- && loop == TRUE &&
!(ha->pha->task_daemon_flags & LOOP_RESYNC_NEEDED));
kmem_free(list, list_size);
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
void
ql_dev_list(ql_adapter_state_t *ha, union ql_dev_id_list *list,
uint32_t index, port_id_t *d_id, uint16_t *id)
{
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
struct ql_24_dev_id *list24 = (struct ql_24_dev_id *)list;
d_id->b.al_pa = list24[index].al_pa;
d_id->b.area = list24[index].area;
d_id->b.domain = list24[index].domain;
*id = CHAR_TO_SHORT(list24[index].n_port_hdl_l,
list24[index].n_port_hdl_h);
} else if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
struct ql_ex_dev_id *list23 = (struct ql_ex_dev_id *)list;
d_id->b.al_pa = list23[index].al_pa;
d_id->b.area = list23[index].area;
d_id->b.domain = list23[index].domain;
*id = CHAR_TO_SHORT(list23[index].loop_id_l,
list23[index].loop_id_h);
} else {
struct ql_dev_id *list22 = (struct ql_dev_id *)list;
d_id->b.al_pa = list22[index].al_pa;
d_id->b.area = list22[index].area;
d_id->b.domain = list22[index].domain;
*id = (uint16_t)list22[index].loop_id;
}
}
static int
ql_configure_fabric(ql_adapter_state_t *ha)
{
port_id_t d_id;
ql_tgt_t *tq;
int rval = QL_FUNCTION_FAILED;
QL_PRINT_10(ha, "started\n");
if (ha->topology & QL_FABRIC_CONNECTION) {
d_id.b24 = FS_FABRIC_F_PORT;
tq = ql_d_id_to_queue(ha, d_id);
if (tq != NULL) {
(void) ql_get_port_database(ha, tq, PDF_NONE);
d_id.b24 = FS_NAME_SERVER;
tq = ql_d_id_to_queue(ha, d_id);
if (tq != NULL) {
(void) ql_get_port_database(ha, tq, PDF_NONE);
rval = QL_SUCCESS;
}
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
void
ql_reset_chip(ql_adapter_state_t *vha)
{
uint32_t cnt;
uint16_t cmd;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_10(ha, "started\n");
if (ha->power_level == PM_LEVEL_D3) {
QL_PRINT_2(ha, "Low Power exit\n");
return;
}
ql_disable_intr(ha);
for (cnt = 0; cnt < ha->reg_off->mbox_cnt; cnt++) {
WRT16_IO_REG(ha, mailbox_in[cnt], (uint16_t)0);
}
if (CFG_IST(ha, CFG_CTRL_82XX)) {
ha->timeout_cnt = 0;
ql_8021_reset_chip(ha);
QL_PRINT_10(ha, "8021 exit\n");
return;
}
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
ql_reset_24xx_chip(ha);
QL_PRINT_10(ha, "24xx exit\n");
return;
}
QL_PRINT_10(ha, "CFG_ISP_FW_TYPE_1 reset\n");
cmd = (uint16_t)ql_pci_config_get16(ha, PCI_CONF_COMM);
cmd = (uint16_t)(cmd & ~PCI_COMM_ME);
ql_pci_config_put16(ha, PCI_CONF_COMM, cmd);
WRT16_IO_REG(ha, hccr, HC_PAUSE_RISC);
for (cnt = 0; cnt < 30000; cnt++) {
if ((RD16_IO_REG(ha, hccr) & HC_RISC_PAUSE) != 0) {
break;
}
drv_usecwait(MILLISEC);
}
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~(FIRMWARE_UP | FIRMWARE_LOADED);
TASK_DAEMON_UNLOCK(ha);
WRT16_IO_REG(ha, ctrl_status, 0x20);
WRT16_IO_REG(ha, fpm_diag_config, 0x100);
if (CFG_IST(ha, CFG_CTRL_2363)) {
WRT16_IO_REG(ha, fpm_diag_config, 0);
}
WRT16_IO_REG(ha, ctrl_status, 0x10);
if (CFG_IST(ha, CFG_CTRL_2363)) {
WRT16_IO_REG(ha, fb_cmd, 0x00fc);
for (cnt = 0; cnt < 300000; cnt++) {
if ((RD16_IO_REG(ha, fb_cmd) & 0xff) == 0) {
break;
}
drv_usecwait(10);
}
} else {
WRT16_IO_REG(ha, fb_cmd, 0xa000);
}
WRT16_IO_REG(ha, ctrl_status, 0);
WRT16_IO_REG(ha, hccr, HC_RESET_RISC);
WRT16_IO_REG(ha, semaphore, 0);
WRT16_IO_REG(ha, hccr, HC_RELEASE_RISC);
WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
WRT16_IO_REG(ha, hccr, HC_CLR_HOST_INT);
INTR_LOCK(ha);
ha->mcp = NULL;
INTR_UNLOCK(ha);
MBX_REGISTER_LOCK(ha);
ha->mailbox_flags = (uint8_t)(ha->mailbox_flags &
~(MBX_BUSY_FLG | MBX_WANT_FLG | MBX_ABORT | MBX_INTERRUPT));
MBX_REGISTER_UNLOCK(ha);
if (CFG_IST(ha, CFG_CTRL_2363)) {
WRT16_IO_REG(ha, ctrl_status, ISP_RESET);
drv_usecwait(MILLISEC);
for (cnt = 0; cnt < 30000; cnt++) {
if ((RD16_IO_REG(ha, ctrl_status) & ISP_RESET) == 0) {
break;
}
drv_usecwait(MILLISEC);
}
}
for (cnt = 0; cnt < 30000; cnt++) {
if (RD16_IO_REG(ha, mailbox_out[0]) != MBS_ROM_BUSY) {
break;
}
drv_usecwait(MILLISEC);
}
cmd = (uint16_t)ql_pci_config_get16(ha, PCI_CONF_COMM);
cmd = (uint16_t)(cmd | PCI_COMM_ME);
ql_pci_config_put16(ha, PCI_CONF_COMM, cmd);
WRT16_IO_REG(ha, hccr, HC_DISABLE_PARITY_PAUSE);
if (CFG_IST(ha, CFG_CTRL_22XX) &&
RD16_IO_REG(ha, mailbox_out[7]) == 4) {
ha->fw_transfer_size = 128;
}
if (CFG_IST(ha, CFG_SBUS_CARD)) {
WRT16_IO_REG(ha, hccr, HC_PAUSE_RISC);
for (cnt = 0; cnt < 30000; cnt++) {
if ((RD16_IO_REG(ha, hccr) & HC_RISC_PAUSE) != 0) {
break;
} else {
drv_usecwait(MILLISEC);
}
}
WRT16_IO_REG(ha, ctrl_status, 0x30);
WRT16_IO_REG(ha, mailbox_in[23], 0x204c);
WRT16_IO_REG(ha, ctrl_status, 0);
WRT16_IO_REG(ha, hccr, HC_RELEASE_RISC);
}
QL_PRINT_10(ha, "done\n");
}
static void
ql_reset_24xx_chip(ql_adapter_state_t *ha)
{
uint32_t timer, stat;
QL_PRINT_10(ha, "started\n");
if (CFG_IST(ha, CFG_MWB_4096_SUPPORT)) {
WRT32_IO_REG(ha, ctrl_status, DMA_SHUTDOWN | MWB_4096_BYTES);
} else {
WRT32_IO_REG(ha, ctrl_status, DMA_SHUTDOWN);
}
for (timer = 0; timer < 30000; timer++) {
if ((RD32_IO_REG(ha, ctrl_status) & DMA_ACTIVE) == 0) {
break;
}
drv_usecwait(100);
}
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
WRT16_IO_REG(ha, mailbox_in[0], MBC_STOP_FIRMWARE);
WRT16_IO_REG(ha, mailbox_in[1], 0);
WRT16_IO_REG(ha, mailbox_in[2], 0);
WRT16_IO_REG(ha, mailbox_in[3], 0);
WRT16_IO_REG(ha, mailbox_in[4], 0);
WRT16_IO_REG(ha, mailbox_in[5], 0);
WRT16_IO_REG(ha, mailbox_in[6], 0);
WRT16_IO_REG(ha, mailbox_in[7], 0);
WRT16_IO_REG(ha, mailbox_in[8], 0);
WRT32_IO_REG(ha, hccr, HC24_SET_HOST_INT);
for (timer = 0; timer < 30000; timer++) {
stat = RD32_IO_REG(ha, risc2host);
if (stat & BIT_15) {
if ((stat & 0xff) < 0x12) {
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
break;
}
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
}
drv_usecwait(100);
}
WRT32_IO_REG(ha, ctrl_status, ISP_RESET);
drv_usecwait(100);
for (timer = 30000; timer; timer--) {
ha->rom_status = RD16_IO_REG(ha, mailbox_out[0]);
if (CFG_IST(ha, CFG_CTRL_278083)) {
if ((ha->rom_status & MBS_ROM_STATUS_MASK) !=
MBS_ROM_BUSY) {
break;
}
} else {
if (ha->rom_status == MBS_ROM_IDLE) {
break;
}
}
drv_usecwait(100);
}
for (timer = 0; timer < 30000; timer++) {
if ((RD32_IO_REG(ha, ctrl_status) & ISP_RESET) == 0) {
break;
}
drv_usecwait(100);
}
ha->adapter_stats->revlvl.isp2200 = RD16_IO_REG(ha, mailbox_out[4]);
ha->adapter_stats->revlvl.risc = RD16_IO_REG(ha, mailbox_out[5]);
ha->adapter_stats->revlvl.frmbfr = RD16_IO_REG(ha, mailbox_out[6]);
ha->adapter_stats->revlvl.riscrom = RD16_IO_REG(ha, mailbox_out[8]);
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
WRT32_IO_REG(ha, hccr, HC24_CLR_HOST_INT);
INTR_LOCK(ha);
ha->mcp = NULL;
INTR_UNLOCK(ha);
MBX_REGISTER_LOCK(ha);
ha->mailbox_flags = (uint8_t)(ha->mailbox_flags &
~(MBX_BUSY_FLG | MBX_WANT_FLG | MBX_ABORT | MBX_INTERRUPT));
MBX_REGISTER_UNLOCK(ha);
if (ha->flags & MPI_RESET_NEEDED) {
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
WRT16_IO_REG(ha, mailbox_in[0], MBC_RESTART_MPI);
WRT32_IO_REG(ha, hccr, HC24_SET_HOST_INT);
for (timer = 0; timer < 30000; timer++) {
stat = RD32_IO_REG(ha, risc2host);
if (stat & BIT_15) {
if ((stat & 0xff) < 0x12) {
WRT32_IO_REG(ha, hccr,
HC24_CLR_RISC_INT);
break;
}
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
}
drv_usecwait(100);
}
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~MPI_RESET_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
}
QL_PRINT_10(ha, "done\n");
}
int
ql_abort_isp(ql_adapter_state_t *vha)
{
ql_link_t *link, *link2;
uint16_t index;
ql_tgt_t *tq;
ql_lun_t *lq;
int rval = QL_SUCCESS;
ql_adapter_state_t *ha = vha->pha;
boolean_t abort_loop_down = B_FALSE;
QL_PRINT_2(ha, "started\n");
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~ISP_ABORT_NEEDED;
if (ha->task_daemon_flags & ABORT_ISP_ACTIVE ||
(ha->flags & ONLINE) == 0 || ha->flags & ADAPTER_SUSPENDED) {
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_2(ha, "already active or suspended tdf=0x%llx, "
"flgs=0x%llx\n", ha->task_daemon_flags, ha->flags);
return (rval);
}
ha->task_daemon_flags |= ABORT_ISP_ACTIVE;
ha->task_daemon_flags &= ~(MARKER_NEEDED | FIRMWARE_UP |
FIRMWARE_LOADED);
for (vha = ha; vha != NULL; vha = vha->vp_next) {
vha->task_daemon_flags &= ~(COMMAND_WAIT_NEEDED |
LOOP_RESYNC_NEEDED);
vha->task_daemon_flags |= LOOP_DOWN;
if (vha->loop_down_timer == LOOP_DOWN_TIMER_OFF) {
abort_loop_down = B_TRUE;
vha->loop_down_timer = LOOP_DOWN_TIMER_START;
}
}
TASK_DAEMON_UNLOCK(ha);
ql_port_state(ha, FC_STATE_OFFLINE, FC_STATE_CHANGE);
if (ha->mailbox_flags & MBX_BUSY_FLG) {
MBX_REGISTER_LOCK(ha);
ha->mailbox_flags = (uint8_t)(ha->mailbox_flags | MBX_ABORT);
cv_broadcast(&ha->cv_mbx_intr);
MBX_REGISTER_UNLOCK(ha);
for (index = 100; index &&
ha->mailbox_flags & MBX_ABORT; index--) {
delay(1);
}
}
if (ha->flags & PARITY_ERROR) {
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~PARITY_ERROR;
ADAPTER_STATE_UNLOCK(ha);
} else if (ddi_in_panic() == 0) {
ql_cmd_wait(ha);
}
rval = QL_ABORTED;
if (ha->flags & FW_DUMP_NEEDED) {
rval = ql_binary_fw_dump(ha, TRUE);
}
if (ha->flags & IP_INITIALIZED) {
(void) ql_shutdown_ip(ha);
}
if (ha->task_daemon_flags & ISP_ABORT_NEEDED) {
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~ISP_ABORT_NEEDED;
TASK_DAEMON_UNLOCK(ha);
}
if (rval != QL_SUCCESS) {
rval = QL_SUCCESS;
ql_reset_chip(ha);
}
ql_requeue_all_cmds(ha);
for (vha = ha; vha != NULL; vha = vha->vp_next) {
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
link = vha->dev[index].first;
while (link != NULL) {
tq = link->base_address;
link = link->next;
DEVICE_QUEUE_LOCK(tq);
tq->outcnt = 0;
tq->flags &= ~TQF_QUEUE_SUSPENDED;
for (link2 = tq->lun_queues.first;
link2 != NULL; link2 = link2->next) {
lq = link2->base_address;
lq->lun_outcnt = 0;
lq->flags &= ~LQF_UNTAGGED_PENDING;
}
DEVICE_QUEUE_UNLOCK(tq);
}
}
}
if ((rval = ql_check_isp_firmware(ha)) != QL_SUCCESS) {
if (ha->dev_state != NX_DEV_READY) {
EL(ha, "dev_state not ready\n");
} else if ((rval = ql_mbx_wrap_test(ha, NULL)) == QL_SUCCESS) {
rval = ql_load_isp_firmware(ha);
}
}
if (rval == QL_SUCCESS && (rval = ql_set_cache_line(ha)) ==
QL_SUCCESS && (rval = ql_init_rings(ha)) == QL_SUCCESS &&
(rval = ql_fw_ready(ha, 10)) == QL_SUCCESS) {
if (!(ha->flags & INTERRUPTS_ENABLED)) {
ql_enable_intr(ha);
}
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~(ISP_ABORT_NEEDED |
ABORT_ISP_ACTIVE);
TASK_DAEMON_UNLOCK(ha);
ql_loop_online(ha);
} else {
if (!(ha->flags & INTERRUPTS_ENABLED)) {
ql_enable_intr(ha);
}
TASK_DAEMON_LOCK(ha);
for (vha = ha; vha != NULL; vha = vha->vp_next) {
vha->task_daemon_flags |= LOOP_DOWN;
}
ha->task_daemon_flags &= ~ISP_ABORT_NEEDED;
TASK_DAEMON_UNLOCK(ha);
ql_port_state(ha, FC_STATE_OFFLINE, FC_STATE_CHANGE);
ql_abort_queues(ha);
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~ABORT_ISP_ACTIVE;
TASK_DAEMON_UNLOCK(ha);
}
for (vha = ha; vha != NULL; vha = vha->vp_next) {
if (!(vha->task_daemon_flags & LOOP_DOWN) &&
abort_loop_down == B_TRUE) {
vha->loop_down_timer = LOOP_DOWN_TIMER_OFF;
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_2(ha, "done\n");
}
return (rval);
}
void
ql_requeue_all_cmds(ql_adapter_state_t *ha)
{
ql_link_t *link;
ql_tgt_t *tq;
ql_lun_t *lq;
ql_srb_t *sp;
uint16_t index;
for (index = 1; index < ha->osc_max_cnt; index++) {
INTR_LOCK(ha);
REQUEST_RING_LOCK(ha);
if ((link = ha->pending_cmds.first) != NULL) {
sp = link->base_address;
ql_remove_link(&ha->pending_cmds, &sp->cmd);
REQUEST_RING_UNLOCK(ha);
index = 0;
} else {
REQUEST_RING_UNLOCK(ha);
if ((sp = ha->outstanding_cmds[index]) == NULL ||
sp == QL_ABORTED_SRB(ha)) {
INTR_UNLOCK(ha);
continue;
}
}
ha->outstanding_cmds[index] = NULL;
sp->handle = 0;
sp->flags &= ~SRB_IN_TOKEN_ARRAY;
INTR_UNLOCK(ha);
if (sp->flags & SRB_COMMAND_TIMEOUT) {
sp->pkt->pkt_reason = CS_TIMEOUT;
sp->flags &= ~SRB_RETRY;
sp->flags |= SRB_ISP_COMPLETED;
ql_done(&sp->cmd, B_FALSE);
continue;
}
lq = sp->lun_queue;
tq = lq->target_queue;
if (tq->flags & TQF_TAPE_DEVICE) {
sp->pkt->pkt_reason = CS_TRANSPORT;
sp->flags &= ~SRB_RETRY;
sp->flags |= SRB_ISP_COMPLETED;
EL(ha, "rtn seq IO, sp=%ph", sp);
ql_done(&sp->cmd, B_FALSE);
continue;
}
DEVICE_QUEUE_LOCK(tq);
sp->wdg_q_time = sp->init_wdg_q_time;
sp->flags &= ~(SRB_ISP_STARTED | SRB_ISP_COMPLETED |
SRB_RETRY);
ql_add_link_t(&lq->cmd, &sp->cmd);
sp->flags |= SRB_IN_DEVICE_QUEUE;
DEVICE_QUEUE_UNLOCK(tq);
}
}
int
ql_vport_control(ql_adapter_state_t *ha, uint8_t cmd)
{
ql_mbx_iocb_t *pkt;
uint8_t bit;
int rval;
uint32_t pkt_size;
QL_PRINT_10(ha, "started\n");
if (ha->vp_index != 0) {
pkt_size = sizeof (ql_mbx_iocb_t);
pkt = kmem_zalloc(pkt_size, KM_SLEEP);
if (pkt == NULL) {
EL(ha, "failed, kmem_zalloc\n");
return (QL_MEMORY_ALLOC_FAILED);
}
pkt->vpc.entry_type = VP_CONTROL_TYPE;
pkt->vpc.entry_count = 1;
pkt->vpc.command = cmd;
pkt->vpc.vp_count = 1;
pkt->vpc.fcf_index = ha->fcoe_fcf_idx;
bit = (uint8_t)(ha->vp_index - 1);
pkt->vpc.vp_index[bit / 8] = (uint8_t)
(pkt->vpc.vp_index[bit / 8] | BIT_0 << bit % 8);
rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size);
if (rval == QL_SUCCESS && pkt->vpc.status != 0) {
rval = QL_COMMAND_ERROR;
}
kmem_free(pkt, pkt_size);
} else {
rval = QL_SUCCESS;
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
int
ql_vport_modify(ql_adapter_state_t *ha, uint8_t cmd, uint8_t opt)
{
ql_mbx_iocb_t *pkt;
int rval;
uint32_t pkt_size;
QL_PRINT_10(ha, "started\n");
if (ha->pha->task_daemon_flags & LOOP_DOWN) {
QL_PRINT_10(ha, "loop_down\n");
return (QL_FUNCTION_FAILED);
}
pkt_size = sizeof (ql_mbx_iocb_t);
pkt = kmem_zalloc(pkt_size, KM_SLEEP);
if (pkt == NULL) {
EL(ha, "failed, kmem_zalloc\n");
return (QL_MEMORY_ALLOC_FAILED);
}
pkt->vpm.entry_type = VP_MODIFY_TYPE;
pkt->vpm.entry_count = 1;
pkt->vpm.command = cmd;
pkt->vpm.vp_count = 1;
pkt->vpm.first_vp_index = ha->vp_index;
pkt->vpm.first_options = opt;
pkt->vpm.fcf_index = ha->fcoe_fcf_idx;
bcopy(ha->loginparams.nport_ww_name.raw_wwn, pkt->vpm.first_port_name,
8);
bcopy(ha->loginparams.node_ww_name.raw_wwn, pkt->vpm.first_node_name,
8);
rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size);
if (rval == QL_SUCCESS && pkt->vpm.status != 0) {
EL(ha, "failed, ql_issue_mbx_iocb=%xh, status=%xh\n", rval,
pkt->vpm.status);
rval = QL_COMMAND_ERROR;
}
kmem_free(pkt, pkt_size);
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
int
ql_vport_enable(ql_adapter_state_t *ha)
{
int timer;
QL_PRINT_10(ha, "started\n");
ha->state = FC_PORT_SPEED_MASK(ha->state) | FC_STATE_OFFLINE;
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= LOOP_DOWN;
ha->task_daemon_flags &= ~(FC_STATE_CHANGE | STATE_ONLINE);
TASK_DAEMON_UNLOCK(ha);
ADAPTER_STATE_LOCK(ha);
ha->flags |= VP_ENABLED;
ha->flags &= ~VP_ID_NOT_ACQUIRED;
ADAPTER_STATE_UNLOCK(ha);
ha->fcoe_fcf_idx = 0;
if (ql_vport_modify(ha, VPM_MODIFY_ENABLE, VPO_TARGET_MODE_DISABLED |
VPO_INITIATOR_MODE_ENABLED | VPO_ENABLED) != QL_SUCCESS) {
QL_PRINT_2(ha, "failed to enable virtual port\n");
return (QL_FUNCTION_FAILED);
}
if (!(ha->pha->task_daemon_flags & LOOP_DOWN)) {
for (timer = 0; timer < 3000 &&
!(ha->task_daemon_flags & STATE_ONLINE);
timer++) {
if (ha->flags & VP_ID_NOT_ACQUIRED) {
break;
}
delay(1);
}
}
QL_PRINT_10(ha, "done\n");
return (QL_SUCCESS);
}
ql_adapter_state_t *
ql_vport_create(ql_adapter_state_t *ha, uint8_t index)
{
ql_adapter_state_t *vha;
QL_PRINT_10(ha, "started\n");
vha = kmem_alloc(sizeof (ql_adapter_state_t), KM_SLEEP);
ADAPTER_STATE_LOCK(ha);
bcopy(ha, vha, sizeof (ql_adapter_state_t));
vha->pi_attrs = NULL;
vha->ub_outcnt = 0;
vha->ub_allocated = 0;
vha->flags = 0;
vha->task_daemon_flags = 0;
ha->vp_next = vha;
vha->pha = ha;
vha->vp_index = index;
ADAPTER_STATE_UNLOCK(ha);
vha->hba.next = NULL;
vha->hba.prev = NULL;
vha->hba.base_address = vha;
vha->state = FC_PORT_SPEED_MASK(ha->state) | FC_STATE_OFFLINE;
vha->dev = kmem_zalloc(sizeof (*vha->dev) * DEVICE_HEAD_LIST_SIZE,
KM_SLEEP);
vha->ub_array = kmem_zalloc(sizeof (*vha->ub_array) * QL_UB_LIMIT,
KM_SLEEP);
QL_PRINT_10(ha, "done\n");
return (vha);
}
void
ql_vport_destroy(ql_adapter_state_t *ha)
{
ql_adapter_state_t *vha;
QL_PRINT_10(ha, "started\n");
ADAPTER_STATE_LOCK(ha);
for (vha = ha->pha; vha != NULL; vha = vha->vp_next) {
if (vha->vp_next == ha) {
vha->vp_next = ha->vp_next;
break;
}
}
ADAPTER_STATE_UNLOCK(ha);
if (ha->ub_array != NULL) {
kmem_free(ha->ub_array, sizeof (*ha->ub_array) * QL_UB_LIMIT);
}
if (ha->dev != NULL) {
kmem_free(ha->dev, sizeof (*vha->dev) * DEVICE_HEAD_LIST_SIZE);
}
kmem_free(ha, sizeof (ql_adapter_state_t));
QL_PRINT_10(ha, "done\n");
}
static void
ql_mps_reset(ql_adapter_state_t *ha)
{
uint32_t data, dctl = 1000;
do {
if (dctl-- == 0 || ql_wrt_risc_ram_word(ha, 0x7c00, 1) !=
QL_SUCCESS) {
return;
}
if (ql_rd_risc_ram_word(ha, 0x7c00, &data) != QL_SUCCESS) {
(void) ql_wrt_risc_ram_word(ha, 0x7c00, 0);
return;
}
} while (!(data & BIT_0));
if (ql_rd_risc_ram_word(ha, 0x7A15, &data) == QL_SUCCESS) {
dctl = (uint16_t)ql_pci_config_get16(ha, 0x54);
if ((data & 0xe0) < (dctl & 0xe0)) {
data &= 0xff1f;
data |= dctl & 0xe0;
(void) ql_wrt_risc_ram_word(ha, 0x7A15, data);
} else if ((data & 0xe0) != (dctl & 0xe0)) {
data &= 0xff1f;
data |= dctl & 0xe0;
(void) ql_wrt_risc_ram_word(ha, 0x7A15, data);
}
}
(void) ql_wrt_risc_ram_word(ha, 0x7c00, 0);
}
static void
ql_update_dev(ql_adapter_state_t *ha, uint32_t index)
{
ql_link_t *link;
ql_tgt_t *tq;
int rval;
QL_PRINT_3(ha, "started\n");
link = ha->dev[index].first;
while (link != NULL) {
tq = link->base_address;
link = link->next;
if (tq->loop_id & PORT_LOST_ID &&
!(tq->flags & (TQF_INITIATOR_DEVICE | TQF_FABRIC_DEVICE))) {
tq->loop_id &= ~PORT_LOST_ID;
if (VALID_DEVICE_ID(ha, tq->loop_id)) {
rval = ql_get_port_database(ha, tq, PDF_NONE);
if (rval == QL_NOT_LOGGED_IN) {
if (tq->master_state ==
PD_STATE_PORT_UNAVAILABLE) {
(void) ql_logout_fabric_port(
ha, tq);
tq->loop_id = PORT_NO_LOOP_ID;
}
} else if (rval == QL_SUCCESS) {
tq->loop_id = PORT_NO_LOOP_ID;
}
}
} else if (ha->topology & QL_NL_PORT &&
tq->flags & TQF_FABRIC_DEVICE) {
tq->loop_id &= ~PORT_LOST_ID;
if (VALID_DEVICE_ID(ha, tq->loop_id)) {
rval = ql_get_port_database(ha, tq, PDF_NONE);
if (rval == QL_NOT_LOGGED_IN) {
if (tq->master_state ==
PD_STATE_PORT_UNAVAILABLE) {
(void) ql_logout_fabric_port(
ha, tq);
tq->loop_id = PORT_NO_LOOP_ID;
}
} else if (rval == QL_SUCCESS) {
tq->loop_id = PORT_NO_LOOP_ID;
}
}
}
}
QL_PRINT_3(ha, "done\n");
}