#include <ql_apps.h>
#include <ql_api.h>
#include <ql_debug.h>
#include <ql_init.h>
#include <ql_iocb.h>
#include <ql_ioctl.h>
#include <ql_isr.h>
#include <ql_mbx.h>
#include <ql_nx.h>
#include <ql_xioctl.h>
#include <ql_fm.h>
extern pri_t minclsyspri;
extern pri_t maxclsyspri;
static int ql_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
static int ql_attach(dev_info_t *, ddi_attach_cmd_t);
static int ql_detach(dev_info_t *, ddi_detach_cmd_t);
static int ql_power(dev_info_t *, int, int);
static int ql_quiesce(dev_info_t *);
static opaque_t ql_bind_port(dev_info_t *, fc_fca_port_info_t *,
fc_fca_bind_info_t *);
static void ql_unbind_port(opaque_t);
static int ql_init_pkt(opaque_t, fc_packet_t *, int);
static int ql_un_init_pkt(opaque_t, fc_packet_t *);
static int ql_els_send(opaque_t, fc_packet_t *);
static int ql_get_cap(opaque_t, char *, void *);
static int ql_set_cap(opaque_t, char *, void *);
static int ql_getmap(opaque_t, fc_lilpmap_t *);
static int ql_transport(opaque_t, fc_packet_t *);
static int ql_ub_alloc(opaque_t, uint64_t *, uint32_t, uint32_t *, uint32_t);
static int ql_ub_free(opaque_t, uint32_t, uint64_t *);
static int ql_ub_release(opaque_t, uint32_t, uint64_t *);
static int ql_abort(opaque_t, fc_packet_t *, int);
static int ql_reset(opaque_t, uint32_t);
static int ql_port_manage(opaque_t, fc_fca_pm_t *);
static opaque_t ql_get_device(opaque_t, fc_portid_t);
static ql_adapter_state_t *ql_cmd_setup(opaque_t, fc_packet_t *, int *);
static int ql_els_plogi(ql_adapter_state_t *, fc_packet_t *);
static int ql_p2p_plogi(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_flogi(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_logo(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_prli(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_prlo(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_adisc(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_linit(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_lpc(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_lsts(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_scr(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_rscn(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_farp_req(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_farp_reply(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_rnid(ql_adapter_state_t *, fc_packet_t *);
static int ql_els_rls(ql_adapter_state_t *, fc_packet_t *);
static int ql_busy_plogi(ql_adapter_state_t *, fc_packet_t *, ql_tgt_t *);
static int ql_login_port(ql_adapter_state_t *, port_id_t);
static int ql_login_fabric_port(ql_adapter_state_t *, ql_tgt_t *, uint16_t);
static int ql_logout_port(ql_adapter_state_t *, port_id_t);
static ql_lun_t *ql_lun_queue(ql_adapter_state_t *, ql_tgt_t *, uint64_t);
static int ql_fcp_scsi_cmd(ql_adapter_state_t *, fc_packet_t *, ql_srb_t *);
static void ql_task_mgmt(ql_adapter_state_t *, ql_tgt_t *, fc_packet_t *,
ql_srb_t *);
static int ql_fcp_ip_cmd(ql_adapter_state_t *, fc_packet_t *, ql_srb_t *);
static int ql_fc_services(ql_adapter_state_t *, fc_packet_t *);
static int ql_start_cmd(ql_adapter_state_t *, ql_tgt_t *, fc_packet_t *,
ql_srb_t *);
static int ql_poll_cmd(ql_adapter_state_t *, ql_srb_t *, time_t);
static void ql_task_daemon(void *);
static void ql_task_thread(ql_adapter_state_t *);
static void ql_idle_check(ql_adapter_state_t *);
static void ql_unsol_callback(ql_srb_t *);
static int ql_process_logo_for_device(ql_adapter_state_t *, ql_tgt_t *);
static int ql_send_plogi(ql_adapter_state_t *, ql_tgt_t *, ql_head_t *);
static void ql_update_rscn(ql_adapter_state_t *, fc_affected_id_t *);
static int ql_process_rscn(ql_adapter_state_t *, fc_affected_id_t *);
static int ql_process_rscn_for_device(ql_adapter_state_t *, ql_tgt_t *);
static int ql_handle_rscn_update(ql_adapter_state_t *);
static void ql_free_unsolicited_buffer(ql_adapter_state_t *,
fc_unsol_buf_t *);
static void ql_timer(void *);
static void ql_timeout_insert(ql_adapter_state_t *, ql_tgt_t *, ql_srb_t *);
static void ql_watchdog(ql_adapter_state_t *);
static void ql_wdg_tq_list(ql_adapter_state_t *, ql_tgt_t *);
static void ql_cmd_timeout(ql_adapter_state_t *, ql_tgt_t *q, ql_srb_t *);
static uint16_t ql_wait_outstanding(ql_adapter_state_t *);
static void ql_iidma(ql_adapter_state_t *);
static void ql_abort_device_queues(ql_adapter_state_t *ha, ql_tgt_t *tq);
static void ql_loop_resync(ql_adapter_state_t *);
static ql_adapter_state_t *ql_fca_handle_to_state(opaque_t);
static int ql_kstat_update(kstat_t *, int);
static int ql_program_flash_address(ql_adapter_state_t *, uint32_t, uint8_t);
static size_t ql_24xx_ascii_fw_dump(ql_adapter_state_t *, caddr_t);
static size_t ql_25xx_ascii_fw_dump(ql_adapter_state_t *, caddr_t);
static size_t ql_81xx_ascii_fw_dump(ql_adapter_state_t *, caddr_t);
static size_t ql_8021_ascii_fw_dump(ql_adapter_state_t *, caddr_t);
static int ql_2200_binary_fw_dump(ql_adapter_state_t *, ql_fw_dump_t *);
static int ql_2300_binary_fw_dump(ql_adapter_state_t *, ql_fw_dump_t *);
static int ql_24xx_binary_fw_dump(ql_adapter_state_t *, ql_24xx_fw_dump_t *);
static int ql_25xx_binary_fw_dump(ql_adapter_state_t *, ql_25xx_fw_dump_t *);
static int ql_81xx_binary_fw_dump(ql_adapter_state_t *, ql_81xx_fw_dump_t *);
static int ql_read_risc_ram(ql_adapter_state_t *, uint32_t, uint32_t,
void *);
static void *ql_read_regs(ql_adapter_state_t *, void *, void *, uint32_t,
uint8_t);
static int ql_save_config_regs(dev_info_t *);
static int ql_restore_config_regs(dev_info_t *);
static void ql_halt(ql_adapter_state_t *, int);
static int ql_bind_dma_buffer(ql_adapter_state_t *, dma_mem_t *, int);
static void ql_unbind_dma_buffer(ql_adapter_state_t *, dma_mem_t *);
static int ql_suspend_adapter(ql_adapter_state_t *);
static int ql_bstr_to_dec(char *, uint32_t *, uint32_t);
static int ql_setup_interrupts(ql_adapter_state_t *);
static int ql_setup_msi(ql_adapter_state_t *);
static int ql_setup_msix(ql_adapter_state_t *);
static int ql_setup_fixed(ql_adapter_state_t *);
static void ql_release_intr(ql_adapter_state_t *);
static int ql_legacy_intr(ql_adapter_state_t *);
static int ql_init_mutex(ql_adapter_state_t *);
static void ql_destroy_mutex(ql_adapter_state_t *);
static void ql_fca_isp_els_request(ql_adapter_state_t *, ql_request_q_t *,
fc_packet_t *, els_descriptor_t *);
static void ql_isp_els_request_ctor(els_descriptor_t *,
els_passthru_entry_t *);
static int ql_n_port_plogi(ql_adapter_state_t *);
static int ql_create_queues(ql_adapter_state_t *);
static int ql_create_rsp_queue(ql_adapter_state_t *, uint16_t);
static void ql_delete_queues(ql_adapter_state_t *);
static int ql_multi_queue_support(ql_adapter_state_t *);
static int ql_map_mem_bar(ql_adapter_state_t *, ddi_acc_handle_t *, caddr_t *,
uint32_t, uint32_t);
static void ql_completion_thread(void *);
static void ql_process_comp_queue(void *);
static int ql_abort_io(ql_adapter_state_t *vha, ql_srb_t *);
static void ql_idc(ql_adapter_state_t *);
static int ql_83xx_binary_fw_dump(ql_adapter_state_t *, ql_83xx_fw_dump_t *);
static size_t ql_83xx_ascii_fw_dump(ql_adapter_state_t *, caddr_t);
static caddr_t ql_str_ptr(ql_adapter_state_t *, caddr_t, uint32_t *);
static int ql_27xx_binary_fw_dump(ql_adapter_state_t *);
static size_t ql_27xx_ascii_fw_dump(ql_adapter_state_t *, caddr_t);
static uint32_t ql_2700_dmp_parse_template(ql_adapter_state_t *, ql_dt_hdr_t *,
uint8_t *, uint32_t);
static int ql_2700_dt_riob1(ql_adapter_state_t *, ql_dt_riob1_t *, uint8_t *,
uint8_t *);
static void ql_2700_dt_wiob1(ql_adapter_state_t *, ql_dt_wiob1_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_riob2(ql_adapter_state_t *, ql_dt_riob2_t *, uint8_t *,
uint8_t *);
static void ql_2700_dt_wiob2(ql_adapter_state_t *, ql_dt_wiob2_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_rpci(ql_adapter_state_t *, ql_dt_rpci_t *, uint8_t *,
uint8_t *);
static void ql_2700_dt_wpci(ql_adapter_state_t *, ql_dt_wpci_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_rram(ql_adapter_state_t *, ql_dt_rram_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_gque(ql_adapter_state_t *, ql_dt_gque_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_gfce(ql_adapter_state_t *, ql_dt_gfce_t *, uint8_t *,
uint8_t *);
static void ql_2700_dt_prisc(ql_adapter_state_t *, ql_dt_prisc_t *, uint8_t *,
uint8_t *);
static void ql_2700_dt_rrisc(ql_adapter_state_t *, ql_dt_rrisc_t *, uint8_t *,
uint8_t *);
static void ql_2700_dt_dint(ql_adapter_state_t *, ql_dt_dint_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_ghbd(ql_adapter_state_t *, ql_dt_ghbd_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_scra(ql_adapter_state_t *, ql_dt_scra_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_rrreg(ql_adapter_state_t *, ql_dt_rrreg_t *, uint8_t *,
uint8_t *);
static void ql_2700_dt_wrreg(ql_adapter_state_t *, ql_dt_wrreg_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_rrram(ql_adapter_state_t *, ql_dt_rrram_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_rpcic(ql_adapter_state_t *, ql_dt_rpcic_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_gques(ql_adapter_state_t *, ql_dt_gques_t *, uint8_t *,
uint8_t *);
static int ql_2700_dt_wdmp(ql_adapter_state_t *, ql_dt_wdmp_t *, uint8_t *,
uint8_t *);
static int ql_2700_dump_ram(ql_adapter_state_t *, uint16_t, uint32_t, uint32_t,
uint8_t *);
static uint8_t ql_enable_pm = 1;
static int ql_flash_sbus_fpga = 0;
uint32_t ql_os_release_level;
uint32_t ql_disable_aif = 0;
uint32_t ql_disable_intx = 0;
uint32_t ql_disable_msi = 0;
uint32_t ql_disable_msix = 0;
uint32_t ql_enable_ets = 0;
uint16_t ql_osc_wait_count = 1000;
uint32_t ql_task_cb_dly = 64;
uint32_t qlc_disable_load = 0;
static timeout_id_t ql_timer_timeout_id = NULL;
static clock_t ql_timer_ticks;
void *ql_state = NULL;
ql_head_t ql_hba = {
NULL,
NULL
};
uint32_t ql_gfru_hba_index = 1;
uint32_t ql_ip_buffer_count = 128;
uint32_t ql_ip_low_water = 10;
uint8_t ql_ip_fast_post_count = 5;
static int ql_ip_mtu = 65280;
uint8_t ql_alpa_to_index[] = {
0x7e, 0x7d, 0x7c, 0x00, 0x7b, 0x01, 0x02, 0x03, 0x7a, 0x04,
0x05, 0x06, 0x07, 0x08, 0x09, 0x79, 0x78, 0x0a, 0x0b, 0x0c,
0x0d, 0x0e, 0x0f, 0x77, 0x76, 0x10, 0x11, 0x75, 0x12, 0x74,
0x73, 0x72, 0x13, 0x14, 0x15, 0x71, 0x16, 0x70, 0x6f, 0x6e,
0x17, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x18, 0x19, 0x67,
0x66, 0x65, 0x64, 0x63, 0x62, 0x20, 0x21, 0x61, 0x60, 0x23,
0x5f, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x5e, 0x2a, 0x5d,
0x5c, 0x5b, 0x2b, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0x2c,
0x2d, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x2e, 0x2f, 0x4e,
0x4d, 0x30, 0x4c, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x4b,
0x37, 0x4a, 0x49, 0x48, 0x38, 0x47, 0x46, 0x45, 0x44, 0x43,
0x42, 0x39, 0x3a, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0x3b,
0x3c, 0x3b, 0x3a, 0x3d, 0x39, 0x3e, 0x3f, 0x40, 0x38, 0x37,
0x36, 0x41, 0x35, 0x42, 0x43, 0x44, 0x34, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x33, 0x32, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x31, 0x30, 0x51, 0x52, 0x2f, 0x53, 0x2e, 0x2d, 0x2c,
0x54, 0x55, 0x56, 0x2b, 0x57, 0x2a, 0x29, 0x28, 0x58, 0x27,
0x26, 0x25, 0x24, 0x23, 0x22, 0x59, 0x5a, 0x21, 0x20, 0x1f,
0x1e, 0x1d, 0x1c, 0x5b, 0x5c, 0x1b, 0x1a, 0x5d, 0x19, 0x5e,
0x5f, 0x60, 0x61, 0x62, 0x63, 0x18, 0x64, 0x17, 0x16, 0x15,
0x65, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0x66, 0x67, 0x0e,
0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x68, 0x69, 0x08, 0x07, 0x6a,
0x06, 0x6b, 0x6c, 0x6d, 0x05, 0x04, 0x03, 0x6e, 0x02, 0x6f,
0x70, 0x71, 0x01, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x00,
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7f, 0x80, 0x00, 0x01,
0x02, 0x03, 0x80, 0x7f, 0x7e, 0x04
};
static uint8_t ql_index_to_alpa[] = {
0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6,
0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce, 0xcd, 0xcc, 0xcb, 0xca,
0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5,
0xb4, 0xb3, 0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9,
0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b, 0x98, 0x97,
0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79,
0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b,
0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a,
0x49, 0x47, 0x46, 0x45, 0x43, 0x3c, 0x3a, 0x39, 0x36, 0x35,
0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29,
0x27, 0x26, 0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17,
0x10, 0x0f, 0x08, 0x04, 0x02, 0x01
};
static reg_off_t reg_off_2200 = {
0x00,
0x02,
0x06,
0x08,
0x0a,
0x0c,
0x0e,
0x18,
0x18,
0x1a,
0x1a,
0xff,
24,
0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e,
0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee,
0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x96,
0xa4,
0xb0,
0xb8,
0xc0,
0xcc,
0xce,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff
};
static reg_off_t reg_off_2300 = {
0x00,
0x02,
0x06,
0x08,
0x0a,
0x0c,
0x0e,
0x10,
0x12,
0x14,
0x16,
0x18,
32,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e,
0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e,
0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e,
0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e,
0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e,
0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e,
0x96,
0xa4,
0xb0,
0x80,
0xc0,
0xcc,
0xce,
0x1c,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff
};
reg_off_t reg_off_2400_2500 = {
0x00,
0x04,
0x08,
0x0c,
0x10,
0xff,
0xff,
0x1c,
0x20,
0x24,
0x28,
0x44,
32,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae,
0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae,
0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0xff,
0xff,
0xff,
0xff,
0x48,
0x4c,
0x50,
0xff,
0x2c,
0x30,
0x3c,
0x40,
0x54,
0xff,
0xff
};
static reg_off_t reg_off_8021 = {
0x00,
0x04,
0x08,
0x0c,
0x10,
0xff,
0xff,
0xff,
0x0,
0x100,
0x200,
0x500,
32,
0x300, 0x302, 0x304, 0x306, 0x308, 0x30a, 0x30c, 0x30e,
0x310, 0x312, 0x314, 0x316, 0x318, 0x31a, 0x31c, 0x31e,
0x320, 0x322, 0x324, 0x326, 0x328, 0x32a, 0x32c, 0x32e,
0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e,
0x400, 0x402, 0x404, 0x406, 0x408, 0x40a, 0x40c, 0x40e,
0x410, 0x412, 0x414, 0x416, 0x418, 0x41a, 0x41c, 0x41e,
0x420, 0x422, 0x424, 0x426, 0x428, 0x42a, 0x42c, 0x42e,
0x430, 0x432, 0x434, 0x436, 0x438, 0x43a, 0x43c, 0x43e,
0xff,
0xff,
0xff,
0xff,
0x48,
0x4c,
0x50,
0xff,
0x2c,
0x30,
0x3c,
0x40,
0x54,
0x380,
0x504
};
static reg_off_t reg_off_2700_8300 = {
0x00,
0x04,
0x08,
0x0c,
0x10,
0xff,
0xff,
0xff,
0xff,
0xff,
0xff,
0x44,
32,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae,
0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e,
0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e,
0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae,
0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe,
0xff,
0xff,
0xff,
0xff,
0x48,
0x4c,
0x50,
0x58,
0xff,
0xff,
0xff,
0xff,
0x54,
0xff,
0xff
};
kmutex_t ql_global_mutex;
kmutex_t ql_global_hw_mutex;
kmutex_t ql_global_el_mutex;
kmutex_t ql_global_timer_mutex;
ddi_device_acc_attr_t ql_dev_acc_attr = {
DDI_DEVICE_ATTR_V0,
DDI_STRUCTURE_LE_ACC,
DDI_STRICTORDER_ACC
};
ddi_dma_attr_t ql_64bit_io_dma_attr = {
DMA_ATTR_V0,
QL_DMA_LOW_ADDRESS,
QL_DMA_HIGH_64BIT_ADDRESS,
QL_DMA_XFER_COUNTER,
QL_DMA_ADDRESS_ALIGNMENT,
QL_DMA_BURSTSIZES,
QL_DMA_MIN_XFER_SIZE,
QL_DMA_MAX_XFER_SIZE,
QL_DMA_SEGMENT_BOUNDARY,
QL_DMA_SG_LIST_LENGTH,
QL_DMA_GRANULARITY,
QL_DMA_XFER_FLAGS
};
ddi_dma_attr_t ql_32bit_io_dma_attr = {
DMA_ATTR_V0,
QL_DMA_LOW_ADDRESS,
QL_DMA_HIGH_32BIT_ADDRESS,
QL_DMA_XFER_COUNTER,
QL_DMA_ADDRESS_ALIGNMENT,
QL_DMA_BURSTSIZES,
QL_DMA_MIN_XFER_SIZE,
QL_DMA_MAX_XFER_SIZE,
QL_DMA_SEGMENT_BOUNDARY,
QL_DMA_SG_LIST_LENGTH,
QL_DMA_GRANULARITY,
QL_DMA_XFER_FLAGS
};
static struct cb_ops ql_cb_ops = {
ql_open,
ql_close,
nodev,
nodev,
nodev,
nodev,
nodev,
ql_ioctl,
nodev,
nodev,
nodev,
nochpoll,
nodev,
NULL,
D_MP | D_NEW | D_HOTPLUG,
CB_REV,
nodev,
nodev
};
static struct dev_ops ql_devops = {
DEVO_REV,
0,
ql_getinfo,
nulldev,
nulldev,
ql_attach,
ql_detach,
nodev,
&ql_cb_ops,
NULL,
ql_power,
ql_quiesce
};
cmd_table_t els_cmd_tbl[] = ELS_CMD_TABLE();
cmd_table_t mbox_cmd_tbl[] = MBOX_CMD_TABLE();
char ql_driver_version[] = QL_VERSION;
uint32_t ql_log_entries = QL_LOG_ENTRIES;
static struct modldrv modldrv = {
&mod_driverops,
"SunFC Qlogic FCA v" QL_VERSION,
&ql_devops
};
static struct modlinkage modlinkage = {
MODREV_1,
&modldrv,
NULL
};
int
_init(void)
{
uint16_t w16;
int rval = 0;
if (qlc_disable_load) {
cmn_err(CE_WARN, "%s load disabled", QL_NAME);
return (EINVAL);
}
for (w16 = 0; w16 < sizeof (utsname.release); w16++) {
if (utsname.release[w16] == '.') {
w16++;
break;
}
}
if (w16 < sizeof (utsname.release)) {
(void) ql_bstr_to_dec(&utsname.release[w16],
&ql_os_release_level, 0);
} else {
ql_os_release_level = 0;
}
if (ql_os_release_level < 6) {
cmn_err(CE_WARN, "%s Unsupported OS release level = %d",
QL_NAME, ql_os_release_level);
rval = EINVAL;
}
if (ql_os_release_level == 6) {
ql_32bit_io_dma_attr.dma_attr_count_max = 0x00ffffff;
ql_64bit_io_dma_attr.dma_attr_count_max = 0x00ffffff;
}
if (rval == 0) {
rval = ddi_soft_state_init(&ql_state,
sizeof (ql_adapter_state_t), 0);
}
if (rval == 0) {
fc_fca_init(&ql_devops);
mutex_init(&ql_global_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&ql_global_hw_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&ql_global_el_mutex, NULL, MUTEX_DRIVER, NULL);
mutex_init(&ql_global_timer_mutex, NULL, MUTEX_DRIVER, NULL);
rval = mod_install(&modlinkage);
if (rval != 0) {
mutex_destroy(&ql_global_timer_mutex);
mutex_destroy(&ql_global_el_mutex);
mutex_destroy(&ql_global_hw_mutex);
mutex_destroy(&ql_global_mutex);
ddi_soft_state_fini(&ql_state);
}
}
if (rval != 0) {
cmn_err(CE_CONT, "?Unable to install/attach driver '%s'",
QL_NAME);
}
return (rval);
}
int
_fini(void)
{
int rval;
rval = mod_remove(&modlinkage);
if (rval == 0) {
mutex_destroy(&ql_global_timer_mutex);
mutex_destroy(&ql_global_el_mutex);
mutex_destroy(&ql_global_hw_mutex);
mutex_destroy(&ql_global_mutex);
ddi_soft_state_fini(&ql_state);
}
return (rval);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static int
ql_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
{
ql_adapter_state_t *ha;
int minor;
int rval = DDI_FAILURE;
minor = (int)(getminor((dev_t)arg));
ha = ddi_get_soft_state(ql_state, minor);
if (ha == NULL) {
QL_PRINT_2(ha, "failed, unknown minor=%d\n",
getminor((dev_t)arg));
*resultp = NULL;
return (rval);
}
QL_PRINT_3(ha, "started\n");
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
*resultp = ha->dip;
rval = DDI_SUCCESS;
break;
case DDI_INFO_DEVT2INSTANCE:
*resultp = (void *)(uintptr_t)(ha->instance);
rval = DDI_SUCCESS;
break;
default:
EL(ha, "failed, unsupported cmd=%d\n", cmd);
rval = DDI_FAILURE;
break;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
off_t regsize;
uint32_t size;
int rval, *ptr;
uint_t progress = 0;
char *buf, taskq_name[32];
ushort_t caps_ptr, cap;
fc_fca_tran_t *tran;
ql_adapter_state_t *ha = NULL;
int instance = ddi_get_instance(dip);
static char *pmcomps[] = {
NULL,
PM_LEVEL_D3_STR,
PM_LEVEL_D0_STR,
};
QL_PRINT_3(NULL, "started, instance=%d, cmd=%xh\n",
ddi_get_instance(dip), cmd);
buf = (char *)(kmem_zalloc(MAXPATHLEN, KM_SLEEP));
switch (cmd) {
case DDI_ATTACH:
cmn_err(CE_CONT, "!Qlogic %s(%d) FCA Driver v%s\n",
QL_NAME, instance, QL_VERSION);
if (ql_os_release_level != 11) {
cmn_err(CE_WARN, "%s(%d): This driver is for Solaris "
"11", QL_NAME, instance);
goto attach_failed;
}
if (ddi_slaveonly(dip) == DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): slave only", QL_NAME,
instance);
goto attach_failed;
}
if (ddi_soft_state_zalloc(ql_state,
instance) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): soft state alloc failed",
QL_NAME, instance);
goto attach_failed;
}
ha = ddi_get_soft_state(ql_state, instance);
if (ha == NULL) {
cmn_err(CE_WARN, "%s(%d): can't get soft state",
QL_NAME, instance);
goto attach_failed;
}
ha->dip = dip;
ha->instance = instance;
ha->hba.base_address = ha;
ha->pha = ha;
ha->bit32_io_dma_attr = ql_32bit_io_dma_attr;
ha->bit64_io_dma_attr = ql_64bit_io_dma_attr;
(void) ql_el_trace_alloc(ha);
progress |= QL_SOFT_STATE_ALLOCED;
ql_common_properties(ha);
qlc_fm_init(ha);
progress |= QL_FCA_INIT_FM;
ha->io_dma_attr = ha->bit32_io_dma_attr;
if (strcmp(ddi_driver_name(ddi_get_parent(dip)),
"sbus") == 0) {
EL(ha, "%s SBUS card detected\n", QL_NAME);
ha->cfg_flags |= CFG_SBUS_CARD;
}
ha->dev = kmem_zalloc(sizeof (*ha->dev) *
DEVICE_HEAD_LIST_SIZE, KM_SLEEP);
ha->ub_array = kmem_zalloc(sizeof (*ha->ub_array) *
QL_UB_LIMIT, KM_SLEEP);
ha->adapter_stats = kmem_zalloc(sizeof (*ha->adapter_stats),
KM_SLEEP);
(void) ddi_pathname(dip, buf);
ha->devpath = kmem_zalloc(strlen(buf) + 1, KM_SLEEP);
if (ha->devpath == NULL) {
EL(ha, "devpath mem alloc failed\n");
} else {
(void) strcpy(ha->devpath, buf);
EL(ha, "devpath is: %s\n", ha->devpath);
}
if (CFG_IST(ha, CFG_SBUS_CARD)) {
if (ddi_regs_map_setup(dip, 0, (caddr_t *)&ha->iobase,
0x100, 0x300, &ql_dev_acc_attr, &ha->dev_handle) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): Unable to map device"
" registers", QL_NAME, instance);
goto attach_failed;
}
if (ddi_regs_map_setup(dip, 1,
(caddr_t *)&ha->sbus_fpga_iobase, 0, 0x400,
&ql_dev_acc_attr, &ha->sbus_fpga_dev_handle) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): Unable to map FPGA",
QL_NAME, instance);
ha->sbus_fpga_iobase = NULL;
}
progress |= QL_REGS_MAPPED;
if (ddi_regs_map_setup(dip, 0,
(caddr_t *)&ha->sbus_config_base, 0, 0x100,
&ql_dev_acc_attr, &ha->sbus_config_handle) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): Unable to map sbus "
"config registers", QL_NAME, instance);
goto attach_failed;
}
progress |= QL_CONFIG_SPACE_SETUP;
} else {
rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS, "reg", &ptr, &size);
if (rval != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): Unable to get PCI "
"address registers", QL_NAME, instance);
goto attach_failed;
} else {
ha->pci_bus_addr = ptr[0];
ha->pci_function_number = (uint8_t)
(ha->pci_bus_addr >> 8 & 7);
ddi_prop_free(ptr);
}
if (pci_config_setup(ha->dip, &ha->pci_handle) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): can't setup PCI "
"config space", QL_NAME, instance);
goto attach_failed;
}
progress |= QL_CONFIG_SPACE_SETUP;
size = ql_pci_config_get32(ha, PCI_CONF_BASE0) & BIT_0 ?
2 : 1;
if (qlc_fm_check_acc_handle(ha, ha->pci_handle)
!= DDI_FM_OK) {
qlc_fm_report_err_impact(ha,
QL_FM_EREPORT_ACC_HANDLE_CHECK);
goto attach_failed;
}
if (ddi_dev_regsize(dip, size, ®size) !=
DDI_SUCCESS ||
ddi_regs_map_setup(dip, size, &ha->iobase,
0, regsize, &ql_dev_acc_attr, &ha->dev_handle) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): regs_map_setup(mem) "
"failed", QL_NAME, instance);
goto attach_failed;
}
progress |= QL_REGS_MAPPED;
if (qlc_fm_check_acc_handle(ha, ha->dev_handle)
!= DDI_FM_OK) {
qlc_fm_report_err_impact(ha,
QL_FM_EREPORT_ACC_HANDLE_CHECK);
goto attach_failed;
}
if (size == 1) {
ha->iomap_iobase = ha->iobase;
ha->iomap_dev_handle = ha->dev_handle;
} else {
if (ddi_dev_regsize(dip, 1, ®size) !=
DDI_SUCCESS ||
ddi_regs_map_setup(dip, 1,
&ha->iomap_iobase, 0, regsize,
&ql_dev_acc_attr, &ha->iomap_dev_handle) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): regs_map_"
"setup(I/O) failed", QL_NAME,
instance);
goto attach_failed;
}
progress |= QL_IOMAP_IOBASE_MAPPED;
if (qlc_fm_check_acc_handle(ha,
ha->iomap_dev_handle) != DDI_FM_OK) {
qlc_fm_report_err_impact(ha,
QL_FM_EREPORT_ACC_HANDLE_CHECK);
goto attach_failed;
}
}
}
ha->subsys_id = (uint16_t)ql_pci_config_get16(ha,
PCI_CONF_SUBSYSID);
ha->subven_id = (uint16_t)ql_pci_config_get16(ha,
PCI_CONF_SUBVENID);
ha->ven_id = (uint16_t)ql_pci_config_get16(ha,
PCI_CONF_VENID);
ha->device_id = (uint16_t)ql_pci_config_get16(ha,
PCI_CONF_DEVID);
ha->rev_id = (uint8_t)ql_pci_config_get8(ha,
PCI_CONF_REVID);
EL(ha, "ISP%x chip detected (RevID=%x, VenID=%x, SVenID=%x, "
"SSysID=%x)\n", ha->device_id, ha->rev_id, ha->ven_id,
ha->subven_id, ha->subsys_id);
switch (ha->device_id) {
case 0x2300:
case 0x2312:
case 0x2322:
case 0x6312:
case 0x6322:
if (ql_pci_config_get8(ha, PCI_CONF_IPIN) == 2) {
ha->function_number = 1;
}
if (ha->device_id == 0x2322 ||
ha->device_id == 0x6322) {
ha->cfg_flags |= CFG_CTRL_63XX;
ha->fw_class = 0x6322;
ha->risc_dump_size = QL_6322_FW_DUMP_SIZE;
} else {
ha->cfg_flags |= CFG_CTRL_23XX;
ha->fw_class = 0x2300;
ha->risc_dump_size = QL_2300_FW_DUMP_SIZE;
}
ha->reg_off = ®_off_2300;
ha->interrupt_count = 1;
ha->osc_max_cnt = 1024;
if (ql_fwmodule_resolve(ha) != QL_SUCCESS) {
goto attach_failed;
}
ha->fcp_cmd = ql_command_iocb;
ha->ip_cmd = ql_ip_iocb;
ha->ms_cmd = ql_ms_iocb;
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ha->cmd_segs = CMD_TYPE_2_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_0_DATA_SEGMENTS;
} else {
ha->cmd_segs = CMD_TYPE_3_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
}
break;
case 0x2200:
ha->cfg_flags |= CFG_CTRL_22XX;
ha->reg_off = ®_off_2200;
ha->interrupt_count = 1;
ha->osc_max_cnt = 1024;
ha->fw_class = 0x2200;
if (ql_fwmodule_resolve(ha) != QL_SUCCESS) {
goto attach_failed;
}
ha->risc_dump_size = QL_2200_FW_DUMP_SIZE;
ha->fcp_cmd = ql_command_iocb;
ha->ip_cmd = ql_ip_iocb;
ha->ms_cmd = ql_ms_iocb;
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ha->cmd_segs = CMD_TYPE_2_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_0_DATA_SEGMENTS;
} else {
ha->cmd_segs = CMD_TYPE_3_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
}
break;
case 0x2422:
case 0x2432:
case 0x5422:
case 0x5432:
case 0x8432:
if (ql_pci_config_get8(ha, PCI_CONF_IPIN) == 2) {
ha->function_number = 1;
}
ha->cfg_flags |= CFG_CTRL_24XX;
if (ha->device_id == 0x8432) {
ha->cfg_flags |= CFG_CTRL_MENLO;
} else {
ha->flags |= VP_ENABLED;
ha->max_vports = MAX_24_VIRTUAL_PORTS;
}
ha->reg_off = ®_off_2400_2500;
ha->interrupt_count = 2;
ha->osc_max_cnt = 2048;
ha->fw_class = 0x2400;
if (ql_fwmodule_resolve(ha) != QL_SUCCESS) {
goto attach_failed;
}
ha->risc_dump_size = QL_24XX_FW_DUMP_SIZE;
ha->fcp_cmd = ql_command_24xx_iocb;
ha->ip_cmd = ql_ip_24xx_iocb;
ha->ms_cmd = ql_ms_24xx_iocb;
ha->els_cmd = ql_els_24xx_iocb;
ha->cmd_segs = CMD_TYPE_7_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
break;
case 0x2522:
case 0x2532:
if (ql_pci_config_get8(ha, PCI_CONF_IPIN) == 2) {
ha->function_number = 1;
}
ha->cfg_flags |= CFG_CTRL_25XX;
ha->flags |= VP_ENABLED;
ha->max_vports = MAX_25_VIRTUAL_PORTS;
ha->reg_off = ®_off_2400_2500;
ha->mbar_queue_offset = MBAR2_REG_OFFSET;
ha->interrupt_count = 2;
ha->osc_max_cnt = 2048;
ha->fw_class = 0x2500;
if (ql_fwmodule_resolve(ha) != QL_SUCCESS) {
goto attach_failed;
}
ha->risc_dump_size = QL_25XX_FW_DUMP_SIZE;
ha->fcp_cmd = ql_command_24xx_iocb;
ha->ms_cmd = ql_ms_24xx_iocb;
ha->els_cmd = ql_els_24xx_iocb;
ha->cmd_segs = CMD_TYPE_7_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
if (ql_multi_queue_support(ha) == QL_SUCCESS) {
ha->flags |= MULTI_QUEUE;
}
break;
case 0x2031:
if (ddi_dev_regsize(dip, 3, ®size) != DDI_SUCCESS ||
ddi_regs_map_setup(dip, 3, &ha->mbar,
0, regsize, &ql_dev_acc_attr,
&ha->mbar_dev_handle) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): regs_map_setup"
"(mbar) failed", QL_NAME, instance);
goto attach_failed;
}
ha->mbar_size = (uint32_t)regsize;
if (ha->pci_function_number != 0 &&
ha->pci_function_number != 2) {
ha->function_number = 1;
}
ha->cfg_flags |= CFG_CTRL_83XX;
ha->flags |= VP_ENABLED | MULTI_QUEUE;
ha->max_vports = MAX_83_VIRTUAL_PORTS;
ha->reg_off = ®_off_2700_8300;
ha->mbar_queue_offset = MBAR2_REG_OFFSET;
ha->interrupt_count = 2;
ha->osc_max_cnt = 2048;
ha->fw_class = 0x8301fc;
if (ql_fwmodule_resolve(ha) != QL_SUCCESS) {
goto attach_failed;
}
ha->risc_dump_size = QL_83XX_FW_DUMP_SIZE;
ha->fcp_cmd = ql_command_24xx_iocb;
ha->ms_cmd = ql_ms_24xx_iocb;
ha->els_cmd = ql_els_24xx_iocb;
ha->cmd_segs = CMD_TYPE_7_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
break;
case 0x2071:
case 0x2261:
case 0x2271:
if (ddi_dev_regsize(dip, 3, ®size) != DDI_SUCCESS ||
ddi_regs_map_setup(dip, 3, &ha->mbar,
0, regsize, &ql_dev_acc_attr,
&ha->mbar_dev_handle) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): regs_map_setup"
"(mbar) failed", QL_NAME, instance);
goto attach_failed;
}
ha->mbar_size = (uint32_t)regsize;
ha->function_number = ha->pci_function_number;
ha->cfg_flags |= CFG_CTRL_27XX;
ha->flags |= VP_ENABLED | MULTI_QUEUE |
QUEUE_SHADOW_PTRS;
ha->max_vports = MAX_27_VIRTUAL_PORTS;
ha->reg_off = ®_off_2700_8300;
ha->mbar_queue_offset = MBAR2_REG_OFFSET;
ha->interrupt_count = 2;
ha->osc_max_cnt = 2048;
ha->fw_class = 0x2700;
if (ql_fwmodule_resolve(ha) != QL_SUCCESS) {
goto attach_failed;
}
ha->risc_dump_size = QL_27XX_FW_DUMP_SIZE;
ha->fcp_cmd = ql_command_24xx_iocb;
ha->ms_cmd = ql_ms_24xx_iocb;
ha->els_cmd = ql_els_24xx_iocb;
ha->cmd_segs = CMD_TYPE_7_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
break;
case 0x8001:
if (ql_pci_config_get8(ha, PCI_CONF_IPIN) == 4) {
ha->function_number = 1;
}
ha->cfg_flags |= CFG_CTRL_81XX;
ha->flags |= VP_ENABLED;
ha->max_vports = MAX_81XX_VIRTUAL_PORTS;
ha->reg_off = ®_off_2400_2500;
ha->mbar_queue_offset = MBAR2_REG_OFFSET;
ha->interrupt_count = 2;
ha->osc_max_cnt = 2048;
ha->fw_class = 0x8100;
if (ql_fwmodule_resolve(ha) != QL_SUCCESS) {
goto attach_failed;
}
ha->risc_dump_size = QL_81XX_FW_DUMP_SIZE;
ha->fcp_cmd = ql_command_24xx_iocb;
ha->ms_cmd = ql_ms_24xx_iocb;
ha->cmd_segs = CMD_TYPE_7_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
if (ql_multi_queue_support(ha) == QL_SUCCESS) {
ha->flags |= MULTI_QUEUE;
}
break;
case 0x8021:
if (ha->pci_function_number & BIT_0) {
ha->function_number = 1;
}
ha->cfg_flags |= CFG_CTRL_82XX;
ha->flags |= VP_ENABLED;
ha->max_vports = MAX_8021_VIRTUAL_PORTS;
ha->reg_off = ®_off_8021;
ha->interrupt_count = 2;
ha->osc_max_cnt = 2048;
ha->risc_dump_size = QL_25XX_FW_DUMP_SIZE;
ha->fcp_cmd = ql_command_24xx_iocb;
ha->ms_cmd = ql_ms_24xx_iocb;
ha->cmd_segs = CMD_TYPE_7_DATA_SEGMENTS;
ha->cmd_cont_segs = CONT_TYPE_1_DATA_SEGMENTS;
ha->io_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->nx_pcibase = ha->iobase;
ha->iobase += 0xBC000 + (ha->pci_function_number << 11);
ha->iomap_iobase += 0xBC000 +
(ha->pci_function_number << 11);
if (ddi_dev_regsize(dip, 2, ®size) != DDI_SUCCESS ||
ddi_regs_map_setup(dip, 2, &ha->db_iobase,
0, regsize, &ql_dev_acc_attr,
&ha->db_dev_handle) !=
DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): regs_map_setup"
"(doorbell) failed", QL_NAME, instance);
goto attach_failed;
}
progress |= QL_DB_IOBASE_MAPPED;
if (qlc_fm_check_acc_handle(ha, ha->db_dev_handle)
!= DDI_FM_OK) {
qlc_fm_report_err_impact(ha,
QL_FM_EREPORT_ACC_HANDLE_CHECK);
goto attach_failed;
}
ha->nx_req_in = (uint32_t *)(ha->db_iobase +
(ha->pci_function_number << 12));
ha->db_read = ha->nx_pcibase + (512 * 1024) +
(ha->pci_function_number * 8);
ql_8021_update_crb_int_ptr(ha);
ql_8021_set_drv_active(ha);
break;
default:
cmn_err(CE_WARN, "%s(%d): Unsupported device id: %x",
QL_NAME, instance, ha->device_id);
goto attach_failed;
}
ha->outstanding_cmds = kmem_zalloc(
sizeof (*ha->outstanding_cmds) * ha->osc_max_cnt,
KM_SLEEP);
if ((rval = ql_setup_interrupts(ha)) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): Failed to add interrupt, "
"rval=%xh", QL_NAME, instance, rval);
goto attach_failed;
}
progress |= (QL_INTR_ADDED | QL_MUTEX_CV_INITED);
if (ql_create_queues(ha) != QL_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): request queue DMA memory "
"alloc failed", QL_NAME, instance);
goto attach_failed;
}
progress |= QL_HBA_BUFFER_SETUP;
(void) ql_alloc_xioctl_resource(ha);
if (ql_nvram_cache_desc_ctor(ha) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): can't setup nvram cache",
QL_NAME, instance);
goto attach_failed;
}
progress |= QL_NVRAM_CACHE_CREATED;
if (ql_plogi_params_desc_ctor(ha) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): can't setup plogi params",
QL_NAME, instance);
goto attach_failed;
}
progress |= QL_PLOGI_PARAMS_CREATED;
ha->n_port = (ql_n_port_info_t *)
kmem_zalloc(sizeof (ql_n_port_info_t), KM_SLEEP);
if (ha->n_port == NULL) {
cmn_err(CE_WARN, "%s(%d): Failed to create N Port info",
QL_NAME, instance);
goto attach_failed;
}
progress |= QL_N_PORT_INFO_CREATED;
caps_ptr = (uint8_t)ql_pci_config_get8(ha, PCI_CONF_CAP_PTR);
while (caps_ptr != PCI_CAP_NEXT_PTR_NULL) {
cap = (uint8_t)ql_pci_config_get8(ha, caps_ptr);
if (cap == PCI_CAP_ID_PM) {
ha->pm_capable = 1;
break;
}
caps_ptr = (uint8_t)ql_pci_config_get8(ha, caps_ptr +
PCI_CAP_NEXT_PTR);
}
if (ha->pm_capable) {
if (ha->device_id != 0x2200) {
ha->pm_capable = 0;
}
}
if (ha->pm_capable) {
ha->pm_capable = ql_enable_pm;
}
if (ha->pm_capable) {
(void) sprintf(buf, "NAME=%s(%d)", QL_NAME, instance);
pmcomps[0] = buf;
if (ddi_prop_update_string_array(DDI_DEV_T_NONE,
dip, "pm-components", pmcomps,
sizeof (pmcomps) / sizeof (pmcomps[0])) !=
DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): failed to create"
" pm-components property", QL_NAME,
instance);
ha->power_level = PM_LEVEL_D0;
if (ql_initialize_adapter(ha) != QL_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): failed to"
" initialize adapter", QL_NAME,
instance);
goto attach_failed;
}
} else {
ha->power_level = PM_LEVEL_D3;
if (pm_raise_power(dip, QL_POWER_COMPONENT,
PM_LEVEL_D0) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): failed to"
" raise power or initialize"
" adapter", QL_NAME, instance);
}
}
} else {
ha->power_level = PM_LEVEL_D0;
if (ql_initialize_adapter(ha) != QL_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): failed to initialize"
" adapter", QL_NAME, instance);
}
}
if (ha->fw_major_version == 0 && ha->fw_minor_version == 0 &&
ha->fw_subminor_version == 0) {
cmn_err(CE_NOTE, "!%s(%d): Firmware not loaded",
QL_NAME, ha->instance);
} else {
int rval, rval1;
char ver_fmt[256];
rval1 = (int)snprintf(ver_fmt, (size_t)sizeof (ver_fmt),
"Firmware version %d.%d.%d", ha->fw_major_version,
ha->fw_minor_version, ha->fw_subminor_version);
if (CFG_IST(ha, CFG_CTRL_81XX)) {
rval = (int)snprintf(ver_fmt + rval1,
(size_t)sizeof (ver_fmt),
", MPI fw version %d.%d.%d",
ha->mpi_fw_major_version,
ha->mpi_fw_minor_version,
ha->mpi_fw_subminor_version);
if (ha->subsys_id == 0x17B ||
ha->subsys_id == 0x17D) {
(void) snprintf(ver_fmt + rval1 + rval,
(size_t)sizeof (ver_fmt),
", PHY fw version %d.%d.%d",
ha->phy_fw_major_version,
ha->phy_fw_minor_version,
ha->phy_fw_subminor_version);
}
}
cmn_err(CE_NOTE, "!%s(%d): %s",
QL_NAME, ha->instance, ver_fmt);
}
ha->k_stats = kstat_create(QL_NAME, instance, "statistics",
"controller", KSTAT_TYPE_RAW,
(uint32_t)sizeof (ql_adapter_stat_t), KSTAT_FLAG_VIRTUAL);
if (ha->k_stats == NULL) {
cmn_err(CE_WARN, "%s(%d): Failed to create kstat",
QL_NAME, instance);
goto attach_failed;
}
progress |= QL_KSTAT_CREATED;
ha->adapter_stats->version = 1;
ha->k_stats->ks_data = (void *)ha->adapter_stats;
ha->k_stats->ks_private = ha;
ha->k_stats->ks_update = ql_kstat_update;
ha->k_stats->ks_ndata = 1;
ha->k_stats->ks_data_size = sizeof (ql_adapter_stat_t);
kstat_install(ha->k_stats);
if (ddi_create_minor_node(dip, "devctl", S_IFCHR,
instance, DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): failed to create minor node",
QL_NAME, instance);
goto attach_failed;
}
progress |= QL_MINOR_NODE_CREATED;
tran = kmem_zalloc(sizeof (fc_fca_tran_t), KM_SLEEP);
if (tran == NULL) {
cmn_err(CE_WARN, "%s(%d): failed to allocate transport",
QL_NAME, instance);
goto attach_failed;
}
progress |= QL_FCA_TRAN_ALLOCED;
tran->fca_numports = 1;
tran->fca_version = FCTL_FCA_MODREV_5;
tran->fca_num_npivports = ha->max_vports ?
ha->max_vports - 1 : 0;
bcopy(ha->loginparams.node_ww_name.raw_wwn,
tran->fca_perm_pwwn.raw_wwn, 8);
if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
ha->io_dma_attr = ha->bit64_io_dma_attr;
ha->fcsm_cmd_dma_attr = ha->bit64_io_dma_attr;
ha->fcsm_rsp_dma_attr = ha->bit64_io_dma_attr;
ha->fcip_cmd_dma_attr = ha->bit64_io_dma_attr;
ha->fcip_rsp_dma_attr = ha->bit64_io_dma_attr;
ha->fcp_cmd_dma_attr = ha->bit64_io_dma_attr;
ha->fcp_rsp_dma_attr = ha->bit64_io_dma_attr;
ha->fcp_data_dma_attr = ha->bit64_io_dma_attr;
} else {
ha->io_dma_attr = ha->bit32_io_dma_attr;
ha->fcsm_cmd_dma_attr = ha->bit32_io_dma_attr;
ha->fcsm_rsp_dma_attr = ha->bit32_io_dma_attr;
ha->fcip_cmd_dma_attr = ha->bit32_io_dma_attr;
ha->fcip_rsp_dma_attr = ha->bit32_io_dma_attr;
ha->fcp_cmd_dma_attr = ha->bit32_io_dma_attr;
ha->fcp_rsp_dma_attr = ha->bit32_io_dma_attr;
ha->fcp_data_dma_attr = ha->bit32_io_dma_attr;
}
ha->fcsm_cmd_dma_attr.dma_attr_sgllen = QL_FCSM_CMD_SGLLEN;
ha->fcsm_rsp_dma_attr.dma_attr_sgllen = QL_FCSM_RSP_SGLLEN;
ha->fcip_cmd_dma_attr.dma_attr_sgllen = QL_FCIP_CMD_SGLLEN;
ha->fcip_rsp_dma_attr.dma_attr_sgllen = QL_FCIP_RSP_SGLLEN;
ha->fcp_cmd_dma_attr.dma_attr_sgllen = QL_FCP_CMD_SGLLEN;
ha->fcp_rsp_dma_attr.dma_attr_sgllen = QL_FCP_RSP_SGLLEN;
if (CFG_IST(ha, CFG_CTRL_82XX)) {
ha->io_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->fcsm_cmd_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->fcsm_rsp_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->fcip_cmd_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->fcip_rsp_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->fcp_cmd_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->fcp_rsp_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
ha->fcp_data_dma_attr.dma_attr_flags |=
DDI_DMA_RELAXED_ORDERING;
}
tran->fca_pkt_size = sizeof (ql_srb_t);
tran->fca_cmd_max = ha->osc_max_cnt;
tran->fca_dma_attr = &ha->io_dma_attr;
tran->fca_dma_fcp_cmd_attr = &ha->fcp_cmd_dma_attr;
tran->fca_dma_fcp_rsp_attr = &ha->fcp_rsp_dma_attr;
tran->fca_dma_fcp_data_attr = &ha->fcp_data_dma_attr;
tran->fca_dma_fcsm_cmd_attr = &ha->fcsm_cmd_dma_attr;
tran->fca_dma_fcsm_rsp_attr = &ha->fcsm_rsp_dma_attr;
tran->fca_dma_fcip_cmd_attr = &ha->fcip_cmd_dma_attr;
tran->fca_dma_fcip_rsp_attr = &ha->fcip_rsp_dma_attr;
tran->fca_acc_attr = &ql_dev_acc_attr;
tran->fca_iblock = &(ha->iblock_cookie);
tran->fca_bind_port = ql_bind_port;
tran->fca_unbind_port = ql_unbind_port;
tran->fca_init_pkt = ql_init_pkt;
tran->fca_un_init_pkt = ql_un_init_pkt;
tran->fca_els_send = ql_els_send;
tran->fca_get_cap = ql_get_cap;
tran->fca_set_cap = ql_set_cap;
tran->fca_getmap = ql_getmap;
tran->fca_transport = ql_transport;
tran->fca_ub_alloc = ql_ub_alloc;
tran->fca_ub_free = ql_ub_free;
tran->fca_ub_release = ql_ub_release;
tran->fca_abort = ql_abort;
tran->fca_reset = ql_reset;
tran->fca_port_manage = ql_port_manage;
tran->fca_get_device = ql_get_device;
EL(ha, "Transport interface setup. FCA version %d\n",
tran->fca_version);
if (fc_fca_attach(dip, tran) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): FCA attach failed", QL_NAME,
instance);
goto attach_failed;
}
progress |= QL_FCA_ATTACH_DONE;
ha->tran = tran;
GLOBAL_STATE_LOCK();
ql_add_link_b(&ql_hba, &ha->hba);
ql_setup_fruinfo(ha);
GLOBAL_STATE_UNLOCK();
GLOBAL_TIMER_LOCK();
if (ql_timer_timeout_id == NULL) {
ql_timer_ticks = drv_usectohz(1000000);
ql_timer_timeout_id = timeout(ql_timer, (void *)0,
ql_timer_ticks);
}
GLOBAL_TIMER_UNLOCK();
(void) snprintf(taskq_name, sizeof (taskq_name),
"qlc_%d_driver_thread", instance);
ha->driver_thread_taskq = ddi_taskq_create(NULL, taskq_name, 1,
TASKQ_DEFAULTPRI, 0);
(void) ddi_taskq_dispatch(ha->driver_thread_taskq,
ql_task_daemon, ha, DDI_SLEEP);
ha->task_daemon_flags |= TASK_DAEMON_ALIVE_FLG;
(void) snprintf(taskq_name, sizeof (taskq_name),
"qlc_%d_comp_thd", instance);
ha->completion_taskq = ddi_taskq_create(0, taskq_name,
ha->completion_thds, maxclsyspri, 0);
for (size = 0; size < ha->completion_thds; size++) {
(void) ddi_taskq_dispatch(ha->completion_taskq,
ql_completion_thread, ha, DDI_SLEEP);
}
progress |= QL_TASK_DAEMON_STARTED;
ddi_report_dev(dip);
ha->lip_on_panic = 1;
rval = DDI_SUCCESS;
break;
attach_failed:
if (progress & QL_FCA_INIT_FM) {
qlc_fm_fini(ha);
progress &= ~QL_FCA_INIT_FM;
}
if (progress & QL_FCA_ATTACH_DONE) {
(void) fc_fca_detach(dip);
progress &= ~QL_FCA_ATTACH_DONE;
}
if (progress & QL_FCA_TRAN_ALLOCED) {
kmem_free(tran, sizeof (fc_fca_tran_t));
progress &= ~QL_FCA_TRAN_ALLOCED;
}
if (progress & QL_MINOR_NODE_CREATED) {
ddi_remove_minor_node(dip, "devctl");
progress &= ~QL_MINOR_NODE_CREATED;
}
if (progress & QL_KSTAT_CREATED) {
kstat_delete(ha->k_stats);
progress &= ~QL_KSTAT_CREATED;
}
if (progress & QL_N_PORT_INFO_CREATED) {
kmem_free(ha->n_port, sizeof (ql_n_port_info_t));
progress &= ~QL_N_PORT_INFO_CREATED;
}
if (progress & QL_PLOGI_PARAMS_CREATED) {
(void) ql_plogi_params_desc_dtor(ha);
progress &= ~QL_PLOGI_PARAMS_CREATED;
}
if (progress & QL_NVRAM_CACHE_CREATED) {
(void) ql_nvram_cache_desc_dtor(ha);
progress &= ~QL_NVRAM_CACHE_CREATED;
}
if (progress & QL_TASK_DAEMON_STARTED) {
if (ha->driver_thread_taskq) {
while (ha->task_daemon_flags &
TASK_DAEMON_ALIVE_FLG) {
ql_awaken_task_daemon(ha, NULL,
TASK_DAEMON_STOP_FLG, 0);
delay(1);
}
ha->task_daemon_flags &= ~TASK_DAEMON_STOP_FLG;
ddi_taskq_destroy(ha->driver_thread_taskq);
ha->driver_thread_taskq = NULL;
}
if (ha->completion_taskq) {
ADAPTER_STATE_LOCK(ha);
ha->flags |= COMP_THD_TERMINATE;
ADAPTER_STATE_UNLOCK(ha);
do {
COMP_Q_LOCK(ha);
cv_broadcast(&ha->cv_comp_thread);
COMP_Q_UNLOCK(ha);
ql_delay(ha, 10000);
} while (ha->comp_thds_active != 0);
ddi_taskq_destroy(ha->completion_taskq);
ha->completion_taskq = NULL;
}
progress &= ~QL_TASK_DAEMON_STARTED;
}
if (progress & QL_DB_IOBASE_MAPPED) {
ql_8021_clr_drv_active(ha);
ddi_regs_map_free(&ha->db_dev_handle);
progress &= ~QL_DB_IOBASE_MAPPED;
}
if (progress & QL_IOMAP_IOBASE_MAPPED) {
ddi_regs_map_free(&ha->iomap_dev_handle);
progress &= ~QL_IOMAP_IOBASE_MAPPED;
}
if (progress & QL_REGS_MAPPED) {
if (ha->mbar_dev_handle) {
ddi_regs_map_free(&ha->mbar_dev_handle);
ha->mbar_dev_handle = 0;
}
}
if (progress & QL_CONFIG_SPACE_SETUP) {
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ddi_regs_map_free(&ha->sbus_config_handle);
} else {
pci_config_teardown(&ha->pci_handle);
}
progress &= ~QL_CONFIG_SPACE_SETUP;
}
if (progress & QL_INTR_ADDED) {
ql_disable_intr(ha);
ql_release_intr(ha);
progress &= ~QL_INTR_ADDED;
}
if (progress & QL_MUTEX_CV_INITED) {
ql_destroy_mutex(ha);
progress &= ~QL_MUTEX_CV_INITED;
}
if (progress & QL_HBA_BUFFER_SETUP) {
ql_delete_queues(ha);
progress &= ~QL_HBA_BUFFER_SETUP;
}
if (progress & QL_REGS_MAPPED) {
ddi_regs_map_free(&ha->dev_handle);
if (ha->sbus_fpga_iobase != NULL) {
ddi_regs_map_free(&ha->sbus_fpga_dev_handle);
}
progress &= ~QL_REGS_MAPPED;
}
if (progress & QL_SOFT_STATE_ALLOCED) {
ql_fcache_rel(ha->fcache);
kmem_free(ha->adapter_stats,
sizeof (*ha->adapter_stats));
kmem_free(ha->ub_array, sizeof (*ha->ub_array) *
QL_UB_LIMIT);
if (ha->outstanding_cmds != NULL) {
kmem_free(ha->outstanding_cmds,
sizeof (*ha->outstanding_cmds) *
ha->osc_max_cnt);
}
if (ha->devpath != NULL) {
kmem_free(ha->devpath,
strlen(ha->devpath) + 1);
}
kmem_free(ha->dev, sizeof (*ha->dev) *
DEVICE_HEAD_LIST_SIZE);
if (ha->xioctl != NULL) {
ql_free_xioctl_resource(ha);
}
if (ha->fw_module != NULL) {
(void) ddi_modclose(ha->fw_module);
}
(void) ql_el_trace_dealloc(ha);
ddi_soft_state_free(ql_state, instance);
progress &= ~QL_SOFT_STATE_ALLOCED;
}
ddi_prop_remove_all(dip);
rval = DDI_FAILURE;
break;
case DDI_RESUME:
rval = DDI_FAILURE;
ha = ddi_get_soft_state(ql_state, ddi_get_instance(dip));
if (ha == NULL) {
cmn_err(CE_WARN, "%s(%d): can't get soft state",
QL_NAME, instance);
break;
}
ha->power_level = PM_LEVEL_D3;
if (ha->pm_capable) {
if (pm_raise_power(dip, QL_POWER_COMPONENT,
PM_LEVEL_D0) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): can't raise adapter"
" power", QL_NAME, instance);
}
}
if (ha->power_level == PM_LEVEL_D3) {
ha->power_level = PM_LEVEL_D0;
if (ql_initialize_adapter(ha) != QL_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): can't initialize the"
" adapter", QL_NAME, instance);
}
ql_awaken_task_daemon(ha, NULL, TASK_DAEMON_ALIVE_FLG,
0);
}
GLOBAL_TIMER_LOCK();
if (ql_timer_timeout_id == NULL) {
ql_timer_timeout_id = timeout(ql_timer, (void *)0,
ql_timer_ticks);
}
GLOBAL_TIMER_LOCK();
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~ADAPTER_SUSPENDED;
ADAPTER_STATE_UNLOCK(ha);
rval = DDI_SUCCESS;
if (ha->flags & IP_ENABLED && !(ha->flags & IP_INITIALIZED)) {
(void) ql_initialize_ip(ha);
ql_isp_rcvbuf(ha);
}
break;
default:
cmn_err(CE_WARN, "%s(%d): attach, unknown code:"
" %x", QL_NAME, ddi_get_instance(dip), cmd);
rval = DDI_FAILURE;
break;
}
kmem_free(buf, MAXPATHLEN);
if (rval != DDI_SUCCESS) {
QL_PRINT_2(ha, "failed instance=%d, rval = %xh\n",
ddi_get_instance(dip), rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
ql_adapter_state_t *ha, *vha;
ql_tgt_t *tq;
uint16_t index;
ql_link_t *link;
char *buf;
timeout_id_t timer_id = NULL;
int suspend, rval = DDI_SUCCESS;
ha = ddi_get_soft_state(ql_state, ddi_get_instance(dip));
if (ha == NULL) {
QL_PRINT_2(NULL, "no adapter, instance=%d\n",
ddi_get_instance(dip));
return (DDI_FAILURE);
}
QL_PRINT_3(ha, "started, cmd=%xh\n", cmd);
buf = (char *)(kmem_zalloc(MAXPATHLEN, KM_SLEEP));
switch (cmd) {
case DDI_DETACH:
ADAPTER_STATE_LOCK(ha);
ha->flags |= (ADAPTER_SUSPENDED | ABORT_CMDS_LOOP_DOWN_TMO);
ADAPTER_STATE_UNLOCK(ha);
while (!(ha->task_daemon_flags & TASK_DAEMON_STALLED_FLG) &&
ha->task_daemon_flags & TASK_DAEMON_ALIVE_FLG) {
ql_awaken_task_daemon(ha, NULL, 0, 0);
delay(1);
}
if (ha->driver_thread_taskq) {
while (ha->task_daemon_flags & TASK_DAEMON_ALIVE_FLG) {
ql_awaken_task_daemon(ha, NULL,
TASK_DAEMON_STOP_FLG, 0);
delay(1);
}
ha->task_daemon_flags &= ~TASK_DAEMON_STOP_FLG;
ddi_taskq_destroy(ha->driver_thread_taskq);
ha->driver_thread_taskq = NULL;
}
if (ha->completion_taskq) {
ADAPTER_STATE_LOCK(ha);
ha->flags |= COMP_THD_TERMINATE;
ADAPTER_STATE_UNLOCK(ha);
do {
COMP_Q_LOCK(ha);
cv_broadcast(&ha->cv_comp_thread);
COMP_Q_UNLOCK(ha);
ql_delay(ha, 10000);
} while (ha->comp_thds_active != 0);
ddi_taskq_destroy(ha->completion_taskq);
ha->completion_taskq = NULL;
}
GLOBAL_TIMER_LOCK();
if (ql_timer_timeout_id && ql_hba.first == &ha->hba &&
ql_hba.last == &ha->hba) {
timer_id = ql_timer_timeout_id;
ql_timer_timeout_id = NULL;
}
GLOBAL_TIMER_UNLOCK();
if (timer_id) {
(void) untimeout(timer_id);
}
GLOBAL_STATE_LOCK();
ql_remove_link(&ql_hba, &ha->hba);
GLOBAL_STATE_UNLOCK();
if (ha->pm_capable) {
if (pm_lower_power(dip, QL_POWER_COMPONENT,
PM_LEVEL_D3) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): failed to lower the"
" power", QL_NAME, ha->instance);
}
}
if (ha->power_level != PM_LEVEL_D3) {
ql_halt(ha, PM_LEVEL_D3);
}
while ((vha = ha->vp_next) != NULL) {
ql_vport_destroy(vha);
}
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
link = ha->dev[index].first;
while (link != NULL) {
tq = link->base_address;
link = link->next;
ql_dev_free(ha, tq);
}
}
QL_UB_LOCK(ha);
for (index = 0; index < QL_UB_LIMIT; index++) {
fc_unsol_buf_t *ubp = ha->ub_array[index];
if (ubp != NULL) {
ql_srb_t *sp = ubp->ub_fca_private;
sp->flags |= SRB_UB_FREE_REQUESTED;
while (!(sp->flags & SRB_UB_IN_FCA) ||
(sp->flags & (SRB_UB_CALLBACK |
SRB_UB_ACQUIRED))) {
QL_UB_UNLOCK(ha);
delay(drv_usectohz(100000));
QL_UB_LOCK(ha);
}
ha->ub_array[index] = NULL;
QL_UB_UNLOCK(ha);
ql_free_unsolicited_buffer(ha, ubp);
QL_UB_LOCK(ha);
}
}
QL_UB_UNLOCK(ha);
if (ha->risc_code != NULL) {
kmem_free(ha->risc_code, ha->risc_code_size);
ha->risc_code = NULL;
ha->risc_code_size = 0;
}
if (ha->fw_module != NULL) {
(void) ddi_modclose(ha->fw_module);
ha->fw_module = NULL;
}
ddi_prop_remove_all(dip);
(void) fc_fca_detach(dip);
kmem_free(ha->tran, sizeof (fc_fca_tran_t));
ddi_remove_minor_node(dip, "devctl");
if (ha->k_stats != NULL) {
kstat_delete(ha->k_stats);
}
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ddi_regs_map_free(&ha->sbus_config_handle);
} else {
if (CFG_IST(ha, CFG_CTRL_82XX)) {
ql_8021_clr_drv_active(ha);
ddi_regs_map_free(&ha->db_dev_handle);
}
if (ha->iomap_dev_handle != ha->dev_handle) {
ddi_regs_map_free(&ha->iomap_dev_handle);
}
pci_config_teardown(&ha->pci_handle);
}
ql_disable_intr(ha);
ql_release_intr(ha);
ql_free_xioctl_resource(ha);
ql_destroy_mutex(ha);
ql_delete_queues(ha);
ql_free_phys(ha, &ha->fwexttracebuf);
ql_free_phys(ha, &ha->fwfcetracebuf);
ddi_regs_map_free(&ha->dev_handle);
if (ha->sbus_fpga_iobase != NULL) {
ddi_regs_map_free(&ha->sbus_fpga_dev_handle);
}
if (ha->mbar_dev_handle != NULL) {
ddi_regs_map_free(&ha->mbar_dev_handle);
}
ql_fcache_rel(ha->fcache);
if (ha->vcache != NULL) {
kmem_free(ha->vcache, QL_24XX_VPD_SIZE);
}
if (ha->pi_attrs != NULL) {
kmem_free(ha->pi_attrs, sizeof (fca_port_attrs_t));
}
kmem_free(ha->adapter_stats, sizeof (*ha->adapter_stats));
kmem_free(ha->ub_array, sizeof (*ha->ub_array) * QL_UB_LIMIT);
kmem_free(ha->outstanding_cmds,
sizeof (*ha->outstanding_cmds) * ha->osc_max_cnt);
if (ha->n_port != NULL) {
kmem_free(ha->n_port, sizeof (ql_n_port_info_t));
}
if (ha->devpath != NULL) {
kmem_free(ha->devpath, strlen(ha->devpath) + 1);
}
kmem_free(ha->dev, sizeof (*ha->dev) * DEVICE_HEAD_LIST_SIZE);
(void) ql_plogi_params_desc_dtor(ha);
(void) ql_nvram_cache_desc_dtor(ha);
(void) qlc_fm_fini(ha);
EL(ha, "detached\n");
(void) ql_el_trace_dealloc(ha);
ddi_soft_state_free(ql_state, (int)ha->instance);
rval = DDI_SUCCESS;
break;
case DDI_SUSPEND:
ADAPTER_STATE_LOCK(ha);
ha->flags |= ADAPTER_SUSPENDED;
ADAPTER_STATE_UNLOCK(ha);
GLOBAL_TIMER_LOCK();
if (ql_timer_timeout_id && ql_hba.first == &ha->hba &&
ql_hba.last == &ha->hba) {
timer_id = ql_timer_timeout_id;
ql_timer_timeout_id = NULL;
}
GLOBAL_TIMER_UNLOCK();
if (timer_id) {
(void) untimeout(timer_id);
}
if (ha->flags & IP_INITIALIZED) {
(void) ql_shutdown_ip(ha);
}
if ((suspend = ql_suspend_adapter(ha)) != QL_SUCCESS) {
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~ADAPTER_SUSPENDED;
ADAPTER_STATE_UNLOCK(ha);
cmn_err(CE_WARN, "%s(%d): Fail suspend rval %xh",
QL_NAME, ha->instance, suspend);
if (ha->flags & IP_ENABLED &&
!(ha->flags & IP_INITIALIZED)) {
(void) ql_initialize_ip(ha);
ql_isp_rcvbuf(ha);
}
rval = DDI_FAILURE;
break;
}
EL(ha, "suspended\n");
break;
default:
rval = DDI_FAILURE;
break;
}
kmem_free(buf, MAXPATHLEN);
if (rval != DDI_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_power(dev_info_t *dip, int component, int level)
{
int rval = DDI_FAILURE;
off_t csr;
uint8_t saved_pm_val;
ql_adapter_state_t *ha;
char *buf;
char *path;
ha = ddi_get_soft_state(ql_state, ddi_get_instance(dip));
if (ha == NULL || ha->pm_capable == 0) {
QL_PRINT_2(ha, "no hba or PM not supported\n");
return (rval);
}
QL_PRINT_10(ha, "started\n");
buf = (char *)(kmem_zalloc(MAXPATHLEN, KM_SLEEP));
path = (char *)(kmem_zalloc(MAXPATHLEN, KM_SLEEP));
if (component != QL_POWER_COMPONENT || (level != PM_LEVEL_D0 &&
level != PM_LEVEL_D3)) {
EL(ha, "invalid, component=%xh or level=%xh\n",
component, level);
return (rval);
}
GLOBAL_HW_LOCK();
csr = (uint8_t)ql_pci_config_get8(ha, PCI_CONF_CAP_PTR) + PCI_PMCSR;
GLOBAL_HW_UNLOCK();
(void) snprintf(buf, MAXPATHLEN,
"Qlogic %s(%d): %s\n\t", QL_NAME, ddi_get_instance(dip),
ddi_pathname(dip, path));
switch (level) {
case PM_LEVEL_D0:
QL_PM_LOCK(ha);
if (ha->power_level == PM_LEVEL_D0) {
QL_PM_UNLOCK(ha);
rval = DDI_SUCCESS;
break;
}
saved_pm_val = ha->power_level;
ha->power_level = PM_LEVEL_D0;
QL_PM_UNLOCK(ha);
GLOBAL_HW_LOCK();
ql_pci_config_put16(ha, csr, PCI_PMCSR_D0);
drv_usecwait(200000);
GLOBAL_HW_UNLOCK();
if (ha->config_saved) {
ha->config_saved = 0;
if (QL_RESTORE_CONFIG_REGS(dip) != DDI_SUCCESS) {
QL_PM_LOCK(ha);
ha->power_level = saved_pm_val;
QL_PM_UNLOCK(ha);
cmn_err(CE_WARN, "%s failed to restore "
"config regs", buf);
break;
}
}
if (ql_initialize_adapter(ha) != QL_SUCCESS) {
cmn_err(CE_WARN, "%s adapter initialization failed",
buf);
}
ql_awaken_task_daemon(ha, NULL, TASK_DAEMON_ALIVE_FLG |
TASK_DAEMON_SLEEPING_FLG, 0);
if (ha->flags & IP_ENABLED && !(ha->flags & IP_INITIALIZED)) {
(void) ql_initialize_ip(ha);
ql_isp_rcvbuf(ha);
}
cmn_err(CE_NOTE, QL_BANG "ql_power(%d): %s is powered ON\n",
ha->instance, QL_NAME);
rval = DDI_SUCCESS;
break;
case PM_LEVEL_D3:
QL_PM_LOCK(ha);
if (ha->pm_busy || ((ha->task_daemon_flags &
TASK_DAEMON_SLEEPING_FLG) == 0)) {
QL_PM_UNLOCK(ha);
break;
}
if (ha->power_level == PM_LEVEL_D3) {
rval = DDI_SUCCESS;
QL_PM_UNLOCK(ha);
break;
}
QL_PM_UNLOCK(ha);
if (QL_SAVE_CONFIG_REGS(dip) != DDI_SUCCESS) {
cmn_err(CE_WARN, "!Qlogic %s(%d): %s failed to save"
" config regs", QL_NAME, ha->instance, buf);
break;
}
ha->config_saved = 1;
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= TASK_DAEMON_POWERING_DOWN;
TASK_DAEMON_UNLOCK(ha);
ql_halt(ha, PM_LEVEL_D3);
QL_PM_LOCK(ha);
ha->power_level = PM_LEVEL_D3;
QL_PM_UNLOCK(ha);
INTR_LOCK(ha);
ql_pci_config_put16(ha, csr, PCI_PMCSR_D3HOT);
INTR_UNLOCK(ha);
cmn_err(CE_NOTE, QL_BANG "ql_power(%d): %s is powered OFF\n",
ha->instance, QL_NAME);
rval = DDI_SUCCESS;
break;
}
kmem_free(buf, MAXPATHLEN);
kmem_free(path, MAXPATHLEN);
QL_PRINT_10(ha, "done\n");
return (rval);
}
static int
ql_quiesce(dev_info_t *dip)
{
ql_adapter_state_t *ha;
uint32_t timer;
uint32_t stat;
ha = ddi_get_soft_state(ql_state, ddi_get_instance(dip));
if (ha == NULL) {
QL_PRINT_2(NULL, "no adapter, instance=%d\n",
ddi_get_instance(dip));
return (DDI_SUCCESS);
}
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_82XX)) {
ql_8021_clr_hw_intr(ha);
ql_8021_clr_fw_intr(ha);
WRT16_IO_REG(ha, mailbox_in[0], MBC_TOGGLE_INTERRUPT);
WRT16_IO_REG(ha, mailbox_in[1], 0);
WRT32_IO_REG(ha, nx_host_int, NX_MBX_CMD);
for (timer = 0; timer < 20000; timer++) {
stat = RD32_IO_REG(ha, risc2host);
if (stat & BIT_15) {
ql_8021_clr_hw_intr(ha);
if ((stat & 0xff) < 0x12) {
ql_8021_clr_fw_intr(ha);
break;
}
ql_8021_clr_fw_intr(ha);
}
drv_usecwait(100);
}
ql_8021_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
WRT16_IO_REG(ha, mailbox_in[0], MBC_STOP_FIRMWARE);
WRT16_IO_REG(ha, mailbox_in[1], 0);
WRT32_IO_REG(ha, nx_host_int, NX_MBX_CMD);
for (timer = 0; timer < 20000; timer++) {
stat = RD32_IO_REG(ha, risc2host);
if (stat & BIT_15) {
ql_8021_clr_hw_intr(ha);
if ((stat & 0xff) < 0x12) {
ql_8021_clr_fw_intr(ha);
break;
}
ql_8021_clr_fw_intr(ha);
}
drv_usecwait(100);
}
} else if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
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);
}
if (CFG_IST(ha, CFG_MWB_4096_SUPPORT)) {
WRT32_IO_REG(ha, ctrl_status, ISP_RESET | DMA_SHUTDOWN |
MWB_4096_BYTES);
} else {
WRT32_IO_REG(ha, ctrl_status, ISP_RESET | DMA_SHUTDOWN);
}
drv_usecwait(100);
} else {
WRT16_IO_REG(ha, ictrl, 0);
WRT16_IO_REG(ha, ctrl_status, 0);
WRT16_IO_REG(ha, semaphore, 0);
WRT16_IO_REG(ha, hccr, HC_RESET_RISC);
WRT16_IO_REG(ha, hccr, HC_RELEASE_RISC);
}
QL_PRINT_3(ha, "done\n");
return (DDI_SUCCESS);
}
static opaque_t
ql_bind_port(dev_info_t *dip, fc_fca_port_info_t *port_info,
fc_fca_bind_info_t *bind_info)
{
ql_adapter_state_t *ha, *vha;
opaque_t fca_handle = NULL;
port_id_t d_id;
int port_npiv = bind_info->port_npiv;
uchar_t *port_nwwn = bind_info->port_nwwn.raw_wwn;
uchar_t *port_pwwn = bind_info->port_pwwn.raw_wwn;
ha = ddi_get_soft_state(ql_state, ddi_get_instance(dip));
if (ha == NULL) {
QL_PRINT_2(ha, "no adapter, instance=%d\n",
ddi_get_instance(dip));
return (NULL);
}
QL_PRINT_10(ha, "started\n");
if (port_npiv != 0) {
if (!(ha->flags & VP_ENABLED)) {
QL_PRINT_2(ha, "FC_NPIV_NOT_SUPPORTED\n");
port_info->pi_error = FC_NPIV_NOT_SUPPORTED;
return (NULL);
}
if (!(ha->flags & POINT_TO_POINT)) {
QL_PRINT_2(ha, "FC_NPIV_WRONG_TOPOLOGY\n");
port_info->pi_error = FC_NPIV_WRONG_TOPOLOGY;
return (NULL);
}
if (!(ha->flags & FDISC_ENABLED)) {
QL_PRINT_2(ha, "switch does not support "
"FDISC\n");
port_info->pi_error = FC_NPIV_FDISC_FAILED;
return (NULL);
}
if (bind_info->port_num >= ha->max_vports) {
QL_PRINT_2(ha, "port number=%d "
"FC_OUTOFBOUNDS\n", bind_info->port_num);
port_info->pi_error = FC_OUTOFBOUNDS;
return (NULL);
}
} else if (bind_info->port_num != 0) {
QL_PRINT_2(ha, "failed, port number=%d is not "
"supported\n", bind_info->port_num);
port_info->pi_error = FC_OUTOFBOUNDS;
return (NULL);
}
for (vha = ha; vha != NULL; vha = vha->vp_next) {
if (vha->vp_index == bind_info->port_num) {
break;
}
}
if (vha == NULL) {
vha = ql_vport_create(ha, (uint8_t)bind_info->port_num);
}
if (vha->flags & FCA_BOUND) {
port_info->pi_error = FC_ALREADY;
} else {
if (vha->vp_index != 0) {
bcopy(port_nwwn,
vha->loginparams.node_ww_name.raw_wwn, 8);
bcopy(port_pwwn,
vha->loginparams.nport_ww_name.raw_wwn, 8);
}
if (vha->vp_index != 0 && !(vha->flags & VP_ENABLED)) {
if (ql_vport_enable(vha) != QL_SUCCESS) {
QL_PRINT_2(ha, "failed to enable "
"virtual port=%d\n",
vha->vp_index);
port_info->pi_error = FC_NPIV_FDISC_FAILED;
return (NULL);
}
cmn_err(CE_CONT, "!Qlogic %s(%d) NPIV(%d) "
"WWPN=%02x%02x%02x%02x%02x%02x%02x%02x : "
"WWNN=%02x%02x%02x%02x%02x%02x%02x%02x\n",
QL_NAME, ha->instance, vha->vp_index,
port_pwwn[0], port_pwwn[1], port_pwwn[2],
port_pwwn[3], port_pwwn[4], port_pwwn[5],
port_pwwn[6], port_pwwn[7],
port_nwwn[0], port_nwwn[1], port_nwwn[2],
port_nwwn[3], port_nwwn[4], port_nwwn[5],
port_nwwn[6], port_nwwn[7]);
}
vha->bind_info.port_handle = bind_info->port_handle;
vha->bind_info.port_statec_cb = bind_info->port_statec_cb;
vha->bind_info.port_unsol_cb = bind_info->port_unsol_cb;
port_info->pi_s_id.port_id = vha->d_id.b24;
bcopy((void *)&vha->loginparams,
(void *)&port_info->pi_login_params,
sizeof (la_els_logi_t));
port_info->pi_hard_addr.hard_addr = 0;
if (bind_info->port_num == 0) {
d_id.b24 = ha->d_id.b24;
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
if (ha->init_ctrl_blk.cb24.
firmware_options_1[0] & BIT_0) {
d_id.b.al_pa = ql_index_to_alpa[ha->
init_ctrl_blk.cb24.
hard_address[0]];
port_info->pi_hard_addr.hard_addr =
d_id.b24;
}
} else if (ha->init_ctrl_blk.cb.firmware_options[0] &
BIT_0) {
d_id.b.al_pa = ql_index_to_alpa[ha->
init_ctrl_blk.cb.hard_address[0]];
port_info->pi_hard_addr.hard_addr = d_id.b24;
}
if (ql_get_rnid_params(ha,
sizeof (port_info->pi_rnid_params.params),
(caddr_t)&port_info->pi_rnid_params.params) ==
QL_SUCCESS) {
port_info->pi_rnid_params.status = FC_SUCCESS;
} else {
port_info->pi_rnid_params.status = FC_FAILURE;
}
ql_populate_hba_fru_details(ha, port_info);
ha->pi_attrs = kmem_zalloc(sizeof (fca_port_attrs_t),
KM_SLEEP);
if (ha->pi_attrs != NULL) {
bcopy(&port_info->pi_attrs, ha->pi_attrs,
sizeof (fca_port_attrs_t));
}
} else {
port_info->pi_rnid_params.status = FC_FAILURE;
if (ha->pi_attrs != NULL) {
bcopy(ha->pi_attrs, &port_info->pi_attrs,
sizeof (fca_port_attrs_t));
}
}
fca_handle = (opaque_t)vha;
ADAPTER_STATE_LOCK(ha);
vha->flags |= FCA_BOUND;
ADAPTER_STATE_UNLOCK(ha);
port_info->pi_port_state = vha->state;
}
QL_PRINT_10(ha, "done, pi_port_state=%xh, "
"pi_s_id.port_id=%xh\n",
port_info->pi_port_state, port_info->pi_s_id.port_id);
return (fca_handle);
}
static void
ql_unbind_port(opaque_t fca_handle)
{
ql_adapter_state_t *ha;
ql_tgt_t *tq;
uint32_t flgs;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
} else {
QL_PRINT_10(ha, "started\n");
if (!(ha->flags & FCA_BOUND)) {
QL_PRINT_2(ha, "port already unbound\n");
} else {
if (ha->vp_index != 0 && ha->flags & VP_ENABLED) {
(void) ql_vport_control(ha, (uint8_t)
(CFG_IST(ha, CFG_FC_TYPE) ?
VPC_DISABLE_INIT : VPC_DISABLE_LOGOUT));
if ((tq = ql_loop_id_to_queue(ha,
FL_PORT_24XX_HDL)) != NULL) {
(void) ql_logout_fabric_port(ha, tq);
}
flgs = FCA_BOUND | VP_ENABLED;
} else {
flgs = FCA_BOUND;
}
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~flgs;
ADAPTER_STATE_UNLOCK(ha);
}
QL_PRINT_10(ha, "done\n");
}
}
static int
ql_init_pkt(opaque_t fca_handle, fc_packet_t *pkt, int sleep)
{
ql_adapter_state_t *ha;
ql_srb_t *sp;
int rval = FC_SUCCESS;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started\n");
sp = (ql_srb_t *)pkt->pkt_fca_private;
sp->flags = 0;
sp->handle = 0;
sp->cmd.base_address = sp;
sp->cmd.prev = NULL;
sp->cmd.next = NULL;
sp->cmd.head = NULL;
sp->wdg.base_address = sp;
sp->wdg.prev = NULL;
sp->wdg.next = NULL;
sp->wdg.head = NULL;
sp->pkt = pkt;
sp->ha = ha;
sp->magic_number = QL_FCA_BRAND;
sp->sg_dma.dma_handle = NULL;
#ifndef __sparc
if (CFG_IST(ha, CFG_CTRL_82XX)) {
sp->sg_dma.size = sizeof (cmd6_2400_dma_t);
sp->sg_dma.type = LITTLE_ENDIAN_DMA;
sp->sg_dma.max_cookie_count = 1;
sp->sg_dma.alignment = 64;
if (ql_alloc_phys(ha, &sp->sg_dma, KM_SLEEP) != QL_SUCCESS) {
rval = FC_NOMEM;
}
}
#endif
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_un_init_pkt(opaque_t fca_handle, fc_packet_t *pkt)
{
ql_adapter_state_t *ha;
int rval;
ql_srb_t *sp;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started\n");
sp = (ql_srb_t *)pkt->pkt_fca_private;
if (sp->magic_number != QL_FCA_BRAND) {
EL(ha, "failed, FC_BADPACKET\n");
rval = FC_BADPACKET;
} else {
sp->magic_number = 0;
ql_free_phys(ha, &sp->sg_dma);
rval = FC_SUCCESS;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_els_send(opaque_t fca_handle, fc_packet_t *pkt)
{
ql_adapter_state_t *ha;
int rval;
clock_t timer = drv_usectohz(30000000);
ls_code_t els;
la_els_rjt_t rjt;
ql_srb_t *sp = (ql_srb_t *)pkt->pkt_fca_private;
ha = ql_cmd_setup(fca_handle, pkt, &rval);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, ql_cmd_setup=%xh, fcah=%ph\n",
rval, fca_handle);
return (FC_INVALID_REQUEST);
}
QL_PRINT_3(ha, "started\n");
TASK_DAEMON_LOCK(ha);
while (DRIVER_SUSPENDED(ha)) {
ha->task_daemon_flags |= SUSPENDED_WAKEUP_FLG;
if (cv_reltimedwait(&ha->pha->cv_dr_suspended,
&ha->pha->task_daemon_mutex, timer, TR_CLOCK_TICK) == -1) {
pkt->pkt_state = FC_PKT_TRAN_BSY;
pkt->pkt_reason = FC_REASON_XCHG_BSY;
TASK_DAEMON_UNLOCK(ha);
EL(ha, "QL_SUSPENDED failed=%xh\n",
QL_FUNCTION_TIMEOUT);
return (FC_TRAN_BUSY);
}
}
TASK_DAEMON_UNLOCK(ha);
bcopy((void *)&pkt->pkt_cmd_fhdr, (void *)&pkt->pkt_resp_fhdr,
sizeof (fc_frame_hdr_t));
if (pkt->pkt_rsplen) {
bzero((void *)pkt->pkt_resp, pkt->pkt_rsplen);
}
pkt->pkt_resp_fhdr.d_id = ha->d_id.b24;
pkt->pkt_resp_fhdr.s_id = pkt->pkt_cmd_fhdr.d_id;
pkt->pkt_resp_fhdr.r_ctl = R_CTL_EXTENDED_SVC |
R_CTL_SOLICITED_CONTROL;
pkt->pkt_resp_fhdr.f_ctl = F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ |
F_CTL_END_SEQ;
sp->flags &= ~(SRB_UB_CALLBACK | SRB_UB_RSCN | SRB_UB_FCP |
SRB_FCP_CMD_PKT | SRB_FCP_DATA_PKT | SRB_FCP_RSP_PKT |
SRB_IP_PKT | SRB_COMMAND_TIMEOUT | SRB_UB_ACQUIRED | SRB_MS_PKT);
sp->flags |= SRB_ELS_PKT;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
QL_PRINT_10(ha, "els.ls_code=%xh, d_id=%xh\n", els.ls_code,
pkt->pkt_cmd_fhdr.d_id);
sp->iocb = ha->els_cmd;
sp->req_cnt = 1;
switch (els.ls_code) {
case LA_ELS_RJT:
case LA_ELS_ACC:
pkt->pkt_state = FC_PKT_SUCCESS;
rval = FC_SUCCESS;
break;
case LA_ELS_PLOGI:
case LA_ELS_PDISC:
rval = ql_els_plogi(ha, pkt);
break;
case LA_ELS_FLOGI:
case LA_ELS_FDISC:
rval = ql_els_flogi(ha, pkt);
break;
case LA_ELS_LOGO:
rval = ql_els_logo(ha, pkt);
break;
case LA_ELS_PRLI:
rval = ql_els_prli(ha, pkt);
break;
case LA_ELS_PRLO:
rval = ql_els_prlo(ha, pkt);
break;
case LA_ELS_ADISC:
rval = ql_els_adisc(ha, pkt);
break;
case LA_ELS_LINIT:
rval = ql_els_linit(ha, pkt);
break;
case LA_ELS_LPC:
rval = ql_els_lpc(ha, pkt);
break;
case LA_ELS_LSTS:
rval = ql_els_lsts(ha, pkt);
break;
case LA_ELS_SCR:
rval = ql_els_scr(ha, pkt);
break;
case LA_ELS_RSCN:
rval = ql_els_rscn(ha, pkt);
break;
case LA_ELS_FARP_REQ:
rval = ql_els_farp_req(ha, pkt);
break;
case LA_ELS_FARP_REPLY:
rval = ql_els_farp_reply(ha, pkt);
break;
case LA_ELS_RLS:
rval = ql_els_rls(ha, pkt);
break;
case LA_ELS_RNID:
rval = ql_els_rnid(ha, pkt);
break;
default:
EL(ha, "LA_ELS_RJT, FC_REASON_CMD_UNSUPPORTED=%xh\n",
els.ls_code);
bzero(&rjt, sizeof (rjt));
rjt.ls_code.ls_code = LA_ELS_RJT;
rjt.reason = FC_REASON_CMD_UNSUPPORTED;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&rjt,
(uint8_t *)pkt->pkt_resp, sizeof (rjt), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_UNSUPPORTED;
rval = FC_SUCCESS;
break;
}
if (rval == QL_CONSUMED) {
rval = FC_SUCCESS;
} else if (rval == FC_SUCCESS &&
!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) && pkt->pkt_comp) {
ql_io_comp(sp);
}
if (rval != FC_SUCCESS) {
EL(ha, "rval=%x, ls_code=%xh sent to d_id=%xh, sp=%ph\n",
rval, els.ls_code, pkt->pkt_cmd_fhdr.d_id, sp);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
static int
ql_get_cap(opaque_t fca_handle, char *cap, void *ptr)
{
ql_adapter_state_t *ha;
int rval;
uint32_t *rptr = (uint32_t *)ptr;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started\n");
if (strcmp(cap, FC_NODE_WWN) == 0) {
bcopy((void *)&ha->loginparams.node_ww_name.raw_wwn[0],
ptr, 8);
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_LOGIN_PARAMS) == 0) {
bcopy((void *)&ha->loginparams, ptr,
sizeof (la_els_logi_t));
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_UNSOL_BUF) == 0) {
*rptr = (uint32_t)QL_UB_LIMIT;
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_NOSTREAM_ON_UNALIGN_BUF) == 0) {
dev_info_t *psydip = NULL;
#ifdef __sparc
if (ha->flags & MULTI_CHIP_ADAPTER &&
!CFG_IST(ha, CFG_SBUS_CARD)) {
for (psydip = ddi_get_parent(ha->dip); psydip;
psydip = ddi_get_parent(psydip)) {
if (strcmp(ddi_driver_name(psydip),
"pcipsy") == 0) {
break;
}
}
}
#endif
if (psydip) {
*rptr = (uint32_t)FC_NO_STREAMING;
EL(ha, "No Streaming\n");
} else {
*rptr = (uint32_t)FC_ALLOW_STREAMING;
EL(ha, "Allow Streaming\n");
}
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_PAYLOAD_SIZE) == 0) {
*rptr = ha->loginparams.common_service.rx_bufsize;
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_POST_RESET_BEHAVIOR) == 0) {
*rptr = FC_RESET_RETURN_ALL;
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_FCP_DMA) == 0) {
*rptr = FC_NO_DVMA_SPACE;
rval = FC_CAP_FOUND;
} else {
EL(ha, "unknown=%s, FC_CAP_ERROR\n", cap);
rval = FC_CAP_ERROR;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_set_cap(opaque_t fca_handle, char *cap, void *ptr)
{
ql_adapter_state_t *ha;
int rval;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started\n");
if (strcmp(cap, FC_NODE_WWN) == 0) {
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_LOGIN_PARAMS) == 0) {
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_UNSOL_BUF) == 0) {
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_PAYLOAD_SIZE) == 0) {
rval = FC_CAP_FOUND;
} else if (strcmp(cap, FC_CAP_POST_RESET_BEHAVIOR) == 0) {
rval = FC_CAP_FOUND;
} else {
EL(ha, "unknown=%s, FC_CAP_ERROR\n", cap);
rval = FC_CAP_ERROR;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_getmap(opaque_t fca_handle, fc_lilpmap_t *mapbuf)
{
ql_adapter_state_t *ha;
clock_t timer = drv_usectohz(30000000);
int rval = FC_SUCCESS;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started\n");
mapbuf->lilp_magic = (uint16_t)MAGIC_LIRP;
mapbuf->lilp_myalpa = ha->d_id.b.al_pa;
TASK_DAEMON_LOCK(ha);
while (DRIVER_SUSPENDED(ha)) {
ha->task_daemon_flags |= SUSPENDED_WAKEUP_FLG;
if (cv_reltimedwait(&ha->pha->cv_dr_suspended,
&ha->pha->task_daemon_mutex, timer, TR_CLOCK_TICK) == -1) {
TASK_DAEMON_UNLOCK(ha);
EL(ha, "QL_SUSPENDED failed, FC_TRAN_BUSY\n");
return (FC_TRAN_BUSY);
}
}
TASK_DAEMON_UNLOCK(ha);
if (ql_get_loop_position_map(ha, LOOP_POSITION_MAP_SIZE,
(caddr_t)&mapbuf->lilp_length) != QL_SUCCESS) {
ql_delay(ha, 2000000);
EL(ha, "failed, FC_NO_MAP\n");
rval = FC_NO_MAP;
} else {
QL_PRINT_3(ha, "my_alpa %xh len %xh "
"data %xh %xh %xh %xh\n",
mapbuf->lilp_myalpa, mapbuf->lilp_length,
mapbuf->lilp_alpalist[0], mapbuf->lilp_alpalist[1],
mapbuf->lilp_alpalist[2], mapbuf->lilp_alpalist[3]);
}
QL_PRINT_3(ha, "done\n");
#if 0
QL_DUMP_3((uint8_t *)mapbuf, 8, sizeof (fc_lilpmap_t));
#endif
return (rval);
}
static int
ql_transport(opaque_t fca_handle, fc_packet_t *pkt)
{
ql_adapter_state_t *ha;
int rval = FC_TRANSPORT_ERROR;
ql_srb_t *sp = (ql_srb_t *)pkt->pkt_fca_private;
ha = ql_cmd_setup(fca_handle, pkt, &rval);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, ql_cmd_setup=%xh, fcah=%ph\n",
rval, fca_handle);
return (rval);
}
QL_PRINT_3(ha, "started, d_id=%xh\n", pkt->pkt_cmd_fhdr.d_id);
sp->flags &= ~(SRB_ISP_STARTED | SRB_ISP_COMPLETED | SRB_RETRY |
SRB_POLL | SRB_WATCHDOG_ENABLED | SRB_UB_CALLBACK |
SRB_UB_RSCN | SRB_UB_FCP | SRB_FCP_CMD_PKT | SRB_FCP_DATA_PKT |
SRB_FCP_RSP_PKT | SRB_IP_PKT | SRB_GENERIC_SERVICES_PKT |
SRB_COMMAND_TIMEOUT | SRB_ABORTING | SRB_IN_DEVICE_QUEUE |
SRB_IN_TOKEN_ARRAY | SRB_UB_FREE_REQUESTED | SRB_UB_ACQUIRED |
SRB_MS_PKT | SRB_ELS_PKT);
pkt->pkt_resp_fhdr.d_id = ha->d_id.b24;
pkt->pkt_resp_fhdr.r_ctl = R_CTL_STATUS;
pkt->pkt_resp_fhdr.s_id = pkt->pkt_cmd_fhdr.d_id;
pkt->pkt_resp_fhdr.f_ctl = pkt->pkt_cmd_fhdr.f_ctl;
pkt->pkt_resp_fhdr.type = pkt->pkt_cmd_fhdr.type;
switch (pkt->pkt_cmd_fhdr.r_ctl) {
case R_CTL_COMMAND:
if (pkt->pkt_cmd_fhdr.type == FC_TYPE_SCSI_FCP) {
sp->flags |= SRB_FCP_CMD_PKT;
rval = ql_fcp_scsi_cmd(ha, pkt, sp);
} else {
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_UNSUPPORTED;
rval = FC_TRANSPORT_ERROR;
}
break;
default:
if (pkt->pkt_rsplen) {
bzero((void *)pkt->pkt_resp, pkt->pkt_rsplen);
}
switch (pkt->pkt_cmd_fhdr.r_ctl) {
case R_CTL_UNSOL_DATA:
if (pkt->pkt_cmd_fhdr.type == FC_TYPE_IS8802_SNAP) {
if (CFG_IST(ha, CFG_FCIP_SUPPORT) &&
ha->vp_index == 0) {
sp->flags |= SRB_IP_PKT;
rval = ql_fcp_ip_cmd(ha, pkt, sp);
} else {
cmn_err(CE_NOTE, "%s(%d) FC-IP is not "
"supported on this adapter\n",
QL_NAME, ha->instance);
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_UNSUPPORTED;
rval = FC_TRANSPORT_ERROR;
}
}
break;
case R_CTL_UNSOL_CONTROL:
if (pkt->pkt_cmd_fhdr.type == FC_TYPE_FC_SERVICES) {
sp->flags |= SRB_GENERIC_SERVICES_PKT;
rval = ql_fc_services(ha, pkt);
} else {
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_UNSUPPORTED;
rval = FC_TRANSPORT_ERROR;
}
break;
case R_CTL_SOLICITED_DATA:
case R_CTL_STATUS:
default:
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_UNSUPPORTED;
rval = FC_TRANSPORT_ERROR;
EL(ha, "unknown, r_ctl=%xh\n",
pkt->pkt_cmd_fhdr.r_ctl);
break;
}
}
if (rval != FC_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_ub_alloc(opaque_t fca_handle, uint64_t tokens[], uint32_t size,
uint32_t *count, uint32_t type)
{
ql_adapter_state_t *ha;
caddr_t bufp = NULL;
fc_unsol_buf_t *ubp;
ql_srb_t *sp;
uint32_t index;
uint32_t cnt;
uint32_t ub_array_index = 0;
int rval = FC_SUCCESS;
int ub_updated = FALSE;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started, count = %xh\n", *count);
QL_PM_LOCK(ha);
if (ha->power_level != PM_LEVEL_D0) {
QL_PM_UNLOCK(ha);
QL_PRINT_3(ha, "down done\n");
return (FC_FAILURE);
}
QL_PM_UNLOCK(ha);
if ((*count + ha->ub_allocated) > QL_UB_LIMIT) {
*count = 0;
EL(ha, "failed, FC_TOOMANY\n");
rval = FC_TOOMANY;
}
ub_array_index = 0;
for (index = 0; index < *count && rval == FC_SUCCESS; index++) {
ubp = (fc_unsol_buf_t *)kmem_zalloc(sizeof (fc_unsol_buf_t),
KM_SLEEP);
if (ubp == NULL) {
EL(ha, "failed, FC_FAILURE\n");
rval = FC_FAILURE;
} else {
sp = kmem_zalloc(sizeof (ql_srb_t), KM_SLEEP);
if (sp == NULL) {
kmem_free(ubp, sizeof (fc_unsol_buf_t));
rval = FC_FAILURE;
} else {
if (type == FC_TYPE_IS8802_SNAP) {
#ifdef __sparc
if (ql_get_dma_mem(ha,
&sp->ub_buffer, size,
BIG_ENDIAN_DMA,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
rval = FC_FAILURE;
kmem_free(ubp,
sizeof (fc_unsol_buf_t));
kmem_free(sp,
sizeof (ql_srb_t));
} else {
bufp = sp->ub_buffer.bp;
sp->ub_size = size;
}
#else
if (ql_get_dma_mem(ha,
&sp->ub_buffer, size,
LITTLE_ENDIAN_DMA,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
rval = FC_FAILURE;
kmem_free(ubp,
sizeof (fc_unsol_buf_t));
kmem_free(sp,
sizeof (ql_srb_t));
} else {
bufp = sp->ub_buffer.bp;
sp->ub_size = size;
}
#endif
} else {
bufp = kmem_zalloc(size, KM_SLEEP);
if (bufp == NULL) {
rval = FC_FAILURE;
kmem_free(ubp,
sizeof (fc_unsol_buf_t));
kmem_free(sp,
sizeof (ql_srb_t));
} else {
sp->ub_size = size;
}
}
}
}
if (rval == FC_SUCCESS) {
QL_UB_LOCK(ha);
while (ha->ub_array[ub_array_index] != NULL) {
ub_array_index++;
}
ubp->ub_fca_private = (void *)sp;
sp->cmd.base_address = sp;
sp->cmd.prev = NULL;
sp->cmd.next = NULL;
sp->cmd.head = NULL;
sp->wdg.base_address = sp;
sp->wdg.prev = NULL;
sp->wdg.next = NULL;
sp->wdg.head = NULL;
sp->ha = ha;
ubp->ub_buffer = bufp;
ubp->ub_bufsize = size;
ubp->ub_port_handle = fca_handle;
ubp->ub_token = ub_array_index;
tokens[index] = ub_array_index;
sp->ub_type = type;
sp->handle = ub_array_index;
sp->flags |= SRB_UB_IN_FCA;
ha->ub_array[ub_array_index] = ubp;
ha->ub_allocated++;
ub_updated = TRUE;
QL_UB_UNLOCK(ha);
}
}
if (ub_updated) {
if (type == FC_TYPE_IS8802_SNAP &&
CFG_IST(ha, CFG_FCIP_SUPPORT) &&
ha->vp_index == 0) {
ADAPTER_STATE_LOCK(ha);
ha->flags |= IP_ENABLED;
ADAPTER_STATE_UNLOCK(ha);
if (!(ha->flags & IP_INITIALIZED)) {
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
ha->ip_init_ctrl_blk.cb24.mtu_size[0] =
LSB(ql_ip_mtu);
ha->ip_init_ctrl_blk.cb24.mtu_size[1] =
MSB(ql_ip_mtu);
ha->ip_init_ctrl_blk.cb24.buf_size[0] =
LSB(size);
ha->ip_init_ctrl_blk.cb24.buf_size[1] =
MSB(size);
cnt = CHAR_TO_SHORT(
ha->ip_init_ctrl_blk.cb24.cc[0],
ha->ip_init_ctrl_blk.cb24.cc[1]);
if (cnt < *count) {
ha->ip_init_ctrl_blk.cb24.cc[0]
= LSB(*count);
ha->ip_init_ctrl_blk.cb24.cc[1]
= MSB(*count);
}
} else {
ha->ip_init_ctrl_blk.cb.mtu_size[0] =
LSB(ql_ip_mtu);
ha->ip_init_ctrl_blk.cb.mtu_size[1] =
MSB(ql_ip_mtu);
ha->ip_init_ctrl_blk.cb.buf_size[0] =
LSB(size);
ha->ip_init_ctrl_blk.cb.buf_size[1] =
MSB(size);
cnt = CHAR_TO_SHORT(
ha->ip_init_ctrl_blk.cb.cc[0],
ha->ip_init_ctrl_blk.cb.cc[1]);
if (cnt < *count) {
ha->ip_init_ctrl_blk.cb.cc[0] =
LSB(*count);
ha->ip_init_ctrl_blk.cb.cc[1] =
MSB(*count);
}
}
(void) ql_initialize_ip(ha);
}
ql_isp_rcvbuf(ha);
}
}
if (rval != FC_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_ub_free(opaque_t fca_handle, uint32_t count, uint64_t tokens[])
{
ql_adapter_state_t *ha;
ql_srb_t *sp;
uint32_t index;
uint64_t ub_array_index;
int rval = FC_SUCCESS;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started\n");
for (index = 0; index < count; index++) {
fc_unsol_buf_t *ubp;
if ((ub_array_index = tokens[index]) >= QL_UB_LIMIT) {
EL(ha, "failed, FC_UB_BADTOKEN\n");
rval = FC_UB_BADTOKEN;
break;
}
QL_UB_LOCK(ha);
ubp = ha->ub_array[ub_array_index];
if (ubp == NULL) {
EL(ha, "failed, FC_UB_BADTOKEN-2\n");
rval = FC_UB_BADTOKEN;
QL_UB_UNLOCK(ha);
break;
}
sp = ha->ub_array[ub_array_index]->ub_fca_private;
sp->flags |= SRB_UB_FREE_REQUESTED;
while (!(sp->flags & SRB_UB_IN_FCA) ||
(sp->flags & (SRB_UB_CALLBACK | SRB_UB_ACQUIRED))) {
QL_UB_UNLOCK(ha);
delay(drv_usectohz(100000));
QL_UB_LOCK(ha);
}
ha->ub_array[ub_array_index] = NULL;
QL_UB_UNLOCK(ha);
ql_free_unsolicited_buffer(ha, ubp);
}
if (rval == FC_SUCCESS) {
if (ha->ub_allocated == 0) {
QL_UB_LOCK(ha);
cv_broadcast(&ha->pha->cv_ub);
QL_UB_UNLOCK(ha);
}
}
if (rval != FC_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_ub_release(opaque_t fca_handle, uint32_t count, uint64_t tokens[])
{
ql_adapter_state_t *ha;
ql_srb_t *sp;
uint32_t index;
uint64_t ub_array_index;
int rval = FC_SUCCESS;
int ub_ip_updated = FALSE;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, ": failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started\n");
QL_UB_LOCK(ha);
for (index = 0; index < count; index++) {
if ((ub_array_index = tokens[index]) >= QL_UB_LIMIT) {
EL(ha, "failed, FC_UB_BADTOKEN\n");
rval = FC_UB_BADTOKEN;
break;
}
if (ha->ub_array[ub_array_index] == NULL) {
EL(ha, "failed, FC_UB_BADTOKEN-2\n");
rval = FC_UB_BADTOKEN;
break;
}
sp = ha->ub_array[ub_array_index]->ub_fca_private;
if (sp->flags & SRB_UB_IN_FCA) {
EL(ha, "failed, FC_UB_BADTOKEN-3\n");
rval = FC_UB_BADTOKEN;
break;
}
}
if (rval == FC_SUCCESS) {
for (index = 0; index < count; index++) {
fc_unsol_buf_t *ubp;
ub_array_index = tokens[index];
ubp = ha->ub_array[ub_array_index];
sp = ubp->ub_fca_private;
ubp->ub_resp_flags = 0;
sp->flags &= ~(SRB_UB_ACQUIRED | SRB_UB_CALLBACK);
sp->flags |= SRB_UB_IN_FCA;
if (sp->ub_type == FC_TYPE_IS8802_SNAP) {
ub_ip_updated = TRUE;
}
}
}
QL_UB_UNLOCK(ha);
if (ub_ip_updated) {
ql_isp_rcvbuf(ha);
}
if (rval != FC_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_abort(opaque_t fca_handle, fc_packet_t *pkt, int flags)
{
port_id_t d_id;
ql_link_t *link;
ql_adapter_state_t *ha, *pha;
ql_tgt_t *tq;
ql_lun_t *lq;
int rval = FC_ABORTED;
ql_srb_t *sp = (ql_srb_t *)pkt->pkt_fca_private;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
pha = ha->pha;
QL_PRINT_3(ha, "started\n");
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
tq = ql_d_id_to_queue(ha, d_id);
if ((tq == NULL) || (lq = sp->lun_queue) == NULL ||
(pha->task_daemon_flags & LOOP_DOWN)) {
if (tq == NULL || lq == NULL) {
EL(ha, "failed, FC_TRANSPORT_ERROR\n");
rval = FC_TRANSPORT_ERROR;
} else {
EL(ha, "failed, FC_OFFLINE\n");
rval = FC_OFFLINE;
}
return (rval);
}
DEVICE_QUEUE_LOCK(tq);
REQUEST_RING_LOCK(ha);
if (!(sp->flags & SRB_ISP_STARTED)) {
sp = NULL;
for (link = pha->pending_cmds.first; link != NULL;
link = link->next) {
sp = link->base_address;
if (sp == (ql_srb_t *)pkt->pkt_fca_private) {
ql_remove_link(&pha->pending_cmds, &sp->cmd);
break;
} else {
sp = NULL;
}
}
REQUEST_RING_UNLOCK(ha);
if (sp == NULL) {
for (link = lq->cmd.first; link != NULL;
link = link->next) {
sp = link->base_address;
if (sp == (ql_srb_t *)pkt->pkt_fca_private) {
ql_remove_link(&lq->cmd, &sp->cmd);
break;
} else {
sp = NULL;
}
}
}
DEVICE_QUEUE_UNLOCK(tq);
if (sp != NULL) {
sp->flags &= ~SRB_IN_DEVICE_QUEUE;
pkt->pkt_reason = CS_ABORTED;
sp->cmd.next = NULL;
ql_done(&sp->cmd, B_TRUE);
rval = FC_ABORTED;
} else {
EL(ha, "failed, FC_BADEXCHANGE\n");
rval = FC_BADEXCHANGE;
}
} else if (sp->flags & SRB_ISP_COMPLETED) {
REQUEST_RING_UNLOCK(ha);
DEVICE_QUEUE_UNLOCK(tq);
EL(ha, "failed, already done, FC_FAILURE\n");
rval = FC_FAILURE;
} else if ((sp->pkt->pkt_cmd_fhdr.r_ctl == R_CTL_SOLICITED_DATA) ||
(sp->pkt->pkt_cmd_fhdr.r_ctl == R_CTL_STATUS)) {
REQUEST_RING_UNLOCK(ha);
DEVICE_QUEUE_UNLOCK(tq);
rval = FC_ABORTED;
} else {
ql_request_q_t *req_q;
request_t *pio;
uint32_t index;
REQUEST_RING_UNLOCK(ha);
DEVICE_QUEUE_UNLOCK(tq);
INTR_LOCK(ha);
sp->flags |= SRB_ABORTING;
if (sp->handle != 0) {
index = sp->handle & OSC_INDEX_MASK;
if (ha->outstanding_cmds[index] == sp) {
ha->outstanding_cmds[index] =
QL_ABORTED_SRB(ha);
}
if (ha->req_q[1] != NULL && sp->rsp_q_number != 0) {
req_q = ha->req_q[1];
} else {
req_q = ha->req_q[0];
}
pio = sp->request_ring_ptr;
if (sp->handle ==
ddi_get32(req_q->req_ring.acc_handle,
&pio->handle)) {
EL(ha, "inflight sp=%ph, handle=%xh, "
"invalidated\n", (void *)sp, sp->handle);
for (index = 0; index < sp->req_cnt; index++) {
ddi_put8(req_q->req_ring.acc_handle,
&pio->entry_type,
ABORTED_ENTRY_TYPE);
pio++;
if (pio == (request_t *)
((uintptr_t)req_q->req_ring.bp +
req_q->req_ring.size)) {
pio = req_q->req_ring.bp;
}
}
}
if (tq->outcnt != 0) {
tq->outcnt--;
}
if (sp->flags & SRB_FCP_CMD_PKT &&
lq->lun_outcnt != 0) {
lq->lun_outcnt--;
}
if (sp->flags & SRB_WATCHDOG_ENABLED) {
ql_remove_link(&tq->wdg, &sp->wdg);
sp->flags &= ~SRB_WATCHDOG_ENABLED;
}
INTR_UNLOCK(ha);
(void) ql_abort_command(ha, sp);
sp->handle = 0;
} else {
INTR_UNLOCK(ha);
}
sp->flags &= ~SRB_IN_TOKEN_ARRAY;
sp->flags |= SRB_ISP_COMPLETED;
pkt->pkt_reason = CS_ABORTED;
rval = FC_ABORTED;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_reset(opaque_t fca_handle, uint32_t cmd)
{
ql_adapter_state_t *ha;
int rval = FC_SUCCESS, rval2;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
QL_PRINT_3(ha, "started, cmd=%d\n", cmd);
if (ha->task_daemon_flags & (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE |
DRIVER_STALL | ISP_ABORT_NEEDED | LOOP_RESYNC_NEEDED)) {
EL(ha, "driver stalled, FC_TRAN_BUSY, dtf=%xh\n",
ha->task_daemon_flags);
return (FC_TRAN_BUSY);
}
switch (cmd) {
case FC_FCA_CORE:
if (ha->vp_index == 0) {
if (ql_dump_firmware(ha) != QL_SUCCESS) {
EL(ha, "failed, FC_FAILURE\n");
rval = FC_FAILURE;
}
}
break;
case FC_FCA_LINK_RESET:
if (!(ha->pha->task_daemon_flags & LOOP_DOWN)) {
if (ql_loop_reset(ha) != QL_SUCCESS) {
EL(ha, "failed, FC_FAILURE-2\n");
rval = FC_FAILURE;
}
}
break;
case FC_FCA_RESET_CORE:
case FC_FCA_RESET:
if (cmd == FC_FCA_RESET_CORE) {
if (ha->vp_index != 0) {
rval2 = ha->pha->task_daemon_flags & LOOP_DOWN
? QL_SUCCESS : ql_loop_reset(ha);
} else {
rval2 = ql_dump_firmware(ha);
}
if (rval2 != QL_SUCCESS) {
EL(ha, "failed, FC_FAILURE-3\n");
rval = FC_FAILURE;
}
}
if (ha->ub_allocated != 0) {
ha->state = FC_PORT_SPEED_MASK(ha->state);
ha->state |= FC_STATE_RESET_REQUESTED;
if (ha->flags & FCA_BOUND) {
(ha->bind_info.port_statec_cb)
(ha->bind_info.port_handle,
ha->state);
}
}
ha->state = FC_PORT_SPEED_MASK(ha->state);
if (ha->ub_allocated == 0) {
if (cmd == FC_FCA_RESET) {
if (ha->vp_index == 0) {
(void) ql_abort_isp(ha);
} else if (!(ha->pha->task_daemon_flags &
LOOP_DOWN)) {
(void) ql_loop_reset(ha);
}
}
ha->state |= FC_STATE_RESET;
} else {
if (ha->topology & QL_LOOP_CONNECTION) {
ha->state |= FC_STATE_LOOP;
} else {
ha->state |= FC_STATE_ONLINE;
}
}
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= FC_STATE_CHANGE;
TASK_DAEMON_UNLOCK(ha);
ql_awaken_task_daemon(ha, NULL, FC_STATE_CHANGE, 0);
break;
default:
EL(ha, "unknown cmd=%xh\n", cmd);
break;
}
if (rval != FC_SUCCESS) {
EL(ha, "cmd=%xh, failed=%xh\n", cmd, rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_port_manage(opaque_t fca_handle, fc_fca_pm_t *cmd)
{
clock_t timer;
uint16_t index;
uint32_t *bp;
port_id_t d_id;
ql_link_t *link;
ql_adapter_state_t *ha, *pha;
ql_tgt_t *tq;
dma_mem_t buffer_xmt, buffer_rcv;
size_t length;
uint32_t cnt;
char buf[80];
lbp_t *lb;
ql_mbx_data_t mr;
app_mbx_cmd_t *mcp;
int i0;
uint8_t *bptr;
int rval2, rval = FC_SUCCESS;
uint32_t opcode;
uint32_t set_flags = 0;
fc_fca_p2p_info_t *p2p_info;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, ": failed, no adapter=%ph\n",
(void *)fca_handle);
return (FC_UNBOUND);
}
pha = ha->pha;
#ifdef QL_DEBUG_LEVEL_10
if (cmd->pm_cmd_code != FC_PORT_GET_FW_REV) {
QL_PRINT_10(ha, "started=%xh\n", cmd->pm_cmd_code);
}
#endif
if (ha->task_daemon_flags & (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE |
DRIVER_STALL | ISP_ABORT_NEEDED | LOOP_RESYNC_NEEDED)) {
EL(ha, "driver stalled, FC_TRAN_BUSY, dtf=%xh\n",
ha->task_daemon_flags);
return (FC_TRAN_BUSY);
}
switch (cmd->pm_cmd_code) {
case FC_PORT_BYPASS:
d_id.b24 = *cmd->pm_cmd_buf;
tq = ql_d_id_to_queue(ha, d_id);
if (tq == NULL || ql_loop_port_bypass(ha, tq) != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_BYPASS FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case FC_PORT_UNBYPASS:
d_id.b24 = *cmd->pm_cmd_buf;
tq = ql_d_id_to_queue(ha, d_id);
if (tq == NULL || ql_loop_port_enable(ha, tq) != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_UNBYPASS FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case FC_PORT_GET_FW_REV:
(void) sprintf(buf, "%d.%d.%d", pha->fw_major_version,
pha->fw_minor_version, pha->fw_subminor_version);
length = strlen(buf) + 1;
if (cmd->pm_data_len < length) {
cmd->pm_data_len = length;
EL(ha, "failed, FC_PORT_GET_FW_REV FC_FAILURE\n");
rval = FC_FAILURE;
} else {
(void) strcpy(cmd->pm_data_buf, buf);
}
break;
case FC_PORT_GET_FCODE_REV: {
caddr_t fcode_ver_buf = NULL;
i0 = 0;
rval2 = ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version",
(caddr_t)&fcode_ver_buf, &i0);
length = (uint_t)i0;
if (rval2 != DDI_PROP_SUCCESS) {
EL(ha, "failed, getting version = %xh\n", rval2);
length = 20;
fcode_ver_buf = kmem_alloc(length, KM_SLEEP);
if (fcode_ver_buf != NULL) {
(void) sprintf(fcode_ver_buf,
"NO FCODE FOUND");
}
}
if (cmd->pm_data_len < length) {
EL(ha, "length error, FC_PORT_GET_FCODE_REV "
"dst=%ld, src=%ld\n", cmd->pm_data_len, length);
cmd->pm_data_len = length;
rval = FC_FAILURE;
} else if (fcode_ver_buf != NULL) {
bcopy((void *)fcode_ver_buf, (void *)cmd->pm_data_buf,
length);
}
if (fcode_ver_buf != NULL) {
kmem_free(fcode_ver_buf, length);
}
break;
}
case FC_PORT_GET_DUMP:
QL_DUMP_LOCK(pha);
if (cmd->pm_data_len < (size_t)pha->risc_dump_size) {
EL(ha, "failed, FC_PORT_GET_DUMP incorrect "
"length=%lxh\n", cmd->pm_data_len);
cmd->pm_data_len = pha->risc_dump_size;
rval = FC_FAILURE;
} else if (pha->ql_dump_state & QL_DUMPING) {
EL(ha, "failed, FC_PORT_GET_DUMP FC_TRAN_BUSY\n");
rval = FC_TRAN_BUSY;
} else if (pha->ql_dump_state & QL_DUMP_VALID) {
(void) ql_ascii_fw_dump(ha, cmd->pm_data_buf);
pha->ql_dump_state |= QL_DUMP_UPLOADED;
} else {
EL(ha, "failed, FC_PORT_GET_DUMP no dump file\n");
rval = FC_FAILURE;
}
QL_DUMP_UNLOCK(pha);
break;
case FC_PORT_FORCE_DUMP:
if (ql_dump_firmware(ha) != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_FORCE_DUMP FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case FC_PORT_GET_DUMP_SIZE:
bp = (uint32_t *)cmd->pm_data_buf;
*bp = pha->risc_dump_size;
break;
case FC_PORT_DIAG:
EL(ha, "diag cmd=%xh\n", cmd->pm_cmd_flags);
for (timer = 0; timer < 3000 &&
pha->task_daemon_flags & QL_LOOP_TRANSITION; timer++) {
ql_delay(ha, 10000);
}
if (pha->task_daemon_flags & QL_LOOP_TRANSITION) {
EL(ha, "failed, FC_TRAN_BUSY-2\n");
rval = FC_TRAN_BUSY;
break;
}
if ((rval2 = ql_stall_driver(ha, 0)) != QL_SUCCESS) {
EL(ha, "stall_driver status=%xh, FC_TRAN_BUSY\n",
rval2);
ql_restart_driver(ha);
rval = FC_TRAN_BUSY;
break;
}
switch (cmd->pm_cmd_flags) {
case QL_DIAG_EXEFMW:
if (ql_start_firmware(ha) != QL_SUCCESS) {
EL(ha, "failed, QL_DIAG_EXEFMW FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case QL_DIAG_CHKCMDQUE:
for (i0 = 1, cnt = 0; i0 < pha->osc_max_cnt;
i0++) {
cnt += (pha->outstanding_cmds[i0] != NULL);
}
if (cnt != 0) {
EL(ha, "failed, QL_DIAG_CHKCMDQUE "
"FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case QL_DIAG_FMWCHKSUM:
if (ql_verify_checksum(ha) != QL_SUCCESS) {
EL(ha, "failed, QL_DIAG_FMWCHKSUM "
"FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case QL_DIAG_SLFTST:
if (ql_online_selftest(ha) != QL_SUCCESS) {
EL(ha, "failed, QL_DIAG_SLFTST FC_FAILURE\n");
rval = FC_FAILURE;
}
ql_reset_chip(ha);
set_flags |= ISP_ABORT_NEEDED;
break;
case QL_DIAG_REVLVL:
if (cmd->pm_stat_len <
sizeof (ql_adapter_revlvl_t)) {
EL(ha, "failed, QL_DIAG_REVLVL FC_NOMEM, "
"slen=%lxh, rlvllen=%lxh\n",
cmd->pm_stat_len,
sizeof (ql_adapter_revlvl_t));
rval = FC_NOMEM;
} else {
bcopy((void *)&(pha->adapter_stats->revlvl),
cmd->pm_stat_buf,
(size_t)cmd->pm_stat_len);
cmd->pm_stat_len =
sizeof (ql_adapter_revlvl_t);
}
break;
case QL_DIAG_LPBMBX:
if (cmd->pm_data_len != sizeof (struct app_mbx_cmd)) {
EL(ha, "failed, QL_DIAG_LPBMBX "
"FC_INVALID_REQUEST, pmlen=%lxh, "
"reqd=%lxh\n", cmd->pm_data_len,
sizeof (struct app_mbx_cmd));
rval = FC_INVALID_REQUEST;
break;
}
if (!CFG_IST(ha, CFG_CTRL_22XX)) {
mcp = (app_mbx_cmd_t *)cmd->pm_data_buf;
mr.mb[1] = mcp->mb[1];
mr.mb[2] = mcp->mb[2];
mr.mb[3] = mcp->mb[3];
mr.mb[4] = mcp->mb[4];
mr.mb[5] = mcp->mb[5];
mr.mb[6] = mcp->mb[6];
mr.mb[7] = mcp->mb[7];
bcopy(&mr.mb[0], &mr.mb[10],
sizeof (uint16_t) * 8);
if (ql_mbx_wrap_test(ha, &mr) != QL_SUCCESS) {
EL(ha, "failed, QL_DIAG_LPBMBX "
"FC_FAILURE\n");
rval = FC_FAILURE;
break;
} else {
for (i0 = 1; i0 < 8; i0++) {
if (mr.mb[i0] !=
mr.mb[i0 + 10]) {
EL(ha, "failed, "
"QL_DIAG_LPBMBX "
"FC_FAILURE-2\n");
rval = FC_FAILURE;
break;
}
}
}
if (rval == FC_FAILURE) {
(void) ql_flash_errlog(ha,
FLASH_ERRLOG_ISP_ERR, 0,
RD16_IO_REG(ha, hccr),
RD16_IO_REG(ha, istatus));
set_flags |= ISP_ABORT_NEEDED;
}
}
break;
case QL_DIAG_LPBDTA:
if (cmd->pm_data_len > 65536) {
rval = FC_TOOMANY;
EL(ha, "failed, QL_DIAG_LPBDTA "
"FC_TOOMANY=%lxh\n", cmd->pm_data_len);
break;
}
if (ql_get_dma_mem(ha, &buffer_xmt,
(uint32_t)cmd->pm_data_len, LITTLE_ENDIAN_DMA,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
EL(ha, "failed, QL_DIAG_LPBDTA FC_NOMEM\n");
rval = FC_NOMEM;
break;
}
if (ql_get_dma_mem(ha, &buffer_rcv,
(uint32_t)cmd->pm_data_len, LITTLE_ENDIAN_DMA,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
EL(ha, "failed, QL_DIAG_LPBDTA FC_NOMEM-2\n");
rval = FC_NOMEM;
break;
}
ddi_rep_put8(buffer_xmt.acc_handle,
(uint8_t *)cmd->pm_data_buf,
(uint8_t *)buffer_xmt.bp,
cmd->pm_data_len, DDI_DEV_AUTOINCR);
if (CFG_IST(ha, CFG_CTRL_22XX)) {
bptr = &ha->init_ctrl_blk.cb.add_fw_opt[0];
if (ha->flags & POINT_TO_POINT ||
(ha->task_daemon_flags & LOOP_DOWN &&
*bptr & (BIT_6 | BIT_5 | BIT_4))) {
cnt = *bptr;
*bptr = (uint8_t)
(*bptr & ~(BIT_6|BIT_5|BIT_4));
(void) ql_abort_isp(ha);
*bptr = (uint8_t)cnt;
}
}
if (pha->flags & IP_INITIALIZED) {
(void) ql_shutdown_ip(pha);
}
lb = (lbp_t *)cmd->pm_cmd_buf;
lb->transfer_count =
(uint32_t)cmd->pm_data_len;
lb->transfer_segment_count = 0;
lb->receive_segment_count = 0;
lb->transfer_data_address =
buffer_xmt.cookie.dmac_address;
lb->receive_data_address =
buffer_rcv.cookie.dmac_address;
if (CFG_IST(ha, CFG_LOOP_POINT_SUPPORT)) {
(void) ql_set_loop_point(ha, lb->options);
}
if (ql_loop_back(ha, 0, lb,
buffer_xmt.cookie.dmac_notused,
buffer_rcv.cookie.dmac_notused) == QL_SUCCESS) {
bzero((void *)cmd->pm_stat_buf,
cmd->pm_stat_len);
ddi_rep_get8(buffer_rcv.acc_handle,
(uint8_t *)cmd->pm_stat_buf,
(uint8_t *)buffer_rcv.bp,
cmd->pm_stat_len, DDI_DEV_AUTOINCR);
rval = FC_SUCCESS;
} else {
EL(ha, "failed, QL_DIAG_LPBDTA FC_FAILURE\n");
rval = FC_FAILURE;
}
if (CFG_IST(ha, CFG_LOOP_POINT_SUPPORT)) {
(void) ql_set_loop_point(ha, 0);
}
ql_free_phys(ha, &buffer_xmt);
ql_free_phys(ha, &buffer_rcv);
set_flags |= ISP_ABORT_NEEDED;
if (pha->flags & IP_ENABLED &&
!(pha->flags & IP_INITIALIZED)) {
(void) ql_initialize_ip(pha);
ql_isp_rcvbuf(pha);
}
break;
case QL_DIAG_ECHO: {
echo_t echo;
opcode = QL_ECHO_CMD;
BIG_ENDIAN_32(&opcode);
if ((cmd->pm_cmd_len > QL_ECHO_CMD_LENGTH) ||
(cmd->pm_stat_len > QL_ECHO_CMD_LENGTH)) {
EL(ha, "failed, QL_DIAG_ECHO FC_TOOMANY, "
"cmdl1=%lxh, statl2=%lxh\n",
cmd->pm_cmd_len, cmd->pm_stat_len);
rval = FC_TOOMANY;
break;
}
if (cmd->pm_cmd_len > cmd->pm_stat_len) {
EL(ha, "failed, QL_DIAG_ECHO FC_TOOMANY-2,"
" cmdl1=%lxh, statl2=%lxh\n",
cmd->pm_cmd_len, cmd->pm_stat_len);
rval = FC_TOOMANY;
break;
}
echo.transfer_count = (uint32_t)(cmd->pm_cmd_len + 4);
echo.options = BIT_15;
if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING) &&
!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
echo.options = (uint16_t)
(echo.options | BIT_6);
}
if (ql_get_dma_mem(ha, &buffer_xmt,
(uint32_t)(cmd->pm_data_len + 4),
LITTLE_ENDIAN_DMA,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
EL(ha, "failed, QL_DIAG_ECHO FC_NOMEM\n");
rval = FC_NOMEM;
break;
}
echo.transfer_data_address = buffer_xmt.cookie;
if (ql_get_dma_mem(ha, &buffer_rcv,
(uint32_t)(cmd->pm_data_len + 4),
LITTLE_ENDIAN_DMA,
QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
ql_free_phys(ha, &buffer_xmt);
EL(ha, "failed, QL_DIAG_ECHO FC_NOMEM-2\n");
rval = FC_NOMEM;
break;
}
echo.receive_data_address = buffer_rcv.cookie;
ddi_rep_put8(buffer_xmt.acc_handle, (uint8_t *)&opcode,
(uint8_t *)buffer_xmt.bp, 4, DDI_DEV_AUTOINCR);
ddi_rep_put8(buffer_xmt.acc_handle,
(uint8_t *)cmd->pm_cmd_buf,
(uint8_t *)buffer_xmt.bp + 4, cmd->pm_cmd_len,
DDI_DEV_AUTOINCR);
if (pha->flags & IP_INITIALIZED) {
(void) ql_shutdown_ip(pha);
}
if (ql_echo(ha, 0, &echo) == QL_SUCCESS) {
ddi_rep_put8(buffer_rcv.acc_handle,
(uint8_t *)buffer_rcv.bp + 4,
(uint8_t *)cmd->pm_stat_buf,
cmd->pm_stat_len, DDI_DEV_AUTOINCR);
} else {
EL(ha, "failed, QL_DIAG_ECHO FC_FAILURE\n");
rval = FC_FAILURE;
}
if (pha->flags & IP_ENABLED &&
!(pha->flags & IP_INITIALIZED)) {
(void) ql_initialize_ip(pha);
ql_isp_rcvbuf(pha);
}
ql_free_phys(ha, &buffer_xmt);
ql_free_phys(ha, &buffer_rcv);
break;
}
default:
EL(ha, "unknown=%xh, FC_PORT_DIAG "
"FC_INVALID_REQUEST\n", cmd->pm_cmd_flags);
rval = FC_INVALID_REQUEST;
break;
}
ql_restart_driver(ha);
break;
case FC_PORT_LINK_STATE:
for (index = 0; index < 8 && index < cmd->pm_cmd_len;
index++) {
if (cmd->pm_cmd_buf[index] != 0) {
break;
}
}
if (index < 8 && cmd->pm_cmd_len >= 8) {
tq = NULL;
for (index = 0; index < DEVICE_HEAD_LIST_SIZE &&
tq == NULL; index++) {
for (link = ha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
if (bcmp((void *)&tq->port_name[0],
(void *)cmd->pm_cmd_buf, 8) == 0) {
break;
} else {
tq = NULL;
}
}
}
if (tq != NULL && VALID_DEVICE_ID(ha, tq->loop_id)) {
cmd->pm_stat_buf[0] = (int8_t)LSB(ha->state);
cmd->pm_stat_buf[1] = (int8_t)MSB(ha->state);
} else {
cnt = FC_PORT_SPEED_MASK(ha->state) |
FC_STATE_OFFLINE;
cmd->pm_stat_buf[0] = (int8_t)LSB(cnt);
cmd->pm_stat_buf[1] = (int8_t)MSB(cnt);
}
} else {
cmd->pm_stat_buf[0] = (int8_t)LSB(ha->state);
cmd->pm_stat_buf[1] = (int8_t)MSB(ha->state);
}
break;
case FC_PORT_INITIALIZE:
if ((rval2 = ql_stall_driver(ha, 0)) != QL_SUCCESS) {
EL(ha, "stall_driver status=%xh, FC_TRAN_BUSY\n",
rval2);
ql_restart_driver(ha);
rval = FC_TRAN_BUSY;
break;
}
if (cmd->pm_cmd_len >= 8) {
tq = NULL;
for (index = 0; index < DEVICE_HEAD_LIST_SIZE &&
tq == NULL; index++) {
for (link = ha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
if (bcmp((void *)&tq->port_name[0],
(void *)cmd->pm_cmd_buf, 8) == 0) {
if (!VALID_DEVICE_ID(ha,
tq->loop_id)) {
tq = NULL;
}
break;
} else {
tq = NULL;
}
}
}
if (tq == NULL || ql_target_reset(ha, tq,
ha->loop_reset_delay) != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_INITIALIZE "
"FC_FAILURE\n");
rval = FC_FAILURE;
}
} else {
EL(ha, "failed, FC_PORT_INITIALIZE FC_FAILURE-2, "
"clen=%lxh\n", cmd->pm_cmd_len);
rval = FC_FAILURE;
}
ql_restart_driver(ha);
break;
case FC_PORT_RLS:
if (cmd->pm_data_len < sizeof (fc_rls_acc_t)) {
EL(ha, "failed, buffer size passed: %lxh, "
"req: %lxh\n", cmd->pm_data_len,
(sizeof (fc_rls_acc_t)));
rval = FC_FAILURE;
} else if (LOOP_NOT_READY(pha)) {
EL(ha, "loop NOT ready\n");
bzero(cmd->pm_data_buf, cmd->pm_data_len);
} else if (ql_get_link_status(ha, ha->loop_id,
cmd->pm_data_len, cmd->pm_data_buf, 0) != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_RLS FC_FAILURE\n");
rval = FC_FAILURE;
#ifdef _BIG_ENDIAN
} else {
fc_rls_acc_t *rls;
rls = (fc_rls_acc_t *)cmd->pm_data_buf;
LITTLE_ENDIAN_32(&rls->rls_link_fail);
LITTLE_ENDIAN_32(&rls->rls_sync_loss);
LITTLE_ENDIAN_32(&rls->rls_sig_loss);
LITTLE_ENDIAN_32(&rls->rls_prim_seq_err);
LITTLE_ENDIAN_32(&rls->rls_invalid_word);
LITTLE_ENDIAN_32(&rls->rls_invalid_crc);
#endif
}
break;
case FC_PORT_GET_NODE_ID:
if (ql_get_rnid_params(ha, cmd->pm_data_len,
cmd->pm_data_buf) != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_GET_NODE_ID FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case FC_PORT_SET_NODE_ID:
if (ql_set_rnid_params(ha, cmd->pm_data_len,
cmd->pm_data_buf) != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_SET_NODE_ID FC_FAILURE\n");
rval = FC_FAILURE;
}
break;
case FC_PORT_DOWNLOAD_FCODE:
if ((rval2 = ql_stall_driver(ha, 0)) != QL_SUCCESS) {
EL(ha, "stall_driver status=%xh, FC_TRAN_BUSY\n",
rval2);
ql_restart_driver(ha);
rval = FC_TRAN_BUSY;
break;
}
if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
rval = ql_load_flash(ha, (uint8_t *)cmd->pm_data_buf,
(uint32_t)cmd->pm_data_len);
} else {
if (cmd->pm_data_buf[0] == 4 &&
cmd->pm_data_buf[8] == 0 &&
cmd->pm_data_buf[9] == 0x10 &&
cmd->pm_data_buf[10] == 0 &&
cmd->pm_data_buf[11] == 0) {
rval = ql_24xx_load_flash(ha,
(uint8_t *)cmd->pm_data_buf,
(uint32_t)cmd->pm_data_len,
ha->flash_fw_addr << 2);
} else {
rval = ql_24xx_load_flash(ha,
(uint8_t *)cmd->pm_data_buf,
(uint32_t)cmd->pm_data_len, 0);
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, FC_PORT_DOWNLOAD_FCODE FC_FAILURE\n");
rval = FC_FAILURE;
} else {
rval = FC_SUCCESS;
}
ql_reset_chip(ha);
set_flags |= ISP_ABORT_NEEDED;
ql_restart_driver(ha);
break;
case FC_PORT_GET_P2P_INFO:
bzero(cmd->pm_data_buf, cmd->pm_data_len);
if (cmd->pm_data_len < sizeof (fc_fca_p2p_info_t)) {
EL(ha, "inadequate data length")
rval = FC_NOMEM;
break;
}
p2p_info = (fc_fca_p2p_info_t *)cmd->pm_data_buf;
if ((ha->topology & QL_N_PORT) &&
(ha->flags & POINT_TO_POINT)) {
p2p_info->fca_d_id = ha->d_id.b24;
p2p_info->d_id = ha->n_port->d_id.b24;
bcopy((void *) &ha->n_port->port_name[0],
(caddr_t)&p2p_info->pwwn, 8);
bcopy((void *) &ha->n_port->node_name[0],
(caddr_t)&p2p_info->nwwn, 8);
rval = FC_SUCCESS;
EL(ha, "P2P HID=%xh, d_id=%xh, WWPN=%02x%02x%02x%02x"
"%02x%02x%02x%02x : "
"WWNN=%02x%02x%02x%02x%02x%02x%02x%02x\n",
p2p_info->fca_d_id, p2p_info->d_id,
ha->n_port->port_name[0],
ha->n_port->port_name[1], ha->n_port->port_name[2],
ha->n_port->port_name[3], ha->n_port->port_name[4],
ha->n_port->port_name[5], ha->n_port->port_name[6],
ha->n_port->port_name[7], ha->n_port->node_name[0],
ha->n_port->node_name[1], ha->n_port->node_name[2],
ha->n_port->node_name[3], ha->n_port->node_name[4],
ha->n_port->node_name[5], ha->n_port->node_name[6],
ha->n_port->node_name[7]);
break;
} else {
EL(ha, "No p2p info reported in non n2n topology\n");
rval = FC_BADCMD;
}
break;
case FC_PORT_DOWNLOAD_FW:
EL(ha, "unsupported=%xh, FC_BADCMD\n", cmd->pm_cmd_code);
rval = FC_BADCMD;
break;
default:
EL(ha, "unknown=%xh, FC_BADCMD\n", cmd->pm_cmd_code);
rval = FC_BADCMD;
break;
}
ql_awaken_task_daemon(ha, NULL, set_flags, DRIVER_STALL);
timer = 0;
while (timer++ < 3000 &&
ha->task_daemon_flags & (QL_LOOP_TRANSITION | DRIVER_STALL)) {
ql_delay(ha, 10000);
}
if (rval != FC_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static opaque_t
ql_get_device(opaque_t fca_handle, fc_portid_t d_id)
{
port_id_t id;
ql_adapter_state_t *ha;
ql_tgt_t *tq;
id.r.rsvd_1 = 0;
id.b24 = d_id.port_id;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (NULL);
}
QL_PRINT_3(ha, "started, d_id=%xh\n", id.b24);
tq = ql_d_id_to_queue(ha, id);
if (tq == NULL && id.b24 != 0 && id.b24 != FS_BROADCAST) {
EL(ha, "failed, no tq available for d_id: %xh\n", id.b24);
} else {
QL_PRINT_3(ha, "done\n");
}
return (tq);
}
static ql_adapter_state_t *
ql_cmd_setup(opaque_t fca_handle, fc_packet_t *pkt, int *rval)
{
ql_adapter_state_t *ha, *pha;
ql_srb_t *sp = (ql_srb_t *)pkt->pkt_fca_private;
ql_tgt_t *tq;
port_id_t d_id;
pkt->pkt_resp_resid = 0;
pkt->pkt_data_resid = 0;
ha = ql_fca_handle_to_state(fca_handle);
if (ha == NULL) {
*rval = FC_UNBOUND;
QL_PRINT_2(NULL, "failed, no adapter=%ph\n",
(void *)fca_handle);
return (NULL);
}
pha = ha->pha;
QL_PRINT_3(ha, "started\n");
if (ddi_in_panic() || pkt->pkt_tran_flags & FC_TRAN_DUMPING) {
return (ha);
}
if (!(pha->flags & ONLINE)) {
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_HW_ERROR;
*rval = FC_TRANSPORT_ERROR;
EL(ha, "failed, not online hf=%xh\n", pha->flags);
return (NULL);
}
if (CFG_IST(ha, CFG_ENABLE_LINK_DOWN_REPORTING) &&
pha->task_daemon_flags & LOOP_DOWN &&
pha->loop_down_timer <= pha->loop_down_abort_time) {
pkt->pkt_state = FC_PKT_PORT_OFFLINE;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
*rval = FC_OFFLINE;
EL(ha, "failed, loop down tdf=%xh\n", pha->task_daemon_flags);
return (NULL);
}
if (pkt->pkt_cmd_fhdr.r_ctl == R_CTL_COMMAND &&
pkt->pkt_cmd_fhdr.type == FC_TYPE_SCSI_FCP) {
tq = (ql_tgt_t *)pkt->pkt_fca_device;
if ((tq == NULL) || (!VALID_DEVICE_ID(ha, tq->loop_id))) {
d_id.r.rsvd_1 = 0;
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
tq = ql_d_id_to_queue(ha, d_id);
pkt->pkt_fca_device = (opaque_t)tq;
}
if (tq != NULL) {
DEVICE_QUEUE_LOCK(tq);
if (tq->flags & (TQF_RSCN_RCVD |
TQF_NEED_AUTHENTICATION)) {
*rval = FC_DEVICE_BUSY;
DEVICE_QUEUE_UNLOCK(tq);
EL(ha, "failed, busy qf=%xh, d_id=%xh\n",
tq->flags, tq->d_id.b24);
return (NULL);
}
DEVICE_QUEUE_UNLOCK(tq);
}
}
if (sp->handle != 0) {
*rval = FC_DEVICE_BUSY;
cmn_err(CE_WARN, "%s(%d) already running pkt=%p, sp=%p, "
"sp->pkt=%p, sp->hdl=%x, spf=%x, cq=%p\n", QL_NAME,
ha->instance, (void *)pkt, (void *)sp, (void *)sp->pkt,
sp->handle, sp->flags, (void *)sp->cmd.head);
return (NULL);
}
if (ha->rsp_queues_cnt > 1) {
ADAPTER_STATE_LOCK(ha);
sp->rsp_q_number = ha->rsp_q_number++;
if (ha->rsp_q_number == ha->rsp_queues_cnt) {
ha->rsp_q_number = 0;
}
ADAPTER_STATE_UNLOCK(ha);
} else {
sp->rsp_q_number = 0;
}
*rval = DDI_SUCCESS;
if (pkt->pkt_cmd_acc != NULL && pkt->pkt_cmdlen) {
QL_CLEAR_DMA_HANDLE(pkt->pkt_cmd_dma);
*rval = qlc_fm_check_dma_handle(ha, pkt->pkt_cmd_dma);
if (*rval == DDI_FM_OK) {
*rval = qlc_fm_check_acc_handle(ha,
pkt->pkt_cmd_acc);
}
}
if (pkt->pkt_resp_acc != NULL && *rval == DDI_SUCCESS &&
pkt->pkt_rsplen != 0) {
QL_CLEAR_DMA_HANDLE(pkt->pkt_resp_dma);
*rval = qlc_fm_check_dma_handle(ha, pkt->pkt_resp_dma);
if (*rval == DDI_FM_OK) {
*rval = qlc_fm_check_acc_handle(ha,
pkt->pkt_resp_acc);
}
}
if (((pkt->pkt_data_acc != NULL) & (*rval == DDI_SUCCESS) &
(pkt->pkt_datalen != 0)) != 0) {
QL_CLEAR_DMA_HANDLE(pkt->pkt_data_dma);
*rval = qlc_fm_check_dma_handle(ha, pkt->pkt_data_dma);
if (*rval == DDI_FM_OK) {
*rval = qlc_fm_check_acc_handle(ha,
pkt->pkt_data_acc);
}
}
if (*rval != DDI_FM_OK) {
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_DMA_ERROR;
pkt->pkt_expln = FC_EXPLN_NONE;
pkt->pkt_action = FC_ACTION_RETRYABLE;
if (!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) && pkt->pkt_comp) {
ql_io_comp(sp);
}
*rval = FC_BADPACKET;
EL(ha, "failed, bad DMA pointers\n");
return (NULL);
}
if (sp->magic_number != QL_FCA_BRAND) {
*rval = FC_BADPACKET;
EL(ha, "failed, magic number=%xh\n", sp->magic_number);
return (NULL);
}
*rval = FC_SUCCESS;
QL_PRINT_3(ha, "done\n");
return (ha);
}
static int
ql_els_plogi(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ql_tgt_t *tq = NULL;
port_id_t d_id;
la_els_logi_t acc;
class_svc_param_t *class3_param;
int ret;
int rval = FC_SUCCESS;
QL_PRINT_3(ha, "started, d_id=%xh\n", pkt->pkt_cmd_fhdr.d_id);
TASK_DAEMON_LOCK(ha);
if (!(ha->task_daemon_flags & STATE_ONLINE)) {
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_3(ha, "offline done\n");
return (FC_OFFLINE);
}
TASK_DAEMON_UNLOCK(ha);
bzero(&acc, sizeof (acc));
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
ret = QL_SUCCESS;
if (CFG_IST(ha, CFG_N2N_SUPPORT) && ha->topology & QL_N_PORT) {
ret = ql_p2p_plogi(ha, pkt);
}
if (ret == QL_CONSUMED) {
return (ret);
}
switch (ret = ql_login_port(ha, d_id)) {
case QL_SUCCESS:
tq = ql_d_id_to_queue(ha, d_id);
break;
case QL_LOOP_ID_USED:
if ((ret = ql_login_port(ha, d_id)) == QL_SUCCESS) {
tq = ql_d_id_to_queue(ha, d_id);
}
break;
default:
break;
}
if (ret != QL_SUCCESS) {
tq = ql_d_id_to_queue(ha, d_id);
if (tq && (ret != QL_MEMORY_ALLOC_FAILED)) {
tq->loop_id = PORT_NO_LOOP_ID;
}
} else if (tq) {
(void) ql_get_port_database(ha, tq, PDF_ADISC);
}
if (tq != NULL && VALID_DEVICE_ID(ha, tq->loop_id) &&
(ret != QL_MEMORY_ALLOC_FAILED) && PD_PORT_LOGIN(tq)) {
acc.ls_code.ls_code = LA_ELS_ACC;
acc.common_service.fcph_version = 0x2006;
acc.common_service.cmn_features = 0x8800;
acc.common_service.rx_bufsize =
ha->loginparams.common_service.rx_bufsize;
acc.common_service.conc_sequences = 0xff;
acc.common_service.relative_offset = 0x03;
acc.common_service.e_d_tov = 0x7d0;
bcopy((void *)&tq->port_name[0],
(void *)&acc.nport_ww_name.raw_wwn[0], 8);
bcopy((void *)&tq->node_name[0],
(void *)&acc.node_ww_name.raw_wwn[0], 8);
class3_param = (class_svc_param_t *)&acc.class_3;
class3_param->class_valid_svc_opt = 0x8000;
class3_param->recipient_ctl = tq->class3_recipient_ctl;
class3_param->rcv_data_size = tq->class3_rcv_data_size;
class3_param->conc_sequences = tq->class3_conc_sequences;
class3_param->open_sequences_per_exch =
tq->class3_open_sequences_per_exch;
if ((ql_busy_plogi(ha, pkt, tq) == FC_TRAN_BUSY)) {
acc.ls_code.ls_code = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_BSY;
pkt->pkt_reason = FC_REASON_XCHG_BSY;
EL(ha, "LA_ELS_RJT, FC_REASON_XCHG_BSY\n");
rval = FC_TRAN_BUSY;
} else {
DEVICE_QUEUE_LOCK(tq);
tq->logout_sent = 0;
tq->flags &= ~TQF_NEED_AUTHENTICATION;
if (CFG_IST(ha, CFG_IIDMA_SUPPORT)) {
tq->flags |= TQF_IIDMA_NEEDED;
}
DEVICE_QUEUE_UNLOCK(tq);
if (CFG_IST(ha, CFG_IIDMA_SUPPORT)) {
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= TD_IIDMA_NEEDED;
TASK_DAEMON_UNLOCK(ha);
}
pkt->pkt_state = FC_PKT_SUCCESS;
}
} else {
acc.ls_code.ls_code = LA_ELS_RJT;
switch (ret) {
case QL_FUNCTION_TIMEOUT:
pkt->pkt_state = FC_PKT_TIMEOUT;
pkt->pkt_reason = FC_REASON_HW_ERROR;
break;
case QL_MEMORY_ALLOC_FAILED:
pkt->pkt_state = FC_PKT_LOCAL_BSY;
pkt->pkt_reason = FC_REASON_NOMEM;
rval = FC_TRAN_BUSY;
break;
case QL_FABRIC_NOT_INITIALIZED:
pkt->pkt_state = FC_PKT_FABRIC_BSY;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
rval = FC_TRAN_BUSY;
break;
default:
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
break;
}
EL(ha, "Plogi unsuccess for %xh state %xh reason %xh "
"ret %xh rval %xh\n", d_id.b24, pkt->pkt_state,
pkt->pkt_reason, ret, rval);
}
if (tq != NULL) {
DEVICE_QUEUE_LOCK(tq);
tq->flags &= ~(TQF_PLOGI_PROGRS | TQF_QUEUE_SUSPENDED);
if (rval == FC_TRAN_BUSY) {
if (tq->d_id.b24 != BROADCAST_ADDR) {
tq->flags |= TQF_NEED_AUTHENTICATION;
}
}
DEVICE_QUEUE_UNLOCK(tq);
}
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
if (rval != FC_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_p2p_plogi(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
uint16_t id;
ql_tgt_t tmp;
ql_tgt_t *tq = &tmp;
int rval;
port_id_t d_id;
ql_srb_t *sp = (ql_srb_t *)pkt->pkt_fca_private;
uint16_t loop_id;
tq->d_id.b.al_pa = 0;
tq->d_id.b.area = 0;
tq->d_id.b.domain = 0;
for (id = 0; id <= LAST_LOCAL_LOOP_ID; id++) {
tq->loop_id = id;
rval = ql_get_port_database(ha, tq, PDF_NONE);
EL(ha, "rval=%xh, id=%x\n", rval, id);
if (rval == QL_NOT_LOGGED_IN) {
if (tq->master_state == PD_STATE_PLOGI_PENDING) {
ha->n_port->n_port_handle = tq->loop_id;
EL(ha, "loop_id=%xh, master state=%x\n",
tq->loop_id, tq->master_state);
break;
}
if (tq->master_state == PD_STATE_PORT_UNAVAILABLE) {
if (pkt->pkt_cmd_fhdr.d_id == tq->d_id.b24) {
EL(ha, "n_port_handle loop_id=%xh, "
"master state=%xh\n",
tq->loop_id, tq->master_state);
break;
} else if (tq->loop_id ==
ha->n_port->n_port_handle) {
uint16_t *hndl;
uint16_t val;
hndl = &ha->n_port->n_port_handle;
val = *hndl;
val++;
val++;
*hndl = val;
}
EL(ha, "rval=%xh, id=%d, n_port_handle loop_id=%xh, "
"master state=%x\n", rval, id, tq->loop_id,
tq->master_state);
}
}
if (rval == QL_SUCCESS) {
if ((tq->flags & TQF_INITIATOR_DEVICE) == 0) {
ha->n_port->n_port_handle = tq->loop_id;
EL(ha, "n_port_handle =%xh, master state=%x\n",
tq->loop_id, tq->master_state);
break;
}
EL(ha, "rval=%xh, id=%d, n_port_handle loop_id=%xh, "
"master state=%x\n", rval, id, tq->loop_id,
tq->master_state);
}
}
(void) ddi_dma_sync(pkt->pkt_cmd_dma, 0, 0, DDI_DMA_SYNC_FORDEV);
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
if (id == LAST_LOCAL_LOOP_ID + 1) {
EL(ha, "out of range loop id; rval=%xh, id=%xh, d_id=%xh\n",
rval, id, d_id.b24);
} else {
EL(ha, "remote port loop_id '%x' has been logged in, d_id=%x\n",
id, d_id.b24);
}
tq = ql_d_id_to_queue(ha, d_id);
if (tq == NULL) {
if (id != LAST_LOCAL_LOOP_ID + 1) {
loop_id = id;
} else {
loop_id = 0;
}
ADAPTER_STATE_LOCK(ha);
tq = ql_dev_init(ha, d_id, loop_id);
ADAPTER_STATE_UNLOCK(ha);
}
sp->lun_queue = ql_lun_queue(ha, tq, 0);
DEVICE_QUEUE_LOCK(tq);
ql_timeout_insert(ha, tq, sp);
DEVICE_QUEUE_UNLOCK(tq);
ql_start_iocb(ha, sp);
return (QL_CONSUMED);
}
static int
ql_els_flogi(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ql_tgt_t *tq = NULL;
port_id_t d_id;
la_els_logi_t acc;
class_svc_param_t *class3_param;
int rval = FC_SUCCESS;
int accept = 0;
QL_PRINT_3(ha, "started, d_id=%xh\n", pkt->pkt_cmd_fhdr.d_id);
bzero(&acc, sizeof (acc));
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
if (CFG_IST(ha, CFG_N2N_SUPPORT) && ha->topology & QL_N_PORT) {
pkt->pkt_resp_fhdr.d_id = 0;
if (LOCAL_LOOP_ID(ha->n_port->n_port_handle)) {
tq = ql_loop_id_to_queue(ha, ha->n_port->n_port_handle);
}
if (tq != NULL) {
if (ql_wwn_cmp(ha, (la_wwn_t *)tq->port_name,
(la_wwn_t *)ha->loginparams.nport_ww_name.raw_wwn)
== 1) {
ha->send_plogi_timer = 3;
} else {
ha->send_plogi_timer = 0;
}
pkt->pkt_resp_fhdr.s_id = tq->d_id.b24;
} else {
accept = 1;
}
} else {
tq = ql_d_id_to_queue(ha, d_id);
}
if ((tq != NULL) || (accept != 0)) {
pkt->pkt_state = FC_PKT_SUCCESS;
class3_param = (class_svc_param_t *)&acc.class_3;
acc.ls_code.ls_code = LA_ELS_ACC;
acc.common_service.fcph_version = 0x2006;
if (ha->topology & QL_N_PORT) {
acc.common_service.cmn_features = 0x0800;
} else {
acc.common_service.cmn_features = 0x1b00;
}
acc.common_service.rx_bufsize =
ha->loginparams.common_service.rx_bufsize;
acc.common_service.conc_sequences = 0xff;
acc.common_service.relative_offset = 0x03;
acc.common_service.e_d_tov = 0x7d0;
if (accept) {
if (ha->n_port != NULL) {
bcopy((void *)&ha->n_port->port_name[0],
(void *)&acc.nport_ww_name.raw_wwn[0], 8);
bcopy((void *)&ha->n_port->node_name[0],
(void *)&acc.node_ww_name.raw_wwn[0], 8);
class3_param->class_valid_svc_opt = 0x0800;
} else {
EL(ha, "ha->n_port is NULL\n");
acc.ls_code.ls_code = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
}
} else {
bcopy((void *)&tq->port_name[0],
(void *)&acc.nport_ww_name.raw_wwn[0], 8);
bcopy((void *)&tq->node_name[0],
(void *)&acc.node_ww_name.raw_wwn[0], 8);
class3_param = (class_svc_param_t *)&acc.class_3;
class3_param->class_valid_svc_opt = 0x8800;
class3_param->recipient_ctl = tq->class3_recipient_ctl;
class3_param->rcv_data_size = tq->class3_rcv_data_size;
class3_param->conc_sequences =
tq->class3_conc_sequences;
class3_param->open_sequences_per_exch =
tq->class3_open_sequences_per_exch;
}
} else {
acc.ls_code.ls_code = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
if (rval != FC_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_els_logo(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
port_id_t d_id;
ql_tgt_t *tq;
la_els_logo_t acc;
QL_PRINT_3(ha, "started, d_id=%xh\n", pkt->pkt_cmd_fhdr.d_id);
bzero(&acc, sizeof (acc));
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
tq = ql_d_id_to_queue(ha, d_id);
if (tq) {
DEVICE_QUEUE_LOCK(tq);
if (tq->d_id.b24 == BROADCAST_ADDR) {
DEVICE_QUEUE_UNLOCK(tq);
return (FC_SUCCESS);
}
tq->flags |= TQF_NEED_AUTHENTICATION;
do {
DEVICE_QUEUE_UNLOCK(tq);
(void) ql_abort_device(ha, tq, 1);
ql_delay(ha, 10000);
DEVICE_QUEUE_LOCK(tq);
} while (tq->outcnt);
DEVICE_QUEUE_UNLOCK(tq);
}
if (ql_logout_port(ha, d_id) == QL_SUCCESS) {
acc.ls_code.ls_code = LA_ELS_ACC;
pkt->pkt_state = FC_PKT_SUCCESS;
} else {
acc.ls_code.ls_code = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_prli(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ql_tgt_t *tq;
port_id_t d_id;
la_els_prli_t acc;
prli_svc_param_t *param;
ql_srb_t *sp = (ql_srb_t *)pkt->pkt_fca_private;
int rval = FC_SUCCESS;
QL_PRINT_3(ha, "started, d_id=%xh\n", pkt->pkt_cmd_fhdr.d_id);
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
tq = ql_d_id_to_queue(ha, d_id);
if (tq != NULL) {
(void) ql_get_port_database(ha, tq, PDF_NONE);
if ((ha->topology & QL_N_PORT) &&
(tq->master_state == PD_STATE_PLOGI_COMPLETED)) {
sp->lun_queue = ql_lun_queue(ha, tq, 0);
DEVICE_QUEUE_LOCK(tq);
ql_timeout_insert(ha, tq, sp);
DEVICE_QUEUE_UNLOCK(tq);
ql_start_iocb(ha, sp);
rval = QL_CONSUMED;
} else {
bzero(&acc, sizeof (acc));
acc.ls_code = LA_ELS_ACC;
acc.page_length = 0x10;
acc.payload_length = tq->prli_payload_length;
param = (prli_svc_param_t *)&acc.service_params[0];
param->type = 0x08;
param->rsvd = 0x00;
param->process_assoc_flags = tq->prli_svc_param_word_0;
param->process_flags = tq->prli_svc_param_word_3;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc),
DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_SUCCESS;
}
} else {
if (ha->topology & QL_N_PORT) {
ADAPTER_STATE_LOCK(ha);
tq = ql_dev_init(ha, d_id, ha->n_port->n_port_handle);
ADAPTER_STATE_UNLOCK(ha);
sp->lun_queue = ql_lun_queue(ha, tq, 0);
bcopy((void *)&ha->n_port->port_name[0],
(void *) &tq->port_name[0], 8);
bcopy((void *)&ha->n_port->node_name[0],
(void *) &tq->node_name[0], 8);
DEVICE_QUEUE_LOCK(tq);
ql_timeout_insert(ha, tq, sp);
DEVICE_QUEUE_UNLOCK(tq);
ql_start_iocb(ha, sp);
rval = QL_CONSUMED;
} else {
la_els_rjt_t rjt;
bzero(&rjt, sizeof (rjt));
rjt.ls_code.ls_code = LA_ELS_RJT;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&rjt,
(uint8_t *)pkt->pkt_resp, sizeof (rjt),
DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
}
if ((rval != FC_SUCCESS) && (rval != QL_CONSUMED)) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_els_prlo(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
la_els_prli_t acc;
QL_PRINT_3(ha, "started, d_id=%xh\n", pkt->pkt_cmd_fhdr.d_id);
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_cmd, sizeof (acc), DDI_DEV_AUTOINCR);
acc.ls_code = LA_ELS_ACC;
acc.service_params[2] = 1;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_SUCCESS;
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_adisc(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ql_dev_id_list_t *list;
uint32_t list_size;
ql_link_t *link;
ql_tgt_t *tq;
ql_lun_t *lq;
port_id_t d_id;
la_els_adisc_t acc;
uint16_t index, loop_id;
ql_mbx_data_t mr;
QL_PRINT_3(ha, "started\n");
bzero(&acc, sizeof (acc));
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
index = ql_alpa_to_index[d_id.b.al_pa];
tq = NULL;
for (link = ha->dev[index].first; link != NULL; link = link->next) {
tq = link->base_address;
if (tq->d_id.b24 == d_id.b24) {
break;
} else {
tq = NULL;
}
}
if ((tq != NULL) && (!VALID_DEVICE_ID(ha, tq->loop_id))) {
list_size = sizeof (ql_dev_id_list_t) * DEVICE_LIST_ENTRIES;
list = (ql_dev_id_list_t *)kmem_zalloc(list_size, KM_SLEEP);
if (list != NULL &&
ql_get_id_list(ha, (caddr_t)list, list_size, &mr) ==
QL_SUCCESS) {
for (index = 0; index < mr.mb[1]; index++) {
ql_dev_list(ha, list, index, &d_id, &loop_id);
if (tq->d_id.b24 == d_id.b24) {
tq->loop_id = loop_id;
break;
}
}
} else {
cmn_err(CE_WARN, "!%s(%d) didn't get list for %xh",
QL_NAME, ha->instance, d_id.b24);
tq = NULL;
}
if ((tq != NULL) && (!VALID_DEVICE_ID(ha, tq->loop_id))) {
cmn_err(CE_WARN, "!%s(%d) no loop_id for adisc %xh",
QL_NAME, ha->instance, tq->d_id.b24);
tq = NULL;
}
if (list != NULL) {
kmem_free(list, list_size);
}
}
if ((tq != NULL) && (VALID_DEVICE_ID(ha, tq->loop_id)) &&
ql_get_port_database(ha, tq, PDF_ADISC) == QL_SUCCESS) {
DEVICE_QUEUE_LOCK(tq);
tq->flags &= ~TQF_NEED_AUTHENTICATION;
if (tq->prli_svc_param_word_3 & PRLI_W3_RETRY) {
for (link = tq->lun_queues.first; link != NULL;
link = link->next) {
lq = link->base_address;
if (lq->cmd.first != NULL) {
ql_next(ha, lq);
DEVICE_QUEUE_LOCK(tq);
}
}
}
DEVICE_QUEUE_UNLOCK(tq);
acc.ls_code.ls_code = LA_ELS_ACC;
acc.hard_addr.hard_addr = tq->hard_addr.b24;
bcopy((void *)&tq->port_name[0],
(void *)&acc.port_wwn.raw_wwn[0], 8);
bcopy((void *)&tq->node_name[0],
(void *)&acc.node_wwn.raw_wwn[0], 8);
acc.nport_id.port_id = tq->d_id.b24;
pkt->pkt_state = FC_PKT_SUCCESS;
} else {
acc.ls_code.ls_code = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_linit(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ddi_dma_cookie_t *cp;
uint32_t cnt;
conv_num_t n;
port_id_t d_id;
QL_PRINT_3(ha, "started\n");
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
if (ha->topology & QL_FABRIC_CONNECTION) {
fc_linit_req_t els;
lfa_cmd_t lfa;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
bzero((void *)&lfa, sizeof (lfa_cmd_t));
lfa.resp_buffer_length[0] = 4;
cp = pkt->pkt_resp_cookie;
if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
n.size64 = (uint64_t)cp->dmac_laddress;
LITTLE_ENDIAN_64(&n.size64);
} else {
n.size32[0] = LSD(cp->dmac_laddress);
LITTLE_ENDIAN_32(&n.size32[0]);
n.size32[1] = MSD(cp->dmac_laddress);
LITTLE_ENDIAN_32(&n.size32[1]);
}
for (cnt = 0; cnt < 8; cnt++) {
lfa.resp_buffer_address[cnt] = n.size8[cnt];
}
lfa.subcommand_length[0] = 4;
n.size32[0] = d_id.b24;
LITTLE_ENDIAN_32(&n.size32[0]);
lfa.addr[0] = n.size8[0];
lfa.addr[1] = n.size8[1];
lfa.addr[2] = n.size8[2];
lfa.subcommand[1] = 0x70;
lfa.payload[2] = els.func;
lfa.payload[4] = els.lip_b3;
lfa.payload[5] = els.lip_b4;
if (ql_send_lfa(ha, &lfa) != QL_SUCCESS) {
pkt->pkt_state = FC_PKT_TRAN_ERROR;
} else {
pkt->pkt_state = FC_PKT_SUCCESS;
}
} else {
fc_linit_resp_t rjt;
bzero(&rjt, sizeof (rjt));
rjt.ls_code.ls_code = LA_ELS_RJT;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&rjt,
(uint8_t *)pkt->pkt_resp, sizeof (rjt), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_lpc(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ddi_dma_cookie_t *cp;
uint32_t cnt;
conv_num_t n;
port_id_t d_id;
QL_PRINT_3(ha, "started\n");
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
if (ha->topology & QL_FABRIC_CONNECTION) {
ql_lpc_t els;
lfa_cmd_t lfa;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
bzero((void *)&lfa, sizeof (lfa_cmd_t));
lfa.resp_buffer_length[0] = 4;
cp = pkt->pkt_resp_cookie;
if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
n.size64 = (uint64_t)(cp->dmac_laddress);
LITTLE_ENDIAN_64(&n.size64);
} else {
n.size32[0] = cp->dmac_address;
LITTLE_ENDIAN_32(&n.size32[0]);
n.size32[1] = 0;
}
for (cnt = 0; cnt < 8; cnt++) {
lfa.resp_buffer_address[cnt] = n.size8[cnt];
}
lfa.subcommand_length[0] = 20;
n.size32[0] = d_id.b24;
LITTLE_ENDIAN_32(&n.size32[0]);
lfa.addr[0] = n.size8[0];
lfa.addr[1] = n.size8[1];
lfa.addr[2] = n.size8[2];
lfa.subcommand[1] = 0x71;
lfa.payload[4] = els.port_control;
bcopy((void *)&els.lpb[0], (void *)&lfa.payload[6], 16);
if (ql_send_lfa(ha, &lfa) != QL_SUCCESS) {
pkt->pkt_state = FC_PKT_TRAN_ERROR;
} else {
pkt->pkt_state = FC_PKT_SUCCESS;
}
} else {
ql_lpc_resp_t rjt;
bzero(&rjt, sizeof (rjt));
rjt.ls_code.ls_code = LA_ELS_RJT;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&rjt,
(uint8_t *)pkt->pkt_resp, sizeof (rjt), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_lsts(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ddi_dma_cookie_t *cp;
uint32_t cnt;
conv_num_t n;
port_id_t d_id;
QL_PRINT_3(ha, "started\n");
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
if (ha->topology & QL_FABRIC_CONNECTION) {
fc_lsts_req_t els;
lfa_cmd_t lfa;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
bzero((void *)&lfa, sizeof (lfa_cmd_t));
lfa.resp_buffer_length[0] = 84;
cp = pkt->pkt_resp_cookie;
if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
n.size64 = cp->dmac_laddress;
LITTLE_ENDIAN_64(&n.size64);
} else {
n.size32[0] = cp->dmac_address;
LITTLE_ENDIAN_32(&n.size32[0]);
n.size32[1] = 0;
}
for (cnt = 0; cnt < 8; cnt++) {
lfa.resp_buffer_address[cnt] = n.size8[cnt];
}
lfa.subcommand_length[0] = 2;
n.size32[0] = d_id.b24;
LITTLE_ENDIAN_32(&n.size32[0]);
lfa.addr[0] = n.size8[0];
lfa.addr[1] = n.size8[1];
lfa.addr[2] = n.size8[2];
lfa.subcommand[1] = 0x72;
if (ql_send_lfa(ha, &lfa) != QL_SUCCESS) {
pkt->pkt_state = FC_PKT_TRAN_ERROR;
} else {
pkt->pkt_state = FC_PKT_SUCCESS;
}
} else {
fc_lsts_resp_t rjt;
bzero(&rjt, sizeof (rjt));
rjt.lsts_ls_code.ls_code = LA_ELS_RJT;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&rjt,
(uint8_t *)pkt->pkt_resp, sizeof (rjt), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_scr(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
fc_scr_resp_t acc;
QL_PRINT_3(ha, "started\n");
bzero(&acc, sizeof (acc));
if (ha->topology & QL_FABRIC_CONNECTION) {
fc_scr_req_t els;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
if (ql_send_change_request(ha, els.scr_func) ==
QL_SUCCESS) {
acc.scr_acc = LA_ELS_ACC;
pkt->pkt_state = FC_PKT_SUCCESS;
} else {
acc.scr_acc = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_HW_ERROR;
EL(ha, "LA_ELS_RJT, FC_REASON_HW_ERROR\n");
}
} else {
acc.scr_acc = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_rscn(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ql_rscn_resp_t acc;
QL_PRINT_3(ha, "started\n");
bzero(&acc, sizeof (acc));
if (ha->topology & QL_FABRIC_CONNECTION) {
acc.scr_acc = LA_ELS_ACC;
pkt->pkt_state = FC_PKT_SUCCESS;
} else {
acc.scr_acc = LA_ELS_RJT;
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
}
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_farp_req(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ql_acc_rjt_t acc;
QL_PRINT_3(ha, "started\n");
bzero(&acc, sizeof (acc));
acc.ls_code.ls_code = LA_ELS_ACC;
pkt->pkt_state = FC_PKT_SUCCESS;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_farp_reply(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
ql_acc_rjt_t acc;
QL_PRINT_3(ha, "started\n");
bzero(&acc, sizeof (acc));
acc.ls_code.ls_code = LA_ELS_ACC;
pkt->pkt_state = FC_PKT_SUCCESS;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_rnid(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
uchar_t *rnid_acc;
port_id_t d_id;
ql_link_t *link;
ql_tgt_t *tq;
uint16_t index;
la_els_rnid_acc_t acc;
la_els_rnid_t *req;
size_t req_len;
QL_PRINT_3(ha, "started\n");
req_len = FCIO_RNID_MAX_DATA_LEN + sizeof (fc_rnid_hdr_t);
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
index = ql_alpa_to_index[d_id.b.al_pa];
tq = NULL;
for (link = ha->dev[index].first; link != NULL; link = link->next) {
tq = link->base_address;
if (tq->d_id.b24 == d_id.b24) {
break;
} else {
tq = NULL;
}
}
rnid_acc = kmem_zalloc(req_len, KM_SLEEP);
bzero(&acc, sizeof (acc));
req = (la_els_rnid_t *)pkt->pkt_cmd;
if ((tq == NULL) || (!VALID_DEVICE_ID(ha, tq->loop_id)) ||
(ql_send_rnid_els(ha, tq->loop_id, req->data_format, req_len,
(caddr_t)rnid_acc) != QL_SUCCESS)) {
kmem_free(rnid_acc, req_len);
acc.ls_code.ls_code = LA_ELS_RJT;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
return (FC_FAILURE);
}
acc.ls_code.ls_code = LA_ELS_ACC;
bcopy(rnid_acc, &acc.hdr, sizeof (fc_rnid_hdr_t));
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
kmem_free(rnid_acc, req_len);
pkt->pkt_state = FC_PKT_SUCCESS;
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_els_rls(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
fc_rls_acc_t *rls_acc;
port_id_t d_id;
ql_link_t *link;
ql_tgt_t *tq;
uint16_t index;
la_els_rls_acc_t acc;
QL_PRINT_3(ha, "started\n");
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
index = ql_alpa_to_index[d_id.b.al_pa];
tq = NULL;
for (link = ha->dev[index].first; link != NULL; link = link->next) {
tq = link->base_address;
if (tq->d_id.b24 == d_id.b24) {
break;
} else {
tq = NULL;
}
}
rls_acc = kmem_zalloc(sizeof (*rls_acc), KM_SLEEP);
bzero(&acc, sizeof (la_els_rls_acc_t));
if ((tq == NULL) || (!VALID_DEVICE_ID(ha, tq->loop_id)) ||
(ql_get_link_status(ha, tq->loop_id, sizeof (*rls_acc),
(caddr_t)rls_acc, 0) != QL_SUCCESS)) {
kmem_free(rls_acc, sizeof (*rls_acc));
acc.ls_code.ls_code = LA_ELS_RJT;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_TRAN_ERROR;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
EL(ha, "LA_ELS_RJT, FC_REASON_NO_CONNECTION\n");
return (FC_FAILURE);
}
LITTLE_ENDIAN_32(&rls_acc->rls_link_fail);
LITTLE_ENDIAN_32(&rls_acc->rls_sync_loss);
LITTLE_ENDIAN_32(&rls_acc->rls_sig_loss);
LITTLE_ENDIAN_32(&rls_acc->rls_invalid_word);
LITTLE_ENDIAN_32(&rls_acc->rls_invalid_crc);
acc.ls_code.ls_code = LA_ELS_ACC;
acc.rls_link_params.rls_link_fail = rls_acc->rls_link_fail;
acc.rls_link_params.rls_sync_loss = rls_acc->rls_sync_loss;
acc.rls_link_params.rls_sig_loss = rls_acc->rls_sig_loss;
acc.rls_link_params.rls_invalid_word = rls_acc->rls_invalid_word;
acc.rls_link_params.rls_invalid_crc = rls_acc->rls_invalid_crc;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&acc,
(uint8_t *)pkt->pkt_resp, sizeof (acc), DDI_DEV_AUTOINCR);
kmem_free(rls_acc, sizeof (*rls_acc));
pkt->pkt_state = FC_PKT_SUCCESS;
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_busy_plogi(ql_adapter_state_t *ha, fc_packet_t *pkt, ql_tgt_t *tq)
{
port_id_t d_id;
ql_srb_t *sp;
fc_unsol_buf_t *ubp;
ql_link_t *link, *next_link;
int rval = FC_SUCCESS;
int cnt = 5;
QL_PRINT_3(ha, "started\n");
DEVICE_QUEUE_LOCK(tq);
do {
if (tq->outcnt != 0) {
rval = FC_TRAN_BUSY;
DEVICE_QUEUE_UNLOCK(tq);
ql_delay(ha, 10000);
DEVICE_QUEUE_LOCK(tq);
cnt--;
if (!cnt) {
cmn_err(CE_NOTE, "!%s(%d) Plogi busy"
" for %xh outcount %xh", QL_NAME,
ha->instance, tq->d_id.b24, tq->outcnt);
}
} else {
rval = FC_SUCCESS;
break;
}
} while (cnt > 0);
DEVICE_QUEUE_UNLOCK(tq);
if ((rval != FC_SUCCESS) ||
(!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) &&
pkt->pkt_comp)) {
QL_PRINT_3(ha, "done, busy or async\n");
return (rval);
}
TASK_DAEMON_LOCK(ha);
for (link = ha->unsol_callback_queue.first; link != NULL;
link = next_link) {
next_link = link->next;
sp = link->base_address;
if (sp->flags & SRB_UB_CALLBACK) {
ubp = ha->ub_array[sp->handle];
d_id.b24 = ubp->ub_frame.s_id;
} else {
d_id.b24 = sp->pkt->pkt_cmd_fhdr.d_id;
}
if (tq->d_id.b24 == d_id.b24) {
cmn_err(CE_NOTE, "!%s(%d) Plogi busy for %xh", QL_NAME,
ha->instance, tq->d_id.b24);
rval = FC_TRAN_BUSY;
break;
}
}
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_login_port(ql_adapter_state_t *ha, port_id_t d_id)
{
ql_adapter_state_t *vha;
ql_link_t *link;
uint16_t index;
ql_tgt_t *tq, *tq2;
uint16_t loop_id, first_loop_id, last_loop_id;
int rval = QL_SUCCESS;
QL_PRINT_3(ha, "started, d_id=%xh\n", d_id.b24);
for (vha = ha->pha; vha != NULL; vha = vha->vp_next) {
if (vha->d_id.b24 == d_id.b24) {
EL(ha, "failed=%xh, d_id=%xh vp_index=%xh\n",
QL_FUNCTION_FAILED, d_id.b24, vha->vp_index);
return (QL_FUNCTION_FAILED);
}
}
index = ql_alpa_to_index[d_id.b.al_pa];
tq = NULL;
for (link = ha->dev[index].first; link != NULL; link = link->next) {
tq = link->base_address;
if (tq->d_id.b24 == d_id.b24) {
loop_id = tq->loop_id;
break;
} else {
tq = NULL;
}
}
if ((tq != NULL) && (!(ddi_in_panic()))) {
DEVICE_QUEUE_LOCK(tq);
tq->flags |= (TQF_QUEUE_SUSPENDED | TQF_PLOGI_PROGRS);
tq->flags &= ~TQF_RSCN_RCVD;
DEVICE_QUEUE_UNLOCK(tq);
}
if ((tq != NULL) && (tq->loop_id & PORT_LOST_ID) &&
!(tq->flags & TQF_FABRIC_DEVICE)) {
loop_id = (uint16_t)(tq->loop_id & ~PORT_LOST_ID);
}
if (d_id.b24 == FS_NAME_SERVER) {
if (!(ha->topology & QL_FABRIC_CONNECTION)) {
EL(ha, "failed=%xh, d_id=%xh no fabric\n",
QL_FUNCTION_FAILED, d_id.b24);
return (QL_FUNCTION_FAILED);
}
loop_id = (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
SNS_24XX_HDL : SIMPLE_NAME_SERVER_LOOP_ID);
if (tq == NULL) {
ADAPTER_STATE_LOCK(ha);
tq = ql_dev_init(ha, d_id, loop_id);
ADAPTER_STATE_UNLOCK(ha);
if (tq == NULL) {
EL(ha, "failed=%xh, d_id=%xh\n",
QL_FUNCTION_FAILED, d_id.b24);
return (QL_FUNCTION_FAILED);
}
}
if (!(CFG_IST(ha, CFG_CTRL_82XX))) {
rval = ql_login_fabric_port(ha, tq, loop_id);
if (rval == QL_SUCCESS) {
tq->loop_id = loop_id;
tq->flags |= TQF_FABRIC_DEVICE;
(void) ql_get_port_database(ha, tq, PDF_NONE);
}
}
} else if (tq != NULL && VALID_DEVICE_ID(ha, loop_id)) {
if (tq->flags & TQF_FABRIC_DEVICE) {
rval = ql_login_fabric_port(ha, tq, loop_id);
if (rval == QL_PORT_ID_USED) {
rval = QL_SUCCESS;
}
} else if (LOCAL_LOOP_ID(loop_id)) {
rval = ql_login_lport(ha, tq, loop_id, (uint16_t)
(tq->flags & TQF_INITIATOR_DEVICE ?
LLF_NONE : LLF_PLOGI));
if (rval == QL_SUCCESS) {
DEVICE_QUEUE_LOCK(tq);
tq->loop_id = loop_id;
DEVICE_QUEUE_UNLOCK(tq);
}
}
} else if (ha->topology & QL_FABRIC_CONNECTION) {
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
first_loop_id = 0;
last_loop_id = LAST_N_PORT_HDL;
} else if (ha->topology & QL_F_PORT) {
first_loop_id = 0;
last_loop_id = SNS_LAST_LOOP_ID;
} else {
first_loop_id = SNS_FIRST_LOOP_ID;
last_loop_id = SNS_LAST_LOOP_ID;
}
ADAPTER_STATE_LOCK(ha);
tq = ql_dev_init(ha, d_id, PORT_NO_LOOP_ID);
if (tq == NULL) {
EL(ha, "failed=%xh, d_id=%xh\n", QL_FUNCTION_FAILED,
d_id.b24);
ADAPTER_STATE_UNLOCK(ha);
return (QL_FUNCTION_FAILED);
}
rval = QL_FUNCTION_FAILED;
loop_id = ha->pha->free_loop_id++;
for (index = (uint16_t)(last_loop_id - first_loop_id); index;
index--) {
if (loop_id < first_loop_id ||
loop_id > last_loop_id) {
loop_id = first_loop_id;
ha->pha->free_loop_id = (uint16_t)
(loop_id + 1);
}
for (vha = ha->pha; vha != NULL; vha = vha->vp_next) {
tq2 = ql_loop_id_to_queue(vha, loop_id);
if (tq2 != NULL && tq2 != tq) {
break;
}
}
if (vha != NULL || RESERVED_LOOP_ID(ha, loop_id) ||
loop_id == ha->loop_id) {
loop_id = ha->pha->free_loop_id++;
continue;
}
ADAPTER_STATE_UNLOCK(ha);
rval = ql_login_fabric_port(ha, tq, loop_id);
switch (rval) {
case QL_PORT_ID_USED:
ADAPTER_STATE_LOCK(ha);
ha->pha->free_loop_id--;
ADAPTER_STATE_UNLOCK(ha);
loop_id = tq->loop_id;
break;
case QL_SUCCESS:
tq->flags |= TQF_FABRIC_DEVICE;
(void) ql_get_port_database(ha,
tq, PDF_NONE);
index = 1;
break;
case QL_LOOP_ID_USED:
tq->loop_id = PORT_NO_LOOP_ID;
ADAPTER_STATE_LOCK(ha);
loop_id = ha->pha->free_loop_id++;
ADAPTER_STATE_UNLOCK(ha);
break;
case QL_ALL_IDS_IN_USE:
tq->loop_id = PORT_NO_LOOP_ID;
index = 1;
break;
default:
tq->loop_id = PORT_NO_LOOP_ID;
index = 1;
break;
}
ADAPTER_STATE_LOCK(ha);
}
ADAPTER_STATE_UNLOCK(ha);
} else {
rval = QL_FUNCTION_FAILED;
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval=%xh, d_id=%xh\n",
rval, d_id.b24);
} else {
EL(ha, "d_id=%xh, loop_id=%xh, "
"wwpn=%02x%02x%02x%02x%02x%02x%02x%02xh\n", tq->d_id.b24,
tq->loop_id, tq->port_name[0], tq->port_name[1],
tq->port_name[2], tq->port_name[3], tq->port_name[4],
tq->port_name[5], tq->port_name[6], tq->port_name[7]);
}
return (rval);
}
static int
ql_login_fabric_port(ql_adapter_state_t *ha, ql_tgt_t *tq, uint16_t loop_id)
{
int rval;
int index;
int retry = 0;
port_id_t d_id;
ql_tgt_t *newq;
ql_mbx_data_t mr;
QL_PRINT_3(ha, "started, d_id=%xh\n", tq->d_id.b24);
do {
rval = ql_login_fport(ha, tq, loop_id, LFF_NONE, &mr);
if ((rval == QL_PARAMETER_ERROR) ||
((rval == QL_COMMAND_ERROR) && (mr.mb[1] == 2 ||
mr.mb[1] == 3 || mr.mb[1] == 7 || mr.mb[1] == 0xd))) {
retry++;
drv_usecwait(ha->plogi_params->retry_dly_usec);
} else {
break;
}
} while (retry < ha->plogi_params->retry_cnt);
switch (rval) {
case QL_SUCCESS:
tq->loop_id = loop_id;
break;
case QL_PORT_ID_USED:
newq = ql_loop_id_to_queue(ha, mr.mb[1]);
if (newq != NULL && newq != tq && tq->logout_sent == 0) {
cmn_err(CE_WARN, "ql_login_fabric_port(%d): logout of "
"dup loop_id=%xh, d_id=%xh", ha->instance,
newq->loop_id, newq->d_id.b24);
ql_send_logo(ha, newq, NULL);
}
tq->loop_id = mr.mb[1];
break;
case QL_LOOP_ID_USED:
d_id.b.al_pa = LSB(mr.mb[2]);
d_id.b.area = MSB(mr.mb[2]);
d_id.b.domain = LSB(mr.mb[1]);
newq = ql_d_id_to_queue(ha, d_id);
if (newq && (newq->loop_id != loop_id)) {
QL_PRINT_2(ha, "Loop ID is now "
"reassigned; old pairs: [%xh, %xh] and [%xh, %xh];"
"new pairs: [%xh, unknown] and [%xh, %xh]\n",
tq->d_id.b24, loop_id,
newq->d_id.b24, newq->loop_id, tq->d_id.b24,
newq->d_id.b24, loop_id);
if ((newq->d_id.b24 & 0xff) != (d_id.b24 & 0xff)) {
ADAPTER_STATE_LOCK(ha);
index = ql_alpa_to_index[newq->d_id.b.al_pa];
ql_add_link_b(&ha->dev[index], &newq->device);
newq->d_id.b24 = d_id.b24;
index = ql_alpa_to_index[d_id.b.al_pa];
ql_add_link_b(&ha->dev[index], &newq->device);
ADAPTER_STATE_UNLOCK(ha);
}
(void) ql_get_port_database(ha, newq, PDF_NONE);
}
tq->loop_id = PORT_NO_LOOP_ID;
break;
case QL_ALL_IDS_IN_USE:
rval = QL_FUNCTION_FAILED;
EL(ha, "no loop id's available\n");
break;
default:
if (rval == QL_COMMAND_ERROR) {
switch (mr.mb[1]) {
case 2:
case 3:
rval = QL_MEMORY_ALLOC_FAILED;
break;
case 0xd:
case 4:
rval = QL_FUNCTION_TIMEOUT;
break;
case 1:
case 5:
case 7:
rval = QL_FABRIC_NOT_INITIALIZED;
break;
default:
EL(ha, "cmd rtn; mb1=%xh\n", mr.mb[1]);
break;
}
} else {
cmn_err(CE_WARN, "%s(%d): login fabric port failed"
" D_ID=%xh, rval=%xh, mb1=%xh", QL_NAME,
ha->instance, tq->d_id.b24, rval, mr.mb[1]);
}
break;
}
if (rval != QL_SUCCESS && rval != QL_PORT_ID_USED &&
rval != QL_LOOP_ID_USED) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_logout_port(ql_adapter_state_t *ha, port_id_t d_id)
{
ql_link_t *link;
ql_tgt_t *tq;
uint16_t index;
QL_PRINT_3(ha, "started\n");
index = ql_alpa_to_index[d_id.b.al_pa];
tq = NULL;
for (link = ha->dev[index].first; link != NULL; link = link->next) {
tq = link->base_address;
if (tq->d_id.b24 == d_id.b24) {
break;
} else {
tq = NULL;
}
}
if (tq != NULL && tq->flags & TQF_FABRIC_DEVICE) {
(void) ql_logout_fabric_port(ha, tq);
tq->loop_id = PORT_NO_LOOP_ID;
}
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
ql_tgt_t *
ql_dev_init(ql_adapter_state_t *ha, port_id_t d_id, uint16_t loop_id)
{
ql_link_t *link;
uint16_t index;
ql_tgt_t *tq;
QL_PRINT_3(ha, "started, d_id=%xh, loop_id=%xh\n", d_id.b24, loop_id);
index = ql_alpa_to_index[d_id.b.al_pa];
for (link = ha->dev[index].first; link != NULL; link = link->next) {
tq = link->base_address;
if (tq->d_id.b24 == d_id.b24) {
tq->loop_id = loop_id;
tq->port_down_retry_count = ha->port_down_retry_count;
tq->qfull_retry_count = ha->qfull_retry_count;
break;
}
}
if (link == NULL) {
tq = (ql_tgt_t *)kmem_zalloc(sizeof (ql_tgt_t), KM_SLEEP);
if (tq != NULL) {
mutex_init(&tq->mutex, NULL, MUTEX_DRIVER,
ha->intr_pri);
tq->d_id.b24 = d_id.b24;
tq->loop_id = loop_id;
tq->device.base_address = tq;
tq->iidma_rate = IIDMA_RATE_INIT;
tq->port_down_retry_count = ha->port_down_retry_count;
tq->qfull_retry_count = ha->qfull_retry_count;
ql_add_link_b(&ha->dev[index], &tq->device);
}
}
if (tq == NULL) {
EL(ha, "failed, d_id=%xh, loop_id=%xh\n", d_id.b24, loop_id);
} else {
QL_PRINT_3(ha, "done\n");
}
return (tq);
}
void
ql_dev_free(ql_adapter_state_t *ha, ql_tgt_t *tq)
{
ql_link_t *link;
uint16_t index;
ql_lun_t *lq;
QL_PRINT_3(ha, "started\n");
for (link = tq->lun_queues.first; link != NULL; link = link->next) {
lq = link->base_address;
if (lq->cmd.first != NULL) {
EL(ha, "cmd %ph pending in lq=%ph, lun=%xh\n",
lq->cmd.first, lq, lq->lun_no);
return;
}
}
if (tq->outcnt == 0) {
index = ql_alpa_to_index[tq->d_id.b.al_pa];
for (link = ha->dev[index].first; link != NULL;
link = link->next) {
if (link->base_address == tq) {
ql_remove_link(&ha->dev[index], link);
link = tq->lun_queues.first;
while (link != NULL) {
lq = link->base_address;
link = link->next;
ql_remove_link(&tq->lun_queues,
&lq->link);
kmem_free(lq, sizeof (ql_lun_t));
}
mutex_destroy(&tq->mutex);
kmem_free(tq, sizeof (ql_tgt_t));
break;
}
}
}
QL_PRINT_3(ha, "done\n");
}
static ql_lun_t *
ql_lun_queue(ql_adapter_state_t *ha, ql_tgt_t *tq, uint64_t lun_addr)
{
ql_lun_t *lq;
ql_link_t *link;
uint16_t lun_no, lun_no_tmp;
fcp_ent_addr_t *fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
QL_PRINT_3(ha, "started\n");
if (tq->last_lun_queue != NULL && tq->last_lun_queue->lun_addr ==
lun_addr) {
QL_PRINT_3(ha, "fast done\n");
return (tq->last_lun_queue);
}
for (link = tq->lun_queues.first; link != NULL; link = link->next) {
lq = link->base_address;
if (lq->lun_addr == lun_addr) {
QL_PRINT_3(ha, "found done\n");
tq->last_lun_queue = lq;
return (lq);
}
}
if (fcp_ent_addr->ent_addr_1 != 0 || fcp_ent_addr->ent_addr_2 != 0 ||
fcp_ent_addr->ent_addr_3 != 0) {
EL(ha, "Unsupported LUN Addressing level=0x%llxh", lun_addr);
}
lun_no_tmp = CHAR_TO_SHORT(lobyte(fcp_ent_addr->ent_addr_0),
hibyte(fcp_ent_addr->ent_addr_0));
lun_no = lun_no_tmp & ~(QL_LUN_AM_MASK << 8);
if (lun_no_tmp & (QL_LUN_AM_LUN << 8)) {
EL(ha, "Unsupported first level LUN Addressing method=%xh, "
"lun=%d(%xh)\n", lun_no_tmp & (QL_LUN_AM_MASK << 8),
lun_no, lun_no_tmp);
}
lq = (ql_lun_t *)kmem_zalloc(sizeof (ql_lun_t), KM_SLEEP);
if (lq != NULL) {
lq->link.base_address = lq;
lq->target_queue = tq;
lq->lun_addr = lun_addr;
lq->lun_no = lun_no;
DEVICE_QUEUE_LOCK(tq);
ql_add_link_b(&tq->lun_queues, &lq->link);
DEVICE_QUEUE_UNLOCK(tq);
tq->last_lun_queue = lq;
}
QL_PRINT_3(ha, "done\n");
return (lq);
}
static int
ql_fcp_scsi_cmd(ql_adapter_state_t *ha, fc_packet_t *pkt, ql_srb_t *sp)
{
port_id_t d_id;
ql_tgt_t *tq;
uint64_t *ptr;
uint64_t fcp_ent_addr = 0;
QL_PRINT_3(ha, "started\n");
tq = (ql_tgt_t *)pkt->pkt_fca_device;
if (tq == NULL) {
d_id.r.rsvd_1 = 0;
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
tq = ql_d_id_to_queue(ha, d_id);
}
sp->fcp = (struct fcp_cmd *)pkt->pkt_cmd;
fcp_ent_addr = *(uint64_t *)(&sp->fcp->fcp_ent_addr);
if (tq != NULL &&
(sp->lun_queue = ql_lun_queue(ha, tq, fcp_ent_addr)) != NULL) {
ptr = (uint64_t *)pkt->pkt_resp;
*ptr++ = 0; *ptr++ = 0; *ptr++ = 0;
if ((sp->fcp->fcp_cntl.cntl_kill_tsk |
sp->fcp->fcp_cntl.cntl_clr_aca |
sp->fcp->fcp_cntl.cntl_reset_tgt |
sp->fcp->fcp_cntl.cntl_reset_lun |
sp->fcp->fcp_cntl.cntl_clr_tsk |
sp->fcp->fcp_cntl.cntl_abort_tsk) != 0) {
ql_task_mgmt(ha, tq, pkt, sp);
} else {
ha->pha->xioctl->IosRequested++;
ha->pha->xioctl->BytesRequested += (uint32_t)
sp->fcp->fcp_data_len;
sp->iocb = ha->fcp_cmd;
sp->req_cnt = 1;
if (sp->fcp->fcp_data_len != 0) {
if (sp->fcp->fcp_cntl.cntl_write_data) {
(void) ddi_dma_sync(pkt->pkt_data_dma,
0, 0, DDI_DMA_SYNC_FORDEV);
}
if (pkt->pkt_data_cookie_cnt > ha->cmd_segs &&
(!CFG_IST(ha, CFG_CTRL_82XX) ||
sp->sg_dma.dma_handle == NULL)) {
uint32_t cnt;
cnt = pkt->pkt_data_cookie_cnt -
ha->cmd_segs;
sp->req_cnt = (uint16_t)
(cnt / ha->cmd_cont_segs);
if (cnt % ha->cmd_cont_segs) {
sp->req_cnt = (uint16_t)
(sp->req_cnt + 2);
} else {
sp->req_cnt++;
}
}
}
QL_PRINT_3(ha, "done\n");
return (ql_start_cmd(ha, tq, pkt, sp));
}
} else {
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
if (!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) && pkt->pkt_comp) {
ql_io_comp(sp);
}
}
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static void
ql_task_mgmt(ql_adapter_state_t *ha, ql_tgt_t *tq, fc_packet_t *pkt,
ql_srb_t *sp)
{
fcp_rsp_t *fcpr;
struct fcp_rsp_info *rsp;
ql_lun_t *lq = sp->lun_queue;
QL_PRINT_3(ha, "started\n");
fcpr = (fcp_rsp_t *)pkt->pkt_resp;
rsp = (struct fcp_rsp_info *)(pkt->pkt_resp + sizeof (fcp_rsp_t));
bzero(fcpr, pkt->pkt_rsplen);
fcpr->fcp_u.fcp_status.rsp_len_set = 1;
fcpr->fcp_response_len = 8;
if (sp->fcp->fcp_cntl.cntl_clr_aca) {
if (ql_clear_aca(ha, tq, lq) != QL_SUCCESS) {
rsp->rsp_code = FCP_TASK_MGMT_FAILED;
}
} else if (sp->fcp->fcp_cntl.cntl_reset_lun) {
if (ql_lun_reset(ha, tq, lq) != QL_SUCCESS) {
rsp->rsp_code = FCP_TASK_MGMT_FAILED;
}
} else if (sp->fcp->fcp_cntl.cntl_reset_tgt) {
if (ql_target_reset(ha, tq, ha->loop_reset_delay) !=
QL_SUCCESS) {
rsp->rsp_code = FCP_TASK_MGMT_FAILED;
}
} else if (sp->fcp->fcp_cntl.cntl_clr_tsk) {
if (ql_clear_task_set(ha, tq, lq) != QL_SUCCESS) {
rsp->rsp_code = FCP_TASK_MGMT_FAILED;
}
} else if (sp->fcp->fcp_cntl.cntl_abort_tsk) {
if (ql_abort_task_set(ha, tq, lq) != QL_SUCCESS) {
rsp->rsp_code = FCP_TASK_MGMT_FAILED;
}
} else {
rsp->rsp_code = FCP_TASK_MGMT_NOT_SUPPTD;
}
pkt->pkt_state = FC_PKT_SUCCESS;
if (!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) && pkt->pkt_comp) {
ql_io_comp(sp);
}
QL_PRINT_3(ha, "done\n");
}
static int
ql_fcp_ip_cmd(ql_adapter_state_t *ha, fc_packet_t *pkt, ql_srb_t *sp)
{
port_id_t d_id;
ql_tgt_t *tq;
QL_PRINT_3(ha, "started\n");
tq = (ql_tgt_t *)pkt->pkt_fca_device;
if (tq == NULL) {
d_id.r.rsvd_1 = 0;
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
tq = ql_d_id_to_queue(ha, d_id);
}
if (tq != NULL && (sp->lun_queue = ql_lun_queue(ha, tq, 0)) != NULL) {
(void) ddi_dma_sync(pkt->pkt_cmd_dma,
0, 0, DDI_DMA_SYNC_FORDEV);
sp->iocb = ha->ip_cmd;
if (pkt->pkt_cmd_cookie_cnt > ha->cmd_segs) {
uint32_t cnt;
cnt = pkt->pkt_cmd_cookie_cnt - ha->cmd_segs;
sp->req_cnt = (uint16_t)(cnt / ha->cmd_cont_segs);
if (cnt % ha->cmd_cont_segs) {
sp->req_cnt = (uint16_t)(sp->req_cnt + 2);
} else {
sp->req_cnt++;
}
} else {
sp->req_cnt = 1;
}
QL_PRINT_3(ha, "done\n");
return (ql_start_cmd(ha, tq, pkt, sp));
} else {
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
if (!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) && pkt->pkt_comp)
ql_io_comp(sp);
}
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
static int
ql_fc_services(ql_adapter_state_t *ha, fc_packet_t *pkt)
{
uint32_t cnt;
fc_ct_header_t hdr;
la_els_rjt_t rjt;
port_id_t d_id;
ql_tgt_t *tq;
ql_srb_t *sp;
int rval;
QL_PRINT_3(ha, "started\n");
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&hdr,
(uint8_t *)pkt->pkt_cmd, sizeof (hdr), DDI_DEV_AUTOINCR);
bzero(&rjt, sizeof (rjt));
cnt = (uint32_t)((uint32_t)(hdr.ct_aiusize * 4) +
sizeof (fc_ct_header_t));
if (cnt > (uint32_t)pkt->pkt_rsplen) {
EL(ha, "FC_ELS_MALFORMED, cnt=%xh, size=%xh\n", cnt,
pkt->pkt_rsplen);
return (FC_ELS_MALFORMED);
}
switch (hdr.ct_fcstype) {
case FCSTYPE_DIRECTORY:
case FCSTYPE_MGMTSERVICE:
ql_cthdr_endian(pkt->pkt_cmd_acc, pkt->pkt_cmd, B_FALSE);
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
tq = ql_d_id_to_queue(ha, d_id);
sp = (ql_srb_t *)pkt->pkt_fca_private;
if (tq == NULL ||
(sp->lun_queue = ql_lun_queue(ha, tq, 0)) == NULL) {
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_NO_CONNECTION;
rval = QL_SUCCESS;
break;
}
if (tq->flags & TQF_LOGIN_NEEDED) {
DEVICE_QUEUE_LOCK(tq);
tq->flags &= ~TQF_LOGIN_NEEDED;
DEVICE_QUEUE_UNLOCK(tq);
(void) ql_login_fport(ha, tq, tq->loop_id, LFF_NONE,
NULL);
}
(void) ddi_dma_sync(pkt->pkt_cmd_dma, 0, 0,
DDI_DMA_SYNC_FORDEV);
sp->flags |= SRB_MS_PKT;
sp->retry_count = 32;
sp->iocb = ha->ms_cmd;
if (pkt->pkt_resp_cookie_cnt > MS_DATA_SEGMENTS) {
cnt = pkt->pkt_resp_cookie_cnt - MS_DATA_SEGMENTS;
sp->req_cnt =
(uint16_t)(cnt / ha->cmd_cont_segs);
if (cnt % ha->cmd_cont_segs) {
sp->req_cnt = (uint16_t)(sp->req_cnt + 2);
} else {
sp->req_cnt++;
}
} else {
sp->req_cnt = 1;
}
rval = ql_start_cmd(ha, tq, pkt, sp);
QL_PRINT_3(ha, "done, ql_start_cmd=%xh\n", rval);
return (rval);
default:
EL(ha, "unknown fcstype=%xh\n", hdr.ct_fcstype);
rval = QL_FUNCTION_PARAMETER_ERROR;
break;
}
if (rval != QL_SUCCESS) {
rjt.ls_code.ls_code = LA_ELS_RJT;
rjt.reason = FC_REASON_CMD_UNSUPPORTED;
ddi_rep_put8(pkt->pkt_resp_acc, (uint8_t *)&rjt,
(uint8_t *)pkt->pkt_resp, sizeof (rjt), DDI_DEV_AUTOINCR);
pkt->pkt_state = FC_PKT_LOCAL_RJT;
pkt->pkt_reason = FC_REASON_UNSUPPORTED;
EL(ha, "LA_ELS_RJT, FC_REASON_UNSUPPORTED\n");
}
if (!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) && pkt->pkt_comp) {
ql_io_comp((ql_srb_t *)pkt->pkt_fca_private);
}
QL_PRINT_3(ha, "done\n");
return (FC_SUCCESS);
}
void
ql_cthdr_endian(ddi_acc_handle_t acc_handle, caddr_t ct_hdr,
boolean_t restore)
{
uint8_t i, *bp;
fc_ct_header_t hdr;
uint32_t *hdrp = (uint32_t *)&hdr;
ddi_rep_get8(acc_handle, (uint8_t *)&hdr,
(uint8_t *)ct_hdr, sizeof (hdr), DDI_DEV_AUTOINCR);
if (restore) {
for (i = 0; i < ((sizeof (hdr)) / (sizeof (uint32_t))); i++) {
*hdrp = BE_32(*hdrp);
hdrp++;
}
}
if (hdr.ct_fcstype == FCSTYPE_DIRECTORY) {
bp = (uint8_t *)ct_hdr + sizeof (fc_ct_header_t);
switch (hdr.ct_cmdrsp) {
case NS_GA_NXT:
case NS_GPN_ID:
case NS_GNN_ID:
case NS_GCS_ID:
case NS_GFT_ID:
case NS_GSPN_ID:
case NS_GPT_ID:
case NS_GID_FT:
case NS_GID_PT:
case NS_RPN_ID:
case NS_RNN_ID:
case NS_RSPN_ID:
case NS_DA_ID:
BIG_ENDIAN_32(bp);
break;
case NS_RFT_ID:
case NS_RCS_ID:
case NS_RPT_ID:
BIG_ENDIAN_32(bp);
bp += 4;
BIG_ENDIAN_32(bp);
break;
case NS_GNN_IP:
case NS_GIPA_IP:
BIG_ENDIAN(bp, 16);
break;
case NS_RIP_NN:
bp += 8;
BIG_ENDIAN(bp, 16);
break;
case NS_RIPA_NN:
bp += 8;
BIG_ENDIAN_64(bp);
break;
default:
break;
}
}
if (restore == B_FALSE) {
for (i = 0; i < ((sizeof (hdr)) / (sizeof (uint32_t))); i++) {
*hdrp = BE_32(*hdrp);
hdrp++;
}
}
ddi_rep_put8(acc_handle, (uint8_t *)&hdr,
(uint8_t *)ct_hdr, sizeof (hdr), DDI_DEV_AUTOINCR);
}
static int
ql_start_cmd(ql_adapter_state_t *ha, ql_tgt_t *tq, fc_packet_t *pkt,
ql_srb_t *sp)
{
int rval = FC_SUCCESS;
time_t poll_wait = 0;
ql_lun_t *lq = sp->lun_queue;
QL_PRINT_3(ha, "started\n");
sp->handle = 0;
if (pkt->pkt_tran_flags & FC_TRAN_NO_INTR) {
sp->flags |= SRB_POLL;
if (pkt->pkt_timeout == 0) {
pkt->pkt_timeout = SCSI_POLL_TIMEOUT;
}
}
DEVICE_QUEUE_LOCK(tq);
if (tq->flags & (TQF_RSCN_RCVD | TQF_NEED_AUTHENTICATION)) {
DEVICE_QUEUE_UNLOCK(tq);
EL(ha, "failed, FC_DEVICE_BUSY=%xh, d_id=%xh\n", tq->flags,
tq->d_id.b24);
return (FC_DEVICE_BUSY);
}
if (!(pkt->pkt_tran_flags & FC_TRAN_DUMPING)) {
ql_timeout_insert(ha, tq, sp);
} else {
sp->flags |= SRB_POLL;
sp->init_wdg_q_time = 0;
sp->isp_timeout = 0;
}
if (sp->flags & SRB_POLL) {
if (sp->flags & SRB_WATCHDOG_ENABLED) {
poll_wait = (sp->wdg_q_time + 2) * WATCHDOG_TIME;
} else {
poll_wait = pkt->pkt_timeout;
}
}
if (ha->pha->flags & ABORT_CMDS_LOOP_DOWN_TMO &&
(CFG_IST(ha, CFG_ENABLE_LINK_DOWN_REPORTING))) {
sp->pkt->pkt_reason = CS_PORT_UNAVAILABLE;
sp->cmd.next = NULL;
DEVICE_QUEUE_UNLOCK(tq);
ql_done(&sp->cmd, B_FALSE);
} else {
if (ddi_in_panic() && (sp->flags & SRB_POLL)) {
int do_lip = 0;
DEVICE_QUEUE_UNLOCK(tq);
ADAPTER_STATE_LOCK(ha);
if ((do_lip = ha->pha->lip_on_panic) == 0) {
ha->pha->lip_on_panic++;
}
ADAPTER_STATE_UNLOCK(ha);
if (!do_lip) {
(void) ql_abort_isp(ha);
}
ql_start_iocb(ha, sp);
} else {
if (pkt->pkt_tran_flags & FC_TRAN_HI_PRIORITY) {
ql_add_link_t(&lq->cmd, &sp->cmd);
} else {
ql_add_link_b(&lq->cmd, &sp->cmd);
}
sp->flags |= SRB_IN_DEVICE_QUEUE;
ql_next(ha, lq);
}
}
if (poll_wait) {
if (ql_poll_cmd(ha, sp, poll_wait) != QL_SUCCESS &&
pkt->pkt_state == FC_PKT_SUCCESS) {
pkt->pkt_state = FC_PKT_TIMEOUT;
pkt->pkt_reason = FC_REASON_HW_ERROR;
}
if (pkt->pkt_state != FC_PKT_SUCCESS) {
EL(ha, "failed, FC_TRANSPORT_ERROR\n");
rval = FC_TRANSPORT_ERROR;
}
if (ddi_in_panic()) {
if (pkt->pkt_state != FC_PKT_SUCCESS) {
port_id_t d_id;
d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
(void) ql_login_port(ha, d_id);
}
}
(void) qlc_fm_check_pkt_dma_handle(ha, sp);
if (!(pkt->pkt_tran_flags & FC_TRAN_NO_INTR) &&
pkt->pkt_comp) {
sp->flags &= ~SRB_POLL;
(*pkt->pkt_comp)(pkt);
}
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_poll_cmd(ql_adapter_state_t *vha, ql_srb_t *sp, time_t poll_wait)
{
uint32_t index;
int rval = QL_SUCCESS;
time_t msecs_left = poll_wait * 100;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_3(ha, "started\n");
while (sp->flags & SRB_POLL) {
if ((ha->flags & INTERRUPTS_ENABLED) == 0 ||
ha->idle_timer >= 15 || ddi_in_panic() ||
curthread->t_flag & T_INTR_THREAD) {
if (ha->port_retry_timer != 0) {
ADAPTER_STATE_LOCK(ha);
ha->port_retry_timer = 0;
ADAPTER_STATE_UNLOCK(ha);
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= PORT_RETRY_NEEDED;
TASK_DAEMON_UNLOCK(ha);
}
ADAPTER_STATE_LOCK(ha);
ha->flags |= POLL_INTR;
ADAPTER_STATE_UNLOCK(ha);
if (INTERRUPT_PENDING(ha)) {
(void) ql_isr_aif((caddr_t)ha, 0);
INTR_LOCK(ha);
ha->intr_claimed = TRUE;
INTR_UNLOCK(ha);
}
if (ha->flags & NO_INTR_HANDSHAKE) {
for (index = 0; index < ha->rsp_queues_cnt;
index++) {
(void) ql_isr_aif((caddr_t)ha,
(caddr_t)((uintptr_t)(index + 1)));
}
}
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~POLL_INTR;
ADAPTER_STATE_UNLOCK(ha);
TASK_DAEMON_LOCK(ha);
if (!ddi_in_panic() && QL_DAEMON_NOT_ACTIVE(ha) &&
QL_TASK_PENDING(ha)) {
ql_task_thread(ha);
}
TASK_DAEMON_UNLOCK(ha);
}
if (msecs_left == 0) {
if (rval == QL_SUCCESS) {
EL(ha, "timeout\n");
rval = QL_FUNCTION_TIMEOUT;
if (ql_abort_io(ha, sp) == QL_SUCCESS) {
sp->pkt->pkt_reason = CS_ABORTED;
sp->cmd.next = NULL;
ql_done(&sp->cmd, B_FALSE);
break;
}
sp->flags |= SRB_COMMAND_TIMEOUT;
EL(ha, "abort failed, isp_abort_needed\n");
ql_awaken_task_daemon(ha, NULL,
ISP_ABORT_NEEDED, 0);
msecs_left = 30 * 100;
} else {
break;
}
}
ql_delay(ha, 10000);
msecs_left -= 10;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
void
ql_next(ql_adapter_state_t *vha, ql_lun_t *lq)
{
ql_srb_t *sp;
ql_link_t *link;
ql_tgt_t *tq = lq->target_queue;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_3(ha, "started\n");
if (ddi_in_panic()) {
DEVICE_QUEUE_UNLOCK(tq);
QL_PRINT_3(ha, "panic/active exit\n");
return;
}
while ((link = lq->cmd.first) != NULL) {
sp = link->base_address;
if (DRIVER_SUSPENDED(ha) ||
(ha->flags & ONLINE) == 0 ||
!VALID_DEVICE_ID(ha, tq->loop_id) ||
tq->flags & (TQF_RSCN_RCVD | TQF_NEED_AUTHENTICATION |
TQF_QUEUE_SUSPENDED)) {
EL(vha, "break, d_id=%xh, tdf=%xh, tqf=%xh, spf=%xh, "
"haf=%xh, loop_id=%xh sp=%ph\n", tq->d_id.b24,
ha->task_daemon_flags, tq->flags, sp->flags,
ha->flags, tq->loop_id, sp);
break;
}
if (sp->flags & SRB_FCP_CMD_PKT) {
if (lq->flags & LQF_UNTAGGED_PENDING ||
lq->lun_outcnt >= ha->execution_throttle) {
QL_PRINT_8(ha, "break, d_id=%xh, "
"lf=%xh, lun_outcnt=%xh\n",
tq->d_id.b24, lq->flags, lq->lun_outcnt);
break;
}
if (sp->fcp->fcp_cntl.cntl_qtype ==
FCP_QTYPE_UNTAGGED) {
lq->flags |= LQF_UNTAGGED_PENDING;
}
lq->lun_outcnt++;
}
ql_remove_link(&lq->cmd, &sp->cmd);
sp->flags &= ~SRB_IN_DEVICE_QUEUE;
tq->outcnt++;
ql_start_iocb(vha, sp);
}
DEVICE_QUEUE_UNLOCK(tq);
QL_PRINT_3(ha, "done\n");
}
void
ql_done(ql_link_t *link, boolean_t cmplt)
{
ql_adapter_state_t *ha;
ql_link_t *next_link;
ql_srb_t *sp;
ql_tgt_t *tq;
ql_lun_t *lq;
uint64_t set_flags;
QL_PRINT_3(NULL, "started\n");
for (; link != NULL; link = next_link) {
next_link = link->next;
sp = link->base_address;
link->prev = link->next = NULL;
link->head = NULL;
ha = sp->ha;
set_flags = 0;
if (sp->flags & SRB_UB_CALLBACK) {
QL_UB_LOCK(ha);
if (sp->flags & SRB_UB_IN_ISP) {
if (ha->ub_outcnt != 0) {
ha->ub_outcnt--;
}
if (ha->flags & IP_ENABLED) {
set_flags |= NEED_UNSOLICITED_BUFFERS;
}
}
QL_UB_UNLOCK(ha);
ql_awaken_task_daemon(ha, sp, set_flags, 0);
} else {
INTR_LOCK(ha);
if (sp->handle != 0) {
EL(ha, "free sp=%ph, sp->hdl=%xh\n",
(void *)sp, sp->handle);
ha->pha->outstanding_cmds[
sp->handle & OSC_INDEX_MASK] = NULL;
sp->handle = 0;
sp->flags &= ~SRB_IN_TOKEN_ARRAY;
}
INTR_UNLOCK(ha);
lq = sp->lun_queue;
tq = lq->target_queue;
DEVICE_QUEUE_LOCK(tq);
if (tq->outcnt != 0) {
tq->outcnt--;
}
if (sp->flags & SRB_FCP_CMD_PKT) {
if (sp->fcp->fcp_cntl.cntl_qtype ==
FCP_QTYPE_UNTAGGED) {
lq->flags &= ~LQF_UNTAGGED_PENDING;
}
if (lq->lun_outcnt != 0) {
lq->lun_outcnt--;
}
}
if (sp->pkt->pkt_reason == CS_COMPLETE) {
tq->port_down_retry_count =
ha->port_down_retry_count;
tq->qfull_retry_count = ha->qfull_retry_count;
}
if (CFG_IST(ha, CFG_FAST_TIMEOUT) &&
(sp->flags & (SRB_MS_PKT | SRB_ELS_PKT) ||
!(tq->flags & TQF_NEED_AUTHENTICATION)) &&
sp->flags & SRB_RETRY &&
(sp->flags & SRB_WATCHDOG_ENABLED &&
sp->wdg_q_time > 1)) {
EL(ha, "fast abort modify change\n");
sp->flags &= ~(SRB_RETRY);
sp->pkt->pkt_reason = CS_TIMEOUT;
}
if ((sp->flags & (SRB_MS_PKT | SRB_ELS_PKT) ||
!(tq->flags & TQF_NEED_AUTHENTICATION)) &&
sp->flags & SRB_RETRY &&
(sp->flags & SRB_WATCHDOG_ENABLED &&
sp->wdg_q_time > 1)) {
sp->flags &= ~(SRB_ISP_STARTED |
SRB_ISP_COMPLETED | SRB_RETRY);
sp->wdg_q_time = sp->init_wdg_q_time;
if (!(ha->task_daemon_flags & LOOP_DOWN) &&
(sp->pkt->pkt_reason == CS_RESET ||
(CFG_IST(ha, CFG_ISP_FW_TYPE_2) &&
sp->pkt->pkt_reason == CS_ABORTED))) {
(void) ql_marker(ha, tq->loop_id, 0,
MK_SYNC_ID);
}
ql_add_link_t(&lq->cmd, &sp->cmd);
sp->flags |= SRB_IN_DEVICE_QUEUE;
ql_next(ha, lq);
} else {
if (sp->flags & SRB_WATCHDOG_ENABLED) {
ql_remove_link(&tq->wdg, &sp->wdg);
sp->flags &= ~SRB_WATCHDOG_ENABLED;
}
if (lq->cmd.first != NULL) {
ql_next(ha, lq);
} else {
DEVICE_QUEUE_UNLOCK(tq);
if (ha->pha->pending_cmds.first !=
NULL) {
ql_start_iocb(ha, NULL);
}
}
if (sp->flags & (SRB_MS_PKT | SRB_ELS_PKT)) {
(void) ddi_dma_sync(
sp->pkt->pkt_resp_dma,
0, 0, DDI_DMA_SYNC_FORCPU);
}
sp->pkt->pkt_expln = FC_EXPLN_NONE;
sp->pkt->pkt_action = FC_ACTION_RETRYABLE;
switch (sp->pkt->pkt_reason) {
case CS_COMPLETE:
sp->pkt->pkt_state = FC_PKT_SUCCESS;
break;
case CS_RESET:
sp->pkt->pkt_state =
FC_PKT_PORT_OFFLINE;
sp->pkt->pkt_reason =
FC_REASON_ABORTED;
break;
case CS_RESOUCE_UNAVAILABLE:
sp->pkt->pkt_state = FC_PKT_LOCAL_BSY;
sp->pkt->pkt_reason =
FC_REASON_PKT_BUSY;
break;
case CS_TIMEOUT:
sp->pkt->pkt_state = FC_PKT_TIMEOUT;
sp->pkt->pkt_reason =
FC_REASON_HW_ERROR;
break;
case CS_DATA_OVERRUN:
sp->pkt->pkt_state = FC_PKT_LOCAL_RJT;
sp->pkt->pkt_reason =
FC_REASON_OVERRUN;
break;
case CS_PORT_UNAVAILABLE:
case CS_PORT_LOGGED_OUT:
sp->pkt->pkt_state =
FC_PKT_PORT_OFFLINE;
sp->pkt->pkt_reason =
FC_REASON_LOGIN_REQUIRED;
ql_send_logo(ha, tq, NULL);
break;
case CS_PORT_CONFIG_CHG:
sp->pkt->pkt_state =
FC_PKT_PORT_OFFLINE;
sp->pkt->pkt_reason =
FC_REASON_OFFLINE;
break;
case CS_QUEUE_FULL:
sp->pkt->pkt_state = FC_PKT_LOCAL_RJT;
sp->pkt->pkt_reason = FC_REASON_QFULL;
break;
case CS_ABORTED:
DEVICE_QUEUE_LOCK(tq);
if (tq->flags & (TQF_RSCN_RCVD |
TQF_NEED_AUTHENTICATION)) {
sp->pkt->pkt_state =
FC_PKT_PORT_OFFLINE;
sp->pkt->pkt_reason =
FC_REASON_LOGIN_REQUIRED;
} else {
sp->pkt->pkt_state =
FC_PKT_LOCAL_RJT;
sp->pkt->pkt_reason =
FC_REASON_ABORTED;
}
DEVICE_QUEUE_UNLOCK(tq);
break;
case CS_TRANSPORT:
case CS_DEV_NOT_READY:
sp->pkt->pkt_state = FC_PKT_LOCAL_RJT;
sp->pkt->pkt_reason =
FC_PKT_TRAN_ERROR;
break;
case CS_DATA_UNDERRUN:
sp->pkt->pkt_state = FC_PKT_LOCAL_RJT;
sp->pkt->pkt_reason =
FC_REASON_UNDERRUN;
break;
case CS_DMA_ERROR:
case CS_BAD_PAYLOAD:
case CS_UNKNOWN:
case CS_CMD_FAILED:
default:
sp->pkt->pkt_state = FC_PKT_LOCAL_RJT;
sp->pkt->pkt_reason =
FC_REASON_HW_ERROR;
break;
}
(void) qlc_fm_check_pkt_dma_handle(ha, sp);
if (sp->flags & SRB_POLL) {
sp->flags &= ~SRB_POLL;
} else if (cmplt == B_TRUE &&
sp->pkt->pkt_comp) {
(sp->pkt->pkt_comp)(sp->pkt);
} else {
ql_io_comp(sp);
}
}
}
}
QL_PRINT_3(ha, "done\n");
}
void
ql_awaken_task_daemon(ql_adapter_state_t *vha, ql_srb_t *sp,
uint64_t set_flags, uint64_t reset_flags)
{
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_3(ha, "started, sp=%p set_flags=%llx reset_flags=%llx\n",
sp, set_flags, reset_flags);
TASK_DAEMON_LOCK(ha);
if (set_flags) {
ha->task_daemon_flags |= set_flags;
}
if (reset_flags) {
ha->task_daemon_flags &= ~reset_flags;
}
if (!(ha->task_daemon_flags & TASK_DAEMON_ALIVE_FLG)) {
EL(ha, "done, not alive dtf=%xh\n", ha->task_daemon_flags);
TASK_DAEMON_UNLOCK(ha);
return;
}
if (sp != NULL) {
if (sp->flags & SRB_UB_CALLBACK) {
ql_add_link_b(&ha->unsol_callback_queue, &sp->cmd);
} else {
EL(ha, "sp=%p, spf=%xh is not SRB_UB_CALLBACK",
sp->flags);
}
}
if (!ha->driver_thread_awake) {
QL_PRINT_3(ha, "driver_thread_awake\n");
cv_broadcast(&ha->cv_task_daemon);
}
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
static void
ql_task_daemon(void *arg)
{
ql_adapter_state_t *ha = (void *)arg;
QL_PRINT_3(ha, "started\n");
TASK_DAEMON_LOCK(ha);
while ((ha->task_daemon_flags & TASK_DAEMON_STOP_FLG) == 0) {
ql_task_thread(ha);
if (ha->task_daemon_flags & TASK_DAEMON_STOP_FLG) {
break;
}
QL_PRINT_3(ha, "Going to sleep\n");
ha->task_daemon_flags |= TASK_DAEMON_SLEEPING_FLG;
if (cv_wait_sig(&ha->cv_task_daemon,
&ha->task_daemon_mutex) == 0) {
QL_PRINT_10(ha, "killed\n");
break;
}
QL_PRINT_3(ha, "Awakened\n");
ha->task_daemon_flags &= ~TASK_DAEMON_SLEEPING_FLG;
}
ha->task_daemon_flags &= ~(TASK_DAEMON_SLEEPING_FLG |
TASK_DAEMON_ALIVE_FLG);
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
static void
ql_task_thread(ql_adapter_state_t *ha)
{
boolean_t loop_again;
ql_srb_t *sp;
ql_link_t *link;
caddr_t msg;
ql_adapter_state_t *vha;
ha->driver_thread_awake++;
do {
loop_again = B_FALSE;
if (ha->sf != ha->flags ||
(ha->task_daemon_flags & ~DTF_EL_MSG_SKIP_FLGS) != ha->df ||
ha->cf != ha->cfg_flags) {
ha->sf = ha->flags;
ha->df = ha->task_daemon_flags & ~DTF_EL_MSG_SKIP_FLGS;
ha->cf = ha->cfg_flags;
EL(ha, "df=%xh, sf=%xh, cf=%xh\n",
ha->df, ha->sf, ha->cf);
}
QL_PM_LOCK(ha);
if (ha->power_level != PM_LEVEL_D0) {
QL_PM_UNLOCK(ha);
ha->task_daemon_flags |= DRIVER_STALL |
TASK_DAEMON_STALLED_FLG;
break;
}
QL_PM_UNLOCK(ha);
if (ha->flags & ADAPTER_SUSPENDED) {
ha->task_daemon_flags |= TASK_DAEMON_STALLED_FLG;
break;
}
while (ha->flags & (IDC_STALL_NEEDED | IDC_RESTART_NEEDED |
IDC_ACK_NEEDED)) {
TASK_DAEMON_UNLOCK(ha);
ql_idc(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags &
(TASK_DAEMON_STOP_FLG | DRIVER_STALL) ||
!(ha->flags & ONLINE)) {
ha->task_daemon_flags |= TASK_DAEMON_STALLED_FLG;
break;
}
ha->task_daemon_flags &= ~TASK_DAEMON_STALLED_FLG;
if (ha->errlog[0] != 0 &&
!(ha->task_daemon_flags & ISP_ABORT_NEEDED)) {
TASK_DAEMON_UNLOCK(ha);
(void) ql_flash_errlog(ha, ha->errlog[0],
ha->errlog[1], ha->errlog[2], ha->errlog[3]);
ha->errlog[0] = 0;
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & TASK_DAEMON_IDLE_CHK_FLG) {
ha->task_daemon_flags &= ~TASK_DAEMON_IDLE_CHK_FLG;
if (!DRIVER_SUSPENDED(ha)) {
TASK_DAEMON_UNLOCK(ha);
ql_idle_check(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
}
if (ha->task_daemon_flags & HANDLE_PORT_BYPASS_CHANGE) {
ha->task_daemon_flags &= ~HANDLE_PORT_BYPASS_CHANGE;
TASK_DAEMON_UNLOCK(ha);
(void) ql_initiate_lip(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & ABORT_QUEUES_NEEDED) {
ha->task_daemon_flags &= ~ABORT_QUEUES_NEEDED;
if (ha->flags & ABORT_CMDS_LOOP_DOWN_TMO) {
TASK_DAEMON_UNLOCK(ha);
ql_abort_queues(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
}
if (!DRIVER_SUSPENDED(ha) &&
ha->task_daemon_flags & SUSPENDED_WAKEUP_FLG) {
ha->task_daemon_flags &= ~SUSPENDED_WAKEUP_FLG;
cv_broadcast(&ha->cv_dr_suspended);
loop_again = B_TRUE;
}
for (vha = ha; vha != NULL; vha = vha->vp_next) {
if (vha->task_daemon_flags & RSCN_UPDATE_NEEDED) {
vha->task_daemon_flags &= ~RSCN_UPDATE_NEEDED;
TASK_DAEMON_UNLOCK(ha);
(void) ql_handle_rscn_update(vha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
}
for (vha = ha; vha != NULL; vha = vha->vp_next) {
if (vha->task_daemon_flags & FC_STATE_CHANGE &&
!(ha->task_daemon_flags &
TASK_DAEMON_POWERING_DOWN)) {
EL(vha, "state change = %xh\n", vha->state);
vha->task_daemon_flags &= ~FC_STATE_CHANGE;
if (vha->task_daemon_flags &
COMMAND_WAIT_NEEDED) {
vha->task_daemon_flags &=
~COMMAND_WAIT_NEEDED;
if (!(ha->task_daemon_flags &
COMMAND_WAIT_ACTIVE)) {
ha->task_daemon_flags |=
COMMAND_WAIT_ACTIVE;
TASK_DAEMON_UNLOCK(ha);
ql_cmd_wait(ha);
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &=
~COMMAND_WAIT_ACTIVE;
loop_again = B_TRUE;
}
}
msg = NULL;
if (FC_PORT_STATE_MASK(vha->state) ==
FC_STATE_OFFLINE) {
if (vha->task_daemon_flags &
STATE_ONLINE) {
if (ha->topology &
QL_LOOP_CONNECTION) {
msg = "Loop OFFLINE";
} else {
msg = "Link OFFLINE";
}
}
vha->task_daemon_flags &=
~STATE_ONLINE;
} else if (FC_PORT_STATE_MASK(vha->state) ==
FC_STATE_LOOP) {
if (!(vha->task_daemon_flags &
STATE_ONLINE)) {
msg = "Loop ONLINE";
}
vha->task_daemon_flags |= STATE_ONLINE;
} else if (FC_PORT_STATE_MASK(vha->state) ==
FC_STATE_ONLINE) {
if (!(vha->task_daemon_flags &
STATE_ONLINE)) {
msg = "Link ONLINE";
}
vha->task_daemon_flags |= STATE_ONLINE;
} else {
msg = "Unknown Link state";
}
if (msg != NULL) {
cmn_err(CE_NOTE, "!Qlogic %s(%d,%d): "
"%s", QL_NAME, ha->instance,
vha->vp_index, msg);
}
if (vha->flags & FCA_BOUND) {
QL_PRINT_10(vha, "statec_"
"cb state=%xh\n",
vha->state);
TASK_DAEMON_UNLOCK(ha);
(vha->bind_info.port_statec_cb)
(vha->bind_info.port_handle,
vha->state);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
}
}
if (ha->task_daemon_flags & NEED_UNSOLICITED_BUFFERS &&
ha->task_daemon_flags & FIRMWARE_UP) {
ha->task_daemon_flags &= ~NEED_UNSOLICITED_BUFFERS;
TASK_DAEMON_UNLOCK(ha);
ql_isp_rcvbuf(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & WATCHDOG_NEEDED) {
ha->task_daemon_flags &= ~WATCHDOG_NEEDED;
TASK_DAEMON_UNLOCK(ha);
ql_watchdog(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & ISP_ABORT_NEEDED) {
TASK_DAEMON_UNLOCK(ha);
(void) ql_abort_isp(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (!(ha->task_daemon_flags & (COMMAND_WAIT_NEEDED |
ABORT_QUEUES_NEEDED | ISP_ABORT_NEEDED | LOOP_DOWN)) &&
ha->task_daemon_flags & FIRMWARE_UP) {
if (ha->task_daemon_flags & MARKER_NEEDED) {
if (!(ha->task_daemon_flags & MARKER_ACTIVE)) {
ha->task_daemon_flags |= MARKER_ACTIVE;
ha->task_daemon_flags &= ~MARKER_NEEDED;
TASK_DAEMON_UNLOCK(ha);
for (vha = ha; vha != NULL;
vha = vha->vp_next) {
(void) ql_marker(vha, 0, 0,
MK_SYNC_ALL);
}
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~MARKER_ACTIVE;
TASK_DAEMON_UNLOCK(ha);
ql_restart_queues(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
} else {
ha->task_daemon_flags &= ~MARKER_NEEDED;
}
}
if (ha->task_daemon_flags & LOOP_RESYNC_NEEDED) {
if (!(ha->task_daemon_flags &
LOOP_RESYNC_ACTIVE)) {
ha->task_daemon_flags |=
LOOP_RESYNC_ACTIVE;
TASK_DAEMON_UNLOCK(ha);
ql_loop_resync(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
}
}
if (ha->task_daemon_flags & PORT_RETRY_NEEDED) {
ha->task_daemon_flags &= ~PORT_RETRY_NEEDED;
ADAPTER_STATE_LOCK(ha);
ha->port_retry_timer = 0;
ADAPTER_STATE_UNLOCK(ha);
TASK_DAEMON_UNLOCK(ha);
ql_restart_queues(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & TD_IIDMA_NEEDED) {
ha->task_daemon_flags &= ~TD_IIDMA_NEEDED;
TASK_DAEMON_UNLOCK(ha);
ql_iidma(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & SEND_PLOGI) {
ha->task_daemon_flags &= ~SEND_PLOGI;
TASK_DAEMON_UNLOCK(ha);
(void) ql_n_port_plogi(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->unsol_callback_queue.first != NULL) {
sp = (ha->unsol_callback_queue.first)->base_address;
link = &sp->cmd;
ql_remove_link(&ha->unsol_callback_queue, link);
TASK_DAEMON_UNLOCK(ha);
ql_unsol_callback(sp);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & IDC_POLL_NEEDED) {
ha->task_daemon_flags &= ~IDC_POLL_NEEDED;
TASK_DAEMON_UNLOCK(ha);
ql_8021_idc_poll(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
if (ha->task_daemon_flags & LED_BLINK) {
ha->task_daemon_flags &= ~LED_BLINK;
TASK_DAEMON_UNLOCK(ha);
ql_blink_led(ha);
TASK_DAEMON_LOCK(ha);
loop_again = B_TRUE;
}
} while (loop_again == B_TRUE);
if (ha->driver_thread_awake) {
ha->driver_thread_awake--;
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_idle_check(ql_adapter_state_t *ha)
{
int rval;
ql_mbx_data_t mr;
QL_PRINT_3(ha, "started\n");
rval = ql_get_firmware_state(ha, &mr);
if (!DRIVER_SUSPENDED(ha) &&
(rval != QL_SUCCESS || mr.mb[1] != FSTATE_READY)) {
EL(ha, "failed, Firmware Ready Test = %xh\n", rval);
TASK_DAEMON_LOCK(ha);
if (!(ha->task_daemon_flags & ABORT_ISP_ACTIVE)) {
EL(ha, "fstate_ready, isp_abort_needed\n");
ha->task_daemon_flags |= ISP_ABORT_NEEDED;
}
TASK_DAEMON_UNLOCK(ha);
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_unsol_callback(ql_srb_t *sp)
{
fc_affected_id_t *af;
fc_unsol_buf_t *ubp;
uchar_t r_ctl;
uchar_t ls_code;
ql_tgt_t *tq;
ql_adapter_state_t *ha = sp->ha, *pha = sp->ha->pha;
QL_PRINT_3(ha, "started\n");
ubp = ha->ub_array[sp->handle];
r_ctl = ubp->ub_frame.r_ctl;
ls_code = ubp->ub_buffer[0];
if (sp->lun_queue == NULL) {
tq = NULL;
} else {
tq = sp->lun_queue->target_queue;
}
QL_UB_LOCK(ha);
if (sp->flags & SRB_UB_FREE_REQUESTED ||
pha->task_daemon_flags & TASK_DAEMON_POWERING_DOWN) {
sp->flags &= ~(SRB_UB_IN_ISP | SRB_UB_CALLBACK |
SRB_UB_RSCN | SRB_UB_FCP | SRB_UB_ACQUIRED);
sp->flags |= SRB_UB_IN_FCA;
QL_UB_UNLOCK(ha);
return;
}
if (sp->flags & SRB_UB_RSCN) {
int sendup;
QL_UB_UNLOCK(ha);
af = (fc_affected_id_t *)((caddr_t)ubp->ub_buffer + 4);
sendup = ql_process_rscn(ha, af);
if (sendup == 0) {
TASK_DAEMON_LOCK(ha);
ql_add_link_b(&pha->unsol_callback_queue, &sp->cmd);
TASK_DAEMON_UNLOCK(ha);
ql_delay(ha, 10000);
QL_PRINT_2(ha, "done rscn_sendup=0, "
"fmt=%xh, d_id=%xh\n",
af->aff_format, af->aff_d_id);
return;
}
QL_UB_LOCK(ha);
EL(ha, "sending unsol rscn, fmt=%xh, d_id=%xh to transport\n",
af->aff_format, af->aff_d_id);
}
if ((r_ctl == R_CTL_ELS_REQ) && (ls_code == LA_ELS_LOGO)) {
QL_UB_UNLOCK(ha);
if (tq && (ql_process_logo_for_device(ha, tq) == 0)) {
TASK_DAEMON_LOCK(ha);
ql_add_link_b(&pha->unsol_callback_queue, &sp->cmd);
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_2(ha, "logo_sendup=0, d_id=%xh"
"\n", tq->d_id.b24);
return;
}
QL_UB_LOCK(ha);
EL(ha, "sending unsol logout for %xh to transport\n",
ubp->ub_frame.s_id);
}
if ((r_ctl == R_CTL_ELS_REQ) && (ls_code == LA_ELS_PLOGI)) {
EL(ha, "sending unsol plogi for %xh to transport\n",
ubp->ub_frame.s_id);
}
sp->flags &= ~(SRB_UB_IN_FCA | SRB_UB_IN_ISP | SRB_UB_RSCN |
SRB_UB_FCP);
if (sp->ub_type == FC_TYPE_IS8802_SNAP) {
(void) ddi_dma_sync(sp->ub_buffer.dma_handle, 0,
ubp->ub_bufsize, DDI_DMA_SYNC_FORCPU);
}
QL_UB_UNLOCK(ha);
(ha->bind_info.port_unsol_cb)(ha->bind_info.port_handle,
ubp, sp->ub_type);
QL_PRINT_3(ha, "done\n");
}
void
ql_send_logo(ql_adapter_state_t *vha, ql_tgt_t *tq, ql_head_t *done_q)
{
fc_unsol_buf_t *ubp;
ql_srb_t *sp;
la_els_logo_t *payload;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_3(ha, "started, d_id=%xh\n", tq->d_id.b24);
if ((tq->d_id.b24 == 0) || (tq->d_id.b24 == FS_BROADCAST)) {
EL(ha, "no device, d_id=%xh\n", tq->d_id.b24);
return;
}
if ((tq->flags & (TQF_RSCN_RCVD | TQF_PLOGI_PROGRS)) == 0 &&
tq->logout_sent == 0 && (ha->task_daemon_flags & LOOP_DOWN) == 0) {
ubp = ql_get_unsolicited_buffer(vha, FC_TYPE_EXTENDED_LS);
if (ubp == NULL) {
EL(vha, "Failed, get_unsolicited_buffer\n");
return;
}
DEVICE_QUEUE_LOCK(tq);
tq->flags |= TQF_NEED_AUTHENTICATION;
tq->logout_sent++;
DEVICE_QUEUE_UNLOCK(tq);
sp = ubp->ub_fca_private;
ubp->ub_frame.d_id = vha->d_id.b24;
ubp->ub_frame.r_ctl = R_CTL_ELS_REQ;
ubp->ub_frame.s_id = tq->d_id.b24;
ubp->ub_frame.rsvd = 0;
ubp->ub_frame.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ |
F_CTL_SEQ_INITIATIVE;
ubp->ub_frame.type = FC_TYPE_EXTENDED_LS;
ubp->ub_frame.seq_cnt = 0;
ubp->ub_frame.df_ctl = 0;
ubp->ub_frame.seq_id = 0;
ubp->ub_frame.rx_id = 0xffff;
ubp->ub_frame.ox_id = 0xffff;
payload = (la_els_logo_t *)ubp->ub_buffer;
bzero(payload, sizeof (la_els_logo_t));
ubp->ub_buffer[0] = LA_ELS_LOGO;
ubp->ub_buffer[1] = 0;
ubp->ub_buffer[2] = 0;
ubp->ub_buffer[3] = 0;
bcopy(&vha->loginparams.node_ww_name.raw_wwn[0],
&payload->nport_ww_name.raw_wwn[0], 8);
payload->nport_id.port_id = tq->d_id.b24;
QL_UB_LOCK(ha);
sp->flags |= SRB_UB_CALLBACK;
QL_UB_UNLOCK(ha);
if (tq->lun_queues.first != NULL) {
sp->lun_queue = (tq->lun_queues.first)->base_address;
} else {
sp->lun_queue = ql_lun_queue(vha, tq, 0);
}
if (done_q) {
ql_add_link_b(done_q, &sp->cmd);
} else {
ql_awaken_task_daemon(ha, sp, 0, 0);
}
}
QL_PRINT_3(ha, "done\n");
}
static int
ql_process_logo_for_device(ql_adapter_state_t *ha, ql_tgt_t *tq)
{
port_id_t d_id;
ql_srb_t *sp;
ql_link_t *link;
int sendup = 1;
QL_PRINT_3(ha, "started\n");
DEVICE_QUEUE_LOCK(tq);
if (tq->outcnt) {
DEVICE_QUEUE_UNLOCK(tq);
sendup = 0;
(void) ql_abort_device(ha, tq, 1);
ql_delay(ha, 10000);
} else {
DEVICE_QUEUE_UNLOCK(tq);
TASK_DAEMON_LOCK(ha);
for (link = ha->pha->unsol_callback_queue.first; link != NULL;
link = link->next) {
sp = link->base_address;
if (sp->flags & SRB_UB_CALLBACK) {
continue;
}
d_id.b24 = sp->pkt->pkt_cmd_fhdr.d_id;
if (tq->d_id.b24 == d_id.b24) {
sendup = 0;
break;
}
}
TASK_DAEMON_UNLOCK(ha);
}
QL_PRINT_3(ha, "done\n");
return (sendup);
}
static int
ql_send_plogi(ql_adapter_state_t *ha, ql_tgt_t *tq, ql_head_t *done_q)
{
fc_unsol_buf_t *ubp;
ql_srb_t *sp;
la_els_logi_t *payload;
class_svc_param_t *class3_param;
QL_PRINT_3(ha, "started\n");
if ((tq->flags & TQF_RSCN_RCVD) || (ha->task_daemon_flags &
LOOP_DOWN)) {
EL(ha, "Failed, tqf=%xh\n", tq->flags);
return (QL_FUNCTION_FAILED);
}
ubp = ql_get_unsolicited_buffer(ha, FC_TYPE_EXTENDED_LS);
if (ubp == NULL) {
EL(ha, "Failed\n");
return (QL_FUNCTION_FAILED);
}
QL_PRINT_3(ha, "Received LOGO from = %xh\n", tq->d_id.b24);
EL(ha, "Emulate PLOGI from = %xh tq = %x\n", tq->d_id.b24, tq);
sp = ubp->ub_fca_private;
ubp->ub_frame.d_id = ha->d_id.b24;
ubp->ub_frame.r_ctl = R_CTL_ELS_REQ;
ubp->ub_frame.s_id = tq->d_id.b24;
ubp->ub_frame.rsvd = 0;
ubp->ub_frame.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ |
F_CTL_SEQ_INITIATIVE;
ubp->ub_frame.type = FC_TYPE_EXTENDED_LS;
ubp->ub_frame.seq_cnt = 0;
ubp->ub_frame.df_ctl = 0;
ubp->ub_frame.seq_id = 0;
ubp->ub_frame.rx_id = 0xffff;
ubp->ub_frame.ox_id = 0xffff;
payload = (la_els_logi_t *)ubp->ub_buffer;
bzero(payload, sizeof (la_els_logi_t));
payload->ls_code.ls_code = LA_ELS_PLOGI;
payload->common_service.fcph_version = 0x2006;
payload->common_service.cmn_features =
ha->topology & QL_N_PORT ? 0x8000 : 0x8800;
payload->common_service.rx_bufsize =
ha->loginparams.common_service.rx_bufsize;
payload->common_service.conc_sequences = 0xff;
payload->common_service.relative_offset = 0x03;
payload->common_service.e_d_tov = 0x7d0;
bcopy((void *)&tq->port_name[0],
(void *)&payload->nport_ww_name.raw_wwn[0], 8);
bcopy((void *)&tq->node_name[0],
(void *)&payload->node_ww_name.raw_wwn[0], 8);
class3_param = (class_svc_param_t *)&payload->class_3;
class3_param->class_valid_svc_opt = 0x8000;
class3_param->recipient_ctl = tq->class3_recipient_ctl;
class3_param->rcv_data_size = tq->class3_rcv_data_size;
class3_param->conc_sequences = tq->class3_conc_sequences;
class3_param->open_sequences_per_exch =
tq->class3_open_sequences_per_exch;
QL_UB_LOCK(ha);
sp->flags |= SRB_UB_CALLBACK;
QL_UB_UNLOCK(ha);
if (done_q) {
ql_add_link_b(done_q, &sp->cmd);
} else {
ql_awaken_task_daemon(ha, sp, 0, 0);
}
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
int
ql_abort_device(ql_adapter_state_t *ha, ql_tgt_t *tq, int drain)
{
ql_link_t *link, *link2;
ql_lun_t *lq;
int rval = QL_SUCCESS;
ql_srb_t *sp;
ql_head_t done_q = { NULL, NULL };
QL_PRINT_10(ha, "started\n");
DEVICE_QUEUE_LOCK(tq);
for (link = tq->lun_queues.first; link != NULL; link = link->next) {
lq = link->base_address;
link2 = lq->cmd.first;
while (link2 != NULL) {
sp = link2->base_address;
link2 = link2->next;
ql_remove_link(&lq->cmd, &sp->cmd);
sp->flags &= ~SRB_IN_DEVICE_QUEUE;
sp->pkt->pkt_reason = CS_ABORTED;
ql_add_link_b(&done_q, &sp->cmd);
}
}
DEVICE_QUEUE_UNLOCK(tq);
if (done_q.first != NULL) {
ql_done(done_q.first, B_FALSE);
}
if (drain && VALID_TARGET_ID(ha, tq->loop_id) && PD_PORT_LOGIN(tq)) {
rval = ql_abort_target(ha, tq, 0);
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh, d_id=%xh\n", rval, tq->d_id.b24);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
void
ql_rcv_rscn_els(ql_adapter_state_t *ha, uint16_t *mb, ql_head_t *done_q)
{
fc_unsol_buf_t *ubp;
ql_srb_t *sp;
fc_rscn_t *rn;
fc_affected_id_t *af;
port_id_t d_id;
QL_PRINT_3(ha, "started\n");
ubp = ql_get_unsolicited_buffer(ha, FC_TYPE_EXTENDED_LS);
if (ubp != NULL) {
sp = ubp->ub_fca_private;
ubp->ub_frame.d_id = ha->d_id.b24;
ubp->ub_frame.r_ctl = R_CTL_ELS_REQ;
ubp->ub_frame.s_id = FS_FABRIC_CONTROLLER;
ubp->ub_frame.rsvd = 0;
ubp->ub_frame.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ |
F_CTL_SEQ_INITIATIVE;
ubp->ub_frame.type = FC_TYPE_EXTENDED_LS;
ubp->ub_frame.seq_cnt = 0;
ubp->ub_frame.df_ctl = 0;
ubp->ub_frame.seq_id = 0;
ubp->ub_frame.rx_id = 0xffff;
ubp->ub_frame.ox_id = 0xffff;
rn = (fc_rscn_t *)ubp->ub_buffer;
af = (fc_affected_id_t *)((caddr_t)ubp->ub_buffer + 4);
rn->rscn_code = LA_ELS_RSCN;
rn->rscn_len = 4;
rn->rscn_payload_len = 8;
d_id.b.al_pa = LSB(mb[2]);
d_id.b.area = MSB(mb[2]);
d_id.b.domain = LSB(mb[1]);
af->aff_d_id = d_id.b24;
af->aff_format = MSB(mb[1]);
EL(ha, "LA_ELS_RSCN fmt=%xh, d_id=%xh\n", af->aff_format,
af->aff_d_id);
ql_update_rscn(ha, af);
QL_UB_LOCK(ha);
sp->flags |= SRB_UB_CALLBACK | SRB_UB_RSCN;
QL_UB_UNLOCK(ha);
ql_add_link_b(done_q, &sp->cmd);
}
if (ubp == NULL) {
EL(ha, "Failed, get_unsolicited_buffer\n");
} else {
QL_PRINT_3(ha, "done\n");
}
}
static void
ql_update_rscn(ql_adapter_state_t *ha, fc_affected_id_t *af)
{
ql_link_t *link;
uint16_t index;
ql_tgt_t *tq;
QL_PRINT_3(ha, "started\n");
if (af->aff_format == FC_RSCN_PORT_ADDRESS) {
port_id_t d_id;
d_id.r.rsvd_1 = 0;
d_id.b24 = af->aff_d_id;
tq = ql_d_id_to_queue(ha, d_id);
if (tq) {
EL(ha, "SD_RSCN_RCVD %xh RPA\n", d_id.b24);
DEVICE_QUEUE_LOCK(tq);
tq->flags |= TQF_RSCN_RCVD;
ql_requeue_pending_cmds(ha, tq);
DEVICE_QUEUE_UNLOCK(tq);
}
QL_PRINT_3(ha, "FC_RSCN_PORT_ADDRESS done\n");
return;
}
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
for (link = ha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
switch (af->aff_format) {
case FC_RSCN_FABRIC_ADDRESS:
if (!RESERVED_LOOP_ID(ha, tq->loop_id)) {
EL(ha, "SD_RSCN_RCVD %xh RFA\n",
tq->d_id.b24);
DEVICE_QUEUE_LOCK(tq);
tq->flags |= TQF_RSCN_RCVD;
ql_requeue_pending_cmds(ha, tq);
DEVICE_QUEUE_UNLOCK(tq);
}
break;
case FC_RSCN_AREA_ADDRESS:
if ((tq->d_id.b24 & 0xffff00) == af->aff_d_id) {
EL(ha, "SD_RSCN_RCVD %xh RAA\n",
tq->d_id.b24);
DEVICE_QUEUE_LOCK(tq);
tq->flags |= TQF_RSCN_RCVD;
ql_requeue_pending_cmds(ha, tq);
DEVICE_QUEUE_UNLOCK(tq);
}
break;
case FC_RSCN_DOMAIN_ADDRESS:
if ((tq->d_id.b24 & 0xff0000) == af->aff_d_id) {
EL(ha, "SD_RSCN_RCVD %xh RDA\n",
tq->d_id.b24);
DEVICE_QUEUE_LOCK(tq);
tq->flags |= TQF_RSCN_RCVD;
ql_requeue_pending_cmds(ha, tq);
DEVICE_QUEUE_UNLOCK(tq);
}
break;
default:
break;
}
}
}
QL_PRINT_3(ha, "done\n");
}
void
ql_requeue_pending_cmds(ql_adapter_state_t *vha, ql_tgt_t *tq)
{
ql_link_t *link;
ql_srb_t *sp;
ql_lun_t *lq;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_3(ha, "started\n");
REQUEST_RING_LOCK(ha);
for (link = ha->pending_cmds.first; link != NULL; link = link->next) {
sp = link->base_address;
if ((lq = sp->lun_queue) == NULL || lq->target_queue != tq) {
continue;
}
ql_remove_link(&ha->pending_cmds, &sp->cmd);
if (tq->outcnt) {
tq->outcnt--;
}
if (sp->flags & SRB_FCP_CMD_PKT) {
if (sp->fcp->fcp_cntl.cntl_qtype ==
FCP_QTYPE_UNTAGGED) {
lq->flags &= ~LQF_UNTAGGED_PENDING;
}
if (lq->lun_outcnt != 0) {
lq->lun_outcnt--;
}
}
ql_add_link_t(&lq->cmd, &sp->cmd);
sp->flags |= SRB_IN_DEVICE_QUEUE;
}
REQUEST_RING_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
static int
ql_process_rscn(ql_adapter_state_t *ha, fc_affected_id_t *af)
{
int sendit;
int sendup = 1;
ql_link_t *link;
uint16_t index;
ql_tgt_t *tq;
QL_PRINT_3(ha, "started\n");
if (af->aff_format == FC_RSCN_PORT_ADDRESS) {
port_id_t d_id;
d_id.r.rsvd_1 = 0;
d_id.b24 = af->aff_d_id;
tq = ql_d_id_to_queue(ha, d_id);
if (tq) {
sendup = ql_process_rscn_for_device(ha, tq);
}
QL_PRINT_3(ha, "done\n");
return (sendup);
}
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 (tq == NULL) {
continue;
}
switch (af->aff_format) {
case FC_RSCN_FABRIC_ADDRESS:
if (!RESERVED_LOOP_ID(ha, tq->loop_id)) {
sendit = ql_process_rscn_for_device(
ha, tq);
if (sendup) {
sendup = sendit;
}
}
break;
case FC_RSCN_AREA_ADDRESS:
if ((tq->d_id.b24 & 0xffff00) ==
af->aff_d_id) {
sendit = ql_process_rscn_for_device(
ha, tq);
if (sendup) {
sendup = sendit;
}
}
break;
case FC_RSCN_DOMAIN_ADDRESS:
if ((tq->d_id.b24 & 0xff0000) ==
af->aff_d_id) {
sendit = ql_process_rscn_for_device(
ha, tq);
if (sendup) {
sendup = sendit;
}
}
break;
default:
break;
}
}
}
QL_PRINT_3(ha, "done\n");
return (sendup);
}
static int
ql_process_rscn_for_device(ql_adapter_state_t *ha, ql_tgt_t *tq)
{
int sendup = 1;
QL_PRINT_3(ha, "started\n");
DEVICE_QUEUE_LOCK(tq);
if (((tq->flags & TQF_INITIATOR_DEVICE) == 0) &&
(tq->prli_svc_param_word_3 & PRLI_W3_RETRY)) {
DEVICE_QUEUE_UNLOCK(tq);
(void) ql_get_port_database(ha, tq, PDF_NONE);
DEVICE_QUEUE_LOCK(tq);
tq->flags &= ~TQF_RSCN_RCVD;
} else if (tq->loop_id != PORT_NO_LOOP_ID) {
if (tq->d_id.b24 != BROADCAST_ADDR) {
tq->flags |= TQF_NEED_AUTHENTICATION;
}
DEVICE_QUEUE_UNLOCK(tq);
(void) ql_abort_device(ha, tq, 1);
DEVICE_QUEUE_LOCK(tq);
if (tq->outcnt) {
EL(ha, "busy tq->outcnt=%d\n", tq->outcnt);
sendup = 0;
} else {
tq->flags &= ~TQF_RSCN_RCVD;
}
} else {
tq->flags &= ~TQF_RSCN_RCVD;
}
if (sendup) {
if (tq->d_id.b24 != BROADCAST_ADDR) {
tq->flags |= TQF_NEED_AUTHENTICATION;
}
}
DEVICE_QUEUE_UNLOCK(tq);
QL_PRINT_3(ha, "done\n");
return (sendup);
}
static int
ql_handle_rscn_update(ql_adapter_state_t *ha)
{
int rval;
ql_tgt_t *tq;
uint16_t index, loop_id;
ql_dev_id_list_t *list;
uint32_t list_size;
port_id_t d_id;
ql_mbx_data_t mr;
ql_head_t done_q = { NULL, NULL };
QL_PRINT_3(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, "kmem_zalloc failed=%xh\n", rval);
return (rval);
}
rval = ql_get_id_list(ha, (caddr_t)list, list_size, &mr);
if (rval != QL_SUCCESS) {
kmem_free(list, list_size);
EL(ha, "get_id_list failed=%xh\n", rval);
return (rval);
}
ADAPTER_STATE_LOCK(ha);
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)) {
d_id.r.rsvd_1 = 0;
tq = ql_d_id_to_queue(ha, d_id);
if (tq != NULL) {
continue;
}
tq = ql_dev_init(ha, d_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;
}
ADAPTER_STATE_UNLOCK(ha);
if (ql_get_port_database(ha, tq, PDF_NONE) !=
QL_SUCCESS) {
tq->loop_id = PORT_NO_LOOP_ID;
}
ADAPTER_STATE_LOCK(ha);
if (VALID_DEVICE_ID(ha, tq->loop_id)) {
(void) ql_send_plogi(ha, tq, &done_q);
}
}
}
ADAPTER_STATE_UNLOCK(ha);
if (done_q.first != NULL) {
ql_done(done_q.first, B_FALSE);
}
kmem_free(list, list_size);
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static void
ql_free_unsolicited_buffer(ql_adapter_state_t *ha, fc_unsol_buf_t *ubp)
{
ql_srb_t *sp;
int status;
QL_PRINT_3(ha, "started\n");
sp = ubp->ub_fca_private;
if (sp->ub_type == FC_TYPE_IS8802_SNAP) {
if (ha->flags & IP_INITIALIZED) {
status = ql_shutdown_ip(ha);
if (status != QL_SUCCESS) {
cmn_err(CE_WARN,
"!Qlogic %s(%d): Failed to shutdown IP",
QL_NAME, ha->instance);
return;
}
ha->flags &= ~IP_ENABLED;
}
ql_free_phys(ha, &sp->ub_buffer);
} else {
kmem_free(ubp->ub_buffer, ubp->ub_bufsize);
}
kmem_free(sp, sizeof (ql_srb_t));
kmem_free(ubp, sizeof (fc_unsol_buf_t));
QL_UB_LOCK(ha);
if (ha->ub_allocated != 0) {
ha->ub_allocated--;
}
QL_UB_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
fc_unsol_buf_t *
ql_get_unsolicited_buffer(ql_adapter_state_t *ha, uint32_t type)
{
fc_unsol_buf_t *ubp;
ql_srb_t *sp;
uint16_t index;
QL_PRINT_3(ha, "started\n");
ubp = NULL;
QL_UB_LOCK(ha);
for (index = 0; index < QL_UB_LIMIT; index++) {
ubp = ha->ub_array[index];
if (ubp != NULL) {
sp = ubp->ub_fca_private;
if ((sp->ub_type == type) &&
(sp->flags & SRB_UB_IN_FCA) &&
(!(sp->flags & (SRB_UB_CALLBACK |
SRB_UB_FREE_REQUESTED | SRB_UB_ACQUIRED)))) {
sp->flags |= SRB_UB_ACQUIRED;
ubp->ub_resp_flags = 0;
break;
}
ubp = NULL;
}
}
QL_UB_UNLOCK(ha);
if (ubp) {
ubp->ub_resp_token = NULL;
ubp->ub_class = FC_TRAN_CLASS3;
}
QL_PRINT_3(ha, "done\n");
return (ubp);
}
int
ql_ub_frame_hdr(ql_adapter_state_t *ha, ql_tgt_t *tq, uint16_t index,
ql_head_t *done_q)
{
fc_unsol_buf_t *ubp;
ql_srb_t *sp;
uint16_t loop_id;
int rval = QL_FUNCTION_FAILED;
QL_PRINT_3(ha, "started\n");
QL_UB_LOCK(ha);
if (index >= QL_UB_LIMIT || (ubp = ha->ub_array[index]) == NULL) {
EL(ha, "Invalid buffer index=%xh\n", index);
QL_UB_UNLOCK(ha);
return (rval);
}
sp = ubp->ub_fca_private;
if (sp->flags & SRB_UB_FREE_REQUESTED) {
EL(ha, "buffer freed index=%xh\n", index);
sp->flags &= ~(SRB_UB_IN_ISP | SRB_UB_CALLBACK |
SRB_UB_RSCN | SRB_UB_FCP | SRB_UB_ACQUIRED);
sp->flags |= SRB_UB_IN_FCA;
QL_UB_UNLOCK(ha);
return (rval);
}
if ((sp->handle == index) &&
(sp->flags & SRB_UB_IN_ISP) &&
(sp->ub_type == FC_TYPE_IS8802_SNAP) &&
(!(sp->flags & SRB_UB_ACQUIRED))) {
loop_id = (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
BROADCAST_24XX_HDL : IP_BROADCAST_LOOP_ID);
if (tq->ub_loop_id == loop_id) {
if (ha->topology & QL_FL_PORT) {
ubp->ub_frame.d_id = 0x000000;
} else {
ubp->ub_frame.d_id = FS_BROADCAST;
}
} else {
ubp->ub_frame.d_id = ha->d_id.b24;
}
ubp->ub_frame.r_ctl = R_CTL_UNSOL_DATA;
ubp->ub_frame.rsvd = 0;
ubp->ub_frame.s_id = tq->d_id.b24;
ubp->ub_frame.type = FC_TYPE_IS8802_SNAP;
ubp->ub_frame.seq_cnt = tq->ub_seq_cnt;
ubp->ub_frame.df_ctl = 0;
ubp->ub_frame.seq_id = tq->ub_seq_id;
ubp->ub_frame.rx_id = 0xffff;
ubp->ub_frame.ox_id = 0xffff;
ubp->ub_bufsize = sp->ub_size < tq->ub_sequence_length ?
sp->ub_size : tq->ub_sequence_length;
ubp->ub_frame.ro = tq->ub_frame_ro;
tq->ub_sequence_length = (uint16_t)
(tq->ub_sequence_length - ubp->ub_bufsize);
tq->ub_frame_ro += ubp->ub_bufsize;
tq->ub_seq_cnt++;
if (tq->ub_seq_cnt == tq->ub_total_seg_cnt) {
if (tq->ub_seq_cnt == 1) {
ubp->ub_frame.f_ctl = F_CTL_RO_PRESENT |
F_CTL_FIRST_SEQ | F_CTL_END_SEQ;
} else {
ubp->ub_frame.f_ctl = F_CTL_RO_PRESENT |
F_CTL_END_SEQ;
}
tq->ub_total_seg_cnt = 0;
} else if (tq->ub_seq_cnt == 1) {
ubp->ub_frame.f_ctl = F_CTL_RO_PRESENT |
F_CTL_FIRST_SEQ;
ubp->ub_frame.df_ctl = 0x20;
}
QL_PRINT_3(ha, "ub_frame.d_id=%xh\n", ubp->ub_frame.d_id);
QL_PRINT_3(ha, "ub_frame.s_id=%xh\n", ubp->ub_frame.s_id);
QL_PRINT_3(ha, "ub_frame.seq_cnt=%xh\n", ubp->ub_frame.seq_cnt);
QL_PRINT_3(ha, "ub_frame.seq_id=%xh\n", ubp->ub_frame.seq_id);
QL_PRINT_3(ha, "ub_frame.ro=%xh\n", ubp->ub_frame.ro);
QL_PRINT_3(ha, "ub_frame.f_ctl=%xh\n", ubp->ub_frame.f_ctl);
QL_PRINT_3(ha, "ub_bufsize=%xh\n", ubp->ub_bufsize);
QL_DUMP_3(ubp->ub_buffer, 8,
ubp->ub_bufsize < 64 ? ubp->ub_bufsize : 64);
sp->flags |= SRB_UB_CALLBACK | SRB_UB_ACQUIRED;
ql_add_link_b(done_q, &sp->cmd);
rval = QL_SUCCESS;
} else {
if (sp->handle != index) {
EL(ha, "Bad index=%xh, expect=%xh\n", index,
sp->handle);
}
if ((sp->flags & SRB_UB_IN_ISP) == 0) {
EL(ha, "buffer was already in driver, index=%xh\n",
index);
}
if ((sp->ub_type == FC_TYPE_IS8802_SNAP) == 0) {
EL(ha, "buffer was not an IP buffer, index=%xh\n",
index);
}
if (sp->flags & SRB_UB_ACQUIRED) {
EL(ha, "buffer was being used by driver, index=%xh\n",
index);
}
}
QL_UB_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
return (rval);
}
static void
ql_timer(void *arg)
{
ql_link_t *link;
uint64_t set_flags;
ql_adapter_state_t *ha;
static uint32_t sec_cnt = 0;
QL_PRINT_6(NULL, "started\n");
GLOBAL_TIMER_LOCK();
if (ql_timer_timeout_id == NULL) {
GLOBAL_TIMER_UNLOCK();
return;
}
sec_cnt++;
for (link = ql_hba.first; link != NULL; link = link->next) {
ha = link->base_address;
if (ha->flags & ADAPTER_SUSPENDED ||
ha->task_daemon_flags & DRIVER_STALL ||
!(ha->task_daemon_flags & FIRMWARE_UP)) {
continue;
}
QL_PM_LOCK(ha);
if (ha->power_level != PM_LEVEL_D0) {
QL_PM_UNLOCK(ha);
continue;
}
ha->pm_busy++;
QL_PM_UNLOCK(ha);
set_flags = 0;
if (ha->comp_thds_awake == ha->comp_thds_active &&
ha->comp_q.first != NULL) {
QL_PRINT_10(ha, "comp queue helper thrd started\n");
(void) timeout(ql_process_comp_queue, (void *)ha, 1);
}
if (LOOP_READY(ha)) {
ADAPTER_STATE_LOCK(ha);
if (ha->port_retry_timer != 0) {
ha->port_retry_timer--;
if (ha->port_retry_timer == 0) {
set_flags |= PORT_RETRY_NEEDED;
}
}
ADAPTER_STATE_UNLOCK(ha);
}
if (LOOP_RECONFIGURE(ha) == 0) {
if (ha->loop_down_timer > LOOP_DOWN_TIMER_END) {
ha->loop_down_timer--;
if (ha->loop_down_timer == LOOP_DOWN_RESET) {
if (CFG_IST(ha,
CFG_DUMP_LOOP_OFFLINE_TIMEOUT)) {
ADAPTER_STATE_LOCK(ha);
ha->flags |= FW_DUMP_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
}
EL(ha, "loop_down_reset, "
"isp_abort_needed\n");
set_flags |= ISP_ABORT_NEEDED;
}
}
if (CFG_IST(ha, CFG_ENABLE_LINK_DOWN_REPORTING)) {
if (ha->loop_down_timer ==
ha->loop_down_abort_time) {
ADAPTER_STATE_LOCK(ha);
ha->flags |= ABORT_CMDS_LOOP_DOWN_TMO;
ADAPTER_STATE_UNLOCK(ha);
set_flags |= ABORT_QUEUES_NEEDED;
EL(ha, "loop_down_abort_time, "
"abort_queues_needed\n");
}
if (ha->watchdog_timer == 0) {
ha->watchdog_timer = WATCHDOG_TIME;
} else if (LOOP_READY(ha)) {
ha->watchdog_timer--;
if (ha->watchdog_timer == 0) {
set_flags |= WATCHDOG_NEEDED;
}
}
}
}
if (!DRIVER_SUSPENDED(ha)) {
if (++ha->idle_timer >= IDLE_CHECK_TIMER) {
#if defined(QL_DEBUG_LEVEL_6) || !defined(QL_DEBUG_LEVEL_3)
set_flags |= TASK_DAEMON_IDLE_CHK_FLG;
#endif
ha->idle_timer = 0;
}
if (ha->send_plogi_timer != 0) {
ha->send_plogi_timer--;
if (ha->send_plogi_timer == 0) {
set_flags |= SEND_PLOGI;
}
}
}
if (CFG_IST(ha, CFG_CTRL_82XX) && ha->flags & ONLINE &&
!(ha->task_daemon_flags & (ISP_ABORT_NEEDED |
ABORT_ISP_ACTIVE)) &&
!(sec_cnt % 2)) {
set_flags |= IDC_POLL_NEEDED;
}
if (ha->ledstate.BeaconState == BEACON_ON) {
set_flags |= LED_BLINK;
}
if (set_flags != 0) {
ql_awaken_task_daemon(ha, NULL, set_flags, 0);
}
if (ha->xioctl->IOInputByteCnt >= 0x100000) {
ha->xioctl->IOInputMByteCnt +=
(ha->xioctl->IOInputByteCnt / 0x100000);
ha->xioctl->IOInputByteCnt %= 0x100000;
}
if (ha->xioctl->IOOutputByteCnt >= 0x100000) {
ha->xioctl->IOOutputMByteCnt +=
(ha->xioctl->IOOutputByteCnt / 0x100000);
ha->xioctl->IOOutputByteCnt %= 0x100000;
}
QL_PM_LOCK(ha);
if (ha->pm_busy) {
ha->pm_busy--;
}
QL_PM_UNLOCK(ha);
}
if (ql_timer_timeout_id != NULL) {
ql_timer_timeout_id = timeout(ql_timer, arg, ql_timer_ticks);
}
GLOBAL_TIMER_UNLOCK();
QL_PRINT_6(ha, "done\n");
}
static void
ql_timeout_insert(ql_adapter_state_t *ha, ql_tgt_t *tq, ql_srb_t *sp)
{
QL_PRINT_3(ha, "started\n");
if (sp->pkt->pkt_timeout != 0 && sp->pkt->pkt_timeout < 0x10000) {
sp->isp_timeout = (uint16_t)(sp->pkt->pkt_timeout);
sp->wdg_q_time = (sp->isp_timeout + WATCHDOG_TIME - 1) /
WATCHDOG_TIME;
sp->wdg_q_time += 10;
sp->wdg_q_time += 6;
sp->init_wdg_q_time = sp->wdg_q_time;
ql_add_link_b(&tq->wdg, &sp->wdg);
sp->flags |= SRB_WATCHDOG_ENABLED;
} else {
sp->isp_timeout = 0;
sp->wdg_q_time = 0;
sp->init_wdg_q_time = 0;
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_watchdog(ql_adapter_state_t *ha)
{
ql_link_t *link;
ql_tgt_t *tq;
uint16_t index;
ql_adapter_state_t *vha;
QL_PRINT_6(ha, "started\n");
for (vha = ha; vha != NULL; vha = vha->vp_next) {
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
for (link = vha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
if (TRY_DEVICE_QUEUE_LOCK(tq) == 0) {
break;
}
if (!(CFG_IST(ha,
CFG_ENABLE_LINK_DOWN_REPORTING)) &&
(tq->port_down_retry_count == 0)) {
DEVICE_QUEUE_UNLOCK(tq);
continue;
}
ql_wdg_tq_list(vha, tq);
}
}
}
ha->watchdog_timer = WATCHDOG_TIME;
QL_PRINT_6(ha, "done\n");
}
static void
ql_wdg_tq_list(ql_adapter_state_t *ha, ql_tgt_t *tq)
{
ql_srb_t *sp;
ql_link_t *link, *next_cmd;
ql_lun_t *lq;
boolean_t q_sane, timeout = B_FALSE;
QL_PRINT_6(ha, "started\n");
if (tq->flags & (TQF_RSCN_RCVD | TQF_NEED_AUTHENTICATION |
TQF_QUEUE_SUSPENDED)) {
q_sane = B_FALSE;
} else {
q_sane = B_TRUE;
}
for (link = tq->wdg.first; link != NULL; link = next_cmd) {
next_cmd = link->next;
sp = link->base_address;
lq = sp->lun_queue;
if (ha->task_daemon_flags & STATE_ONLINE &&
!(sp->flags & SRB_ISP_STARTED) &&
q_sane == B_TRUE &&
sp->flags & SRB_FCP_CMD_PKT &&
lq->lun_outcnt >= ha->execution_throttle) {
continue;
}
if (sp->wdg_q_time != 0) {
sp->wdg_q_time--;
if (sp->wdg_q_time != 0) {
continue;
}
sp->flags |= SRB_COMMAND_TIMEOUT;
timeout = B_TRUE;
}
}
if (timeout == B_TRUE) {
for (link = tq->wdg.first; link != NULL; link = next_cmd) {
sp = link->base_address;
next_cmd = link->next;
if (sp->flags & SRB_COMMAND_TIMEOUT) {
ql_remove_link(&tq->wdg, &sp->wdg);
sp->flags &= ~(SRB_WATCHDOG_ENABLED |
SRB_COMMAND_TIMEOUT);
ql_cmd_timeout(ha, tq, sp);
next_cmd = tq->wdg.first;
}
}
}
DEVICE_QUEUE_UNLOCK(tq);
QL_PRINT_6(ha, "done\n");
}
static void
ql_cmd_timeout(ql_adapter_state_t *ha, ql_tgt_t *tq, ql_srb_t *sp)
{
int rval = 0;
QL_PRINT_3(ha, "started\n");
REQUEST_RING_LOCK(ha);
if (!(sp->flags & SRB_ISP_STARTED)) {
EL(ha, "command timed out in driver, sp=%ph spf=%xh\n",
(void *)sp, sp->flags);
if (sp->cmd.head) {
ql_remove_link(sp->cmd.head, &sp->cmd);
}
sp->flags &= ~SRB_IN_DEVICE_QUEUE;
REQUEST_RING_UNLOCK(ha);
DEVICE_QUEUE_UNLOCK(tq);
sp->pkt->pkt_reason = CS_TIMEOUT;
sp->flags &= ~SRB_RETRY;
ql_done(&sp->cmd, B_FALSE);
} else if (CFG_IST(ha, CFG_CTRL_82XX)) {
REQUEST_RING_UNLOCK(ha);
DEVICE_QUEUE_UNLOCK(tq);
EL(ha, "command timed out in isp=%ph, osc=%ph, index=%xh, "
"spf=%xh\n", (void *)sp,
(void *)ha->outstanding_cmds[sp->handle & OSC_INDEX_MASK],
sp->handle & OSC_INDEX_MASK, sp->flags);
if (ha->pha->timeout_cnt++ > TIMEOUT_THRESHOLD ||
(rval = ql_abort_io(ha, sp)) != QL_SUCCESS) {
sp->flags |= SRB_COMMAND_TIMEOUT;
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= ISP_ABORT_NEEDED;
TASK_DAEMON_UNLOCK(ha);
EL(ha, "abort status=%xh, tc=%xh, isp_abort_"
"needed\n", rval, ha->pha->timeout_cnt);
}
} else {
REQUEST_RING_UNLOCK(ha);
DEVICE_QUEUE_UNLOCK(tq);
EL(ha, "command timed out in isp=%ph, osc=%ph, index=%xh, "
"spf=%xh, isp_abort_needed\n", (void *)sp,
(void *)ha->outstanding_cmds[sp->handle & OSC_INDEX_MASK],
sp->handle & OSC_INDEX_MASK, sp->flags);
INTR_LOCK(ha);
ha->pha->xioctl->ControllerErrorCount++;
INTR_UNLOCK(ha);
sp->flags |= SRB_COMMAND_TIMEOUT;
if (CFG_IST(ha, CFG_DUMP_DRIVER_COMMAND_TIMEOUT)) {
ADAPTER_STATE_LOCK(ha);
ha->flags |= FW_DUMP_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
}
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= ISP_ABORT_NEEDED;
TASK_DAEMON_UNLOCK(ha);
}
DEVICE_QUEUE_LOCK(tq);
QL_PRINT_3(ha, "done\n");
}
void
ql_cmd_wait(ql_adapter_state_t *ha)
{
uint16_t index;
ql_link_t *link;
ql_tgt_t *tq;
ql_adapter_state_t *vha;
QL_PRINT_3(ha, "started\n");
(void) ql_wait_outstanding(ha);
for (vha = ha; vha != NULL; vha = vha->vp_next) {
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
for (link = vha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
if (tq &&
(!(tq->prli_svc_param_word_3 &
PRLI_W3_RETRY) ||
ha->task_daemon_flags & ABORT_ISP_ACTIVE)) {
(void) ql_abort_device(vha, tq, 0);
}
}
}
}
QL_PRINT_3(ha, "done\n");
}
static uint16_t
ql_wait_outstanding(ql_adapter_state_t *ha)
{
ql_srb_t *sp;
uint16_t index, count;
QL_PRINT_3(ha, "started\n");
count = ql_osc_wait_count;
for (index = 1; index < ha->pha->osc_max_cnt; index++) {
if (ha->pha->pending_cmds.first != NULL) {
ql_start_iocb(ha, NULL);
index = 1;
}
if ((sp = ha->pha->outstanding_cmds[index]) != NULL &&
sp != QL_ABORTED_SRB(ha) &&
(sp->flags & SRB_COMMAND_TIMEOUT) == 0) {
if (count-- != 0) {
ql_delay(ha, 10000);
index = 0;
} else {
EL(ha, "still in OSC,sp=%ph,oci=%d,sph=%xh,"
"spf=%xh\n", (void *) sp, index, sp->handle,
sp->flags);
break;
}
}
}
QL_PRINT_3(ha, "done\n");
return (index);
}
void
ql_restart_queues(ql_adapter_state_t *ha)
{
ql_link_t *link, *link2;
ql_tgt_t *tq;
ql_lun_t *lq;
uint16_t index;
ql_adapter_state_t *vha;
QL_PRINT_3(ha, "started\n");
for (vha = ha->pha; vha != NULL; vha = vha->vp_next) {
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
for (link = vha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
DEVICE_QUEUE_LOCK(tq);
tq->flags &= ~TQF_QUEUE_SUSPENDED;
for (link2 = tq->lun_queues.first;
link2 != NULL; link2 = link2->next) {
lq = link2->base_address;
if (lq->cmd.first != NULL) {
ql_next(vha, lq);
DEVICE_QUEUE_LOCK(tq);
}
}
DEVICE_QUEUE_UNLOCK(tq);
}
}
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_iidma(ql_adapter_state_t *ha)
{
ql_link_t *link;
ql_tgt_t *tq;
uint16_t index;
char buf[256];
uint32_t data;
QL_PRINT_3(ha, "started\n");
if (!CFG_IST(ha, CFG_IIDMA_SUPPORT)) {
QL_PRINT_3(ha, "done\n");
return;
}
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 ((tq->flags & TQF_IIDMA_NEEDED) == 0) {
continue;
}
DEVICE_QUEUE_LOCK(tq);
tq->flags &= ~TQF_IIDMA_NEEDED;
DEVICE_QUEUE_UNLOCK(tq);
if ((tq->loop_id > LAST_N_PORT_HDL) ||
(tq->d_id.b24 == FS_MANAGEMENT_SERVER) ||
(tq->flags & TQF_INITIATOR_DEVICE) ||
(tq->iidma_rate == IIDMA_RATE_NDEF)) {
continue;
}
(void) snprintf(buf, sizeof (buf),
"iidma-rate-%02x%02x%02x%02x%02x"
"%02x%02x%02x", tq->port_name[0],
tq->port_name[1], tq->port_name[2],
tq->port_name[3], tq->port_name[4],
tq->port_name[5], tq->port_name[6],
tq->port_name[7]);
if ((data = ql_get_prop(ha, buf)) ==
0xffffffff) {
tq->iidma_rate = IIDMA_RATE_NDEF;
} else {
switch (data) {
case IIDMA_RATE_4GB:
case IIDMA_RATE_8GB:
case IIDMA_RATE_10GB:
case IIDMA_RATE_16GB:
case IIDMA_RATE_32GB:
tq->iidma_rate = data;
break;
default:
EL(ha, "invalid data for "
"parameter: %s: %xh\n",
buf, data);
tq->iidma_rate =
IIDMA_RATE_NDEF;
break;
}
}
EL(ha, "d_id = %xh iidma_rate = %xh\n",
tq->d_id.b24, tq->iidma_rate);
if (!CFG_IST(ha, CFG_FCOE_SUPPORT)) {
if (tq->iidma_rate <= IIDMA_RATE_MAX) {
data = ql_iidma_rate(ha, tq->loop_id,
&tq->iidma_rate,
EXT_IIDMA_MODE_SET);
if (data != QL_SUCCESS) {
EL(ha, "mbx failed: %xh\n",
data);
}
}
}
}
}
QL_PRINT_3(ha, "done\n");
}
void
ql_abort_queues(ql_adapter_state_t *ha)
{
ql_link_t *link;
ql_tgt_t *tq;
ql_srb_t *sp;
uint16_t index;
ql_adapter_state_t *vha;
QL_PRINT_10(ha, "started\n");
INTR_LOCK(ha);
for (index = 1; index < ha->osc_max_cnt; index++) {
if (ha->pending_cmds.first != NULL) {
INTR_UNLOCK(ha);
ql_start_iocb(ha, NULL);
ql_delay(ha, 10000);
INTR_LOCK(ha);
index = 1;
}
sp = ha->outstanding_cmds[index];
if (sp && (sp == QL_ABORTED_SRB(ha) || sp->ha != ha)) {
continue;
}
if (sp != NULL &&
(sp->lun_queue == NULL ||
(tq = sp->lun_queue->target_queue) == NULL ||
!(tq->prli_svc_param_word_3 & PRLI_W3_RETRY) ||
ha->task_daemon_flags & ABORT_ISP_ACTIVE)) {
ha->outstanding_cmds[index] = NULL;
sp->handle = 0;
sp->flags &= ~SRB_IN_TOKEN_ARRAY;
INTR_UNLOCK(ha);
sp->pkt->pkt_reason = CS_PORT_UNAVAILABLE;
sp->flags |= SRB_ISP_COMPLETED;
sp->cmd.next = NULL;
ql_done(&sp->cmd, B_FALSE);
INTR_LOCK(ha);
}
}
INTR_UNLOCK(ha);
for (vha = ha; vha != NULL; vha = vha->vp_next) {
QL_PRINT_10(vha, "abort instance\n");
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
for (link = vha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
if (!(tq->prli_svc_param_word_3 &
PRLI_W3_RETRY) ||
ha->task_daemon_flags & ABORT_ISP_ACTIVE) {
ql_abort_device_queues(ha, tq);
}
}
}
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_abort_device_queues(ql_adapter_state_t *ha, ql_tgt_t *tq)
{
ql_link_t *lun_link, *cmd_link;
ql_srb_t *sp;
ql_lun_t *lq;
QL_PRINT_10(ha, "started\n");
DEVICE_QUEUE_LOCK(tq);
ql_requeue_pending_cmds(ha, tq);
for (lun_link = tq->lun_queues.first; lun_link != NULL;
lun_link = lun_link->next) {
lq = lun_link->base_address;
cmd_link = lq->cmd.first;
while (cmd_link != NULL) {
sp = cmd_link->base_address;
ql_remove_link(&lq->cmd, &sp->cmd);
sp->flags &= ~SRB_IN_DEVICE_QUEUE;
DEVICE_QUEUE_UNLOCK(tq);
sp->pkt->pkt_reason = CS_PORT_UNAVAILABLE;
ql_done(&sp->cmd, B_FALSE);
ql_delay(ha, 10000);
DEVICE_QUEUE_LOCK(tq);
cmd_link = lq->cmd.first;
}
}
DEVICE_QUEUE_UNLOCK(tq);
QL_PRINT_10(ha, "done\n");
}
static void
ql_loop_resync(ql_adapter_state_t *ha)
{
int rval;
QL_PRINT_3(ha, "started\n");
if (ha->flags & IP_INITIALIZED) {
(void) ql_shutdown_ip(ha);
}
rval = ql_fw_ready(ha, 10);
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~LOOP_RESYNC_ACTIVE;
TASK_DAEMON_UNLOCK(ha);
if (rval == QL_SUCCESS) {
ql_loop_online(ha);
QL_PRINT_3(ha, "done\n");
} else {
EL(ha, "failed, rval = %xh\n", rval);
}
}
void
ql_loop_online(ql_adapter_state_t *ha)
{
ql_adapter_state_t *vha;
QL_PRINT_3(ha, "started\n");
for (vha = ha->pha; vha != NULL; vha = vha->vp_next) {
if (!(vha->task_daemon_flags &
(LOOP_RESYNC_NEEDED | LOOP_DOWN))) {
if (vha->vp_index == 0 && vha->flags & IP_ENABLED &&
!(vha->flags & IP_INITIALIZED)) {
(void) ql_initialize_ip(vha);
ql_isp_rcvbuf(vha);
}
if (FC_PORT_STATE_MASK(vha->state) != FC_STATE_LOOP &&
FC_PORT_STATE_MASK(vha->state) !=
FC_STATE_ONLINE) {
vha->state = FC_PORT_SPEED_MASK(vha->state);
if (vha->topology & QL_LOOP_CONNECTION) {
vha->state |= FC_STATE_LOOP;
} else {
vha->state |= FC_STATE_ONLINE;
}
TASK_DAEMON_LOCK(ha);
vha->task_daemon_flags |= FC_STATE_CHANGE;
TASK_DAEMON_UNLOCK(ha);
}
}
}
ql_awaken_task_daemon(ha, NULL, 0, 0);
ql_restart_queues(ha);
QL_PRINT_3(ha, "done\n");
}
static ql_adapter_state_t *
ql_fca_handle_to_state(opaque_t fca_handle)
{
#ifdef QL_DEBUG_ROUTINES
ql_link_t *link;
ql_adapter_state_t *ha = NULL;
ql_adapter_state_t *vha = NULL;
for (link = ql_hba.first; link != NULL; link = link->next) {
ha = link->base_address;
for (vha = ha->vp_next; vha != NULL; vha = vha->vp_next) {
if ((opaque_t)vha == fca_handle) {
ha = vha;
break;
}
}
if ((opaque_t)ha == fca_handle) {
break;
} else {
ha = NULL;
}
}
if (ha == NULL) {
QL_PRINT_2(ha, "failed\n");
}
#endif
return ((ql_adapter_state_t *)fca_handle);
}
ql_tgt_t *
ql_d_id_to_queue(ql_adapter_state_t *ha, port_id_t d_id)
{
uint16_t index;
ql_tgt_t *tq;
ql_link_t *link;
index = ql_alpa_to_index[d_id.b.al_pa];
for (link = ha->dev[index].first; link != NULL; link = link->next) {
tq = link->base_address;
if (tq->d_id.b24 == d_id.b24 &&
VALID_DEVICE_ID(ha, tq->loop_id)) {
return (tq);
}
}
return (NULL);
}
ql_tgt_t *
ql_loop_id_to_queue(ql_adapter_state_t *ha, uint16_t loop_id)
{
uint16_t index;
ql_tgt_t *tq;
ql_link_t *link;
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 (tq->loop_id == loop_id) {
return (tq);
}
}
}
return (NULL);
}
static int
ql_kstat_update(kstat_t *ksp, int rw)
{
int rval;
QL_PRINT_3(ksp->ks_private, "started\n");
if (rw == KSTAT_WRITE) {
rval = EACCES;
} else {
rval = 0;
}
if (rval != 0) {
QL_PRINT_2(ksp->ks_private, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_3(ksp->ks_private, "done\n");
}
return (rval);
}
int
ql_load_flash(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size)
{
uint32_t cnt;
int rval;
uint32_t size_to_offset;
uint32_t size_to_compare;
int erase_all;
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
return (ql_24xx_load_flash(ha, dp, size, 0));
}
QL_PRINT_3(ha, "started\n");
size_to_compare = 0x20000;
size_to_offset = 0;
erase_all = 0;
if (CFG_IST(ha, CFG_SBUS_CARD)) {
if (size == 0x80000) {
size_to_compare = 0x80000;
erase_all = 1;
} else {
size_to_compare = 0x40000;
if (ql_flash_sbus_fpga) {
size_to_offset = 0x40000;
}
}
}
if (size > size_to_compare) {
rval = QL_FUNCTION_PARAMETER_ERROR;
EL(ha, "failed=%xh\n", rval);
return (rval);
}
ql_flash_enable(ha);
rval = ql_erase_flash(ha, erase_all);
if (rval == QL_SUCCESS) {
for (cnt = 0; cnt < size; cnt++) {
if (cnt % 0x1000 == 0) {
ql_delay(ha, 10000);
}
rval = ql_program_flash_address(ha,
cnt + size_to_offset, *dp++);
if (rval != QL_SUCCESS) {
break;
}
}
}
ql_flash_disable(ha);
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_program_flash_address(ql_adapter_state_t *ha, uint32_t addr, uint8_t data)
{
int rval;
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ql_write_flash_byte(ha, 0x5555, 0xa0);
ql_write_flash_byte(ha, addr, data);
} else {
ql_write_flash_byte(ha, 0x5555, 0xaa);
ql_write_flash_byte(ha, 0x2aaa, 0x55);
ql_write_flash_byte(ha, 0x5555, 0xa0);
ql_write_flash_byte(ha, addr, data);
}
rval = ql_poll_flash(ha, addr, data);
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
int
ql_erase_flash(ql_adapter_state_t *ha, int erase_all)
{
int rval;
uint32_t erase_delay = 2000000;
uint32_t sStartAddr;
uint32_t ssize;
uint32_t cnt;
uint8_t *bfp;
uint8_t *tmp;
QL_PRINT_3(ha, "started\n");
if ((CFG_IST(ha, CFG_SBUS_CARD)) && !erase_all) {
if (ql_flash_sbus_fpga == 1) {
ssize = QL_SBUS_FCODE_SIZE;
sStartAddr = QL_FCODE_OFFSET;
} else {
ssize = QL_FPGA_SIZE;
sStartAddr = QL_FPGA_OFFSET;
}
erase_delay = 20000000;
bfp = (uint8_t *)kmem_zalloc(ssize, KM_SLEEP);
tmp = bfp;
for (cnt = sStartAddr; cnt < ssize + sStartAddr; cnt++) {
if (cnt % 0x1000 == 0) {
ql_delay(ha, 10000);
}
*tmp++ = (uint8_t)ql_read_flash_byte(ha, cnt);
}
ql_write_flash_byte(ha, 0x5555, 0xaa);
ql_write_flash_byte(ha, 0x2aaa, 0x55);
ql_write_flash_byte(ha, 0x5555, 0x80);
ql_write_flash_byte(ha, 0x5555, 0xaa);
ql_write_flash_byte(ha, 0x2aaa, 0x55);
ql_write_flash_byte(ha, 0x5555, 0x10);
ql_delay(ha, erase_delay);
rval = ql_poll_flash(ha, 0, 0x80);
if (rval == QL_SUCCESS) {
tmp = bfp;
for (cnt = sStartAddr; cnt < ssize + sStartAddr;
cnt++) {
if (cnt % 0x1000 == 0) {
ql_delay(ha, 10000);
}
rval = ql_program_flash_address(ha, cnt,
*tmp++);
if (rval != QL_SUCCESS) {
break;
}
}
}
kmem_free(bfp, ssize);
} else {
ql_write_flash_byte(ha, 0x5555, 0xaa);
ql_write_flash_byte(ha, 0x2aaa, 0x55);
ql_write_flash_byte(ha, 0x5555, 0x80);
ql_write_flash_byte(ha, 0x5555, 0xaa);
ql_write_flash_byte(ha, 0x2aaa, 0x55);
ql_write_flash_byte(ha, 0x5555, 0x10);
ql_delay(ha, erase_delay);
rval = ql_poll_flash(ha, 0, 0x80);
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
int
ql_poll_flash(ql_adapter_state_t *ha, uint32_t addr, uint8_t poll_data)
{
uint8_t flash_data;
uint32_t cnt;
int rval = QL_FUNCTION_FAILED;
QL_PRINT_3(ha, "started\n");
poll_data = (uint8_t)(poll_data & BIT_7);
for (cnt = 30000000; cnt; cnt--) {
flash_data = (uint8_t)ql_read_flash_byte(ha, addr);
if ((flash_data & BIT_7) == poll_data) {
rval = QL_SUCCESS;
break;
}
if (flash_data & BIT_5 && cnt > 2) {
cnt = 2;
}
drv_usecwait(1);
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
void
ql_flash_enable(ql_adapter_state_t *ha)
{
uint16_t data;
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha, CFG_SBUS_CARD)) {
data = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_CONF));
data = (uint16_t)(data | SBUS_FLASH_WRITE_ENABLE);
ddi_put16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_CONF), data);
ql_write_flash_byte(ha, 0xaaa, 0xaa);
ql_write_flash_byte(ha, 0x555, 0x55);
ql_write_flash_byte(ha, 0xaaa, 0x20);
ql_write_flash_byte(ha, 0x555, 0xf0);
} else {
data = (uint16_t)(RD16_IO_REG(ha, ctrl_status) |
ISP_FLASH_ENABLE);
WRT16_IO_REG(ha, ctrl_status, data);
ql_write_flash_byte(ha, 0x5555, 0xaa);
ql_write_flash_byte(ha, 0x2aaa, 0x55);
ql_write_flash_byte(ha, 0x5555, 0xf0);
}
(void) ql_read_flash_byte(ha, 0);
QL_PRINT_3(ha, "done\n");
}
void
ql_flash_disable(ql_adapter_state_t *ha)
{
uint16_t data;
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ql_write_flash_byte(ha, 0x555, 0x90);
ql_write_flash_byte(ha, 0x555, 0x0);
data = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_CONF));
data = (uint16_t)(data & ~SBUS_FLASH_WRITE_ENABLE);
ddi_put16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_CONF), data);
} else {
data = (uint16_t)(RD16_IO_REG(ha, ctrl_status) &
~ISP_FLASH_ENABLE);
WRT16_IO_REG(ha, ctrl_status, data);
}
QL_PRINT_3(ha, "done\n");
}
void
ql_write_flash_byte(ql_adapter_state_t *ha, uint32_t addr, uint8_t data)
{
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ddi_put16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_EEPROM_LOADDR),
LSW(addr));
ddi_put16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_EEPROM_HIADDR),
MSW(addr));
ddi_put16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_EEPROM_DATA),
(uint16_t)data);
} else {
uint16_t bank_select;
bank_select = (uint16_t)RD16_IO_REG(ha, ctrl_status);
if (ha->device_id == 0x2322 || ha->device_id == 0x6322) {
bank_select = (uint16_t)(bank_select & ~0xf0);
bank_select = (uint16_t)(bank_select |
((addr >> 12 & 0xf0) | ISP_FLASH_64K_BANK));
WRT16_IO_REG(ha, ctrl_status, bank_select);
} else {
if (addr & BIT_16 && !(bank_select &
ISP_FLASH_64K_BANK)) {
bank_select = (uint16_t)(bank_select |
ISP_FLASH_64K_BANK);
WRT16_IO_REG(ha, ctrl_status, bank_select);
} else if (!(addr & BIT_16) && bank_select &
ISP_FLASH_64K_BANK) {
bank_select = (uint16_t)(bank_select &
~ISP_FLASH_64K_BANK);
WRT16_IO_REG(ha, ctrl_status, bank_select);
}
}
if (CFG_IST(ha, CFG_SBUS_CARD)) {
WRT16_IO_REG(ha, flash_address, (uint16_t)addr);
WRT16_IO_REG(ha, flash_data, (uint16_t)data);
} else {
WRT16_IOMAP_REG(ha, flash_address, addr);
WRT16_IOMAP_REG(ha, flash_data, data);
}
}
}
uint8_t
ql_read_flash_byte(ql_adapter_state_t *ha, uint32_t addr)
{
uint8_t data;
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ddi_put16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_EEPROM_LOADDR),
LSW(addr));
ddi_put16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_EEPROM_HIADDR),
MSW(addr));
data = (uint8_t)ddi_get16(ha->sbus_fpga_dev_handle,
(uint16_t *)(ha->sbus_fpga_iobase + FPGA_EEPROM_DATA));
} else {
uint16_t bank_select;
bank_select = RD16_IO_REG(ha, ctrl_status);
if (ha->device_id == 0x2322 || ha->device_id == 0x6322) {
bank_select = (uint16_t)(bank_select & ~0xf0);
bank_select = (uint16_t)(bank_select |
((addr >> 12 & 0xf0) | ISP_FLASH_64K_BANK));
WRT16_IO_REG(ha, ctrl_status, bank_select);
} else {
if (addr & BIT_16 &&
!(bank_select & ISP_FLASH_64K_BANK)) {
bank_select = (uint16_t)(bank_select |
ISP_FLASH_64K_BANK);
WRT16_IO_REG(ha, ctrl_status, bank_select);
} else if (!(addr & BIT_16) &&
bank_select & ISP_FLASH_64K_BANK) {
bank_select = (uint16_t)(bank_select &
~ISP_FLASH_64K_BANK);
WRT16_IO_REG(ha, ctrl_status, bank_select);
}
}
if (CFG_IST(ha, CFG_SBUS_CARD)) {
WRT16_IO_REG(ha, flash_address, addr);
data = (uint8_t)RD16_IO_REG(ha, flash_data);
} else {
WRT16_IOMAP_REG(ha, flash_address, addr);
data = (uint8_t)RD16_IOMAP_REG(ha, flash_data);
}
}
return (data);
}
int
ql_24xx_flash_id(ql_adapter_state_t *vha)
{
int rval;
uint32_t fdata = 0;
ql_adapter_state_t *ha = vha->pha;
ql_xioctl_t *xp = ha->xioctl;
QL_PRINT_3(ha, "started\n");
rval = ql_24xx_read_flash(ha, FLASH_CONF_ADDR | 0x3AB, &fdata);
if (CFG_IST(ha, CFG_CTRL_24XX)) {
if (rval != QL_SUCCESS || fdata == 0) {
fdata = 0;
rval = ql_24xx_read_flash(ha, FLASH_CONF_ADDR | 0x39F,
&fdata);
}
} else {
fdata = 0;
rval = ql_24xx_read_flash(ha, FLASH_CONF_ADDR |
(CFG_IST(ha, CFG_CTRL_25XX) ? 0x49F : 0x39F), &fdata);
}
if (rval != QL_SUCCESS) {
EL(ha, "24xx read_flash failed=%xh\n", rval);
} else if (fdata != 0) {
xp->fdesc.flash_manuf = LSB(LSW(fdata));
xp->fdesc.flash_id = MSB(LSW(fdata));
xp->fdesc.flash_len = LSB(MSW(fdata));
} else {
xp->fdesc.flash_manuf = ATMEL_FLASH;
xp->fdesc.flash_id = ATMEL_FLASHID_1024K;
xp->fdesc.flash_len = 0;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
int
ql_24xx_load_flash(ql_adapter_state_t *vha, uint8_t *dp, uint32_t size,
uint32_t faddr)
{
int rval;
uint32_t cnt, rest_addr, fdata, wc;
dma_mem_t dmabuf = {0};
ql_adapter_state_t *ha = vha->pha;
ql_xioctl_t *xp = ha->xioctl;
QL_PRINT_3(ha, "started, faddr=%xh, size=%xh\n",
ha->instance, faddr, size);
if ((faddr & 0x3) != 0) {
EL(ha, "incorrect buffer size alignment\n");
return (QL_FUNCTION_PARAMETER_ERROR);
}
if (CFG_IST(ha, CFG_FLASH_DMA_SUPPORT)) {
if ((rval = ql_get_dma_mem(ha, &dmabuf, 0xffff,
LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN)) !=
QL_SUCCESS) {
EL(ha, "dma alloc failed, rval=%xh\n", rval);
return (rval);
}
}
if ((rval = ql_24xx_unprotect_flash(ha)) != QL_SUCCESS) {
EL(ha, "unprotect_flash failed, rval=%xh\n", rval);
ql_free_phys(ha, &dmabuf);
return (rval);
}
rest_addr = (xp->fdesc.block_size - 1) >> 2;
faddr = faddr >> 2;
cnt = 0;
size = (size + 3) >> 2;
while (cnt < size) {
if ((faddr & rest_addr) == 0) {
if (CFG_IST(ha, CFG_CTRL_82XX)) {
fdata = ha->flash_data_addr | faddr;
rval = ql_8021_rom_erase(ha, fdata);
if (rval != QL_SUCCESS) {
EL(ha, "8021 erase sector status="
"%xh, start=%xh, end=%xh"
"\n", rval, fdata,
fdata + rest_addr);
break;
}
} else if (CFG_IST(ha, CFG_FLASH_ACC_SUPPORT)) {
fdata = ha->flash_data_addr | faddr;
rval = ql_flash_access(ha,
FAC_ERASE_SECTOR, fdata, fdata +
rest_addr, 0);
if (rval != QL_SUCCESS) {
EL(ha, "erase sector status="
"%xh, start=%xh, end=%xh"
"\n", rval, fdata,
fdata + rest_addr);
break;
}
} else {
fdata = (faddr & ~rest_addr) << 2;
fdata = (fdata & 0xff00) |
(fdata << 16 & 0xff0000) |
(fdata >> 16 & 0xff);
if (rest_addr == 0x1fff) {
rval = ql_24xx_write_flash(ha,
FLASH_CONF_ADDR | 0x0352,
fdata);
} else {
rval = ql_24xx_write_flash(ha,
FLASH_CONF_ADDR | 0x03d8,
fdata);
}
if (rval != QL_SUCCESS) {
EL(ha, "Unable to flash sector"
": address=%xh\n", faddr);
break;
}
}
}
if (CFG_IST(ha, CFG_FLASH_DMA_SUPPORT) &&
((faddr & 0x3f) == 0)) {
wc = ((~faddr & (rest_addr>>1)) + 1);
if (size - cnt < wc) {
wc = size - cnt;
}
ddi_rep_put8(dmabuf.acc_handle, (uint8_t *)dp,
(uint8_t *)dmabuf.bp, wc<<2,
DDI_DEV_AUTOINCR);
rval = ql_wrt_risc_ram(ha, ha->flash_data_addr |
faddr, dmabuf.cookie.dmac_laddress, wc);
if (rval != QL_SUCCESS) {
EL(ha, "unable to dma to flash "
"address=%xh\n", faddr << 2);
break;
}
cnt += wc;
faddr += wc;
dp += wc << 2;
} else {
fdata = *dp++;
fdata |= *dp++ << 8;
fdata |= *dp++ << 16;
fdata |= *dp++ << 24;
rval = ql_24xx_write_flash(ha,
ha->flash_data_addr | faddr, fdata);
if (rval != QL_SUCCESS) {
EL(ha, "Unable to program flash "
"address=%xh data=%xh\n", faddr,
*dp);
break;
}
cnt++;
faddr++;
if (cnt % 0x1000 == 0) {
ql_delay(ha, 10000);
}
}
}
ql_24xx_protect_flash(ha);
if (CFG_IST(ha, CFG_FLASH_DMA_SUPPORT)) {
ql_free_phys(ha, &dmabuf);
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
int
ql_24xx_read_flash(ql_adapter_state_t *vha, uint32_t faddr, uint32_t *bp)
{
uint32_t timer;
int rval = QL_SUCCESS;
ql_adapter_state_t *ha = vha->pha;
if (CFG_IST(ha, CFG_CTRL_82XX)) {
if ((rval = ql_8021_rom_read(ha, faddr, bp)) != QL_SUCCESS) {
EL(ha, "8021 access error\n");
}
return (rval);
}
WRT32_IO_REG(ha, ctrl_status,
RD32_IO_REG(ha, ctrl_status) | FLASH_NVRAM_ACCESS_ERROR);
WRT32_IO_REG(ha, flash_address, faddr & ~FLASH_DATA_FLAG);
for (timer = 300000; timer; timer--) {
if (RD32_IO_REG(ha, flash_address) & FLASH_DATA_FLAG) {
break;
}
drv_usecwait(10);
}
if (timer == 0) {
EL(ha, "failed, timeout\n");
rval = QL_FUNCTION_TIMEOUT;
} else if (RD32_IO_REG(ha, ctrl_status) & FLASH_NVRAM_ACCESS_ERROR) {
EL(ha, "failed, access error\n");
rval = QL_FUNCTION_FAILED;
}
*bp = RD32_IO_REG(ha, flash_data);
return (rval);
}
int
ql_24xx_write_flash(ql_adapter_state_t *vha, uint32_t addr, uint32_t data)
{
uint32_t timer, fdata;
int rval = QL_SUCCESS;
ql_adapter_state_t *ha = vha->pha;
if (CFG_IST(ha, CFG_CTRL_82XX)) {
if ((rval = ql_8021_rom_write(ha, addr, data)) != QL_SUCCESS) {
EL(ha, "8021 access error\n");
}
return (rval);
}
WRT32_IO_REG(ha, ctrl_status,
RD32_IO_REG(ha, ctrl_status) | FLASH_NVRAM_ACCESS_ERROR);
WRT32_IO_REG(ha, flash_data, data);
RD32_IO_REG(ha, flash_data);
WRT32_IO_REG(ha, flash_address, addr | FLASH_DATA_FLAG);
for (timer = 3000000; timer; timer--) {
if ((RD32_IO_REG(ha, flash_address) & FLASH_DATA_FLAG) == 0) {
if ((addr & FLASH_ADDR_MASK) == FLASH_CONF_ADDR) {
(void) ql_24xx_read_flash(ha,
FLASH_CONF_ADDR | 0x105, &fdata);
if (!(fdata & BIT_0)) {
break;
}
} else {
break;
}
}
drv_usecwait(10);
}
if (timer == 0) {
EL(ha, "failed, timeout\n");
rval = QL_FUNCTION_TIMEOUT;
} else if (RD32_IO_REG(ha, ctrl_status) & FLASH_NVRAM_ACCESS_ERROR) {
EL(ha, "access error\n");
rval = QL_FUNCTION_FAILED;
}
return (rval);
}
int
ql_24xx_unprotect_flash(ql_adapter_state_t *vha)
{
int rval;
uint32_t fdata, timer;
ql_adapter_state_t *ha = vha->pha;
ql_xioctl_t *xp = ha->xioctl;
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_82XX)) {
(void) ql_8021_rom_wrsr(ha, xp->fdesc.write_enable_bits);
rval = ql_8021_rom_wrsr(ha, xp->fdesc.write_enable_bits);
if (rval != QL_SUCCESS) {
EL(ha, "8021 access error\n");
}
return (rval);
}
if (CFG_IST(ha, CFG_FLASH_ACC_SUPPORT)) {
if (ha->task_daemon_flags & FIRMWARE_UP) {
for (timer = 3000; timer; timer--) {
if (ha->task_daemon_flags & ISP_ABORT_NEEDED) {
EL(ha, "ISP_ABORT_NEEDED done\n");
return (QL_ABORTED);
}
rval = ql_flash_access(ha, FAC_SEMA_LOCK,
0, 0, NULL);
if (rval == QL_SUCCESS ||
rval == QL_FUNCTION_TIMEOUT) {
EL(ha, "lock status=%xh\n", rval);
break;
}
delay(1);
}
if (rval == QL_SUCCESS &&
(rval = ql_flash_access(ha, FAC_WRT_ENABLE, 0,
0, NULL)) != QL_SUCCESS) {
EL(ha, "WRT_ENABLE status=%xh\n", rval);
(void) ql_flash_access(ha, FAC_SEMA_UNLOCK,
0, 0, NULL);
}
} else {
rval = QL_SUCCESS;
}
QL_PRINT_3(ha, "CFG_FLASH_ACC_SUPPORT done\n");
return (rval);
} else {
WRT32_IO_REG(ha, ctrl_status,
RD32_IO_REG(ha, ctrl_status) | ISP_FLASH_ENABLE);
RD32_IO_REG(ha, ctrl_status);
}
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x100 |
xp->fdesc.write_statusreg_cmd, xp->fdesc.write_enable_bits);
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x100 |
xp->fdesc.write_statusreg_cmd, xp->fdesc.write_enable_bits);
if (xp->fdesc.unprotect_sector_cmd != 0) {
for (fdata = 0; fdata < 0x10; fdata++) {
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR |
0x300 | xp->fdesc.unprotect_sector_cmd, fdata);
}
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x300 |
xp->fdesc.unprotect_sector_cmd, 0x00400f);
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x300 |
xp->fdesc.unprotect_sector_cmd, 0x00600f);
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x300 |
xp->fdesc.unprotect_sector_cmd, 0x00800f);
}
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
void
ql_24xx_protect_flash(ql_adapter_state_t *vha)
{
int rval;
uint32_t fdata, timer;
ql_adapter_state_t *ha = vha->pha;
ql_xioctl_t *xp = ha->xioctl;
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_82XX)) {
(void) ql_8021_rom_wrsr(ha, xp->fdesc.write_enable_bits);
rval = ql_8021_rom_wrsr(ha, xp->fdesc.write_disable_bits);
if (rval != QL_SUCCESS) {
EL(ha, "8021 access error\n");
}
return;
}
if (CFG_IST(ha, CFG_FLASH_ACC_SUPPORT)) {
if (ha->task_daemon_flags & FIRMWARE_UP) {
for (timer = 3000; timer; timer--) {
if (ha->task_daemon_flags & ISP_ABORT_NEEDED) {
EL(ha, "ISP_ABORT_NEEDED done\n");
return;
}
rval = ql_flash_access(ha, FAC_SEMA_LOCK,
0, 0, NULL);
if (rval == QL_SUCCESS ||
rval == QL_FUNCTION_TIMEOUT) {
if (rval != QL_SUCCESS) {
EL(ha, "lock status=%xh\n",
rval);
}
break;
}
delay(1);
}
if (rval == QL_SUCCESS &&
(rval = ql_flash_access(ha, FAC_WRT_PROTECT, 0,
0, NULL)) != QL_SUCCESS) {
EL(ha, "protect status=%xh\n", rval);
(void) ql_flash_access(ha, FAC_SEMA_UNLOCK, 0,
0, NULL);
}
QL_PRINT_3(ha, "CFG_FLASH_ACC_SUPPORT done\n");
return;
}
} else {
WRT32_IO_REG(ha, ctrl_status,
RD32_IO_REG(ha, ctrl_status) | ISP_FLASH_ENABLE);
RD32_IO_REG(ha, ctrl_status);
}
if (xp->fdesc.protect_sector_cmd != 0) {
for (fdata = 0; fdata < 0x10; fdata++) {
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR |
0x300 | xp->fdesc.protect_sector_cmd, fdata);
}
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x300 |
xp->fdesc.protect_sector_cmd, 0x00400f);
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x300 |
xp->fdesc.protect_sector_cmd, 0x00600f);
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x300 |
xp->fdesc.protect_sector_cmd, 0x00800f);
}
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x100 |
xp->fdesc.write_statusreg_cmd, xp->fdesc.write_enable_bits);
(void) ql_24xx_write_flash(ha, FLASH_CONF_ADDR | 0x100 |
xp->fdesc.write_statusreg_cmd, xp->fdesc.write_disable_bits);
if (!CFG_IST(ha, CFG_FLASH_ACC_SUPPORT)) {
WRT32_IO_REG(ha, ctrl_status,
RD32_IO_REG(ha, ctrl_status) & ~ISP_FLASH_ENABLE);
RD32_IO_REG(ha, ctrl_status);
}
QL_PRINT_3(ha, "done\n");
}
int
ql_dump_firmware(ql_adapter_state_t *vha)
{
int rval;
clock_t timer = drv_usectohz(30000000);
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_3(ha, "started\n");
QL_DUMP_LOCK(ha);
if (ha->ql_dump_state & QL_DUMPING ||
(ha->ql_dump_state & QL_DUMP_VALID &&
!(ha->ql_dump_state & QL_DUMP_UPLOADED))) {
QL_PRINT_3(ha, "done\n");
QL_DUMP_UNLOCK(ha);
return (QL_SUCCESS);
}
QL_DUMP_UNLOCK(ha);
(void) ql_stall_driver(ha, 0);
if (CFG_IST(ha, CFG_CTRL_82XX)) {
rval = ql_binary_fw_dump(ha, FALSE);
} else {
rval = ql_binary_fw_dump(ha, TRUE);
}
ql_restart_driver(ha);
ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED, 0);
EL(ha, "restarting, isp_abort_needed\n");
TASK_DAEMON_LOCK(ha);
while (DRIVER_SUSPENDED(ha)) {
ha->task_daemon_flags |= SUSPENDED_WAKEUP_FLG;
if (cv_reltimedwait(&ha->cv_dr_suspended,
&ha->task_daemon_mutex, timer, TR_CLOCK_TICK) == -1) {
break;
}
}
TASK_DAEMON_UNLOCK(ha);
if (rval == QL_SUCCESS || rval == QL_DATA_EXISTS) {
QL_PRINT_3(ha, "done\n");
} else {
EL(ha, "failed, rval = %xh\n", rval);
}
return (rval);
}
int
ql_binary_fw_dump(ql_adapter_state_t *vha, int lock_needed)
{
uint32_t cnt, index;
clock_t timer;
int rval = QL_SUCCESS;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_3(ha, "started\n");
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~FW_DUMP_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
if (CFG_IST(ha, CFG_CTRL_82XX) && ha->md_capture_size == 0) {
EL(ha, "8021 not supported\n");
return (QL_NOT_SUPPORTED);
}
QL_DUMP_LOCK(ha);
if (ha->ql_dump_state & QL_DUMPING ||
(ha->ql_dump_state & QL_DUMP_VALID &&
!(ha->ql_dump_state & QL_DUMP_UPLOADED))) {
EL(ha, "dump already done, qds=%x\n", ha->ql_dump_state);
QL_DUMP_UNLOCK(ha);
return (QL_DATA_EXISTS);
}
ha->ql_dump_state &= ~(QL_DUMP_VALID | QL_DUMP_UPLOADED);
ha->ql_dump_state |= QL_DUMPING;
QL_DUMP_UNLOCK(ha);
if (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE)) {
rval = ql_fw_etrace(ha, &ha->fwexttracebuf,
FTO_INSERT_TIME_STAMP, NULL);
if (rval != QL_SUCCESS) {
EL(ha, "f/w extended trace insert"
"time stamp failed: %xh\n", rval);
}
}
if (lock_needed == TRUE) {
MBX_REGISTER_LOCK(ha);
timer = ((MAILBOX_TOV + 6) * drv_usectohz(1000000));
while (ha->mailbox_flags & MBX_BUSY_FLG) {
ha->mailbox_flags = (uint8_t)
(ha->mailbox_flags | MBX_WANT_FLG);
if (cv_reltimedwait(&ha->cv_mbx_wait, &ha->mbx_mutex,
timer, TR_CLOCK_TICK) == -1) {
MBX_REGISTER_UNLOCK(ha);
EL(ha, "failed, rval = %xh\n",
QL_FUNCTION_TIMEOUT);
return (QL_FUNCTION_TIMEOUT);
}
}
ha->mailbox_flags = (uint8_t)
(ha->mailbox_flags | MBX_BUSY_FLG);
MBX_REGISTER_UNLOCK(ha);
}
if (ha->ql_dump_ptr != NULL) {
kmem_free(ha->ql_dump_ptr, ha->ql_dump_size);
ha->ql_dump_ptr = NULL;
}
if (CFG_IST(ha, CFG_CTRL_24XX)) {
ha->ql_dump_size = (uint32_t)(sizeof (ql_24xx_fw_dump_t) +
ha->fw_ext_memory_size);
} else if (CFG_IST(ha, CFG_CTRL_25XX)) {
cnt = ha->rsp_queues_cnt > 1 ? ha->req_q[0]->req_ring.size +
ha->req_q[1]->req_ring.size : ha->req_q[0]->req_ring.size;
index = ha->rsp_queues[0]->rsp_ring.size * ha->rsp_queues_cnt;
ha->ql_dump_size = (uint32_t)(sizeof (ql_25xx_fw_dump_t) +
cnt + index + ha->fw_ext_memory_size +
(ha->rsp_queues_cnt * 16));
} else if (CFG_IST(ha, CFG_CTRL_81XX)) {
cnt = ha->rsp_queues_cnt > 1 ? ha->req_q[0]->req_ring.size +
ha->req_q[1]->req_ring.size : ha->req_q[0]->req_ring.size;
index = ha->rsp_queues[0]->rsp_ring.size * ha->rsp_queues_cnt;
ha->ql_dump_size = (uint32_t)(sizeof (ql_81xx_fw_dump_t) +
cnt + index + ha->fw_ext_memory_size +
(ha->rsp_queues_cnt * 16));
} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
cnt = ha->rsp_queues_cnt > 1 ? ha->req_q[0]->req_ring.size +
ha->req_q[1]->req_ring.size : ha->req_q[0]->req_ring.size;
index = ha->rsp_queues[0]->rsp_ring.size * ha->rsp_queues_cnt;
ha->ql_dump_size = (uint32_t)(sizeof (ql_83xx_fw_dump_t) +
cnt + index + ha->fw_ext_memory_size +
(ha->rsp_queues_cnt * 16));
} else if (CFG_IST(ha, CFG_CTRL_82XX)) {
ha->ql_dump_size = ha->md_capture_size;
} else {
ha->ql_dump_size = sizeof (ql_fw_dump_t);
}
if (CFG_IST(ha, CFG_CTRL_27XX)) {
rval = ql_27xx_binary_fw_dump(ha);
} else {
if ((ha->ql_dump_ptr =
kmem_zalloc(ha->ql_dump_size, KM_NOSLEEP)) == NULL) {
rval = QL_MEMORY_ALLOC_FAILED;
} else {
if (CFG_IST(ha, CFG_CTRL_2363)) {
rval = ql_2300_binary_fw_dump(ha,
ha->ql_dump_ptr);
} else if (CFG_IST(ha, CFG_CTRL_81XX)) {
rval = ql_81xx_binary_fw_dump(ha,
ha->ql_dump_ptr);
} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
rval = ql_83xx_binary_fw_dump(ha,
ha->ql_dump_ptr);
} else if (CFG_IST(ha, CFG_CTRL_25XX)) {
rval = ql_25xx_binary_fw_dump(ha,
ha->ql_dump_ptr);
} else if (CFG_IST(ha, CFG_CTRL_24XX)) {
rval = ql_24xx_binary_fw_dump(ha,
ha->ql_dump_ptr);
} else if (CFG_IST(ha, CFG_CTRL_82XX)) {
(void) ql_8021_reset_fw(ha);
rval = QL_SUCCESS;
} else {
rval = ql_2200_binary_fw_dump(ha,
ha->ql_dump_ptr);
}
}
}
ql_reset_chip(ha);
QL_DUMP_LOCK(ha);
if (rval != QL_SUCCESS) {
if (ha->ql_dump_ptr != NULL) {
kmem_free(ha->ql_dump_ptr, ha->ql_dump_size);
ha->ql_dump_ptr = NULL;
}
ha->ql_dump_state &= ~(QL_DUMPING | QL_DUMP_VALID |
QL_DUMP_UPLOADED);
EL(ha, "failed, rval = %xh\n", rval);
} else {
ha->ql_dump_state &= ~(QL_DUMPING | QL_DUMP_UPLOADED);
ha->ql_dump_state |= QL_DUMP_VALID;
EL(ha, "done\n");
}
QL_DUMP_UNLOCK(ha);
return (rval);
}
size_t
ql_ascii_fw_dump(ql_adapter_state_t *vha, caddr_t bufp)
{
uint32_t cnt;
caddr_t bp;
int mbox_cnt;
ql_adapter_state_t *ha = vha->pha;
ql_fw_dump_t *fw = ha->ql_dump_ptr;
if (CFG_IST(ha, CFG_CTRL_24XX)) {
return (ql_24xx_ascii_fw_dump(ha, bufp));
} else if (CFG_IST(ha, CFG_CTRL_25XX)) {
return (ql_25xx_ascii_fw_dump(ha, bufp));
} else if (CFG_IST(ha, CFG_CTRL_81XX)) {
return (ql_81xx_ascii_fw_dump(ha, bufp));
} else if (CFG_IST(ha, CFG_CTRL_82XX)) {
return (ql_8021_ascii_fw_dump(ha, bufp));
} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
return (ql_83xx_ascii_fw_dump(ha, bufp));
} else if (CFG_IST(ha, CFG_CTRL_27XX)) {
return (ql_27xx_ascii_fw_dump(ha, bufp));
}
QL_PRINT_3(ha, "started\n");
if (CFG_IST(ha, CFG_CTRL_23XX)) {
(void) sprintf(bufp, "\nISP 2300IP ");
} else if (CFG_IST(ha, CFG_CTRL_63XX)) {
(void) sprintf(bufp, "\nISP 2322/6322FLX ");
} else {
(void) sprintf(bufp, "\nISP 2200IP ");
}
bp = bufp + strlen(bufp);
(void) sprintf(bp, "Firmware Version %d.%d.%d\n",
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version);
(void) strcat(bufp, "\nPBIU Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->pbiu_reg[cnt]);
bp = bp + 6;
}
if (CFG_IST(ha, CFG_CTRL_2363)) {
(void) strcat(bufp, "\n\nReqQ-RspQ-Risc2Host Status "
"registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_host_reg[cnt]);
bp = bp + 6;
}
}
(void) strcat(bp, "\n\nMailbox Registers:");
bp = bufp + strlen(bufp);
mbox_cnt = CFG_IST(ha, CFG_CTRL_2363) ? 16 : 8;
for (cnt = 0; cnt < mbox_cnt; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->mailbox_reg[cnt]);
bp = bp + 6;
}
if (CFG_IST(ha, CFG_CTRL_2363)) {
(void) strcat(bp, "\n\nAuto Request Response DMA Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->resp_dma_reg[cnt]);
bp = bp + 6;
}
}
(void) strcat(bp, "\n\nDMA Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->dma_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC Hardware Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_hdw_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP0 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp0_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP1 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp1_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP2 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp2_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP3 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp3_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP4 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp4_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP5 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp5_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP6 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp6_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nRISC GP7 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->risc_gp7_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nFrame Buffer Hardware Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
if (cnt == 16 && !CFG_IST(ha, CFG_CTRL_2363)) {
break;
}
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->frame_buf_hdw_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nFPM B0 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->fpm_b0_reg[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nFPM B1 Registers:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
if (cnt % 8 == 0) {
*bp++ = '\n';
}
(void) sprintf(bp, "%04x ", fw->fpm_b1_reg[cnt]);
bp = bp + 6;
}
if (CFG_IST(ha, CFG_CTRL_2363)) {
(void) strcat(bp, "\n\nCode RAM Dump:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%05x: ", cnt + 0x0800);
bp = bp + 8;
}
(void) sprintf(bp, "%04x ", fw->risc_ram[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nStack RAM Dump:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%05x: ", cnt + 0x010000);
bp = bp + 8;
}
(void) sprintf(bp, "%04x ", fw->stack_ram[cnt]);
bp = bp + 6;
}
(void) strcat(bp, "\n\nData RAM Dump:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < sizeof (fw->data_ram) / 2; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%05x: ", cnt + 0x010800);
bp = bp + 8;
}
(void) sprintf(bp, "%04x ", fw->data_ram[cnt]);
bp = bp + 6;
}
} else {
(void) strcat(bp, "\n\nRISC SRAM:");
bp = bufp + strlen(bufp);
for (cnt = 0; cnt < 0xf000; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%04x: ", cnt + 0x1000);
bp = bp + 7;
}
(void) sprintf(bp, "%04x ", fw->risc_ram[cnt]);
bp = bp + 6;
}
}
(void) strcat(bp, "\n\n[<==END] ISP Debug Dump.");
bp += strlen(bp);
(void) sprintf(bp, "\n\nRequest Queue");
bp += strlen(bp);
for (cnt = 0; cnt < REQUEST_QUEUE_SIZE / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", fw->req_q[cnt]);
bp += strlen(bp);
}
(void) sprintf(bp, "\n\nResponse Queue");
bp += strlen(bp);
for (cnt = 0; cnt < RESPONSE_QUEUE_SIZE / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", fw->rsp_q[cnt]);
bp += strlen(bp);
}
(void) sprintf(bp, "\n");
QL_PRINT_10(ha, "done, size=0x%x\n", strlen(bufp));
return (strlen(bufp));
}
static size_t
ql_24xx_ascii_fw_dump(ql_adapter_state_t *ha, caddr_t bufp)
{
uint32_t cnt;
caddr_t bp = bufp;
ql_24xx_fw_dump_t *fw = ha->ql_dump_ptr;
QL_PRINT_3(ha, "started\n");
(void) sprintf(bp, "ISP FW Version %d.%02d.%02d Attributes %X\n",
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version, ha->fw_attributes);
bp += strlen(bp);
(void) sprintf(bp, "\nHCCR Register\n%08x\n", fw->hccr);
(void) strcat(bp, "\nHost Interface Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->host_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->host_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nMailbox Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
if (cnt % 16 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%04x ", fw->mailbox_reg[cnt]);
bp += 5;
}
(void) sprintf(bp, "\n\nXSEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXSEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXSEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-2 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_2_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nCommand DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->cmd_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->cmd_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRequest0 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->req0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->req0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nResponse0 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->resp0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->resp0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRequest1 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->req1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->req1_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT0 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT1 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt1_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT2 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt2_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt2_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT3 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt3_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt3_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT4 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt4_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt4_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT Data DMA Common Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRCV Thread 0 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rcvt0_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rcvt0_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRCV Thread 1 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rcvt1_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rcvt1_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRISC GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->risc_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->risc_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bufp + strlen(bufp), "\n\nShadow Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->shadow_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->shadow_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nLMC Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->lmc_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->lmc_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nFPM Hardware Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->fpm_hdw_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->fpm_hdw_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nFB Hardware Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->fb_hdw_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->fb_hdw_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nCode RAM");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt + 0x20000);
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->code_ram[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nExternal Memory");
bp += strlen(bp);
for (cnt = 0; cnt < ha->fw_ext_memory_size / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt + 0x100000);
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->ext_mem[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n[<==END] ISP Debug Dump");
bp += strlen(bp);
(void) sprintf(bp, "\n\nRequest Queue");
bp += strlen(bp);
for (cnt = 0; cnt < REQUEST_QUEUE_SIZE / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", fw->req_q[cnt]);
bp += strlen(bp);
}
(void) sprintf(bp, "\n\nResponse Queue");
bp += strlen(bp);
for (cnt = 0; cnt < RESPONSE_QUEUE_SIZE / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", fw->rsp_q[cnt]);
bp += strlen(bp);
}
if (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) &&
(ha->fwexttracebuf.bp != NULL)) {
uint32_t cnt_b = 0;
uint64_t w64 = (uintptr_t)ha->fwexttracebuf.bp;
(void) sprintf(bp, "\n\nExtended Trace Buffer Memory");
bp += strlen(bp);
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) sprintf(bp, "\n%08x: ",
(int)(w64 + cnt_b));
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->ext_trace_buf[cnt]);
bp += 9;
}
}
if (CFG_IST(ha, CFG_ENABLE_FWFCETRACE) &&
(ha->fwfcetracebuf.bp != NULL)) {
uint32_t cnt_b = 0;
uint64_t w64 = (uintptr_t)ha->fwfcetracebuf.bp;
(void) sprintf(bp, "\n\nFC Event Trace Buffer Memory");
bp += strlen(bp);
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) sprintf(bp, "\n%08x: ",
(int)(w64 + cnt_b));
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->fce_trace_buf[cnt]);
bp += 9;
}
}
(void) sprintf(bp, "\n\n");
bp += strlen(bp);
cnt = (uint32_t)((uintptr_t)bp - (uintptr_t)bufp);
QL_PRINT_10(ha, "done=%xh\n", cnt);
return (cnt);
}
static size_t
ql_25xx_ascii_fw_dump(ql_adapter_state_t *ha, caddr_t bufp)
{
uint32_t cnt, cnt1, *dp, *dp2;
caddr_t bp = bufp;
ql_25xx_fw_dump_t *fw = ha->ql_dump_ptr;
QL_PRINT_3(ha, "started\n");
(void) sprintf(bp, "\nISP FW Version %d.%02d.%02d Attributes %X\n",
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version, ha->fw_attributes);
bp += strlen(bp);
(void) sprintf(bp, "\nHCCR Register\n%08x\n", fw->hccr);
bp += strlen(bp);
(void) sprintf(bp, "\nR2H Status Register\n%08x\n", fw->r2h_status);
bp += strlen(bp);
(void) sprintf(bp, "\nAER Uncorrectable Error Status Register\n%08x\n",
fw->aer_ues);
bp += strlen(bp);
(void) sprintf(bp, "\nHostRisc Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->hostrisc_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->hostrisc_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nPCIe Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->pcie_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->pcie_reg[cnt]);
bp += 9;
}
(void) strcat(bp, "\n\nHost Interface Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->host_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->host_reg[cnt]);
bp += 9;
}
(void) sprintf(bufp + strlen(bufp), "\n\nShadow Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->shadow_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->shadow_reg[cnt]);
bp += 9;
}
(void) sprintf(bufp + strlen(bufp), "\n\nRISC IO Register\n%08x",
fw->risc_io);
bp += strlen(bp);
(void) sprintf(bp, "\n\nMailbox Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
if (cnt % 16 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%04x ", fw->mailbox_reg[cnt]);
bp += 5;
}
(void) sprintf(bp, "\n\nXSEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXSEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXSEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-2 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_2_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ-2 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_2_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nCommand DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->cmd_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->cmd_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRequest0 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->req0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->req0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nResponse0 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->resp0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->resp0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRequest1 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->req1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->req1_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT0 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT1 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt1_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT2 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt2_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt2_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT3 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt3_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt3_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT4 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt4_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt4_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT Data DMA Common Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRCV Thread 0 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rcvt0_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rcvt0_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRCV Thread 1 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rcvt1_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rcvt1_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRISC GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->risc_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->risc_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nLMC Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->lmc_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->lmc_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nFPM Hardware Registers");
bp += strlen(bp);
cnt1 = sizeof (fw->fpm_hdw_reg);
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->fpm_hdw_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nFB Hardware Registers");
bp += strlen(bp);
cnt1 = sizeof (fw->fb_hdw_reg);
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->fb_hdw_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nCode RAM");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt + 0x20000);
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->code_ram[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nExternal Memory");
bp += strlen(bp);
dp = (uint32_t *)((caddr_t)fw->req_rsp_ext_mem + fw->req_q_size[0] +
fw->req_q_size[1] + fw->rsp_q_size + (ha->rsp_queues_cnt * 16));
for (cnt = 0; cnt < ha->fw_ext_memory_size / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt + 0x100000);
bp += 11;
}
(void) sprintf(bp, "%08x ", *dp++);
bp += 9;
}
(void) sprintf(bp, "\n[<==END] ISP Debug Dump");
bp += strlen(bp);
dp = fw->req_rsp_ext_mem + (ha->rsp_queues_cnt * 4);
for (cnt = 0; cnt < 2 && fw->req_q_size[cnt]; cnt++) {
dp2 = dp;
for (cnt1 = 0; cnt1 < fw->req_q_size[cnt] / 4; cnt1++) {
if (*dp2++) {
break;
}
}
if (cnt1 == fw->req_q_size[cnt] / 4) {
dp = dp2;
continue;
}
(void) sprintf(bp, "\n\nRequest Queue\nQueue %d:", cnt);
bp += strlen(bp);
for (cnt1 = 0; cnt1 < fw->req_q_size[cnt] / 4; cnt1++) {
if (cnt1 % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt1);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", *dp++);
bp += strlen(bp);
}
}
for (cnt = 0; cnt < ha->rsp_queues_cnt && cnt < 16; cnt++) {
dp2 = dp;
for (cnt1 = 0; cnt1 < ha->rsp_queues[cnt]->rsp_ring.size / 4;
cnt1++) {
if (*dp2++) {
break;
}
}
if (cnt1 == ha->rsp_queues[cnt]->rsp_ring.size / 4) {
dp = dp2;
continue;
}
(void) sprintf(bp, "\n\nResponse Queue\nQueue %d:", cnt);
bp += strlen(bp);
for (cnt1 = 0; cnt1 < ha->rsp_queues[cnt]->rsp_ring.size / 4;
cnt1++) {
if (cnt1 % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt1);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", *dp++);
bp += strlen(bp);
}
}
if (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) &&
(ha->fwexttracebuf.bp != NULL)) {
uint32_t cnt_b = 0;
uint64_t w64 = (uintptr_t)ha->fwexttracebuf.bp;
(void) sprintf(bp, "\n\nExtended Trace Buffer Memory");
bp += strlen(bp);
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) sprintf(bp, "\n%08x: ",
(int)(w64 + cnt_b));
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->ext_trace_buf[cnt]);
bp += 9;
}
}
if (CFG_IST(ha, CFG_ENABLE_FWFCETRACE) &&
(ha->fwfcetracebuf.bp != NULL)) {
uint32_t cnt_b = 0;
uint64_t w64 = (uintptr_t)ha->fwfcetracebuf.bp;
(void) sprintf(bp, "\n\nFC Event Trace Buffer Memory");
bp += strlen(bp);
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) sprintf(bp, "\n%08x: ",
(int)(w64 + cnt_b));
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->fce_trace_buf[cnt]);
bp += 9;
}
}
(void) sprintf(bp, "\n\n");
bp += strlen(bp);
cnt = (uint32_t)((uintptr_t)bp - (uintptr_t)bufp);
QL_PRINT_10(ha, "done=%xh\n", cnt);
return (cnt);
}
static size_t
ql_81xx_ascii_fw_dump(ql_adapter_state_t *ha, caddr_t bufp)
{
uint32_t cnt, cnt1, *dp, *dp2;
caddr_t bp = bufp;
ql_81xx_fw_dump_t *fw = ha->ql_dump_ptr;
QL_PRINT_3(ha, "started\n");
(void) sprintf(bp, "\nISP FW Version %d.%02d.%02d Attributes %X\n",
ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version, ha->fw_attributes);
bp += strlen(bp);
(void) sprintf(bp, "\nHCCR Register\n%08x\n", fw->hccr);
bp += strlen(bp);
(void) sprintf(bp, "\nR2H Status Register\n%08x\n", fw->r2h_status);
bp += strlen(bp);
(void) sprintf(bp, "\nAER Uncorrectable Error Status Register\n%08x\n",
fw->aer_ues);
bp += strlen(bp);
(void) sprintf(bp, "\nHostRisc Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->hostrisc_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->hostrisc_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nPCIe Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->pcie_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->pcie_reg[cnt]);
bp += 9;
}
(void) strcat(bp, "\n\nHost Interface Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->host_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->host_reg[cnt]);
bp += 9;
}
(void) sprintf(bufp + strlen(bufp), "\n\nShadow Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->shadow_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->shadow_reg[cnt]);
bp += 9;
}
(void) sprintf(bufp + strlen(bufp), "\n\nRISC IO Register\n%08x",
fw->risc_io);
bp += strlen(bp);
(void) sprintf(bp, "\n\nMailbox Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
if (cnt % 16 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%04x ", fw->mailbox_reg[cnt]);
bp += 5;
}
(void) sprintf(bp, "\n\nXSEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXSEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXSEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRSEQ-2 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rseq_2_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ-0 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_0_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ-1 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_1_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nASEQ-2 Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->aseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->aseq_2_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nCommand DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->cmd_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->cmd_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRequest0 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->req0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->req0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nResponse0 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->resp0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->resp0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRequest1 Queue DMA Channel Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->req1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->req1_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT0 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt0_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT1 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt1_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT2 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt2_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt2_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT3 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt3_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt3_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT4 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt4_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt4_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nXMT Data DMA Common Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->xmt_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->xmt_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRCV Thread 0 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rcvt0_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rcvt0_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRCV Thread 1 Data DMA Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->rcvt1_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->rcvt1_data_dma_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nRISC GP Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->risc_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->risc_gp_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nLMC Registers");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->lmc_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->lmc_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nFPM Hardware Registers");
bp += strlen(bp);
cnt1 = sizeof (fw->fpm_hdw_reg);
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->fpm_hdw_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nFB Hardware Registers");
bp += strlen(bp);
cnt1 = sizeof (fw->fb_hdw_reg);
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp++, "\n");
}
(void) sprintf(bp, "%08x ", fw->fb_hdw_reg[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nCode RAM");
bp += strlen(bp);
for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt + 0x20000);
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->code_ram[cnt]);
bp += 9;
}
(void) sprintf(bp, "\n\nExternal Memory");
bp += strlen(bp);
dp = (uint32_t *)((caddr_t)fw->req_rsp_ext_mem + fw->req_q_size[0] +
fw->req_q_size[1] + fw->rsp_q_size + (ha->rsp_queues_cnt * 16));
for (cnt = 0; cnt < ha->fw_ext_memory_size / 4; cnt++) {
if (cnt % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt + 0x100000);
bp += 11;
}
(void) sprintf(bp, "%08x ", *dp++);
bp += 9;
}
(void) sprintf(bp, "\n[<==END] ISP Debug Dump");
bp += strlen(bp);
dp = fw->req_rsp_ext_mem + (ha->rsp_queues_cnt * 4);
for (cnt = 0; cnt < 2 && fw->req_q_size[cnt]; cnt++) {
dp2 = dp;
for (cnt1 = 0; cnt1 < fw->req_q_size[cnt] / 4; cnt1++) {
if (*dp2++) {
break;
}
}
if (cnt1 == fw->req_q_size[cnt] / 4) {
dp = dp2;
continue;
}
(void) sprintf(bp, "\n\nRequest Queue\nQueue %d:", cnt);
bp += strlen(bp);
for (cnt1 = 0; cnt1 < fw->req_q_size[cnt] / 4; cnt1++) {
if (cnt1 % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt1);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", *dp++);
bp += strlen(bp);
}
}
for (cnt = 0; cnt < ha->rsp_queues_cnt && cnt < 16; cnt++) {
dp2 = dp;
for (cnt1 = 0; cnt1 < ha->rsp_queues[cnt]->rsp_ring.size / 4;
cnt1++) {
if (*dp2++) {
break;
}
}
if (cnt1 == ha->rsp_queues[cnt]->rsp_ring.size / 4) {
dp = dp2;
continue;
}
(void) sprintf(bp, "\n\nResponse Queue\nQueue %d:", cnt);
bp += strlen(bp);
for (cnt1 = 0; cnt1 < ha->rsp_queues[cnt]->rsp_ring.size / 4;
cnt1++) {
if (cnt1 % 8 == 0) {
(void) sprintf(bp, "\n%08x: ", cnt1);
bp += strlen(bp);
}
(void) sprintf(bp, "%08x ", *dp++);
bp += strlen(bp);
}
}
if (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) &&
(ha->fwexttracebuf.bp != NULL)) {
uint32_t cnt_b = 0;
uint64_t w64 = (uintptr_t)ha->fwexttracebuf.bp;
(void) sprintf(bp, "\n\nExtended Trace Buffer Memory");
bp += strlen(bp);
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) sprintf(bp, "\n%08x: ",
(int)(w64 + cnt_b));
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->ext_trace_buf[cnt]);
bp += 9;
}
}
if (CFG_IST(ha, CFG_ENABLE_FWFCETRACE) &&
(ha->fwfcetracebuf.bp != NULL)) {
uint32_t cnt_b = 0;
uint64_t w64 = (uintptr_t)ha->fwfcetracebuf.bp;
(void) sprintf(bp, "\n\nFC Event Trace Buffer Memory");
bp += strlen(bp);
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) sprintf(bp, "\n%08x: ",
(int)(w64 + cnt_b));
bp += 11;
}
(void) sprintf(bp, "%08x ", fw->fce_trace_buf[cnt]);
bp += 9;
}
}
(void) sprintf(bp, "\n\n");
bp += strlen(bp);
cnt = (uint32_t)((uintptr_t)bp - (uintptr_t)bufp);
QL_PRINT_10(ha, "done=%xh\n", cnt);
return (cnt);
}
static size_t
ql_8021_ascii_fw_dump(ql_adapter_state_t *ha, caddr_t bufp)
{
uint32_t cnt;
caddr_t bp = bufp;
uint8_t *fw = ha->ql_dump_ptr;
cnt = 0;
while (cnt < ha->ql_dump_size) {
(void) sprintf(bp, "%02x ", *fw++);
bp += strlen(bp);
if (++cnt % 16 == 0) {
(void) sprintf(bp, "\n");
bp += strlen(bp);
}
}
if (cnt % 16 != 0) {
(void) sprintf(bp, "\n");
bp += strlen(bp);
}
cnt = (uint32_t)((uintptr_t)bp - (uintptr_t)bufp);
QL_PRINT_10(ha, "done=%xh\n", cnt);
return (cnt);
}
static int
ql_2200_binary_fw_dump(ql_adapter_state_t *ha, ql_fw_dump_t *fw)
{
uint32_t cnt;
uint16_t risc_address;
clock_t timer;
mbx_cmd_t mc;
mbx_cmd_t *mcp = &mc;
int rval = QL_SUCCESS;
QL_PRINT_3(ha, "started\n");
ql_disable_intr(ha);
WRT16_IO_REG(ha, semaphore, 0);
WRT16_IO_REG(ha, hccr, HC_PAUSE_RISC);
timer = 30000;
while ((RD16_IO_REG(ha, hccr) & HC_RISC_PAUSE) == 0) {
if (timer-- != 0) {
drv_usecwait(MILLISEC);
} else {
rval = QL_FUNCTION_TIMEOUT;
break;
}
}
if (rval == QL_SUCCESS) {
(void) ql_read_regs(ha, fw->pbiu_reg, ha->iobase,
sizeof (fw->pbiu_reg) / 2, 16);
(void) ql_read_regs(ha, fw->mailbox_reg, ha->iobase + 0x10,
8, 16);
(void) ql_read_regs(ha, fw->dma_reg, ha->iobase + 0x20,
sizeof (fw->dma_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0);
(void) ql_read_regs(ha, fw->risc_hdw_reg, ha->iobase + 0xA0,
sizeof (fw->risc_hdw_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2000);
(void) ql_read_regs(ha, fw->risc_gp0_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp0_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2100);
(void) ql_read_regs(ha, fw->risc_gp1_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp1_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2200);
(void) ql_read_regs(ha, fw->risc_gp2_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp2_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2300);
(void) ql_read_regs(ha, fw->risc_gp3_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp3_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2400);
(void) ql_read_regs(ha, fw->risc_gp4_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp4_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2500);
(void) ql_read_regs(ha, fw->risc_gp5_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp5_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2600);
(void) ql_read_regs(ha, fw->risc_gp6_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp6_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2700);
(void) ql_read_regs(ha, fw->risc_gp7_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp7_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x10);
(void) ql_read_regs(ha, fw->frame_buf_hdw_reg,
ha->iobase + 0x80, 16, 16);
WRT16_IO_REG(ha, ctrl_status, 0x20);
(void) ql_read_regs(ha, fw->fpm_b0_reg, ha->iobase + 0x80,
sizeof (fw->fpm_b0_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x30);
(void) ql_read_regs(ha, fw->fpm_b1_reg, ha->iobase + 0x80,
sizeof (fw->fpm_b1_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x20);
WRT16_IO_REG(ha, fpm_diag_config, 0x100);
WRT16_IO_REG(ha, ctrl_status, 0x10);
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);
timer = 30000;
while (RD16_IO_REG(ha, mailbox_out[0]) == MBS_ROM_BUSY) {
if (timer-- != 0) {
drv_usecwait(MILLISEC);
} else {
rval = QL_FUNCTION_TIMEOUT;
break;
}
}
WRT16_IO_REG(ha, hccr, HC_DISABLE_PARITY_PAUSE);
}
if (rval == QL_SUCCESS) {
WRT16_IO_REG(ha, hccr, HC_PAUSE_RISC);
timer = 30000;
while ((RD16_IO_REG(ha, hccr) & HC_RISC_PAUSE) == 0) {
if (timer-- != 0) {
drv_usecwait(MILLISEC);
} else {
rval = QL_FUNCTION_TIMEOUT;
break;
}
}
}
if (rval == QL_SUCCESS) {
WRT16_IO_REG(ha, mctr, 0xf2);
WRT16_IO_REG(ha, hccr, HC_RELEASE_RISC);
risc_address = 0x1000;
WRT16_IO_REG(ha, mailbox_in[0], MBC_READ_RAM_WORD);
for (cnt = 0; cnt < 0xf000; cnt++) {
WRT16_IO_REG(ha, mailbox_in[1], risc_address++);
WRT16_IO_REG(ha, hccr, HC_SET_HOST_INT);
for (timer = 6000000; timer != 0; timer--) {
if (INTERRUPT_PENDING(ha)) {
if (RD16_IO_REG(ha, semaphore) &
BIT_0) {
WRT16_IO_REG(ha, hccr,
HC_CLR_RISC_INT);
mcp->mb[0] = RD16_IO_REG(ha,
mailbox_out[0]);
fw->risc_ram[cnt] =
RD16_IO_REG(ha,
mailbox_out[2]);
WRT16_IO_REG(ha,
semaphore, 0);
break;
}
WRT16_IO_REG(ha, hccr,
HC_CLR_RISC_INT);
}
drv_usecwait(5);
}
if (timer == 0) {
rval = QL_FUNCTION_TIMEOUT;
} else {
rval = mcp->mb[0];
}
if (rval != QL_SUCCESS) {
break;
}
}
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_2300_binary_fw_dump(ql_adapter_state_t *ha, ql_fw_dump_t *fw)
{
clock_t timer;
int rval = QL_SUCCESS;
QL_PRINT_3(ha, "started\n");
ql_disable_intr(ha);
WRT16_IO_REG(ha, semaphore, 0);
WRT16_IO_REG(ha, hccr, HC_PAUSE_RISC);
timer = 30000;
while ((RD16_IO_REG(ha, hccr) & HC_RISC_PAUSE) == 0) {
if (timer-- != 0) {
drv_usecwait(MILLISEC);
} else {
rval = QL_FUNCTION_TIMEOUT;
break;
}
}
if (rval == QL_SUCCESS) {
(void) ql_read_regs(ha, fw->pbiu_reg, ha->iobase,
sizeof (fw->pbiu_reg) / 2, 16);
(void) ql_read_regs(ha, fw->risc_host_reg, ha->iobase + 0x10,
sizeof (fw->risc_host_reg) / 2, 16);
(void) ql_read_regs(ha, fw->mailbox_reg, ha->iobase + 0x40,
sizeof (fw->mailbox_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x40);
(void) ql_read_regs(ha, fw->resp_dma_reg, ha->iobase + 0x80,
sizeof (fw->resp_dma_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x50);
(void) ql_read_regs(ha, fw->dma_reg, ha->iobase + 0x80,
sizeof (fw->dma_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0);
(void) ql_read_regs(ha, fw->risc_hdw_reg, ha->iobase + 0xA0,
sizeof (fw->risc_hdw_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2000);
(void) ql_read_regs(ha, fw->risc_gp0_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp0_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2200);
(void) ql_read_regs(ha, fw->risc_gp1_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp1_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2400);
(void) ql_read_regs(ha, fw->risc_gp2_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp2_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2600);
(void) ql_read_regs(ha, fw->risc_gp3_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp3_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2800);
(void) ql_read_regs(ha, fw->risc_gp4_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp4_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2A00);
(void) ql_read_regs(ha, fw->risc_gp5_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp5_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2C00);
(void) ql_read_regs(ha, fw->risc_gp6_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp6_reg) / 2, 16);
WRT16_IO_REG(ha, pcr, 0x2E00);
(void) ql_read_regs(ha, fw->risc_gp7_reg, ha->iobase + 0x80,
sizeof (fw->risc_gp7_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x10);
(void) ql_read_regs(ha, fw->frame_buf_hdw_reg,
ha->iobase + 0x80, sizeof (fw->frame_buf_hdw_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x20);
(void) ql_read_regs(ha, fw->fpm_b0_reg, ha->iobase + 0x80,
sizeof (fw->fpm_b0_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x30);
(void) ql_read_regs(ha, fw->fpm_b1_reg, ha->iobase + 0x80,
sizeof (fw->fpm_b1_reg) / 2, 16);
WRT16_IO_REG(ha, ctrl_status, 0x20);
WRT16_IO_REG(ha, fpm_diag_config, 0x100);
WRT16_IO_REG(ha, ctrl_status, 0x10);
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);
timer = 30000;
while (RD16_IO_REG(ha, mailbox_out[0]) == MBS_ROM_BUSY) {
if (timer-- != 0) {
drv_usecwait(MILLISEC);
} else {
rval = QL_FUNCTION_TIMEOUT;
break;
}
}
WRT16_IO_REG(ha, hccr, HC_DISABLE_PARITY_PAUSE);
}
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x800, 0xf800, fw->risc_ram);
}
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x10000, 0x800, fw->stack_ram);
}
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x10800, 0xf800, fw->data_ram);
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static int
ql_24xx_binary_fw_dump(ql_adapter_state_t *ha, ql_24xx_fw_dump_t *fw)
{
uint32_t *reg32;
void *bp;
clock_t timer;
int rval = QL_SUCCESS;
QL_PRINT_3(ha, "started\n");
fw->hccr = RD32_IO_REG(ha, hccr);
if ((RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0) {
ql_disable_intr(ha);
WRT32_IO_REG(ha, hccr, HC24_PAUSE_RISC);
for (timer = 30000;
(RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0 &&
rval == QL_SUCCESS; timer--) {
if (timer) {
drv_usecwait(100);
} else {
rval = QL_FUNCTION_TIMEOUT;
}
}
}
if (rval == QL_SUCCESS) {
(void) ql_read_regs(ha, fw->host_reg, ha->iobase,
sizeof (fw->host_reg) / 4, 32);
ql_disable_intr(ha);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
RD32_IO_REG(ha, io_base_addr);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0000000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[0] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0100000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[1] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0200000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[2] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0300000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[3] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0400000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[4] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0500000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[5] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0600000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[6] = RD_REG_DWORD(ha, reg32);
(void) ql_read_regs(ha, fw->mailbox_reg, ha->iobase + 0x80,
sizeof (fw->mailbox_reg) / 2, 16);
WRT32_IO_REG(ha, io_base_addr, 0xBF00);
bp = ql_read_regs(ha, fw->xseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFE0);
(void) ql_read_regs(ha, fw->xseq_0_reg, ha->iobase + 0xC0,
sizeof (fw->xseq_0_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFF0);
(void) ql_read_regs(ha, fw->xseq_1_reg, ha->iobase + 0xC0,
sizeof (fw->xseq_1_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF00);
bp = ql_read_regs(ha, fw->rseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFD0);
(void) ql_read_regs(ha, fw->rseq_0_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_0_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFE0);
(void) ql_read_regs(ha, fw->rseq_1_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_1_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFF0);
(void) ql_read_regs(ha, fw->rseq_2_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_2_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7100);
(void) ql_read_regs(ha, fw->cmd_dma_reg, ha->iobase + 0xC0,
sizeof (fw->cmd_dma_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7200);
bp = ql_read_regs(ha, fw->req0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7300);
bp = ql_read_regs(ha, fw->resp0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7400);
bp = ql_read_regs(ha, fw->req1_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7600);
bp = ql_read_regs(ha, fw->xmt0_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7610);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7620);
bp = ql_read_regs(ha, fw->xmt1_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7630);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7640);
bp = ql_read_regs(ha, fw->xmt2_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7650);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7660);
bp = ql_read_regs(ha, fw->xmt3_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7670);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7680);
bp = ql_read_regs(ha, fw->xmt4_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7690);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x76A0);
(void) ql_read_regs(ha, fw->xmt_data_dma_reg,
ha->iobase + 0xC0, sizeof (fw->xmt_data_dma_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7700);
bp = ql_read_regs(ha, fw->rcvt0_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7710);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7720);
bp = ql_read_regs(ha, fw->rcvt1_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7730);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F00);
bp = ql_read_regs(ha, fw->risc_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3000);
bp = ql_read_regs(ha, fw->lmc_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3060);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4000);
bp = ql_read_regs(ha, fw->fpm_hdw_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4070);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4080);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4090);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40A0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40B0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6000);
bp = ql_read_regs(ha, fw->fb_hdw_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6100);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6130);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6150);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6170);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6190);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x61B0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
}
if (rval == QL_SUCCESS) {
uint32_t cnt;
uint32_t *w32 = (uint32_t *)ha->req_q[0]->req_ring.bp;
(void) ddi_dma_sync(ha->req_q[0]->req_ring.dma_handle,
0, sizeof (fw->req_q), DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < sizeof (fw->req_q) / 4; cnt++) {
fw->req_q[cnt] = *w32++;
LITTLE_ENDIAN_32(&fw->req_q[cnt]);
}
}
if (rval == QL_SUCCESS) {
uint32_t cnt;
uint32_t *w32 =
(uint32_t *)ha->rsp_queues[0]->rsp_ring.bp;
(void) ddi_dma_sync(ha->rsp_queues[0]->rsp_ring.dma_handle,
0, sizeof (fw->rsp_q), DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < sizeof (fw->rsp_q) / 4; cnt++) {
fw->rsp_q[cnt] = *w32++;
LITTLE_ENDIAN_32(&fw->rsp_q[cnt]);
}
}
ql_reset_chip(ha);
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x20000,
sizeof (fw->code_ram) / 4, fw->code_ram);
}
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x100000,
ha->fw_ext_memory_size / 4, fw->ext_mem);
}
if (rval == QL_SUCCESS) {
if (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) &&
(ha->fwexttracebuf.bp != NULL)) {
uint32_t cnt;
uint32_t *w32 = ha->fwexttracebuf.bp;
(void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0,
FWEXTSIZE, DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
fw->ext_trace_buf[cnt] = *w32++;
}
}
}
if (rval == QL_SUCCESS) {
if (CFG_IST(ha, CFG_ENABLE_FWFCETRACE) &&
(ha->fwfcetracebuf.bp != NULL)) {
uint32_t cnt;
uint32_t *w32 = ha->fwfcetracebuf.bp;
(void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0,
FWFCESIZE, DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
fw->fce_trace_buf[cnt] = *w32++;
}
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_25xx_binary_fw_dump(ql_adapter_state_t *ha, ql_25xx_fw_dump_t *fw)
{
uint32_t *reg32, cnt, *w32ptr, index, *dp;
void *bp;
clock_t timer;
int rval = QL_SUCCESS;
QL_PRINT_3(ha, "started\n");
fw->req_q_size[0] = ha->req_q[0]->req_ring.size;
if (ha->req_q[1] != NULL) {
fw->req_q_size[1] = ha->req_q[1]->req_ring.size;
}
fw->rsp_q_size = ha->rsp_queues[0]->rsp_ring.size * ha->rsp_queues_cnt;
fw->hccr = RD32_IO_REG(ha, hccr);
fw->r2h_status = RD32_IO_REG(ha, risc2host);
fw->aer_ues = ql_pci_config_get32(ha, 0x104);
if ((RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0) {
ql_disable_intr(ha);
WRT32_IO_REG(ha, hccr, HC24_PAUSE_RISC);
for (timer = 30000;
(RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0 &&
rval == QL_SUCCESS; timer--) {
if (timer) {
drv_usecwait(100);
if (timer % 10000 == 0) {
EL(ha, "risc pause %d\n", timer);
}
} else {
EL(ha, "risc pause timeout\n");
rval = QL_FUNCTION_TIMEOUT;
}
}
}
if (rval == QL_SUCCESS) {
WRT32_IO_REG(ha, io_base_addr, 0x7000);
bp = ql_read_regs(ha, fw->hostrisc_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7010);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7c00);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, 0x1);
bp = ql_read_regs(ha, fw->pcie_reg, ha->iobase + 0xC4,
3, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 1, 32);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, 0x0);
(void) ql_read_regs(ha, fw->host_reg, ha->iobase,
sizeof (fw->host_reg) / 4, 32);
ql_disable_intr(ha);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
RD32_IO_REG(ha, io_base_addr);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0000000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[0] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0100000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[1] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0200000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[2] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0300000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[3] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0400000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[4] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0500000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[5] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0600000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[6] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0700000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[7] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0800000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[8] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0900000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[9] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0A00000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[0xa] = RD_REG_DWORD(ha, reg32);
WRT32_IO_REG(ha, io_base_addr, 0x0010);
(void) ql_read_regs(ha, &fw->risc_io, ha->iobase + 0xC0,
1, 32);
(void) ql_read_regs(ha, fw->mailbox_reg, ha->iobase + 0x80,
sizeof (fw->mailbox_reg) / 2, 16);
WRT32_IO_REG(ha, io_base_addr, 0xBF00);
bp = ql_read_regs(ha, fw->xseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFC0);
bp = ql_read_regs(ha, fw->xseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFD0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFE0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFF0);
(void) ql_read_regs(ha, fw->xseq_1_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF00);
bp = ql_read_regs(ha, fw->rseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFC0);
bp = ql_read_regs(ha, fw->rseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFD0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFE0);
(void) ql_read_regs(ha, fw->rseq_1_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_1_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFF0);
(void) ql_read_regs(ha, fw->rseq_2_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_2_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB000);
bp = ql_read_regs(ha, fw->aseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB070);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0C0);
bp = ql_read_regs(ha, fw->aseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0D0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0E0);
(void) ql_read_regs(ha, fw->aseq_1_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0F0);
(void) ql_read_regs(ha, fw->aseq_2_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7100);
(void) ql_read_regs(ha, fw->cmd_dma_reg, ha->iobase + 0xC0,
sizeof (fw->cmd_dma_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7200);
bp = ql_read_regs(ha, fw->req0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7300);
bp = ql_read_regs(ha, fw->resp0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7400);
bp = ql_read_regs(ha, fw->req1_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7600);
bp = ql_read_regs(ha, fw->xmt0_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7610);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7620);
bp = ql_read_regs(ha, fw->xmt1_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7630);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7640);
bp = ql_read_regs(ha, fw->xmt2_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7650);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7660);
bp = ql_read_regs(ha, fw->xmt3_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7670);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7680);
bp = ql_read_regs(ha, fw->xmt4_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7690);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x76A0);
(void) ql_read_regs(ha, fw->xmt_data_dma_reg,
ha->iobase + 0xC0, sizeof (fw->xmt_data_dma_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7700);
bp = ql_read_regs(ha, fw->rcvt0_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7710);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7720);
bp = ql_read_regs(ha, fw->rcvt1_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7730);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F00);
bp = ql_read_regs(ha, fw->risc_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3000);
bp = ql_read_regs(ha, fw->lmc_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3070);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4000);
bp = ql_read_regs(ha, fw->fpm_hdw_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4070);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4080);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4090);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40A0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40B0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6000);
bp = ql_read_regs(ha, fw->fb_hdw_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6100);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6130);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6150);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6170);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6190);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x61B0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6F00);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
}
if (rval == QL_SUCCESS) {
dp = fw->req_rsp_ext_mem;
for (index = 0; index < ha->rsp_queues_cnt; index++) {
if (index == 0 && ha->flags & MULTI_QUEUE) {
*dp = RD32_MBAR_REG(ha,
ha->req_q[0]->mbar_req_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha,
ha->req_q[0]->mbar_req_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else if (index == 1 && ha->flags & MULTI_QUEUE) {
*dp = RD32_MBAR_REG(ha,
ha->req_q[1]->mbar_req_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha,
ha->req_q[1]->mbar_req_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else {
*dp++ = 0;
*dp++ = 0;
}
if (ha->flags & MULTI_QUEUE) {
*dp = RD32_MBAR_REG(ha,
ha->rsp_queues[index]->mbar_rsp_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha,
ha->rsp_queues[index]->mbar_rsp_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else {
*dp++ = 0;
*dp++ = 0;
}
}
(void) ddi_dma_sync(ha->req_q[0]->req_ring.dma_handle, 0, 0,
DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)ha->req_q[0]->req_ring.bp;
for (cnt = 0; cnt < fw->req_q_size[0] / 4; cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
if (ha->req_q[1] != NULL) {
(void) ddi_dma_sync(ha->req_q[1]->req_ring.dma_handle,
0, 0, DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)ha->req_q[1]->req_ring.bp;
for (cnt = 0; cnt < fw->req_q_size[1] / 4; cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
}
for (index = 0; index < ha->rsp_queues_cnt; index++) {
(void) ddi_dma_sync(
ha->rsp_queues[index]->rsp_ring.dma_handle,
0, 0, DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)
ha->rsp_queues[index]->rsp_ring.bp;
for (cnt = 0;
cnt < ha->rsp_queues[index]->rsp_ring.size / 4;
cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
}
}
ql_reset_chip(ha);
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x20000,
sizeof (fw->code_ram) / 4, fw->code_ram);
}
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x100000,
ha->fw_ext_memory_size / 4, dp);
}
if (rval == QL_SUCCESS) {
if (CFG_IST(ha, CFG_ENABLE_FWFCETRACE) &&
(ha->fwfcetracebuf.bp != NULL)) {
uint32_t cnt;
uint32_t *w32 = ha->fwfcetracebuf.bp;
(void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0,
FWFCESIZE, DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
fw->fce_trace_buf[cnt] = *w32++;
}
}
}
if (rval == QL_SUCCESS) {
if (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) &&
(ha->fwexttracebuf.bp != NULL)) {
uint32_t cnt;
uint32_t *w32 = ha->fwexttracebuf.bp;
(void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0,
FWEXTSIZE, DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
fw->ext_trace_buf[cnt] = *w32++;
}
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_81xx_binary_fw_dump(ql_adapter_state_t *ha, ql_81xx_fw_dump_t *fw)
{
uint32_t *reg32, cnt, *w32ptr, index, *dp;
void *bp;
clock_t timer;
int rval = QL_SUCCESS;
QL_PRINT_3(ha, "started\n");
fw->req_q_size[0] = ha->req_q[0]->req_ring.size;
if (ha->req_q[1] != NULL) {
fw->req_q_size[1] = ha->req_q[1]->req_ring.size;
}
fw->rsp_q_size = ha->rsp_queues[0]->rsp_ring.size * ha->rsp_queues_cnt;
fw->hccr = RD32_IO_REG(ha, hccr);
fw->r2h_status = RD32_IO_REG(ha, risc2host);
fw->aer_ues = ql_pci_config_get32(ha, 0x104);
if ((RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0) {
ql_disable_intr(ha);
WRT32_IO_REG(ha, hccr, HC24_PAUSE_RISC);
for (timer = 30000;
(RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0 &&
rval == QL_SUCCESS; timer--) {
if (timer) {
drv_usecwait(100);
if (timer % 10000 == 0) {
EL(ha, "risc pause %d\n", timer);
}
} else {
EL(ha, "risc pause timeout\n");
rval = QL_FUNCTION_TIMEOUT;
}
}
}
if (rval == QL_SUCCESS) {
WRT32_IO_REG(ha, io_base_addr, 0x7000);
bp = ql_read_regs(ha, fw->hostrisc_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7010);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7c00);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, 0x1);
bp = ql_read_regs(ha, fw->pcie_reg, ha->iobase + 0xC4,
3, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 1, 32);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, 0x0);
(void) ql_read_regs(ha, fw->host_reg, ha->iobase,
sizeof (fw->host_reg) / 4, 32);
ql_disable_intr(ha);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
RD32_IO_REG(ha, io_base_addr);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0000000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[0] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0100000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[1] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0200000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[2] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0300000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[3] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0400000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[4] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0500000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[5] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0600000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[6] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0700000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[7] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0800000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[8] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0900000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[9] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0A00000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[0xa] = RD_REG_DWORD(ha, reg32);
WRT32_IO_REG(ha, io_base_addr, 0x0010);
(void) ql_read_regs(ha, &fw->risc_io, ha->iobase + 0xC0,
1, 32);
(void) ql_read_regs(ha, fw->mailbox_reg, ha->iobase + 0x80,
sizeof (fw->mailbox_reg) / 2, 16);
WRT32_IO_REG(ha, io_base_addr, 0xBF00);
bp = ql_read_regs(ha, fw->xseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFC0);
bp = ql_read_regs(ha, fw->xseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFD0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFE0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFF0);
(void) ql_read_regs(ha, fw->xseq_1_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF00);
bp = ql_read_regs(ha, fw->rseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFC0);
bp = ql_read_regs(ha, fw->rseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFD0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFE0);
(void) ql_read_regs(ha, fw->rseq_1_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_1_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFF0);
(void) ql_read_regs(ha, fw->rseq_2_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_2_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB000);
bp = ql_read_regs(ha, fw->aseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB070);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0C0);
bp = ql_read_regs(ha, fw->aseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0D0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0E0);
(void) ql_read_regs(ha, fw->aseq_1_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0F0);
(void) ql_read_regs(ha, fw->aseq_2_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7100);
(void) ql_read_regs(ha, fw->cmd_dma_reg, ha->iobase + 0xC0,
sizeof (fw->cmd_dma_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7200);
bp = ql_read_regs(ha, fw->req0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7300);
bp = ql_read_regs(ha, fw->resp0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7400);
bp = ql_read_regs(ha, fw->req1_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7600);
bp = ql_read_regs(ha, fw->xmt0_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7610);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7620);
bp = ql_read_regs(ha, fw->xmt1_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7630);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7640);
bp = ql_read_regs(ha, fw->xmt2_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7650);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7660);
bp = ql_read_regs(ha, fw->xmt3_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7670);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7680);
bp = ql_read_regs(ha, fw->xmt4_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7690);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x76A0);
(void) ql_read_regs(ha, fw->xmt_data_dma_reg,
ha->iobase + 0xC0, sizeof (fw->xmt_data_dma_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7700);
bp = ql_read_regs(ha, fw->rcvt0_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7710);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7720);
bp = ql_read_regs(ha, fw->rcvt1_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7730);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F00);
bp = ql_read_regs(ha, fw->risc_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3000);
bp = ql_read_regs(ha, fw->lmc_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3070);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4000);
bp = ql_read_regs(ha, fw->fpm_hdw_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4070);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4080);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4090);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40A0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40B0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40C0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40D0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6000);
bp = ql_read_regs(ha, fw->fb_hdw_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6100);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6130);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6150);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6170);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6190);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x61B0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x61C0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6F00);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
}
if (rval == QL_SUCCESS) {
dp = fw->req_rsp_ext_mem;
for (index = 0; index < ha->rsp_queues_cnt; index++) {
if (index == 0 && ha->flags & MULTI_QUEUE) {
*dp = RD32_MBAR_REG(ha,
ha->req_q[0]->mbar_req_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha,
ha->req_q[0]->mbar_req_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else if (index == 1 && ha->flags & MULTI_QUEUE) {
*dp = RD32_MBAR_REG(ha,
ha->req_q[1]->mbar_req_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha,
ha->req_q[1]->mbar_req_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else {
*dp++ = 0;
*dp++ = 0;
}
if (ha->flags & MULTI_QUEUE) {
*dp = RD32_MBAR_REG(ha,
ha->rsp_queues[index]->mbar_rsp_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha,
ha->rsp_queues[index]->mbar_rsp_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else {
*dp++ = 0;
*dp++ = 0;
}
}
(void) ddi_dma_sync(ha->req_q[0]->req_ring.dma_handle, 0, 0,
DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)ha->req_q[0]->req_ring.bp;
for (cnt = 0; cnt < fw->req_q_size[0] / 4; cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
if (ha->req_q[1] != NULL) {
(void) ddi_dma_sync(ha->req_q[1]->req_ring.dma_handle,
0, 0, DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)ha->req_q[1]->req_ring.bp;
for (cnt = 0; cnt < fw->req_q_size[1] / 4; cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
}
for (index = 0; index < ha->rsp_queues_cnt; index++) {
(void) ddi_dma_sync(
ha->rsp_queues[index]->rsp_ring.dma_handle,
0, 0, DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)
ha->rsp_queues[index]->rsp_ring.bp;
for (cnt = 0;
cnt < ha->rsp_queues[index]->rsp_ring.size / 4;
cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
}
}
ql_reset_chip(ha);
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x20000,
sizeof (fw->code_ram) / 4, fw->code_ram);
}
if (rval == QL_SUCCESS) {
rval = ql_read_risc_ram(ha, 0x100000,
ha->fw_ext_memory_size / 4, dp);
}
if (rval == QL_SUCCESS) {
if (CFG_IST(ha, CFG_ENABLE_FWFCETRACE) &&
(ha->fwfcetracebuf.bp != NULL)) {
uint32_t cnt;
uint32_t *w32 = ha->fwfcetracebuf.bp;
(void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0,
FWFCESIZE, DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
fw->fce_trace_buf[cnt] = *w32++;
}
}
}
if (rval == QL_SUCCESS) {
if (CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) &&
(ha->fwexttracebuf.bp != NULL)) {
uint32_t cnt;
uint32_t *w32 = ha->fwexttracebuf.bp;
(void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0,
FWEXTSIZE, DDI_DMA_SYNC_FORKERNEL);
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
fw->ext_trace_buf[cnt] = *w32++;
}
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed=%xh\n", rval);
} else {
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_read_risc_ram(ql_adapter_state_t *ha, uint32_t risc_address, uint32_t len,
void *buf)
{
uint32_t cnt;
uint16_t stat;
clock_t timer;
uint16_t *buf16 = (uint16_t *)buf;
uint32_t *buf32 = (uint32_t *)buf;
int rval = QL_SUCCESS;
for (cnt = 0; cnt < len; cnt++, risc_address++) {
WRT16_IO_REG(ha, mailbox_in[0], MBC_READ_RAM_EXTENDED);
WRT16_IO_REG(ha, mailbox_in[1], LSW(risc_address));
WRT16_IO_REG(ha, mailbox_in[8], MSW(risc_address));
if (CFG_IST(ha, CFG_CTRL_82XX)) {
WRT32_IO_REG(ha, nx_host_int, NX_MBX_CMD);
} else if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
WRT32_IO_REG(ha, hccr, HC24_SET_HOST_INT);
} else {
WRT16_IO_REG(ha, hccr, HC_SET_HOST_INT);
}
for (timer = 6000000; timer && rval == QL_SUCCESS; timer--) {
if (INTERRUPT_PENDING(ha)) {
stat = (uint16_t)
(RD16_IO_REG(ha, risc2host) & 0xff);
if ((stat == 1) || (stat == 0x10)) {
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
buf32[cnt] = SHORT_TO_LONG(
RD16_IO_REG(ha,
mailbox_out[2]),
RD16_IO_REG(ha,
mailbox_out[3]));
} else {
buf16[cnt] =
RD16_IO_REG(ha,
mailbox_out[2]);
}
break;
} else if ((stat == 2) || (stat == 0x11)) {
rval = RD16_IO_REG(ha, mailbox_out[0]);
break;
}
if (CFG_IST(ha, CFG_CTRL_82XX)) {
ql_8021_clr_hw_intr(ha);
ql_8021_clr_fw_intr(ha);
} else if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
WRT32_IO_REG(ha, hccr,
HC24_CLR_RISC_INT);
RD32_IO_REG(ha, hccr);
} else {
WRT16_IO_REG(ha, semaphore, 0);
WRT16_IO_REG(ha, hccr,
HC_CLR_RISC_INT);
RD16_IO_REG(ha, hccr);
}
}
drv_usecwait(5);
}
if (CFG_IST(ha, CFG_CTRL_82XX)) {
ql_8021_clr_hw_intr(ha);
ql_8021_clr_fw_intr(ha);
} else if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
RD32_IO_REG(ha, hccr);
} else {
WRT16_IO_REG(ha, semaphore, 0);
WRT16_IO_REG(ha, hccr, HC_CLR_RISC_INT);
RD16_IO_REG(ha, hccr);
}
if (timer == 0) {
rval = QL_FUNCTION_TIMEOUT;
}
}
return (rval);
}
static void *
ql_read_regs(ql_adapter_state_t *ha, void *buf, void *reg, uint32_t count,
uint8_t wds)
{
uint32_t *bp32, *reg32;
uint16_t *bp16, *reg16;
uint8_t *bp8, *reg8;
switch (wds) {
case 32:
bp32 = buf;
reg32 = reg;
while (count--) {
*bp32++ = RD_REG_DWORD(ha, reg32++);
}
return (bp32);
case 16:
bp16 = buf;
reg16 = reg;
while (count--) {
*bp16++ = RD_REG_WORD(ha, reg16++);
}
return (bp16);
case 8:
bp8 = buf;
reg8 = reg;
while (count--) {
*bp8++ = RD_REG_BYTE(ha, reg8++);
}
return (bp8);
default:
EL(ha, "Unknown word size=%d\n", wds);
return (buf);
}
}
static int
ql_save_config_regs(dev_info_t *dip)
{
ql_adapter_state_t *ha;
int ret;
ql_config_space_t chs;
caddr_t prop = "ql-config-space";
ha = ddi_get_soft_state(ql_state, ddi_get_instance(dip));
if (ha == NULL) {
QL_PRINT_2(NULL, "no adapter instance=%d\n",
ddi_get_instance(dip));
return (DDI_FAILURE);
}
QL_PRINT_3(ha, "started\n");
if (ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, prop) ==
1) {
QL_PRINT_2(ha, "no prop exit\n");
return (DDI_SUCCESS);
}
chs.chs_command = (uint16_t)ql_pci_config_get16(ha, PCI_CONF_COMM);
chs.chs_header_type = (uint8_t)ql_pci_config_get8(ha,
PCI_CONF_HEADER);
if ((chs.chs_header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
chs.chs_bridge_control = (uint8_t)ql_pci_config_get8(ha,
PCI_BCNF_BCNTRL);
}
chs.chs_cache_line_size = (uint8_t)ql_pci_config_get8(ha,
PCI_CONF_CACHE_LINESZ);
chs.chs_latency_timer = (uint8_t)ql_pci_config_get8(ha,
PCI_CONF_LATENCY_TIMER);
if ((chs.chs_header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
chs.chs_sec_latency_timer = (uint8_t)ql_pci_config_get8(ha,
PCI_BCNF_LATENCY_TIMER);
}
chs.chs_base0 = ql_pci_config_get32(ha, PCI_CONF_BASE0);
chs.chs_base1 = ql_pci_config_get32(ha, PCI_CONF_BASE1);
chs.chs_base2 = ql_pci_config_get32(ha, PCI_CONF_BASE2);
chs.chs_base3 = ql_pci_config_get32(ha, PCI_CONF_BASE3);
chs.chs_base4 = ql_pci_config_get32(ha, PCI_CONF_BASE4);
chs.chs_base5 = ql_pci_config_get32(ha, PCI_CONF_BASE5);
ret = ndi_prop_update_byte_array(DDI_DEV_T_NONE, dip, prop,
(uchar_t *)&chs, sizeof (ql_config_space_t));
if (ret != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "!Qlogic %s(%d) can't update prop %s",
QL_NAME, ddi_get_instance(dip), prop);
return (DDI_FAILURE);
}
QL_PRINT_3(ha, "done\n");
return (DDI_SUCCESS);
}
static int
ql_restore_config_regs(dev_info_t *dip)
{
ql_adapter_state_t *ha;
uint_t elements;
ql_config_space_t *chs_p;
caddr_t prop = "ql-config-space";
ha = ddi_get_soft_state(ql_state, ddi_get_instance(dip));
if (ha == NULL) {
QL_PRINT_2(NULL, "no adapter instance=%d\n",
ddi_get_instance(dip));
return (DDI_FAILURE);
}
QL_PRINT_3(ha, "started\n");
if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip,
DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, prop,
(uchar_t **)&chs_p, &elements) != DDI_PROP_SUCCESS) {
QL_PRINT_2(ha, "no prop exit\n");
return (DDI_FAILURE);
}
ql_pci_config_put16(ha, PCI_CONF_COMM, chs_p->chs_command);
if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
ql_pci_config_put16(ha, PCI_BCNF_BCNTRL,
chs_p->chs_bridge_control);
}
ql_pci_config_put8(ha, PCI_CONF_CACHE_LINESZ,
chs_p->chs_cache_line_size);
ql_pci_config_put8(ha, PCI_CONF_LATENCY_TIMER,
chs_p->chs_latency_timer);
if ((chs_p->chs_header_type & PCI_HEADER_TYPE_M) == PCI_HEADER_ONE) {
ql_pci_config_put8(ha, PCI_BCNF_LATENCY_TIMER,
chs_p->chs_sec_latency_timer);
}
ql_pci_config_put32(ha, PCI_CONF_BASE0, chs_p->chs_base0);
ql_pci_config_put32(ha, PCI_CONF_BASE1, chs_p->chs_base1);
ql_pci_config_put32(ha, PCI_CONF_BASE2, chs_p->chs_base2);
ql_pci_config_put32(ha, PCI_CONF_BASE3, chs_p->chs_base3);
ql_pci_config_put32(ha, PCI_CONF_BASE4, chs_p->chs_base4);
ql_pci_config_put32(ha, PCI_CONF_BASE5, chs_p->chs_base5);
ddi_prop_free(chs_p);
if (ndi_prop_remove(DDI_DEV_T_NONE, dip, prop) != DDI_PROP_SUCCESS) {
cmn_err(CE_WARN, "!Qlogic %s(%d): can't remove prop %s",
QL_NAME, ddi_get_instance(dip), prop);
}
QL_PRINT_3(ha, "done\n");
return (DDI_SUCCESS);
}
uint8_t
ql_pci_config_get8(ql_adapter_state_t *ha, off_t off)
{
if (CFG_IST(ha, CFG_SBUS_CARD)) {
return (ddi_get8(ha->sbus_config_handle,
(uint8_t *)(ha->sbus_config_base + off)));
}
return (pci_config_get8(ha->pci_handle, off));
}
uint16_t
ql_pci_config_get16(ql_adapter_state_t *ha, off_t off)
{
if (CFG_IST(ha, CFG_SBUS_CARD)) {
return (ddi_get16(ha->sbus_config_handle,
(uint16_t *)(ha->sbus_config_base + off)));
}
return (pci_config_get16(ha->pci_handle, off));
}
uint32_t
ql_pci_config_get32(ql_adapter_state_t *ha, off_t off)
{
if (CFG_IST(ha, CFG_SBUS_CARD)) {
return (ddi_get32(ha->sbus_config_handle,
(uint32_t *)(ha->sbus_config_base + off)));
}
return (pci_config_get32(ha->pci_handle, off));
}
void
ql_pci_config_put8(ql_adapter_state_t *ha, off_t off, uint8_t val)
{
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ddi_put8(ha->sbus_config_handle,
(uint8_t *)(ha->sbus_config_base + off), val);
} else {
pci_config_put8(ha->pci_handle, off, val);
}
}
void
ql_pci_config_put16(ql_adapter_state_t *ha, off_t off, uint16_t val)
{
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ddi_put16(ha->sbus_config_handle,
(uint16_t *)(ha->sbus_config_base + off), val);
} else {
pci_config_put16(ha->pci_handle, off, val);
}
}
void
ql_pci_config_put32(ql_adapter_state_t *ha, off_t off, uint32_t val)
{
if (CFG_IST(ha, CFG_SBUS_CARD)) {
ddi_put32(ha->sbus_config_handle,
(uint32_t *)(ha->sbus_config_base + off), val);
} else {
pci_config_put32(ha->pci_handle, off, val);
}
}
static void
ql_halt(ql_adapter_state_t *ha, int pwr)
{
ql_link_t *link;
ql_response_q_t *rsp_q;
ql_tgt_t *tq;
ql_srb_t *sp;
uint32_t cnt, i;
uint16_t index;
QL_PRINT_3(ha, "started\n");
for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
for (link = ha->dev[index].first; link != NULL;
link = link->next) {
tq = link->base_address;
(void) ql_abort_device(ha, tq, 0);
for (cnt = 3000; cnt != 0; cnt--) {
DEVICE_QUEUE_LOCK(tq);
if (tq->outcnt == 0) {
DEVICE_QUEUE_UNLOCK(tq);
break;
} else {
DEVICE_QUEUE_UNLOCK(tq);
ql_delay(ha, 10000);
}
}
for (i = 0; i < ha->rsp_queues_cnt; i++) {
if ((rsp_q = ha->rsp_queues[i]) != NULL &&
(sp = rsp_q->status_srb) != NULL) {
rsp_q->status_srb = NULL;
sp->cmd.next = NULL;
ql_done(&sp->cmd, B_FALSE);
}
}
if (cnt == 0) {
for (cnt = 1; cnt < ha->osc_max_cnt;
cnt++) {
if (ha->pending_cmds.first != NULL) {
ql_start_iocb(ha, NULL);
cnt = 1;
}
sp = ha->outstanding_cmds[cnt];
if (sp != NULL &&
sp != QL_ABORTED_SRB(ha) &&
sp->lun_queue->target_queue ==
tq) {
(void) ql_abort_io(ha, sp);
sp->pkt->pkt_reason =
CS_ABORTED;
sp->cmd.next = NULL;
ql_done(&sp->cmd, B_FALSE);
}
}
}
}
}
if (ha->flags & IP_INITIALIZED) {
(void) ql_shutdown_ip(ha);
}
ADAPTER_STATE_LOCK(ha);
ha->port_retry_timer = 0;
ha->loop_down_timer = LOOP_DOWN_TIMER_OFF;
ha->watchdog_timer = 0;
ADAPTER_STATE_UNLOCK(ha);
if (pwr == PM_LEVEL_D3 && ha->flags & ONLINE) {
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~ONLINE;
ADAPTER_STATE_UNLOCK(ha);
if (CFG_IST(ha, CFG_CTRL_82XX)) {
ql_8021_clr_drv_active(ha);
}
ql_reset_chip(ha);
}
QL_PRINT_3(ha, "done\n");
}
int
ql_get_dma_mem(ql_adapter_state_t *ha, dma_mem_t *mem, uint32_t size,
mem_alloc_type_t allocation_type, mem_alignment_t alignment)
{
int rval;
QL_PRINT_3(ha, "started\n");
mem->size = size;
mem->type = allocation_type;
mem->max_cookie_count = 1;
switch (alignment) {
case QL_DMA_DATA_ALIGN:
mem->alignment = QL_DMA_ALIGN_8_BYTE_BOUNDARY;
break;
case QL_DMA_RING_ALIGN:
mem->alignment = QL_DMA_ALIGN_64_BYTE_BOUNDARY;
break;
default:
EL(ha, "failed, unknown alignment type %x\n", alignment);
break;
}
if ((rval = ql_alloc_phys(ha, mem, KM_SLEEP)) != QL_SUCCESS) {
ql_free_phys(ha, mem);
EL(ha, "failed, alloc_phys=%xh\n", rval);
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
void
ql_free_dma_resource(ql_adapter_state_t *ha, dma_mem_t *mem)
{
QL_PRINT_3(ha, "started\n");
ql_free_phys(ha, mem);
QL_PRINT_3(ha, "done\n");
}
int
ql_alloc_phys(ql_adapter_state_t *ha, dma_mem_t *mem, int sleep)
{
size_t rlen;
ddi_dma_attr_t dma_attr = ha->io_dma_attr;
ddi_device_acc_attr_t acc_attr = ql_dev_acc_attr;
QL_PRINT_3(ha, "started\n");
dma_attr.dma_attr_align = mem->alignment;
dma_attr.dma_attr_sgllen = (int)mem->max_cookie_count;
if (mem->size & 7) {
mem->size += 8 - (mem->size & 7);
}
mem->flags = DDI_DMA_CONSISTENT;
if (ddi_dma_alloc_handle(ha->dip, &dma_attr, (sleep == KM_SLEEP) ?
DDI_DMA_SLEEP : DDI_DMA_DONTWAIT, NULL, &mem->dma_handle) !=
DDI_SUCCESS) {
EL(ha, "failed, ddi_dma_alloc_handle\n");
mem->dma_handle = NULL;
return (QL_MEMORY_ALLOC_FAILED);
}
switch (mem->type) {
case KERNEL_MEM:
mem->bp = kmem_zalloc(mem->size, sleep);
break;
case BIG_ENDIAN_DMA:
case LITTLE_ENDIAN_DMA:
case NO_SWAP_DMA:
if (mem->type == BIG_ENDIAN_DMA) {
acc_attr.devacc_attr_endian_flags =
DDI_STRUCTURE_BE_ACC;
} else if (mem->type == NO_SWAP_DMA) {
acc_attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
}
if (ddi_dma_mem_alloc(mem->dma_handle, mem->size, &acc_attr,
mem->flags, (sleep == KM_SLEEP) ? DDI_DMA_SLEEP :
DDI_DMA_DONTWAIT, NULL, (caddr_t *)&mem->bp, &rlen,
&mem->acc_handle) == DDI_SUCCESS) {
bzero(mem->bp, mem->size);
if (dma_attr.dma_attr_addr_hi == 0) {
if (mem->cookie.dmac_notused != 0) {
EL(ha, "failed, ddi_dma_mem_alloc "
"returned 64 bit DMA address\n");
ql_free_phys(ha, mem);
return (QL_MEMORY_ALLOC_FAILED);
}
}
} else {
mem->acc_handle = NULL;
mem->bp = NULL;
}
break;
default:
EL(ha, "failed, unknown type=%xh\n", mem->type);
mem->acc_handle = NULL;
mem->bp = NULL;
break;
}
if (mem->bp == NULL) {
EL(ha, "failed, ddi_dma_mem_alloc\n");
ddi_dma_free_handle(&mem->dma_handle);
mem->dma_handle = NULL;
return (QL_MEMORY_ALLOC_FAILED);
}
mem->flags |= DDI_DMA_RDWR;
if (qlc_fm_check_dma_handle(ha, mem->dma_handle)
!= DDI_FM_OK) {
EL(ha, "failed, ddi_dma_addr_bind_handle\n");
ql_free_phys(ha, mem);
qlc_fm_report_err_impact(ha,
QL_FM_EREPORT_DMA_HANDLE_CHECK);
return (QL_MEMORY_ALLOC_FAILED);
}
if (ql_bind_dma_buffer(ha, mem, sleep) != DDI_DMA_MAPPED) {
EL(ha, "failed, ddi_dma_addr_bind_handle\n");
ql_free_phys(ha, mem);
return (QL_MEMORY_ALLOC_FAILED);
}
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
void
ql_free_phys(ql_adapter_state_t *ha, dma_mem_t *mem)
{
QL_PRINT_3(ha, "started\n");
if (mem != NULL) {
if (mem->memflags == DDI_DMA_MAPPED) {
ql_unbind_dma_buffer(ha, mem);
}
switch (mem->type) {
case KERNEL_MEM:
if (mem->bp != NULL) {
kmem_free(mem->bp, mem->size);
mem->bp = NULL;
}
break;
case LITTLE_ENDIAN_DMA:
case BIG_ENDIAN_DMA:
case NO_SWAP_DMA:
if (mem->acc_handle != NULL) {
ddi_dma_mem_free(&mem->acc_handle);
mem->acc_handle = NULL;
mem->bp = NULL;
}
break;
default:
break;
}
if (mem->dma_handle != NULL) {
ddi_dma_free_handle(&mem->dma_handle);
mem->dma_handle = NULL;
}
}
QL_PRINT_3(ha, "done\n");
}
static int
ql_bind_dma_buffer(ql_adapter_state_t *ha, dma_mem_t *mem, int kmflags)
{
ddi_dma_cookie_t *cookiep;
uint32_t cnt;
QL_PRINT_3(ha, "started\n");
mem->memflags = ddi_dma_addr_bind_handle(mem->dma_handle, NULL,
mem->bp, mem->size, mem->flags, (kmflags == KM_SLEEP) ?
DDI_DMA_SLEEP : DDI_DMA_DONTWAIT, NULL, &mem->cookie,
&mem->cookie_count);
if (mem->memflags == DDI_DMA_MAPPED) {
if (mem->cookie_count > mem->max_cookie_count) {
(void) ddi_dma_unbind_handle(mem->dma_handle);
EL(ha, "failed, cookie_count %d > %d\n",
mem->cookie_count, mem->max_cookie_count);
mem->memflags = (uint32_t)DDI_DMA_TOOBIG;
} else {
if (mem->cookie_count > 1) {
if (mem->cookies = kmem_zalloc(
sizeof (ddi_dma_cookie_t) *
mem->cookie_count, kmflags)) {
*mem->cookies = mem->cookie;
cookiep = mem->cookies;
for (cnt = 1; cnt < mem->cookie_count;
cnt++) {
ddi_dma_nextcookie(
mem->dma_handle,
++cookiep);
}
} else {
(void) ddi_dma_unbind_handle(
mem->dma_handle);
EL(ha, "failed, kmem_zalloc\n");
mem->memflags = (uint32_t)
DDI_DMA_NORESOURCES;
}
} else {
mem->cookies = &mem->cookie;
mem->cookies->dmac_size = mem->size;
}
}
}
if (mem->memflags != DDI_DMA_MAPPED) {
EL(ha, "failed=%xh\n", mem->memflags);
} else {
QL_PRINT_3(ha, "done\n");
}
return (mem->memflags);
}
static void
ql_unbind_dma_buffer(ql_adapter_state_t *ha, dma_mem_t *mem)
{
QL_PRINT_3(ha, "started\n");
if (mem->dma_handle != NULL && mem->memflags == DDI_DMA_MAPPED) {
(void) ddi_dma_unbind_handle(mem->dma_handle);
}
if (mem->cookie_count > 1) {
kmem_free(mem->cookies, sizeof (ddi_dma_cookie_t) *
mem->cookie_count);
mem->cookies = NULL;
}
mem->cookie_count = 0;
mem->memflags = (uint32_t)DDI_DMA_NORESOURCES;
QL_PRINT_3(ha, "done\n");
}
static int
ql_suspend_adapter(ql_adapter_state_t *ha)
{
clock_t timer = (clock_t)(32 * drv_usectohz(1000000));
QL_PRINT_3(ha, "started\n");
(void) ql_wait_outstanding(ha);
ql_halt(ha, PM_LEVEL_D0);
MBX_REGISTER_LOCK(ha);
while (ha->mailbox_flags & MBX_BUSY_FLG) {
ha->mailbox_flags = (uint8_t)
(ha->mailbox_flags | MBX_WANT_FLG);
if (cv_reltimedwait(&ha->cv_mbx_wait, &ha->mbx_mutex,
timer, TR_CLOCK_TICK) == -1) {
MBX_REGISTER_UNLOCK(ha);
EL(ha, "failed, Suspend mbox");
return (QL_FUNCTION_TIMEOUT);
}
}
ha->mailbox_flags = (uint8_t)(ha->mailbox_flags | MBX_BUSY_FLG);
MBX_REGISTER_UNLOCK(ha);
if (ha->power_level != PM_LEVEL_D3) {
ql_disable_intr(ha);
}
MBX_REGISTER_LOCK(ha);
ha->mailbox_flags = (uint8_t)(ha->mailbox_flags & ~MBX_BUSY_FLG);
if (ha->mailbox_flags & MBX_WANT_FLG) {
ha->mailbox_flags = (uint8_t)
(ha->mailbox_flags & ~MBX_WANT_FLG);
cv_broadcast(&ha->cv_mbx_wait);
}
MBX_REGISTER_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
void
ql_add_link_b(ql_head_t *head, ql_link_t *link)
{
if (link->head != NULL) {
EL(NULL, "link in use by list=%ph\n", link->head);
}
link->next = NULL;
if ((link->prev = head->last) == NULL) {
head->first = link;
} else {
head->last->next = link;
}
head->last = link;
link->head = head;
}
void
ql_add_link_t(ql_head_t *head, ql_link_t *link)
{
if (link->head != NULL) {
EL(NULL, "link in use by list=%ph\n", link->head);
}
link->prev = NULL;
if ((link->next = head->first) == NULL) {
head->last = link;
} else {
head->first->prev = link;
}
head->first = link;
link->head = head;
}
void
ql_remove_link(ql_head_t *head, ql_link_t *link)
{
if (head != NULL) {
if (link->prev != NULL) {
if ((link->prev->next = link->next) == NULL) {
head->last = link->prev;
} else {
link->next->prev = link->prev;
}
} else if ((head->first = link->next) == NULL) {
head->last = NULL;
} else {
head->first->prev = NULL;
}
link->prev = link->next = NULL;
link->head = NULL;
}
}
void
ql_chg_endian(uint8_t buf[], size_t size)
{
uint8_t byte;
size_t cnt1;
size_t cnt;
cnt1 = size - 1;
for (cnt = 0; cnt < size / 2; cnt++) {
byte = buf[cnt1];
buf[cnt1] = buf[cnt];
buf[cnt] = byte;
cnt1--;
}
}
static int
ql_bstr_to_dec(char *s, uint32_t *ans, uint32_t size)
{
int mul, num, cnt, pos;
char *str;
if (size == 0) {
for (str = s; *str >= '0' && *str <= '9'; str++) {
size++;
}
}
*ans = 0;
for (cnt = 0; *s != '\0' && size; size--, cnt++) {
if (*s >= '0' && *s <= '9') {
num = *s++ - '0';
} else {
break;
}
for (mul = 1, pos = 1; pos < size; pos++) {
mul *= 10;
}
*ans += num * mul;
}
return (cnt);
}
void
ql_delay(ql_adapter_state_t *ha, clock_t usecs)
{
if (ha->flags & ADAPTER_SUSPENDED || ddi_in_panic() ||
curthread->t_flag & T_INTR_THREAD) {
drv_usecwait(usecs);
} else {
delay(drv_usectohz(usecs));
}
}
int
ql_stall_driver(ql_adapter_state_t *ha, uint32_t options)
{
ql_link_t *link;
ql_adapter_state_t *ha2 = NULL;
uint32_t timer;
QL_PRINT_3(ha, "started\n");
link = ha == NULL ? ql_hba.first : &ha->hba;
while (link != NULL) {
ha2 = link->base_address;
ql_awaken_task_daemon(ha2, NULL, DRIVER_STALL, 0);
link = ha == NULL ? link->next : NULL;
}
timer = 3000;
link = ha == NULL ? ql_hba.first : &ha->hba;
while (link != NULL && timer) {
ha2 = link->base_address;
if ((ha2->task_daemon_flags & TASK_DAEMON_ALIVE_FLG) == 0 ||
(ha2->task_daemon_flags & TASK_DAEMON_STOP_FLG) != 0 ||
(ha2->task_daemon_flags & FIRMWARE_UP) == 0 ||
(ha2->task_daemon_flags & TASK_DAEMON_STALLED_FLG &&
ql_wait_outstanding(ha2) == ha2->pha->osc_max_cnt)) {
link = ha == NULL ? link->next : NULL;
continue;
}
QL_PRINT_2(ha2, "status, dtf=%xh, stf=%xh\n",
ha2->task_daemon_flags, ha2->flags);
ql_delay(ha2, 10000);
timer--;
link = ha == NULL ? ql_hba.first : &ha->hba;
}
if (ha2 != NULL && timer == 0) {
EL(ha2, "failed, tdf=%xh, exiting state is: %s\n",
ha2->task_daemon_flags, (options & BIT_0 ? "stalled" :
"unstalled"));
if (options & BIT_0) {
ql_awaken_task_daemon(ha2, NULL, 0, DRIVER_STALL);
}
return (QL_FUNCTION_TIMEOUT);
}
QL_PRINT_3(ha, "done\n");
return (QL_SUCCESS);
}
void
ql_restart_driver(ql_adapter_state_t *ha)
{
ql_link_t *link;
ql_adapter_state_t *ha2;
uint32_t timer;
QL_PRINT_3(ha, "started\n");
link = ha == NULL ? ql_hba.first : &ha->hba;
while (link != NULL) {
ha2 = link->base_address;
ql_awaken_task_daemon(ha2, NULL, 0, DRIVER_STALL);
link = ha == NULL ? link->next : NULL;
}
timer = 3000;
link = ha == NULL ? ql_hba.first : &ha->hba;
while (link != NULL && timer) {
ha2 = link->base_address;
if ((ha2->task_daemon_flags & TASK_DAEMON_ALIVE_FLG) == 0 ||
(ha2->task_daemon_flags & TASK_DAEMON_STOP_FLG) != 0 ||
(ha2->task_daemon_flags & TASK_DAEMON_STALLED_FLG) == 0) {
QL_PRINT_2(ha2, "restarted\n");
ql_restart_queues(ha2);
link = ha == NULL ? link->next : NULL;
continue;
}
QL_PRINT_2(ha2, "status, tdf=%xh\n", ha2->task_daemon_flags);
ql_delay(ha2, 10000);
timer--;
link = ha == NULL ? ql_hba.first : &ha->hba;
}
QL_PRINT_3(ha, "done\n");
}
static int
ql_setup_interrupts(ql_adapter_state_t *ha)
{
int32_t rval = DDI_FAILURE;
int32_t i;
int32_t itypes = 0;
QL_PRINT_3(ha, "started\n");
if (ql_os_release_level < 10 || ql_disable_aif != 0) {
EL(ha, "interrupt framework is not supported or is "
"disabled, using legacy\n");
return (ql_legacy_intr(ha));
} else if (ql_os_release_level == 10) {
void *fptr = (void *)&ddi_intr_get_supported_types;
if (fptr == NULL) {
EL(ha, "aif is not supported, using legacy "
"interrupts (rev)\n");
return (ql_legacy_intr(ha));
}
}
if ((i = ddi_intr_get_supported_types(ha->dip, &itypes)) !=
DDI_SUCCESS) {
EL(ha, "get supported types failed, rval=%xh, "
"assuming FIXED\n", i);
itypes = DDI_INTR_TYPE_FIXED;
}
EL(ha, "supported types are: %xh\n", itypes);
if ((itypes & DDI_INTR_TYPE_MSIX) &&
(rval = ql_setup_msix(ha)) == DDI_SUCCESS) {
EL(ha, "successful MSI-X setup\n");
} else if ((itypes & DDI_INTR_TYPE_MSI) &&
(rval = ql_setup_msi(ha)) == DDI_SUCCESS) {
EL(ha, "successful MSI setup\n");
} else {
rval = ql_setup_fixed(ha);
}
if (rval != DDI_SUCCESS) {
EL(ha, "failed, aif, rval=%xh\n", rval);
} else {
if ((rval = ql_init_mutex(ha)) != DDI_SUCCESS) {
EL(ha, "failed, mutex init ret=%xh\n", rval);
ql_release_intr(ha);
}
QL_PRINT_3(ha, "done\n");
}
return (rval);
}
static int
ql_setup_msi(ql_adapter_state_t *ha)
{
uint_t i;
int32_t count = 0;
int32_t avail = 0;
int32_t actual = 0;
int32_t msitype = DDI_INTR_TYPE_MSI;
int32_t ret;
QL_PRINT_3(ha, "started\n");
if (ql_disable_msi != 0) {
EL(ha, "MSI is disabled by user\n");
return (DDI_FAILURE);
}
if (!CFG_IST(ha, CFG_MSI_SUPPORT)) {
EL(ha, "HBA does not support MSI\n");
return (DDI_FAILURE);
}
if (((ret = ddi_intr_get_nintrs(ha->dip, msitype, &count)) !=
DDI_SUCCESS) || count == 0) {
EL(ha, "failed, nintrs ret=%xh, cnt=%xh\n", ret, count);
return (DDI_FAILURE);
}
if (((ret = ddi_intr_get_navail(ha->dip, msitype, &avail)) !=
DDI_SUCCESS) || avail == 0) {
EL(ha, "failed, navail ret=%xh, avail=%xh\n", ret, avail);
return (DDI_FAILURE);
}
count = 1;
ha->hsize = ((uint32_t)(sizeof (ddi_intr_handle_t)) * count);
ha->htable = kmem_zalloc(ha->hsize, KM_SLEEP);
ha->iflags |= IFLG_INTR_MSI;
if ((ret = ddi_intr_alloc(ha->dip, ha->htable, msitype, 0, count,
&actual, 0)) != DDI_SUCCESS || actual < count) {
EL(ha, "failed, intr_alloc ret=%xh, count = %xh, "
"actual=%xh\n", ret, count, actual);
ql_release_intr(ha);
return (DDI_FAILURE);
}
ha->intr_cnt = actual;
if ((ret = ddi_intr_get_pri(ha->htable[0], &i)) != DDI_SUCCESS) {
EL(ha, "failed, get_pri ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
ha->intr_pri = DDI_INTR_PRI(i);
if ((ret = ddi_intr_add_handler(ha->htable[0], ql_isr_aif,
(caddr_t)ha, (caddr_t)0)) != DDI_SUCCESS) {
EL(ha, "failed, intr_add ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
(void) ddi_intr_get_cap(ha->htable[0], &ha->intr_cap);
if (ha->intr_cap & DDI_INTR_FLAG_BLOCK) {
if ((ret = ddi_intr_block_enable(ha->htable, ha->intr_cnt)) !=
DDI_SUCCESS) {
EL(ha, "failed, block enable, ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
} else {
for (i = 0; i < actual; i++) {
if ((ret = ddi_intr_enable(ha->htable[i])) !=
DDI_SUCCESS) {
EL(ha, "failed, intr enable, ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
}
}
QL_PRINT_3(ha, "done\n");
return (DDI_SUCCESS);
}
static int
ql_setup_msix(ql_adapter_state_t *ha)
{
int hwvect;
int32_t count = 0;
int32_t avail = 0;
int32_t actual = 0;
int32_t msitype = DDI_INTR_TYPE_MSIX;
int32_t ret;
uint_t i;
QL_PRINT_3(ha, "started\n");
if (ql_disable_msix != 0) {
EL(ha, "MSI-X is disabled by user\n");
return (DDI_FAILURE);
}
if (CFG_IST(ha, CFG_ISP_FW_TYPE_1) ||
(CFG_IST(ha, CFG_CTRL_24XX) && ha->rev_id < 3)) {
EL(ha, "HBA does not support MSI-X\n");
return (DDI_FAILURE);
}
if (ha->ven_id == 0x103C && (ha->subsys_id == 0x7041 ||
ha->subsys_id == 0x7040 || ha->subsys_id == 0x1705)) {
EL(ha, "HBA does not support MSI-X (subdevid)\n");
return (DDI_FAILURE);
}
if (((ret = ddi_intr_get_nintrs(ha->dip, msitype, &hwvect)) !=
DDI_SUCCESS) || hwvect == 0) {
EL(ha, "failed, nintrs ret=%xh, cnt=%xh\n", ret, hwvect);
return (DDI_FAILURE);
}
QL_PRINT_10(ha, "ddi_intr_get_nintrs, hwvect=%d\n", hwvect);
if (((ret = ddi_intr_get_navail(ha->dip, msitype, &avail)) !=
DDI_SUCCESS) || avail == 0) {
EL(ha, "failed, navail ret=%xh, avail=%xh\n", ret, avail);
return (DDI_FAILURE);
}
QL_PRINT_10(ha, "ddi_intr_get_navail, avail=%d\n", avail);
count = ha->interrupt_count;
if (ha->flags & MULTI_QUEUE && count < ha->mq_msix_vectors) {
count = ha->mq_msix_vectors;
if (count > hwvect) {
count = hwvect;
}
}
ha->hsize = ((uint32_t)(sizeof (ddi_intr_handle_t)) * hwvect);
ha->htable = kmem_zalloc(ha->hsize, KM_SLEEP);
ha->iflags |= IFLG_INTR_MSIX;
if (((ret = ddi_intr_alloc(ha->dip, ha->htable, msitype,
DDI_INTR_ALLOC_NORMAL, count, &actual, 0)) != DDI_SUCCESS) ||
actual < ha->interrupt_count) {
EL(ha, "failed, intr_alloc ret=%xh, count = %xh, "
"actual=%xh\n", ret, count, actual);
ql_release_intr(ha);
return (DDI_FAILURE);
}
ha->intr_cnt = actual;
EL(ha, "min=%d, multi-q=%d, req=%d, rcv=%d\n",
ha->interrupt_count, ha->mq_msix_vectors, count,
ha->intr_cnt);
if ((ret = ddi_intr_get_pri(ha->htable[0], &i)) != DDI_SUCCESS) {
EL(ha, "failed, get_pri ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
ha->intr_pri = DDI_INTR_PRI(i);
for (i = 0; i < actual; i++) {
if ((ret = ddi_intr_add_handler(ha->htable[i], ql_isr_aif,
(void *)ha, (void *)((ulong_t)i))) != DDI_SUCCESS) {
EL(ha, "failed, addh#=%xh, act=%xh, ret=%xh\n", i,
actual, ret);
ql_release_intr(ha);
return (ret);
}
}
#ifdef __sparc
for (i = actual; i < hwvect; i++) {
if ((ret = ddi_intr_dup_handler(ha->htable[0], (int)i,
&ha->htable[i])) != DDI_SUCCESS) {
EL(ha, "failed, intr_dup#=%xh, act=%xh, ret=%xh\n",
i, actual, ret);
ql_release_intr(ha);
return (ret);
}
if ((ret = ddi_intr_enable(ha->htable[i])) != DDI_SUCCESS) {
EL(ha, "failed, intr enable, ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
}
#endif
(void) ddi_intr_get_cap(ha->htable[0], &ha->intr_cap);
if (ha->intr_cap & DDI_INTR_FLAG_BLOCK) {
if ((ret = ddi_intr_block_enable(ha->htable, actual)) !=
DDI_SUCCESS) {
EL(ha, "failed, block enable, ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
QL_PRINT_10(ha, "intr_block_enable %d\n", actual);
} else {
for (i = 0; i < actual; i++) {
if ((ret = ddi_intr_enable(ha->htable[i])) !=
DDI_SUCCESS) {
EL(ha, "failed, intr enable, ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
QL_PRINT_10(ha, "intr_enable %d\n", i);
}
}
QL_PRINT_3(ha, "done\n");
return (DDI_SUCCESS);
}
static int
ql_setup_fixed(ql_adapter_state_t *ha)
{
int32_t count = 0;
int32_t actual = 0;
int32_t ret;
uint_t i;
QL_PRINT_3(ha, "started\n");
if (ql_disable_intx != 0) {
EL(ha, "INT-X is disabled by user\n");
return (DDI_FAILURE);
}
if (((ret = ddi_intr_get_nintrs(ha->dip, DDI_INTR_TYPE_FIXED,
&count)) != DDI_SUCCESS) || count == 0) {
EL(ha, "failed, nintrs ret=%xh, cnt=%xh\n", ret, count);
return (DDI_FAILURE);
}
ha->hsize = ((uint32_t)(sizeof (ddi_intr_handle_t)) * count);
ha->htable = kmem_zalloc(ha->hsize, KM_SLEEP);
ha->iflags |= IFLG_INTR_FIXED;
if (((ret = ddi_intr_alloc(ha->dip, ha->htable, DDI_INTR_TYPE_FIXED,
0, count, &actual, DDI_INTR_ALLOC_STRICT)) != DDI_SUCCESS) ||
actual < count) {
EL(ha, "failed, intr_alloc ret=%xh, count=%xh, "
"actual=%xh\n", ret, count, actual);
ql_release_intr(ha);
return (DDI_FAILURE);
}
ha->intr_cnt = actual;
if ((ret = ddi_intr_get_pri(ha->htable[0], &i)) != DDI_SUCCESS) {
EL(ha, "failed, get_pri ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
ha->intr_pri = DDI_INTR_PRI(i);
for (i = 0; i < actual; i++) {
if ((ret = ddi_intr_add_handler(ha->htable[i], ql_isr_aif,
(void *)ha, (void *)((ulong_t)(i)))) != DDI_SUCCESS) {
EL(ha, "failed, intr_add ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
}
for (i = 0; i < actual; i++) {
if ((ret = ddi_intr_enable(ha->htable[i])) != DDI_SUCCESS) {
EL(ha, "failed, intr enable, ret=%xh\n", ret);
ql_release_intr(ha);
return (ret);
}
}
EL(ha, "using FIXED interupts\n");
QL_PRINT_3(ha, "done\n");
return (DDI_SUCCESS);
}
static void
ql_release_intr(ql_adapter_state_t *ha)
{
int32_t i, x;
QL_PRINT_3(ha, "started\n");
if (!(ha->iflags & IFLG_INTR_AIF)) {
ddi_remove_intr(ha->dip, 0, ha->iblock_cookie);
} else {
ha->iflags &= ~(IFLG_INTR_AIF);
if (ha->htable != NULL && ha->hsize > 0) {
i = x = (int32_t)ha->hsize /
(int32_t)sizeof (ddi_intr_handle_t);
if (ha->intr_cap & DDI_INTR_FLAG_BLOCK) {
(void) ddi_intr_block_disable(ha->htable,
ha->intr_cnt);
} else {
while (i-- > 0) {
if (ha->htable[i] == 0) {
EL(ha, "htable[%x]=0h\n", i);
continue;
}
(void) ddi_intr_disable(ha->htable[i]);
}
}
i = x;
while (i-- > 0) {
if (i < ha->intr_cnt) {
(void) ddi_intr_remove_handler(
ha->htable[i]);
}
(void) ddi_intr_free(ha->htable[i]);
}
ha->intr_cnt = 0;
ha->intr_cap = 0;
kmem_free(ha->htable, ha->hsize);
ha->htable = NULL;
ha->hsize = 0;
}
}
ha->intr_pri = NULL;
QL_PRINT_3(ha, "done\n");
}
static int
ql_legacy_intr(ql_adapter_state_t *ha)
{
int rval;
QL_PRINT_3(ha, "started\n");
if ((rval = ddi_get_iblock_cookie(ha->dip, 0, &ha->iblock_cookie)) !=
DDI_SUCCESS) {
EL(ha, "failed, get_iblock: %xh\n", rval);
return (rval);
}
ha->intr_pri = (void *)ha->iblock_cookie;
if (ddi_add_intr(ha->dip, (uint_t)0, &ha->iblock_cookie,
(ddi_idevice_cookie_t *)0, ql_isr, (caddr_t)ha) != DDI_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): Failed to add legacy interrupt",
QL_NAME, ha->instance);
return (rval);
}
ha->iflags |= IFLG_INTR_LEGACY;
if ((rval = ql_init_mutex(ha)) != DDI_SUCCESS) {
EL(ha, "failed, mutex init ret=%xh\n", rval);
ql_release_intr(ha);
} else {
EL(ha, "using legacy interrupts\n");
}
return (rval);
}
static int
ql_init_mutex(ql_adapter_state_t *ha)
{
QL_PRINT_3(ha, "started\n");
mutex_init(&ha->mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
mutex_init(&ha->req_ring_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
mutex_init(&ha->comp_q_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
cv_init(&ha->cv_comp_thread, NULL, CV_DRIVER, NULL);
mutex_init(&ha->mbx_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
cv_init(&ha->cv_mbx_wait, NULL, CV_DRIVER, NULL);
cv_init(&ha->cv_mbx_intr, NULL, CV_DRIVER, NULL);
mutex_init(&ha->pm_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
mutex_init(&ha->ub_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
cv_init(&ha->cv_ub, NULL, CV_DRIVER, NULL);
mutex_init(&ha->task_daemon_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
cv_init(&ha->cv_task_daemon, NULL, CV_DRIVER, NULL);
cv_init(&ha->cv_dr_suspended, NULL, CV_DRIVER, NULL);
mutex_init(&ha->dump_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
QL_PRINT_3(ha, "done\n");
return (DDI_SUCCESS);
}
static void
ql_destroy_mutex(ql_adapter_state_t *ha)
{
QL_PRINT_3(ha, "started\n");
mutex_destroy(&ha->dump_mutex);
cv_destroy(&ha->cv_dr_suspended);
cv_destroy(&ha->cv_task_daemon);
mutex_destroy(&ha->task_daemon_mutex);
cv_destroy(&ha->cv_ub);
mutex_destroy(&ha->ub_mutex);
mutex_destroy(&ha->pm_mutex);
cv_destroy(&ha->cv_mbx_intr);
cv_destroy(&ha->cv_mbx_wait);
mutex_destroy(&ha->mbx_mutex);
cv_destroy(&ha->cv_comp_thread);
mutex_destroy(&ha->comp_q_mutex);
mutex_destroy(&ha->req_ring_mutex);
mutex_destroy(&ha->mutex);
QL_PRINT_3(ha, "done\n");
}
uint32_t
ql_fwmodule_resolve(ql_adapter_state_t *ha)
{
int8_t module[128];
int8_t fw_version[128];
uint32_t rval = QL_SUCCESS;
caddr_t code, code02, code03;
uint8_t *p_ucfw;
uint16_t *p_usaddr, *p_uslen;
uint32_t *p_uiaddr, *p_uilen, *p_uifw;
uint32_t *p_uiaddr02, *p_uilen02, *p_uilen03;
struct fw_table *fwt;
extern struct fw_table fw_table[];
QL_PRINT_3(ha, "started\n");
if (ha->fw_module != NULL) {
EL(ha, "%x f/w module %d.%02d.%02d is already loaded\n",
ha->fw_class, ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version);
return (rval);
}
for (fwt = &fw_table[0]; fwt->fw_version; fwt++) {
if (fwt->fw_class == ha->fw_class)
break;
}
if (fwt->fw_version == NULL) {
cmn_err(CE_WARN, "%s(%d): can't find f/w class %x "
"in driver's fw_table", QL_NAME, ha->instance,
ha->fw_class);
return (QL_FW_NOT_SUPPORTED);
}
(void) snprintf(module, sizeof (module), "misc/qlc/qlc_fw_%x",
ha->fw_class);
ha->fw_module = ddi_modopen(module, KRTLD_MODE_FIRST, NULL);
if (ha->fw_module == NULL) {
cmn_err(CE_WARN, "%s(%d): can't load firmware file %s",
QL_NAME, ha->instance, module);
return (QL_FWMODLOAD_FAILED);
}
switch (ha->fw_class) {
case 0x2200:
case 0x2300:
case 0x6322:
if ((code = ddi_modsym(ha->fw_module, "risc_code01",
NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rc01 symbol\n", module);
} else if ((p_usaddr = ddi_modsym(ha->fw_module,
"risc_code_addr01", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rca01 symbol\n", module);
} else if ((p_uslen = ddi_modsym(ha->fw_module,
"risc_code_length01", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rcl01 symbol\n", module);
} else if ((p_ucfw = ddi_modsym(ha->fw_module,
"firmware_version", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d fwver symbol\n", module);
}
if (rval == QL_SUCCESS) {
ha->risc_fw[0].code = code;
ha->risc_fw[0].addr = *p_usaddr;
ha->risc_fw[0].length = *p_uslen;
(void) snprintf(fw_version, sizeof (fw_version),
"%d.%02d.%02d", p_ucfw[0], p_ucfw[1], p_ucfw[2]);
}
break;
case 0x2400:
case 0x2500:
case 0x2700:
case 0x8100:
case 0x8301fc:
if ((code = ddi_modsym(ha->fw_module, "risc_code01",
NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rc01 symbol\n", module);
} else if ((p_uiaddr = ddi_modsym(ha->fw_module,
"risc_code_addr01", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rca01 symbol\n", module);
} else if ((p_uilen = ddi_modsym(ha->fw_module,
"risc_code_length01", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rcl01 symbol\n", module);
} else if ((p_uifw = ddi_modsym(ha->fw_module,
"firmware_version", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d fwver symbol\n", module);
}
if ((code02 = ddi_modsym(ha->fw_module, "risc_code02",
NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rc02 symbol\n", module);
} else if ((p_uiaddr02 = ddi_modsym(ha->fw_module,
"risc_code_addr02", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rca02 symbol\n", module);
} else if ((p_uilen02 = ddi_modsym(ha->fw_module,
"risc_code_length02", NULL)) == NULL) {
rval = QL_FWSYM_NOT_FOUND;
EL(ha, "failed, f/w module %d rcl02 symbol\n", module);
}
if (rval == QL_SUCCESS) {
if (ha->fw_class == 0x2700) {
if ((code03 = ddi_modsym(ha->fw_module,
"tmplt_code01", NULL)) == NULL) {
EL(ha, "failed, f/w module %d "
"tmplt_code01 symbol\n", module);
} else if ((p_uilen03 = ddi_modsym(
ha->fw_module, "tmplt_code_length01",
NULL)) == NULL) {
code03 = NULL;
EL(ha, "failed, f/w module %d "
"tmplt_code_length01 symbol\n",
module);
}
ha->risc_fw[2].code = code03;
if ((ha->risc_fw[2].code = code03) != NULL) {
ha->risc_fw[2].length = *p_uilen03;
}
}
ha->risc_fw[0].code = code;
ha->risc_fw[0].addr = *p_uiaddr;
ha->risc_fw[0].length = *p_uilen;
ha->risc_fw[1].code = code02;
ha->risc_fw[1].addr = *p_uiaddr02;
ha->risc_fw[1].length = *p_uilen02;
(void) snprintf(fw_version, sizeof (fw_version),
"%d.%02d.%02d", p_uifw[0], p_uifw[1], p_uifw[2]);
}
break;
default:
EL(ha, "fw_class: '%x' is not supported\n", ha->fw_class);
rval = QL_FW_NOT_SUPPORTED;
}
if (rval != QL_SUCCESS) {
cmn_err(CE_WARN, "%s(%d): can't resolve firmware "
"module %s (%x)", QL_NAME, ha->instance, module, rval);
if (ha->fw_module != NULL) {
(void) ddi_modclose(ha->fw_module);
ha->fw_module = NULL;
}
} else {
if (strcmp(fwt->fw_version, fw_version) != 0) {
cmn_err(CE_WARN, "%s(%d): driver / f/w version "
"mismatch for %x: driver-%s module-%s", QL_NAME,
ha->instance, ha->fw_class, fwt->fw_version,
fw_version);
}
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
void
ql_port_state(ql_adapter_state_t *ha, uint32_t state, uint32_t flags)
{
ql_adapter_state_t *vha;
QL_PRINT_3(ha, "started\n");
TASK_DAEMON_LOCK(ha);
for (vha = ha->pha; vha != NULL; vha = vha->vp_next) {
if (FC_PORT_STATE_MASK(vha->state) != state) {
vha->state = state != FC_STATE_OFFLINE ?
(FC_PORT_SPEED_MASK(vha->state) | state) : state;
vha->task_daemon_flags |= flags;
}
}
ha->pha->task_daemon_flags |= flags & LOOP_DOWN;
TASK_DAEMON_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
void
ql_el_trace_alloc(ql_adapter_state_t *ha)
{
ql_trace_entry_t *entry;
size_t maxsize;
ha->ql_trace_desc =
(ql_trace_desc_t *)kmem_zalloc(
sizeof (ql_trace_desc_t), KM_SLEEP);
maxsize = ql_log_entries * sizeof (ql_trace_entry_t);
entry = kmem_zalloc(maxsize, KM_SLEEP);
mutex_init(&ha->ql_trace_desc->mutex, NULL,
MUTEX_DRIVER, NULL);
ha->ql_trace_desc->trace_buffer = entry;
ha->ql_trace_desc->trace_buffer_size = maxsize;
ha->ql_trace_desc->nindex = 0;
ha->ql_trace_desc->nentries = ql_log_entries;
ha->ql_trace_desc->start = ha->ql_trace_desc->end = 0;
ha->ql_trace_desc->csize = 0;
ha->ql_trace_desc->count = 0;
}
void
ql_el_trace_dealloc(ql_adapter_state_t *ha)
{
if (ha->ql_trace_desc != NULL) {
if (ha->ql_trace_desc->trace_buffer != NULL) {
kmem_free(ha->ql_trace_desc->trace_buffer,
ha->ql_trace_desc->trace_buffer_size);
}
mutex_destroy(&ha->ql_trace_desc->mutex);
kmem_free(ha->ql_trace_desc,
sizeof (ql_trace_desc_t));
}
}
char *
els_cmd_text(int els_cmd)
{
cmd_table_t *entry = &els_cmd_tbl[0];
return (cmd_text(entry, els_cmd));
}
char *
mbx_cmd_text(int mbx_cmd)
{
cmd_table_t *entry = &mbox_cmd_tbl[0];
return (cmd_text(entry, mbx_cmd));
}
char *
cmd_text(cmd_table_t *entry, int cmd)
{
for (; entry->cmd != 0; entry++) {
if (entry->cmd == cmd) {
break;
}
}
return (entry->string);
}
void
ql_els_24xx_iocb(ql_adapter_state_t *ha, ql_request_q_t *req_q, ql_srb_t *srb,
void *arg)
{
els_descriptor_t els_desc;
ql_fca_isp_els_request(ha, req_q, (fc_packet_t *)srb->pkt,
&els_desc);
ql_isp_els_request_ctor(&els_desc, (els_passthru_entry_t *)arg);
ql_isp_els_handle_cmd_endian(ha, srb);
}
static void
ql_fca_isp_els_request(ql_adapter_state_t *ha, ql_request_q_t *req_q,
fc_packet_t *pkt, els_descriptor_t *els_desc)
{
ls_code_t els;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
els_desc->els = els.ls_code;
els_desc->els_handle = req_q->req_ring.acc_handle;
els_desc->d_id.b24 = pkt->pkt_cmd_fhdr.d_id;
els_desc->s_id.b24 = pkt->pkt_cmd_fhdr.s_id;
if (LOCAL_LOOP_ID(ha->n_port->n_port_handle)) {
els_desc->n_port_handle = ha->n_port->n_port_handle;
} else {
els_desc->n_port_handle = 0;
}
els_desc->control_flags = 0;
els_desc->cmd_byte_count = pkt->pkt_cmdlen;
els_desc->tx_dsd.addr[0] = LSD(pkt->pkt_cmd_cookie->dmac_laddress);
els_desc->tx_dsd.addr[1] = MSD(pkt->pkt_cmd_cookie->dmac_laddress);
els_desc->tx_dsd.length = (uint32_t)pkt->pkt_cmd_cookie->dmac_size;
els_desc->rsp_byte_count = pkt->pkt_rsplen;
els_desc->rx_dsd.addr[0] = LSD(pkt->pkt_resp_cookie->dmac_laddress);
els_desc->rx_dsd.addr[1] = MSD(pkt->pkt_resp_cookie->dmac_laddress);
els_desc->rx_dsd.length = (uint32_t)pkt->pkt_resp_cookie->dmac_size;
}
static void
ql_isp_els_request_ctor(els_descriptor_t *els_desc,
els_passthru_entry_t *els_entry)
{
uint32_t *ptr32;
ddi_put8(els_desc->els_handle, &els_entry->entry_type,
(uint8_t)ELS_PASSTHRU_TYPE);
ddi_put16(els_desc->els_handle, &els_entry->n_port_hdl,
els_desc->n_port_handle);
ddi_put8(els_desc->els_handle, &els_entry->sof_type, (uint8_t)BIT_4);
ddi_put32(els_desc->els_handle, &els_entry->rcv_exch_address,
(uint32_t)0);
ddi_put8(els_desc->els_handle, &els_entry->els_cmd_opcode,
els_desc->els);
ddi_put8(els_desc->els_handle, &els_entry->d_id_7_0,
els_desc->d_id.b.al_pa);
ddi_put8(els_desc->els_handle, &els_entry->d_id_15_8,
els_desc->d_id.b.area);
ddi_put8(els_desc->els_handle, &els_entry->d_id_23_16,
els_desc->d_id.b.domain);
ddi_put8(els_desc->els_handle, &els_entry->s_id_7_0,
els_desc->s_id.b.al_pa);
ddi_put8(els_desc->els_handle, &els_entry->s_id_15_8,
els_desc->s_id.b.area);
ddi_put8(els_desc->els_handle, &els_entry->s_id_23_16,
els_desc->s_id.b.domain);
ddi_put16(els_desc->els_handle, &els_entry->control_flags,
els_desc->control_flags);
ddi_put32(els_desc->els_handle, &els_entry->rcv_payld_data_bcnt,
els_desc->rsp_byte_count);
ddi_put32(els_desc->els_handle, &els_entry->xmt_payld_data_bcnt,
els_desc->cmd_byte_count);
ptr32 = (uint32_t *)&els_entry->dseg;
ddi_put16(els_desc->els_handle, &els_entry->xmt_dseg_count, 1);
ddi_put32(els_desc->els_handle, ptr32++, els_desc->tx_dsd.addr[0]);
ddi_put32(els_desc->els_handle, ptr32++, els_desc->tx_dsd.addr[1]);
ddi_put32(els_desc->els_handle, ptr32++, els_desc->tx_dsd.length);
ddi_put16(els_desc->els_handle, &els_entry->rcv_dseg_count, 1);
ddi_put32(els_desc->els_handle, ptr32++, els_desc->rx_dsd.addr[0]);
ddi_put32(els_desc->els_handle, ptr32++, els_desc->rx_dsd.addr[1]);
ddi_put32(els_desc->els_handle, ptr32++, els_desc->rx_dsd.length);
}
void
ql_isp_els_handle_cmd_endian(ql_adapter_state_t *ha, ql_srb_t *srb)
{
ls_code_t els;
fc_packet_t *pkt;
uint8_t *ptr;
pkt = srb->pkt;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
ptr = (uint8_t *)pkt->pkt_cmd;
ql_isp_els_handle_endian(ha, ptr, els.ls_code);
}
void
ql_isp_els_handle_rsp_endian(ql_adapter_state_t *ha, ql_srb_t *srb)
{
ls_code_t els;
fc_packet_t *pkt;
uint8_t *ptr;
pkt = srb->pkt;
ddi_rep_get8(pkt->pkt_cmd_acc, (uint8_t *)&els,
(uint8_t *)pkt->pkt_cmd, sizeof (els), DDI_DEV_AUTOINCR);
ptr = (uint8_t *)pkt->pkt_resp;
BIG_ENDIAN_32(&els);
ql_isp_els_handle_endian(ha, ptr, els.ls_code);
}
void
ql_isp_els_handle_endian(ql_adapter_state_t *ha, uint8_t *ptr, uint8_t ls_code)
{
switch (ls_code) {
case LA_ELS_PLOGI: {
BIG_ENDIAN_32(ptr);
ptr += 4;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_32(ptr);
ptr += 4;
ptr += 8;
ptr += 8;
ptr += 16;
ptr += 16;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_16(ptr);
break;
}
case LA_ELS_PRLI: {
BIG_ENDIAN_32(ptr);
ptr += 4;
ptr += 2;
BIG_ENDIAN_16(ptr);
ptr += 2;
BIG_ENDIAN_32(ptr);
ptr += 4;
BIG_ENDIAN_32(ptr);
ptr += 4;
BIG_ENDIAN_32(ptr);
break;
}
default:
EL(ha, "can't handle els code %x\n", ls_code);
break;
}
}
static int
ql_n_port_plogi(ql_adapter_state_t *ha)
{
int rval;
ql_tgt_t *tq = NULL;
ql_head_t done_q = { NULL, NULL };
rval = QL_SUCCESS;
if (ha->topology & QL_N_PORT) {
if (LOCAL_LOOP_ID(ha->n_port->n_port_handle)) {
tq = ql_loop_id_to_queue(ha,
ha->n_port->n_port_handle);
if (tq != NULL) {
(void) ql_send_plogi(ha, tq, &done_q);
} else {
EL(ha, "n_port_handle = %x, tq = %x\n",
ha->n_port->n_port_handle, tq);
}
} else {
EL(ha, "n_port_handle = %x, tq = %x\n",
ha->n_port->n_port_handle, tq);
}
if (done_q.first != NULL) {
ql_done(done_q.first, B_FALSE);
}
}
return (rval);
}
int
ql_wwn_cmp(ql_adapter_state_t *ha, la_wwn_t *first, la_wwn_t *second)
{
la_wwn_t t1, t2;
int rval;
t1.i_wwn[0] = BE_32(first->i_wwn[0]);
t1.i_wwn[1] = BE_32(first->i_wwn[1]);
t2.i_wwn[0] = BE_32(second->i_wwn[0]);
t2.i_wwn[1] = BE_32(second->i_wwn[1]);
if (t1.i_wwn[0] == t2.i_wwn[0]) {
if (t1.i_wwn[1] == t2.i_wwn[1]) {
rval = 0;
} else if (t1.i_wwn[1] > t2.i_wwn[1]) {
rval = 1;
} else {
rval = -1;
}
} else {
if (t1.i_wwn[0] > t2.i_wwn[0]) {
rval = 1;
} else {
rval = -1;
}
}
return (rval);
}
int
ql_nvram_cache_desc_ctor(ql_adapter_state_t *ha)
{
int rval = DDI_SUCCESS;
QL_PRINT_3(ha, "started\n");
ha->nvram_cache =
(nvram_cache_desc_t *)kmem_zalloc(sizeof (nvram_cache_desc_t),
KM_SLEEP);
if (ha->nvram_cache == NULL) {
cmn_err(CE_WARN, "%s(%d): can't construct nvram cache"
" descriptor", QL_NAME, ha->instance);
rval = DDI_FAILURE;
} else {
if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
ha->nvram_cache->size = sizeof (nvram_24xx_t);
} else {
ha->nvram_cache->size = sizeof (nvram_t);
}
ha->nvram_cache->cache =
(void *)kmem_zalloc(ha->nvram_cache->size, KM_SLEEP);
if (ha->nvram_cache->cache == NULL) {
cmn_err(CE_WARN, "%s(%d): can't get nvram cache buffer",
QL_NAME, ha->instance);
kmem_free(ha->nvram_cache,
sizeof (nvram_cache_desc_t));
ha->nvram_cache = 0;
rval = DDI_FAILURE;
} else {
ha->nvram_cache->valid = 0;
}
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
int
ql_nvram_cache_desc_dtor(ql_adapter_state_t *ha)
{
int rval = DDI_SUCCESS;
QL_PRINT_3(ha, "started\n");
if (ha->nvram_cache == NULL) {
cmn_err(CE_WARN, "%s(%d): can't destroy nvram descriptor",
QL_NAME, ha->instance);
rval = DDI_FAILURE;
} else {
if (ha->nvram_cache->cache != NULL) {
kmem_free(ha->nvram_cache->cache,
ha->nvram_cache->size);
}
kmem_free(ha->nvram_cache, sizeof (nvram_cache_desc_t));
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
int
ql_plogi_params_desc_ctor(ql_adapter_state_t *ha)
{
int rval = DDI_SUCCESS;
QL_PRINT_3(ha, "started\n");
ha->plogi_params =
(plogi_params_desc_t *)kmem_zalloc(sizeof (plogi_params_desc_t),
KM_SLEEP);
if (ha->plogi_params == NULL) {
cmn_err(CE_WARN, "%s(%d): can't construct plogi params"
" descriptor", QL_NAME, ha->instance);
rval = DDI_FAILURE;
} else {
ha->plogi_params->retry_cnt = QL_PLOGI_RETRY_CNT;
ha->plogi_params->retry_dly_usec = QL_PLOGI_RETRY_DLY_USEC;
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
int
ql_plogi_params_desc_dtor(ql_adapter_state_t *ha)
{
int rval = DDI_SUCCESS;
QL_PRINT_3(ha, "started\n");
if (ha->plogi_params == NULL) {
cmn_err(CE_WARN, "%s(%d): can't destroy plogi params"
" descriptor", QL_NAME, ha->instance);
rval = DDI_FAILURE;
} else {
kmem_free(ha->plogi_params, sizeof (plogi_params_desc_t));
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
void
ql_toggle_loop_state(ql_adapter_state_t *ha)
{
uint32_t timer;
if (LOOP_READY(ha)) {
ql_port_state(ha, FC_STATE_OFFLINE, FC_STATE_CHANGE);
ql_awaken_task_daemon(ha, NULL, FC_STATE_CHANGE, 0);
for (timer = 30; timer; timer--) {
if (!(ha->task_daemon_flags & FC_STATE_CHANGE)) {
break;
}
delay(100);
}
ql_loop_online(ha);
}
}
static int
ql_create_queues(ql_adapter_state_t *ha)
{
int rval;
uint16_t cnt;
QL_PRINT_10(ha, "started\n");
if (ha->req_q[0] != NULL) {
QL_PRINT_10(ha, "done, queues already exist\n");
return (QL_SUCCESS);
}
if (ha->vp_index != 0) {
QL_PRINT_10(ha, "done, no multi-req-q \n");
ha->req_q[0] = ha->pha->req_q[0];
ha->req_q[1] = ha->pha->req_q[1];
ha->rsp_queues = ha->pha->rsp_queues;
return (QL_SUCCESS);
}
ha->req_q[0] = kmem_zalloc(sizeof (ql_request_q_t), KM_SLEEP);
ha->req_q[0]->req_entry_cnt = REQUEST_ENTRY_CNT;
ha->req_q[0]->req_ring.size = ha->req_q[0]->req_entry_cnt *
REQUEST_ENTRY_SIZE;
if (ha->flags & QUEUE_SHADOW_PTRS) {
ha->req_q[0]->req_ring.size += SHADOW_ENTRY_SIZE;
}
ha->req_q[0]->req_ring.type = LITTLE_ENDIAN_DMA;
ha->req_q[0]->req_ring.max_cookie_count = 1;
ha->req_q[0]->req_ring.alignment = 64;
if ((rval = ql_alloc_phys(ha, &ha->req_q[0]->req_ring, KM_SLEEP)) !=
QL_SUCCESS) {
EL(ha, "request queue status=%xh", rval);
ql_delete_queues(ha);
return (rval);
}
if (ha->flags & QUEUE_SHADOW_PTRS) {
ha->req_q[0]->req_out_shadow_ofst =
ha->req_q[0]->req_entry_cnt * REQUEST_ENTRY_SIZE;
ha->req_q[0]->req_out_shadow_ptr = (uint32_t *)
((caddr_t)ha->req_q[0]->req_ring.bp +
ha->req_q[0]->req_out_shadow_ofst);
}
ha->fw_transfer_size = ha->req_q[0]->req_ring.size;
if (ha->flags & MULTI_QUEUE) {
ha->req_q[0]->mbar_req_in = MBAR2_REQ_IN;
ha->req_q[0]->mbar_req_out = MBAR2_REQ_OUT;
if (ha->req_q[0]->mbar_req_in >= ha->mbar_size) {
EL(ha, "req_q index=0 exceeds mbar size=%xh",
ha->mbar_size);
ql_delete_queues(ha);
return (QL_FUNCTION_PARAMETER_ERROR);
}
}
if (ha->rsp_queues == NULL) {
if (ha->intr_cnt > 1) {
ha->rsp_queues_cnt = (uint8_t)(ha->intr_cnt - 1);
} else {
ha->rsp_queues_cnt = 1;
}
ha->io_min_rsp_q_number = 0;
if (ha->rsp_queues_cnt > 1) {
ha->req_q[1] = kmem_zalloc(sizeof (ql_request_q_t),
KM_SLEEP);
ha->req_q[1]->req_entry_cnt = REQUEST_ENTRY_CNT;
ha->req_q[1]->req_ring.size =
ha->req_q[1]->req_entry_cnt * REQUEST_ENTRY_SIZE;
if (ha->flags & QUEUE_SHADOW_PTRS) {
ha->req_q[1]->req_ring.size +=
SHADOW_ENTRY_SIZE;
}
ha->req_q[1]->req_ring.type = LITTLE_ENDIAN_DMA;
ha->req_q[1]->req_ring.max_cookie_count = 1;
ha->req_q[1]->req_ring.alignment = 64;
if ((rval = ql_alloc_phys(ha, &ha->req_q[1]->req_ring,
KM_SLEEP)) != QL_SUCCESS) {
EL(ha, "ha request queue status=%xh", rval);
ql_delete_queues(ha);
return (rval);
}
if (ha->flags & QUEUE_SHADOW_PTRS) {
ha->req_q[1]->req_out_shadow_ofst =
ha->req_q[1]->req_entry_cnt *
REQUEST_ENTRY_SIZE;
ha->req_q[1]->req_out_shadow_ptr = (uint32_t *)
((caddr_t)ha->req_q[1]->req_ring.bp +
ha->req_q[1]->req_out_shadow_ofst);
}
ha->req_q[1]->req_q_number = 1;
if (ha->flags & MULTI_QUEUE) {
ha->req_q[1]->mbar_req_in =
ha->mbar_queue_offset + MBAR2_REQ_IN;
ha->req_q[1]->mbar_req_out =
ha->mbar_queue_offset + MBAR2_REQ_OUT;
if (ha->req_q[1]->mbar_req_in >=
ha->mbar_size) {
EL(ha, "ha req_q index=1 exceeds mbar "
"size=%xh", ha->mbar_size);
ql_delete_queues(ha);
return (QL_FUNCTION_PARAMETER_ERROR);
}
}
}
ha->rsp_queues_size = (ha->hsize / sizeof (ddi_intr_handle_t)) *
sizeof (ql_response_q_t *);
ha->rsp_queues = kmem_zalloc(ha->rsp_queues_size, KM_SLEEP);
for (cnt = 0; cnt < ha->rsp_queues_cnt; cnt++) {
rval = ql_create_rsp_queue(ha, cnt);
if (rval != QL_SUCCESS) {
ql_delete_queues(ha);
return (rval);
}
}
}
if (CFG_IST(ha, CFG_FCIP_TYPE_1)) {
ha->rcv_ring.size = RCVBUF_QUEUE_SIZE;
ha->rcv_ring.type = LITTLE_ENDIAN_DMA;
ha->rcv_ring.max_cookie_count = 1;
ha->rcv_ring.alignment = 64;
if ((rval = ql_alloc_phys(ha, &ha->rcv_ring, KM_SLEEP)) !=
QL_SUCCESS) {
EL(ha, "receive queue status=%xh", rval);
ql_delete_queues(ha);
return (rval);
}
}
QL_PRINT_10(ha, "done\n");
return (rval);
}
static int
ql_create_rsp_queue(ql_adapter_state_t *ha, uint16_t rsp_q_indx)
{
ql_response_q_t *rsp_q;
int rval = QL_SUCCESS;
QL_PRINT_3(ha, "started\n");
ha->rsp_queues[rsp_q_indx] = rsp_q =
kmem_zalloc(sizeof (ql_response_q_t), KM_SLEEP);
mutex_init(&rsp_q->intr_mutex, NULL, MUTEX_DRIVER, ha->intr_pri);
rsp_q->rsp_q_number = rsp_q_indx;
rsp_q->msi_x_vector = (uint16_t)(rsp_q_indx + 1);
if (ha->flags & MULTI_QUEUE) {
rsp_q->mbar_rsp_in = rsp_q->rsp_q_number *
ha->mbar_queue_offset + MBAR2_RESP_IN;
rsp_q->mbar_rsp_out = rsp_q->rsp_q_number *
ha->mbar_queue_offset + MBAR2_RESP_OUT;
if (rsp_q->mbar_rsp_in >= ha->mbar_size) {
EL(ha, "rsp_q index=%xh exceeds mbar size=%xh",
rsp_q_indx, ha->mbar_size);
return (QL_FUNCTION_PARAMETER_ERROR);
}
}
rsp_q->rsp_entry_cnt = RESPONSE_ENTRY_CNT;
rsp_q->rsp_ring.size = rsp_q->rsp_entry_cnt * RESPONSE_ENTRY_SIZE;
if (ha->flags & QUEUE_SHADOW_PTRS) {
rsp_q->rsp_ring.size += SHADOW_ENTRY_SIZE;
}
rsp_q->rsp_ring.type = LITTLE_ENDIAN_DMA;
rsp_q->rsp_ring.max_cookie_count = 1;
rsp_q->rsp_ring.alignment = 64;
rval = ql_alloc_phys(ha, &rsp_q->rsp_ring, KM_SLEEP);
if (rval != QL_SUCCESS) {
EL(ha, "response queue status=%xh", rval);
}
if (ha->flags & QUEUE_SHADOW_PTRS) {
rsp_q->rsp_in_shadow_ofst =
rsp_q->rsp_entry_cnt * RESPONSE_ENTRY_SIZE;
rsp_q->rsp_in_shadow_ptr = (uint32_t *)
((caddr_t)rsp_q->rsp_ring.bp +
rsp_q->rsp_in_shadow_ofst);
}
QL_PRINT_3(ha, "done\n");
return (rval);
}
static void
ql_delete_queues(ql_adapter_state_t *ha)
{
uint32_t cnt;
QL_PRINT_10(ha, "started\n");
if (ha->vp_index != 0) {
QL_PRINT_10(ha, "done, no multi-req-q \n");
ha->req_q[0] = ha->req_q[1] = NULL;
return;
}
if (ha->req_q[0] != NULL) {
ql_free_phys(ha, &ha->req_q[0]->req_ring);
kmem_free(ha->req_q[0], sizeof (ql_request_q_t));
ha->req_q[0] = NULL;
}
if (ha->req_q[1] != NULL) {
ql_free_phys(ha, &ha->req_q[1]->req_ring);
kmem_free(ha->req_q[1], sizeof (ql_request_q_t));
ha->req_q[1] = NULL;
}
if (ha->rsp_queues != NULL) {
ql_response_q_t *rsp_q;
for (cnt = 0; cnt < ha->rsp_queues_cnt; cnt++) {
if ((rsp_q = ha->rsp_queues[cnt]) == NULL) {
continue;
}
mutex_destroy(&rsp_q->intr_mutex);
ql_free_phys(ha, &rsp_q->rsp_ring);
kmem_free(rsp_q, sizeof (ql_response_q_t));
ha->rsp_queues[cnt] = NULL;
}
kmem_free(ha->rsp_queues, ha->rsp_queues_size);
ha->rsp_queues = NULL;
}
QL_PRINT_10(ha, "done\n");
}
static int
ql_multi_queue_support(ql_adapter_state_t *ha)
{
uint32_t data;
int rval;
data = ql_get_cap_ofst(ha, PCI_CAP_ID_MSI_X);
if ((ql_pci_config_get16(ha, data + PCI_MSIX_CTRL) &
PCI_MSIX_TBL_SIZE_MASK) > 2) {
ha->mbar_size = MBAR2_MULTI_Q_MAX * MBAR2_REG_OFFSET;
if (ql_map_mem_bar(ha, &ha->mbar_dev_handle, &ha->mbar,
PCI_CONF_BASE3, ha->mbar_size) != DDI_SUCCESS) {
return (QL_FUNCTION_FAILED);
}
if ((rval = qlc_fm_check_acc_handle(ha,
ha->mbar_dev_handle)) != DDI_FM_OK) {
qlc_fm_report_err_impact(ha,
QL_FM_EREPORT_ACC_HANDLE_CHECK);
EL(ha, "fm_check_acc_handle mbar_dev_handle "
"status=%xh\n", rval);
return (QL_FUNCTION_FAILED);
}
return (QL_SUCCESS);
}
return (QL_FUNCTION_FAILED);
}
int
ql_get_cap_ofst(ql_adapter_state_t *ha, uint8_t cap_id)
{
int cptr = PCI_CAP_NEXT_PTR_NULL;
QL_PRINT_3(ha, "started\n");
if (ql_pci_config_get16(ha, PCI_CONF_STAT) & PCI_STAT_CAP) {
cptr = ql_pci_config_get8(ha, PCI_CONF_CAP_PTR);
while (cptr != PCI_CAP_NEXT_PTR_NULL) {
if (ql_pci_config_get8(ha, cptr) == cap_id) {
break;
}
cptr = ql_pci_config_get8(ha, cptr + PCI_CAP_NEXT_PTR);
}
}
QL_PRINT_3(ha, "done\n");
return (cptr);
}
static int
ql_map_mem_bar(ql_adapter_state_t *ha, ddi_acc_handle_t *handlep,
caddr_t *addrp, uint32_t ofst, uint32_t len)
{
caddr_t nreg;
pci_regspec_t *reg, *reg2;
int rval;
uint_t rlen;
uint32_t rcnt, w32, nreg_size;
QL_PRINT_10(ha, "started\n");
w32 = ql_pci_config_get32(ha, ofst);
if (w32 == 0) {
EL(ha, "no Mem BAR %xh\n", ofst);
return (DDI_FAILURE);
}
if ((rval = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, ha->dip,
DDI_PROP_DONTPASS, "reg", (int **)®, &rlen)) !=
DDI_PROP_SUCCESS) {
EL(ha, "ddi_prop_lookup_int_array status=%xh\n", rval);
return (DDI_FAILURE);
}
rlen = (uint_t)(rlen * sizeof (int));
rcnt = (uint32_t)(rlen / sizeof (pci_regspec_t));
reg2 = reg;
for (w32 = 0; w32 < rcnt; w32++) {
if ((reg2->pci_phys_hi & PCI_REG_REG_M) == ofst) {
EL(ha, "already mapped\n");
break;
}
reg2++;
}
if (w32 == rcnt) {
nreg_size = (uint32_t)(rlen + sizeof (pci_regspec_t));
nreg = kmem_zalloc(nreg_size, KM_SLEEP);
reg2 = reg;
while ((reg2->pci_phys_hi & PCI_REG_ADDR_M) !=
PCI_ADDR_MEM32 && (reg2->pci_phys_hi & PCI_REG_ADDR_M) !=
PCI_ADDR_MEM64) {
reg2++;
if ((caddr_t)reg2 >= (caddr_t)reg + rlen) {
reg2 = reg;
break;
}
}
w32 = (reg2->pci_phys_hi & ~PCI_REG_REG_M) | ofst;
bcopy(reg, nreg, rlen);
reg2 = (pci_regspec_t *)(nreg + rlen);
reg2->pci_phys_hi = w32;
reg2->pci_phys_mid = 0;
reg2->pci_phys_low = 0;
reg2->pci_size_hi = 0;
reg2->pci_size_low = len;
(void) ndi_prop_update_int_array(DDI_DEV_T_NONE, ha->dip,
"reg", (int *)nreg, (uint_t)(nreg_size / sizeof (int)));
w32 = (uint_t)(nreg_size / sizeof (pci_regspec_t) - 1);
kmem_free((caddr_t)nreg, nreg_size);
}
ddi_prop_free(reg);
rval = ddi_regs_map_setup(ha->dip, w32, addrp, 0, len,
&ql_dev_acc_attr, handlep);
if (rval != DDI_SUCCESS || *addrp == NULL || *handlep == NULL) {
EL(ha, "regs_map status=%xh, base=%xh, handle=%xh\n",
rval, *addrp, *handlep);
if (*handlep != NULL) {
ddi_regs_map_free(handlep);
*handlep = NULL;
}
}
QL_PRINT_10(ha, "done\n");
return (rval);
}
void
ql_intr_lock(ql_adapter_state_t *ha)
{
uint16_t cnt;
QL_PRINT_3(ha, "started\n");
if (ha->rsp_queues != NULL) {
for (cnt = 0; cnt < ha->rsp_queues_cnt; cnt++) {
if (ha->rsp_queues[cnt] != NULL) {
INDX_INTR_LOCK(ha, cnt);
}
}
}
QL_PRINT_3(ha, "done\n");
}
void
ql_intr_unlock(ql_adapter_state_t *ha)
{
uint16_t cnt;
QL_PRINT_3(ha, "started\n");
if (ha->rsp_queues != NULL) {
for (cnt = 0; cnt < ha->rsp_queues_cnt; cnt++) {
if (ha->rsp_queues[cnt] != NULL) {
INDX_INTR_UNLOCK(ha, cnt);
}
}
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_completion_thread(void *arg)
{
ql_srb_t *sp;
ql_adapter_state_t *ha = arg;
QL_PRINT_3(ha, "started, hsp=%p\n", (void *)&sp);
COMP_Q_LOCK(ha);
ha->comp_thds_active++;
ha->comp_thds_awake++;
while (!(ha->flags & COMP_THD_TERMINATE)) {
while (ha->comp_q.first != NULL) {
sp = (ha->comp_q.first)->base_address;
ql_remove_link(&ha->comp_q, &sp->cmd);
COMP_Q_UNLOCK(ha);
QL_PRINT_3(ha, "pkt_comp, sp=%p, pkt_state=%xh, "
"hsp=%p\n", (void*)sp, sp->pkt->pkt_state,
(void *)&sp);
(sp->pkt->pkt_comp)(sp->pkt);
COMP_Q_LOCK(ha);
}
ha->comp_thds_awake--;
QL_PRINT_3(ha, "sleep, hsp=%p\n", (void *)&sp);
cv_wait(&ha->cv_comp_thread, &ha->comp_q_mutex);
QL_PRINT_3(ha, "awoke, hsp=%p\n", (void *)&sp);
}
ha->comp_thds_awake--;
ha->comp_thds_active--;
COMP_Q_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
void
ql_io_comp(ql_srb_t *sp)
{
ql_adapter_state_t *ha = sp->ha->pha;
QL_PRINT_3(ha, "started, sp=%ph, d_id=%xh\n", (void*)sp,
sp->pkt->pkt_cmd_fhdr.d_id);
if (sp->pkt->pkt_comp && !ddi_in_panic()) {
QL_PRINT_3(ha, "added to comp_q\n");
COMP_Q_LOCK(ha);
ql_add_link_b(&ha->comp_q, &sp->cmd);
if (ha->comp_thds_awake < ha->comp_thds_active) {
ha->comp_thds_awake++;
QL_PRINT_3(ha, "signal\n");
cv_signal(&ha->cv_comp_thread);
}
COMP_Q_UNLOCK(ha);
}
QL_PRINT_3(ha, "done\n");
}
static void
ql_process_comp_queue(void *arg)
{
ql_srb_t *sp;
ql_adapter_state_t *ha = arg;
QL_PRINT_3(ha, "started\n");
COMP_Q_LOCK(ha);
while (ha->comp_q.first != NULL) {
sp = (ha->comp_q.first)->base_address;
QL_PRINT_3(ha, "sending comp=0x%p\n", (void *)sp);
ql_remove_link(&ha->comp_q, &sp->cmd);
COMP_Q_UNLOCK(ha);
(sp->pkt->pkt_comp)(sp->pkt);
COMP_Q_LOCK(ha);
}
COMP_Q_UNLOCK(ha);
QL_PRINT_3(ha, "done\n");
}
static int
ql_abort_io(ql_adapter_state_t *vha, ql_srb_t *sp)
{
ql_link_t *link;
ql_srb_t *sp2;
ql_tgt_t *tq;
ql_lun_t *lq;
int rval = QL_FUNCTION_FAILED;
ql_adapter_state_t *ha = vha->pha;
QL_PRINT_10(ha, "started, sp=%ph, handle=%xh\n", (void *)sp,
sp->handle);
if ((lq = sp->lun_queue) != NULL) {
tq = lq->target_queue;
} else {
tq = NULL;
}
if (tq) {
DEVICE_QUEUE_LOCK(tq);
}
REQUEST_RING_LOCK(ha);
if (!(sp->flags & SRB_ISP_STARTED)) {
rval = QL_FUNCTION_PARAMETER_ERROR;
for (link = ha->pending_cmds.first; link != NULL;
link = link->next) {
sp2 = link->base_address;
if (sp2 == sp) {
rval = QL_SUCCESS;
ql_remove_link(&ha->pending_cmds, &sp->cmd);
break;
}
}
if (link == NULL && lq) {
for (link = lq->cmd.first; link != NULL;
link = link->next) {
sp2 = link->base_address;
if (sp2 == sp) {
rval = QL_SUCCESS;
ql_remove_link(&lq->cmd, &sp->cmd);
sp->flags &= ~SRB_IN_DEVICE_QUEUE;
break;
}
}
}
}
REQUEST_RING_UNLOCK(ha);
if (tq) {
DEVICE_QUEUE_UNLOCK(tq);
}
if (sp->flags & SRB_ISP_COMPLETED || rval == QL_SUCCESS) {
rval = QL_SUCCESS;
} else {
uint32_t index;
INTR_LOCK(ha);
sp->flags |= SRB_ABORTING;
if (sp->handle != 0) {
index = sp->handle & OSC_INDEX_MASK;
if (ha->outstanding_cmds[index] == sp) {
ha->outstanding_cmds[index] =
QL_ABORTED_SRB(ha);
}
if (tq != NULL && tq->outcnt != 0) {
tq->outcnt--;
}
if (lq != NULL && sp->flags & SRB_FCP_CMD_PKT &&
lq->lun_outcnt != 0) {
lq->lun_outcnt--;
}
if (sp->flags & SRB_WATCHDOG_ENABLED) {
if (tq != NULL) {
ql_remove_link(&tq->wdg, &sp->wdg);
}
sp->flags &= ~SRB_WATCHDOG_ENABLED;
}
INTR_UNLOCK(ha);
(void) ql_abort_command(ha, sp);
sp->handle = 0;
} else {
INTR_UNLOCK(ha);
}
rval = QL_SUCCESS;
}
if (rval != QL_SUCCESS) {
EL(ha, "sp=%p not aborted=%xh\n", (void *)sp, rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (rval);
}
static void
ql_idc(ql_adapter_state_t *ha)
{
int rval;
uint32_t timer = 300;
QL_PRINT_10(ha, "started\n");
for (;;) {
if (ha->flags & IDC_STALL_NEEDED) {
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~IDC_STALL_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags |= DRIVER_STALL;
TASK_DAEMON_UNLOCK(ha);
if (LOOP_READY(ha)) {
if ((ha->idc_mb[1] & IDC_TIMEOUT_MASK) <
IDC_TIMEOUT_MASK) {
ha->idc_mb[1] = (uint16_t)
(ha->idc_mb[1] | IDC_TIMEOUT_MASK);
rval = ql_idc_time_extend(ha);
if (rval != QL_SUCCESS) {
EL(ha, "idc_time_extend status"
"=%xh\n", rval);
}
}
(void) ql_wait_outstanding(ha);
}
}
if (ha->flags & IDC_ACK_NEEDED) {
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~IDC_ACK_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
rval = ql_idc_ack(ha);
if (rval != QL_SUCCESS) {
EL(ha, "idc_ack status=%xh\n", rval);
ADAPTER_STATE_LOCK(ha);
ha->flags |= IDC_RESTART_NEEDED;
ADAPTER_STATE_UNLOCK(ha);
}
}
if (timer-- == 0 || ha->flags & ADAPTER_SUSPENDED ||
(ha->flags & IDC_RESTART_NEEDED &&
!(ha->flags & LOOPBACK_ACTIVE))) {
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~(IDC_RESTART_NEEDED | IDC_STALL_NEEDED |
IDC_ACK_NEEDED);
ADAPTER_STATE_UNLOCK(ha);
TASK_DAEMON_LOCK(ha);
ha->task_daemon_flags &= ~DRIVER_STALL;
TASK_DAEMON_UNLOCK(ha);
if (LOOP_READY(ha)) {
ql_restart_queues(ha);
}
break;
}
delay(10);
}
QL_PRINT_10(ha, "done\n");
}
uint64_t
ql_get_lun_addr(ql_tgt_t *tq, uint16_t lun)
{
ql_lun_t *lq;
ql_link_t *link = NULL;
uint64_t lun_addr = 0;
fcp_ent_addr_t *fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
if (tq) {
for (link = tq->lun_queues.first; link != NULL;
link = link->next) {
lq = link->base_address;
if (lq->lun_no == lun) {
break;
}
}
}
if (link == NULL) {
if (MSB(lun)) {
fcp_ent_addr->ent_addr_0 = CHAR_TO_SHORT(lobyte(lun),
(hibyte(lun) | QL_LUN_AM_FLAT));
} else {
fcp_ent_addr->ent_addr_0 = CHAR_TO_SHORT(lobyte(lun),
hibyte(lun));
}
} else {
lun_addr = lq->lun_addr;
}
return (lun_addr);
}
static int
ql_83xx_binary_fw_dump(ql_adapter_state_t *ha, ql_83xx_fw_dump_t *fw)
{
uint32_t *reg32, cnt, *w32ptr, index, *dp;
void *bp;
clock_t timer;
int rv, rval = QL_SUCCESS;
QL_PRINT_3(ha, "started\n");
fw->req_q_size[0] = ha->req_q[0]->req_ring.size;
if (ha->req_q[1] != NULL) {
fw->req_q_size[1] = ha->req_q[1]->req_ring.size;
}
fw->rsp_q_size = ha->rsp_queues[0]->rsp_ring.size * ha->rsp_queues_cnt;
fw->hccr = RD32_IO_REG(ha, hccr);
fw->r2h_status = RD32_IO_REG(ha, risc2host);
fw->aer_ues = ql_pci_config_get32(ha, 0x104);
ql_disable_intr(ha);
if ((RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0) {
WRT32_IO_REG(ha, hccr, HC24_PAUSE_RISC);
for (timer = 30000;
(RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0 &&
rval == QL_SUCCESS; timer--) {
if (timer) {
drv_usecwait(100);
if (timer % 10000 == 0) {
EL(ha, "risc pause %d\n", timer);
}
} else {
EL(ha, "risc pause timeout\n");
rval = QL_FUNCTION_TIMEOUT;
}
}
}
WRT32_IO_REG(ha, io_base_addr, 0x6000);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, 0);
WRT_REG_DWORD(ha, ha->iobase + 0xcc, 0);
WRT32_IO_REG(ha, io_base_addr, 0x6010);
WRT_REG_DWORD(ha, ha->iobase + 0xd4, 0);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
WRT_REG_DWORD(ha, ha->iobase + 0xf0, 0x60000000);
WRT32_IO_REG(ha, io_base_addr, 0x7000);
bp = ql_read_regs(ha, fw->hostrisc_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7040);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7c00);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, 0x1);
bp = ql_read_regs(ha, fw->pcie_reg, ha->iobase + 0xC4,
3, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 1, 32);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, 0x0);
(void) ql_read_regs(ha, fw->host_reg, ha->iobase,
sizeof (fw->host_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
RD32_IO_REG(ha, io_base_addr);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0000000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[0] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0100000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[1] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0200000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[2] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0300000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[3] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0400000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[4] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0500000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[5] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0600000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[6] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0700000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[7] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0800000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[8] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0900000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[9] = RD_REG_DWORD(ha, reg32);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xF0);
WRT_REG_DWORD(ha, reg32, 0xB0A00000);
reg32 = (uint32_t *)((caddr_t)ha->iobase + 0xFC);
fw->shadow_reg[0xa] = RD_REG_DWORD(ha, reg32);
WRT32_IO_REG(ha, io_base_addr, 0x0010);
(void) ql_read_regs(ha, &fw->risc_io, ha->iobase + 0xC0,
1, 32);
(void) ql_read_regs(ha, fw->mailbox_reg, ha->iobase + 0x80,
sizeof (fw->mailbox_reg) / 2, 16);
WRT32_IO_REG(ha, io_base_addr, 0xBE00);
bp = ql_read_regs(ha, fw->xseq_gp_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBE10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBE20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBE30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBE40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBE50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBE60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBE70);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF00);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFC0);
bp = ql_read_regs(ha, fw->xseq_0_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFD0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFE0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBFF0);
(void) ql_read_regs(ha, fw->xseq_1_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xBEF0);
(void) ql_read_regs(ha, fw->xseq_2_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE00);
bp = ql_read_regs(ha, fw->rseq_gp_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFE70);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF00);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFF70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFC0);
bp = ql_read_regs(ha, fw->rseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFD0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFE0);
(void) ql_read_regs(ha, fw->rseq_1_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_1_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFFF0);
(void) ql_read_regs(ha, fw->rseq_2_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_2_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xFEF0);
(void) ql_read_regs(ha, fw->rseq_3_reg, ha->iobase + 0xC0,
sizeof (fw->rseq_3_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB000);
bp = ql_read_regs(ha, fw->aseq_gp_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB070);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB100);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB110);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB120);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB130);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB140);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB150);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB160);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB170);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0C0);
bp = ql_read_regs(ha, fw->aseq_0_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0D0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0E0);
(void) ql_read_regs(ha, fw->aseq_1_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB0F0);
(void) ql_read_regs(ha, fw->aseq_2_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0xB1F0);
(void) ql_read_regs(ha, fw->aseq_3_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7100);
bp = ql_read_regs(ha, fw->cmd_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7120);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7130);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x71f0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7200);
bp = ql_read_regs(ha, fw->req0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7300);
bp = ql_read_regs(ha, fw->resp0_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7400);
bp = ql_read_regs(ha, fw->req1_dma_reg, ha->iobase + 0xC0,
8, 32);
(void) ql_read_regs(ha, bp, ha->iobase + 0xE4, 7, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7600);
bp = ql_read_regs(ha, fw->xmt0_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7610);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7620);
bp = ql_read_regs(ha, fw->xmt1_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7630);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7640);
bp = ql_read_regs(ha, fw->xmt2_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7650);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7660);
bp = ql_read_regs(ha, fw->xmt3_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7670);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7680);
bp = ql_read_regs(ha, fw->xmt4_dma_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7690);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x76A0);
(void) ql_read_regs(ha, fw->xmt_data_dma_reg,
ha->iobase + 0xC0, sizeof (fw->xmt_data_dma_reg) / 4, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7700);
bp = ql_read_regs(ha, fw->rcvt0_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7710);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7720);
bp = ql_read_regs(ha, fw->rcvt1_data_dma_reg,
ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7730);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F00);
bp = ql_read_regs(ha, fw->risc_gp_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x0F70);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3000);
bp = ql_read_regs(ha, fw->lmc_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x3070);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4000);
bp = ql_read_regs(ha, fw->fpm_hdw_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4050);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4070);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4080);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x4090);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40A0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40B0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40C0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40D0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40E0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x40F0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C00);
bp = ql_read_regs(ha, fw->rq0_array_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C70);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C80);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5C90);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5CA0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5CB0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5CC0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5CD0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5CE0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5CF0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D00);
bp = ql_read_regs(ha, fw->rq1_array_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D70);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D80);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5D90);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5DA0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5DB0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5DC0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5DD0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5DE0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5DF0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E00);
bp = ql_read_regs(ha, fw->rp0_array_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E70);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E80);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5E90);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5EA0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5EB0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5EC0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5ED0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5EE0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5EF0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F00);
bp = ql_read_regs(ha, fw->rp1_array_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F10);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F20);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F30);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F40);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F50);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F60);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F70);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F80);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5F90);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5FA0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5FB0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5FC0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5FD0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5FE0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x5FF0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7080);
bp = ql_read_regs(ha, fw->ato_array_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7090);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x70A0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x70B0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x70C0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x70D0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x70E0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x70F0);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x7800);
(void) ql_read_regs(ha, fw->queue_control_reg, ha->iobase + 0xC0,
16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6000);
bp = ql_read_regs(ha, fw->fb_hdw_reg, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6010);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6020);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6030);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6040);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6060);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6070);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6100);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6130);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6150);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6170);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6190);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x61B0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x61C0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6530);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6540);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6550);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6560);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6570);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6580);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6590);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x65A0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x65B0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x65C0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x65D0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x65E0);
bp = ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
WRT32_IO_REG(ha, io_base_addr, 0x6F00);
(void) ql_read_regs(ha, bp, ha->iobase + 0xC0, 16, 32);
dp = fw->req_rsp_ext_mem;
for (index = 0; index < ha->rsp_queues_cnt; index++) {
if (index == 0) {
*dp = RD32_MBAR_REG(ha, ha->req_q[0]->mbar_req_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha, ha->req_q[0]->mbar_req_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else if (index == 1) {
*dp = RD32_MBAR_REG(ha, ha->req_q[1]->mbar_req_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha, ha->req_q[1]->mbar_req_out);
LITTLE_ENDIAN_32(dp);
dp++;
} else {
*dp++ = 0;
*dp++ = 0;
}
*dp = RD32_MBAR_REG(ha, ha->rsp_queues[index]->mbar_rsp_in);
LITTLE_ENDIAN_32(dp);
dp++;
*dp = RD32_MBAR_REG(ha, ha->rsp_queues[index]->mbar_rsp_out);
LITTLE_ENDIAN_32(dp);
dp++;
}
(void) ddi_dma_sync(ha->req_q[0]->req_ring.dma_handle, 0, 0,
DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)ha->req_q[0]->req_ring.bp;
for (cnt = 0; cnt < fw->req_q_size[0] / 4; cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
if (ha->req_q[1] != NULL) {
(void) ddi_dma_sync(ha->req_q[1]->req_ring.dma_handle, 0, 0,
DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)ha->req_q[1]->req_ring.bp;
for (cnt = 0; cnt < fw->req_q_size[1] / 4; cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
}
for (index = 0; index < ha->rsp_queues_cnt; index++) {
(void) ddi_dma_sync(ha->rsp_queues[index]->rsp_ring.dma_handle,
0, 0, DDI_DMA_SYNC_FORCPU);
w32ptr = (uint32_t *)ha->rsp_queues[index]->rsp_ring.bp;
for (cnt = 0; cnt < ha->rsp_queues[index]->rsp_ring.size / 4;
cnt++) {
*dp = *w32ptr++;
LITTLE_ENDIAN_32(dp);
dp++;
}
}
ql_reset_chip(ha);
rv = ql_read_risc_ram(ha, 0x20000, sizeof (fw->code_ram) / 4,
fw->code_ram);
if (rval == QL_SUCCESS) {
rval = rv;
}
rv = ql_read_risc_ram(ha, 0x100000,
ha->fw_ext_memory_size / 4, dp);
if (rval == QL_SUCCESS) {
rval = rv;
}
if (ha->fwexttracebuf.dma_handle != NULL) {
(void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0,
FWEXTSIZE, DDI_DMA_SYNC_FORCPU);
w32ptr = ha->fwexttracebuf.bp;
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
fw->ext_trace_buf[cnt] = *w32ptr++;
}
}
if (ha->fwfcetracebuf.dma_handle != NULL) {
(void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0,
FWFCESIZE, DDI_DMA_SYNC_FORCPU);
w32ptr = ha->fwfcetracebuf.bp;
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
fw->fce_trace_buf[cnt] = *w32ptr++;
}
}
if (rval != QL_SUCCESS) {
EL(ha, "failed, rval = %xh\n", rval);
} else {
QL_PRINT_10(ha, "done\n");
}
return (QL_SUCCESS);
}
static size_t
ql_83xx_ascii_fw_dump(ql_adapter_state_t *ha, caddr_t bufp)
{
uint32_t cnt, cnt1, len, *dp, *dp2;
caddr_t bp = bufp;
ql_83xx_fw_dump_t *fw = ha->ql_dump_ptr;
QL_PRINT_3(ha, "started\n");
if ((len = ha->risc_dump_size) == 0) {
QL_PRINT_10(ha, "no buffer\n");
return (0);
}
(void) snprintf(bp, len, "\nISP FW Version %d.%02d.%02d Attributes "
"%X\n", ha->fw_major_version, ha->fw_minor_version,
ha->fw_subminor_version, ha->fw_attributes);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
(void) snprintf(bp, len, "\nHCCR Register\n%08x\n", fw->hccr);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
(void) snprintf(bp, len, "\nR2H Status Register\n%08x\n",
fw->r2h_status);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
(void) snprintf(bp, len,
"\nAER Uncorrectable Error Status Register\n%08x\n", fw->aer_ues);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
(void) snprintf(bp, len, "\nHostRisc Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->hostrisc_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->hostrisc_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nPCIe Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->pcie_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->pcie_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
dp = fw->req_rsp_ext_mem;
for (cnt = 0; cnt < ha->rsp_queues_cnt; cnt++) {
(void) snprintf(bp, len, "\n\nQueue Pointers #%d:\n", cnt);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt1 = 0; cnt1 < 4; cnt1++) {
(void) snprintf(bp, len, "%08x ", *dp++);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
}
(void) snprintf(bp, len, "\n\nHost Interface Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->host_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->host_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nShadow Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->shadow_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->shadow_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRISC IO Register\n%08x", fw->risc_io);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
(void) snprintf(bp, len, "\n\nMailbox Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
if (cnt % 16 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%04x ", fw->mailbox_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXSEQ GP Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xseq_gp_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXSEQ-0 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xseq_0_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXSEQ-1 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xseq_1_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXSEQ-2 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xseq_2_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRSEQ GP Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->rseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rseq_gp_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRSEQ-0 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->rseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rseq_0_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRSEQ-1 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->rseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rseq_1_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRSEQ-2 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->rseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rseq_2_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRSEQ-3 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->rseq_3_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rseq_3_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nASEQ GP Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->aseq_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->aseq_gp_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nASEQ-0 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->aseq_0_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->aseq_0_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nASEQ-1 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->aseq_1_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->aseq_1_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nASEQ-2 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->aseq_2_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->aseq_2_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nASEQ-3 Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->aseq_3_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->aseq_3_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nCommand DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->cmd_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->cmd_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRequest0 Queue DMA Channel Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->req0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->req0_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nResponse0 Queue DMA Channel Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->resp0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->resp0_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRequest1 Queue DMA Channel Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->req1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->req1_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXMT0 Data DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xmt0_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xmt0_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXMT1 Data DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xmt1_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xmt1_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXMT2 Data DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xmt2_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xmt2_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXMT3 Data DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xmt3_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xmt3_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXMT4 Data DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xmt4_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xmt4_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nXMT Data DMA Common Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->xmt_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->xmt_data_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRCV Thread 0 Data DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->rcvt0_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rcvt0_data_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRCV Thread 1 Data DMA Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->rcvt1_data_dma_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rcvt1_data_dma_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRISC GP Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->risc_gp_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->risc_gp_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nLMC Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->lmc_reg) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->lmc_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nFPM Hardware Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->fpm_hdw_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->fpm_hdw_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRQ0 Array Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->rq0_array_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rq0_array_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRQ1 Array Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->rq1_array_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rq1_array_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRP0 Array Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->rp0_array_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rp0_array_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nRP1 Array Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->rp1_array_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->rp1_array_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nAT0 Array Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->ato_array_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->ato_array_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nQueue Control Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->queue_control_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->queue_control_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nFB Hardware Registers");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
cnt1 = (uint32_t)(sizeof (fw->fb_hdw_reg));
for (cnt = 0; cnt < cnt1 / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->fb_hdw_reg[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nCode RAM");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < sizeof (fw->code_ram) / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n%08x: ", cnt + 0x20000);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", fw->code_ram[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\nExternal Memory");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
dp = (uint32_t *)((caddr_t)fw->req_rsp_ext_mem + fw->req_q_size[0] +
fw->req_q_size[1] + fw->rsp_q_size + (ha->rsp_queues_cnt * 16));
for (cnt = 0; cnt < ha->fw_ext_memory_size / 4; cnt++) {
if (cnt % 8 == 0) {
(void) snprintf(bp, len, "\n%08x: ", cnt + 0x100000);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", *dp++);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "\n\n[<==END] ISP Debug Dump");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
dp = fw->req_rsp_ext_mem + (ha->rsp_queues_cnt * 4);
for (cnt = 0; cnt < 2 && fw->req_q_size[cnt]; cnt++) {
dp2 = dp;
for (cnt1 = 0; cnt1 < fw->req_q_size[cnt] / 4; cnt1++) {
if (*dp2++) {
break;
}
}
if (cnt1 == fw->req_q_size[cnt] / 4) {
dp = dp2;
continue;
}
(void) snprintf(bp, len, "\n\nRequest Queue\nQueue %d:", cnt);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt1 = 0; cnt1 < fw->req_q_size[cnt] / 4; cnt1++) {
if (cnt1 % 8 == 0) {
(void) snprintf(bp, len, "\n%08x: ", cnt1);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", *dp++);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
}
for (cnt = 0; cnt < ha->rsp_queues_cnt; cnt++) {
dp2 = dp;
for (cnt1 = 0; cnt1 < ha->rsp_queues[cnt]->rsp_ring.size / 4;
cnt1++) {
if (*dp2++) {
break;
}
}
if (cnt1 == ha->rsp_queues[cnt]->rsp_ring.size / 4) {
dp = dp2;
continue;
}
(void) snprintf(bp, len, "\n\nResponse Queue\nQueue %d:", cnt);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt1 = 0; cnt1 < ha->rsp_queues[cnt]->rsp_ring.size / 4;
cnt1++) {
if (cnt1 % 8 == 0) {
(void) snprintf(bp, len, "\n%08x: ", cnt1);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ", *dp++);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
}
if (ha->fwexttracebuf.dma_handle != NULL) {
uint32_t cnt_b;
uint64_t w64 = (uintptr_t)ha->fwexttracebuf.bp;
(void) snprintf(bp, len, "\n\nExtended Trace Buffer Memory");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < FWEXTSIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) snprintf(bp, len, "\n%08x: ",
(int)(w64 + cnt_b));
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ",
fw->ext_trace_buf[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
}
if (ha->fwfcetracebuf.dma_handle != NULL) {
uint32_t cnt_b;
uint64_t w64 = (uintptr_t)ha->fwfcetracebuf.bp;
(void) snprintf(bp, len, "\n\nFC Event Trace Buffer Memory");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
for (cnt = 0; cnt < FWFCESIZE / 4; cnt++) {
cnt_b = cnt * 4;
if (cnt_b % 32 == 0) {
(void) snprintf(bp, len, "\n%08x: ",
(int)(w64 + cnt_b));
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
(void) snprintf(bp, len, "%08x ",
fw->fce_trace_buf[cnt]);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
}
QL_PRINT_10(ha, "done=%xh\n", strlen(bufp));
return (strlen(bufp));
}
static caddr_t
ql_str_ptr(ql_adapter_state_t *ha, caddr_t bp, uint32_t *len)
{
uint32_t i;
i = strlen(bp);
if (i > *len || !(*len -= i)) {
QL_PRINT_10(ha, "full buffer\n");
return (NULL);
}
return (bp += i);
}
static int
ql_27xx_binary_fw_dump(ql_adapter_state_t *ha)
{
ql_dmp_template_t *template_buff;
int rval;
uint32_t cnt, *dp, *bp, tsize;
QL_PRINT_10(ha, "started\n");
if (ha->dmp_template.dma_handle == NULL) {
rval = CFG_IST(ha, CFG_LOAD_FLASH_FW) ?
ql_2700_get_flash_dmp_template(ha) :
ql_2700_get_module_dmp_template(ha);
if (rval != QL_SUCCESS) {
EL(ha, "no dump template, status=%xh\n", rval);
return (QL_FUNCTION_PARAMETER_ERROR);
}
}
template_buff = ha->dmp_template.bp;
tsize = template_buff->hdr.size_of_template;
if (ha->md_capture_size == 0) {
ha->ql_dump_ptr = kmem_zalloc(tsize, KM_NOSLEEP);
if (ha->ql_dump_ptr == NULL) {
QL_PRINT_10(ha, "done, failed alloc\n");
return (QL_MEMORY_ALLOC_FAILED);
}
cnt = (uint32_t)(tsize / sizeof (uint32_t));
dp = (uint32_t *)ha->ql_dump_ptr;
bp = (uint32_t *)&template_buff->hdr;
while (cnt--) {
*dp++ = ddi_get32(ha->dmp_template.acc_handle, bp++);
}
ha->md_capture_size = ql_2700_dmp_parse_template(ha,
(ql_dt_hdr_t *)ha->ql_dump_ptr, NULL, 0);
kmem_free(ha->ql_dump_ptr, tsize);
ha->ql_dump_ptr = NULL;
if (ha->md_capture_size == 0) {
return (QL_MEMORY_ALLOC_FAILED);
}
ha->risc_dump_size = ha->md_capture_size << 1;
ha->risc_dump_size += ha->md_capture_size;
ha->risc_dump_size += ha->md_capture_size / 16 + 1;
QL_PRINT_10(ha, "md_capture_size=%xh, "
"risc_dump_size=%xh\n", ha->md_capture_size,
ha->risc_dump_size);
}
ha->ql_dump_ptr = kmem_zalloc(ha->md_capture_size, KM_NOSLEEP);
if (ha->ql_dump_ptr == NULL) {
QL_PRINT_10(ha, "done, failed alloc\n");
return (QL_MEMORY_ALLOC_FAILED);
}
ha->ql_dump_size = ha->md_capture_size;
ql_disable_intr(ha);
cnt = (uint32_t)(tsize / sizeof (uint32_t));
dp = (uint32_t *)ha->ql_dump_ptr;
bp = (uint32_t *)&template_buff->hdr;
while (cnt--) {
*dp++ = ddi_get32(ha->dmp_template.acc_handle, bp++);
}
(void) ql_2700_dmp_parse_template(ha,
(ql_dt_hdr_t *)ha->ql_dump_ptr,
(uint8_t *)dp, ha->ql_dump_size);
#ifdef _BIG_ENDIAN
cnt = (uint32_t)(tsize / sizeof (uint32_t));
dp = (uint32_t *)ha->ql_dump_ptr;
while (cnt--) {
ql_chg_endian((uint8_t *)dp, 4);
dp++;
}
#endif
QL_PRINT_10(ha, "done\n");
return (QL_SUCCESS);
}
static size_t
ql_27xx_ascii_fw_dump(ql_adapter_state_t *ha, caddr_t bufp)
{
uint32_t cnt, len, dsize;
uint8_t *fw;
caddr_t bp;
QL_PRINT_10(ha, "started\n");
if ((len = ha->risc_dump_size) == 0) {
QL_PRINT_10(ha, "no buffer\n");
return (0);
}
dsize = ha->ql_dump_size;
fw = (uint8_t *)ha->ql_dump_ptr;
bp = bufp;
QL_PRINT_10(ha, "fw_dump_buffer=%ph, fw_bin_dump_size=%xh\n",
(void *)ha->ql_dump_ptr, ha->ql_dump_size);
cnt = 0;
while (cnt < dsize) {
(void) snprintf(bp, len, "%02x ", *fw++);
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
if (++cnt % 16 == 0) {
(void) snprintf(bp, len, "\n");
if ((bp = ql_str_ptr(ha, bp, &len)) == NULL) {
return (strlen(bufp));
}
}
}
if (cnt % 16 != 0) {
(void) snprintf(bp, len, "\n");
bp = ql_str_ptr(ha, bp, &len);
if (bp == NULL) {
return (strlen(bufp));
}
}
QL_PRINT_10(ha, "done=%xh\n", strlen(bufp));
return (strlen(bufp));
}
int
ql_2700_get_module_dmp_template(ql_adapter_state_t *ha)
{
int rval;
uint32_t word_count, cnt, *bp, *dp;
QL_PRINT_10(ha, "started\n");
if (ha->dmp_template.dma_handle != NULL) {
return (QL_SUCCESS);
}
if ((word_count = ha->risc_fw[2].length) == 0) {
EL(ha, "no dump template, length=0\n");
return (QL_FUNCTION_PARAMETER_ERROR);
}
ha->dmp_template.size = word_count << 2;
ha->dmp_template.type = LITTLE_ENDIAN_DMA;
ha->dmp_template.max_cookie_count = 1;
ha->dmp_template.alignment = 8;
rval = ql_alloc_phys(ha, &ha->dmp_template, KM_SLEEP);
if (rval != QL_SUCCESS) {
EL(ha, "unable to allocate template buffer, "
"status=%xh\n", rval);
return (rval);
}
bp = ha->dmp_template.bp;
dp = (uint32_t *)ha->risc_fw[2].code;
for (cnt = 0; cnt < word_count; cnt++) {
ddi_put32(ha->dmp_template.acc_handle, bp, *dp++);
if (cnt > 6) {
ql_chg_endian((uint8_t *)bp, 4);
}
bp++;
}
QL_PRINT_10(ha, "done\n");
return (rval);
}
int
ql_2700_get_flash_dmp_template(ql_adapter_state_t *ha)
{
int rval;
uint32_t word_count, cnt, *bp;
uint32_t faddr = ha->flash_data_addr | ha->flash_fw_addr;
uint32_t fdata = 0;
QL_PRINT_10(ha, "started, fw_addr=%xh\n", ha->flash_fw_addr);
if (ha->dmp_template.dma_handle != NULL) {
ql_free_phys(ha, &ha->dmp_template);
}
rval = ql_24xx_read_flash(ha, faddr + 3, &fdata);
QL_PRINT_7(ha, "read_flash, fw_addr=0x%x, data=0x%x\n",
faddr + 3, fdata);
if (rval != QL_SUCCESS) {
EL(ha, "2700_read_flash status=%xh\n", rval);
return (rval);
}
if (fdata == 0 || fdata == 0xffffffff) {
EL(ha, "Invalid first array length = %xh\n", fdata);
return (QL_FUNCTION_PARAMETER_ERROR);
}
ql_chg_endian((uint8_t *)&fdata, 4);
QL_PRINT_7(ha, "First array length = %xh\n", fdata);
faddr += fdata;
rval = ql_24xx_read_flash(ha, faddr + 3, &fdata);
QL_PRINT_7(ha, "read_flash, fw_addr=0x%x, data=0x%x\n",
faddr + 3, fdata);
if (rval != QL_SUCCESS) {
EL(ha, "2700_read_flash status=%xh\n", rval);
return (rval);
}
if (fdata == 0 || fdata == 0xffffffff) {
EL(ha, "Invalid second array length = %xh\n", fdata);
return (QL_FUNCTION_PARAMETER_ERROR);
}
ql_chg_endian((uint8_t *)&fdata, 4);
QL_PRINT_7(ha, "Second array length = %xh\n", fdata);
faddr += fdata;
rval = ql_24xx_read_flash(ha, faddr + 2, &fdata);
QL_PRINT_7(ha, "read_flash, fw_addr=0x%x, data=0x%x\n",
faddr + 2, fdata);
if (rval != QL_SUCCESS) {
EL(ha, "2700_read_flash status=%xh\n", rval);
return (rval);
}
if (fdata == 0 || fdata == 0xffffffff) {
EL(ha, "Invalid third array length = %xh\n", fdata);
return (QL_FUNCTION_PARAMETER_ERROR);
}
ql_chg_endian((uint8_t *)&fdata, 4);
QL_PRINT_7(ha, "Third array length = %xh\n", fdata);
word_count = fdata;
ha->dmp_template.size = word_count << 2;
ha->dmp_template.type = LITTLE_ENDIAN_DMA;
ha->dmp_template.max_cookie_count = 1;
ha->dmp_template.alignment = 8;
rval = ql_alloc_phys(ha, &ha->dmp_template, KM_SLEEP);
if (rval != QL_SUCCESS) {
EL(ha, "unable to allocate template buffer, "
"status=%xh\n", rval);
return (rval);
}
bp = ha->dmp_template.bp;
for (cnt = 0; cnt < word_count; cnt++) {
rval = ql_24xx_read_flash(ha, faddr++, &fdata);
if (rval != QL_SUCCESS) {
EL(ha, "2700_read_flash status=%xh\n", rval);
ql_free_phys(ha, &ha->dmp_template);
return (rval);
}
ddi_put32(ha->dmp_template.acc_handle, bp, fdata);
bp++;
}
QL_PRINT_10(ha, "done\n");
return (rval);
}
static uint32_t
ql_2700_dmp_parse_template(ql_adapter_state_t *ha, ql_dt_hdr_t *template_hdr,
uint8_t *dump_buff, uint32_t buff_size)
{
int e_cnt, esize, num_of_entries;
uint32_t bsize;
time_t time;
uint8_t *dbuff, *dbuff_end;
ql_dt_entry_t *entry;
int sane_end = 0;
dbuff = dump_buff;
dbuff_end = dump_buff + buff_size;
template_hdr->ver_attr[0] = ha->fw_major_version;
template_hdr->ver_attr[1] = ha->fw_minor_version;
template_hdr->ver_attr[2] = ha->fw_subminor_version;
template_hdr->ver_attr[3] = ha->fw_attributes;
template_hdr->ver_attr[4] = ha->fw_ext_attributes;
QL_PRINT_7(ha, "started, template_hdr=%ph, dump_buff=%ph, "
"buff_size=%xh, buff_end=%ph\n", (void *)template_hdr,
(void *)dbuff, buff_size, (void *)dbuff_end);
QL_PRINT_7(ha, "type=%d, first_entry_offset=%xh, "
"num_of_entries=%xh ver_attr=%xh,%xh,%xh,%xh,%xh\n",
template_hdr->type, template_hdr->first_entry_offset,
template_hdr->num_of_entries, template_hdr->ver_attr[0],
template_hdr->ver_attr[1], template_hdr->ver_attr[2],
template_hdr->ver_attr[3], template_hdr->ver_attr[4]);
if (template_hdr->type != DT_THDR) {
EL(ha, "Template header not found\n");
return (0);
}
if (dbuff != NULL) {
(void) drv_getparm(TIME, &time);
template_hdr->driver_timestamp = LSD(time);
}
num_of_entries = template_hdr->num_of_entries;
entry = (ql_dt_entry_t *)((caddr_t)template_hdr +
template_hdr->first_entry_offset);
bsize = template_hdr->size_of_template;
for (e_cnt = 0; e_cnt < num_of_entries; e_cnt++) {
QL_PRINT_7(ha, "e_cnt=%xh, entry=%ph, type=%d, size=%xh, "
"capture_flags=%xh, driver_flags=%xh, bofst=%xh\n",
e_cnt, (void *)entry, entry->h.type, entry->h.size,
entry->h.capture_flags, entry->h.driver_flags,
dbuff != NULL ? (uintptr_t)dbuff - (uintptr_t)template_hdr :
bsize);
esize = 0;
switch (entry->h.type) {
case DT_NOP:
if (dbuff != NULL) {
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
QL_PRINT_3(ha, "Skipping Entry ID=%d, type=%d\n",
e_cnt, entry->h.type);
break;
case DT_TEND:
if (dbuff != NULL) {
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
QL_PRINT_3(ha, "Skipping Entry ID=%d, type=%d\n",
e_cnt, entry->h.type);
sane_end++;
break;
case DT_RIOB1:
esize = ql_2700_dt_riob1(ha, (ql_dt_riob1_t *)entry,
dbuff, dbuff_end);
break;
case DT_WIOB1:
ql_2700_dt_wiob1(ha, (ql_dt_wiob1_t *)entry,
dbuff, dbuff_end);
break;
case DT_RIOB2:
esize = ql_2700_dt_riob2(ha, (ql_dt_riob2_t *)entry,
dbuff, dbuff_end);
break;
case DT_WIOB2:
ql_2700_dt_wiob2(ha, (ql_dt_wiob2_t *)entry,
dbuff, dbuff_end);
break;
case DT_RPCI:
esize = ql_2700_dt_rpci(ha, (ql_dt_rpci_t *)entry,
dbuff, dbuff_end);
break;
case DT_WPCI:
ql_2700_dt_wpci(ha, (ql_dt_wpci_t *)entry,
dbuff, dbuff_end);
break;
case DT_RRAM:
esize = ql_2700_dt_rram(ha, (ql_dt_rram_t *)entry,
dbuff, dbuff_end);
break;
case DT_GQUE:
esize = ql_2700_dt_gque(ha, (ql_dt_gque_t *)entry,
dbuff, dbuff_end);
break;
case DT_GFCE:
esize = ql_2700_dt_gfce(ha, (ql_dt_gfce_t *)entry,
dbuff, dbuff_end);
break;
case DT_PRISC:
ql_2700_dt_prisc(ha, (ql_dt_prisc_t *)entry,
dbuff, dbuff_end);
break;
case DT_RRISC:
ql_2700_dt_rrisc(ha, (ql_dt_rrisc_t *)entry,
dbuff, dbuff_end);
break;
case DT_DINT:
ql_2700_dt_dint(ha, (ql_dt_dint_t *)entry,
dbuff, dbuff_end);
break;
case DT_GHBD:
esize = ql_2700_dt_ghbd(ha, (ql_dt_ghbd_t *)entry,
dbuff, dbuff_end);
break;
case DT_SCRA:
esize = ql_2700_dt_scra(ha, (ql_dt_scra_t *)entry,
dbuff, dbuff_end);
break;
case DT_RRREG:
esize = ql_2700_dt_rrreg(ha, (ql_dt_rrreg_t *)entry,
dbuff, dbuff_end);
break;
case DT_WRREG:
ql_2700_dt_wrreg(ha, (ql_dt_wrreg_t *)entry,
dbuff, dbuff_end);
break;
case DT_RRRAM:
esize = ql_2700_dt_rrram(ha, (ql_dt_rrram_t *)entry,
dbuff, dbuff_end);
break;
case DT_RPCIC:
esize = ql_2700_dt_rpcic(ha, (ql_dt_rpcic_t *)entry,
dbuff, dbuff_end);
break;
case DT_GQUES:
esize = ql_2700_dt_gques(ha, (ql_dt_gques_t *)entry,
dbuff, dbuff_end);
break;
case DT_WDMP:
esize = ql_2700_dt_wdmp(ha, (ql_dt_wdmp_t *)entry,
dbuff, dbuff_end);
break;
default:
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
EL(ha, "Entry ID=%d, type=%d unknown\n", e_cnt,
entry->h.type);
break;
}
if (dbuff != NULL && esize) {
QL_PRINT_7(ha, "entry=%d, esize=%xh, capture data\n",
entry->h.type, esize);
QL_DUMP_3(dbuff, 8, esize);
dbuff += esize;
}
bsize += esize;
entry = (ql_dt_entry_t *)((caddr_t)entry + entry->h.size);
}
if (sane_end > 1) {
EL(ha, "Template configuration error. Check Template\n");
}
QL_PRINT_7(ha, "done, num of entries=%xh, size=%xh\n",
template_hdr->num_of_entries, bsize);
return (bsize);
}
static int
ql_2700_dt_riob1(ql_adapter_state_t *ha, ql_dt_riob1_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize;
uint32_t i, cnt;
uint8_t *bp = dbuff;
uint32_t addr = entry->addr;
uint8_t *reg = (uint8_t *)ha->iobase + entry->pci_offset;
QL_PRINT_7(ha, "started, buf=%ph, addr=%xh, reg_size=%xh, "
"reg_count=%x%02xh, pci_offset=%xh\n", (void *)dbuff, entry->addr,
entry->reg_size, entry->reg_count_h, entry->reg_count_l,
entry->pci_offset);
cnt = CHAR_TO_SHORT(entry->reg_count_l, entry->reg_count_h);
esize = cnt * 4;
esize += cnt * entry->reg_size;
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
WRT32_IO_REG(ha, io_base_addr, addr);
while (cnt--) {
*bp++ = LSB(LSW(addr));
*bp++ = MSB(LSW(addr));
*bp++ = LSB(MSW(addr));
*bp++ = MSB(MSW(addr));
for (i = 0; i < entry->reg_size; i++) {
*bp++ = RD_REG_BYTE(ha, reg++);
}
addr++;
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static void
ql_2700_dt_wiob1(ql_adapter_state_t *ha, ql_dt_wiob1_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
uint8_t *reg = (uint8_t *)ha->iobase + entry->pci_offset;
QL_PRINT_7(ha, "started, addr=%xh, data=%xh, pci_offset=%xh\n",
entry->addr, entry->data, entry->pci_offset);
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done\n");
return;
}
if (dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=0\n");
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return;
}
WRT32_IO_REG(ha, io_base_addr, entry->addr);
WRT_REG_DWORD(ha, reg, entry->data);
QL_PRINT_7(ha, "done\n");
}
static int
ql_2700_dt_riob2(ql_adapter_state_t *ha, ql_dt_riob2_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize;
uint32_t i, cnt;
uint8_t *bp = dbuff;
uint8_t *reg = (uint8_t *)ha->iobase + entry->pci_offset;
uint32_t addr = entry->addr;
QL_PRINT_7(ha, "started, buf=%ph, addr=%xh, reg_size=%xh, "
"reg_count=%x%02xh, pci_offset=%xh, bank_sel_offset=%xh, "
"reg_bank=%xh\n", (void *)dbuff, entry->addr,
entry->reg_size, entry->reg_count_h, entry->reg_count_l,
entry->pci_offset, entry->bank_sel_offset, entry->reg_bank);
cnt = CHAR_TO_SHORT(entry->reg_count_l, entry->reg_count_h);
esize = cnt * 4;
esize += cnt * entry->reg_size;
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
WRT32_IO_REG(ha, io_base_addr, addr);
WRT_REG_DWORD(ha, ha->iobase + entry->bank_sel_offset, entry->reg_bank);
while (cnt--) {
*bp++ = LSB(LSW(addr));
*bp++ = MSB(LSW(addr));
*bp++ = LSB(MSW(addr));
*bp++ = MSB(MSW(addr));
for (i = 0; i < entry->reg_size; i++) {
*bp++ = RD_REG_BYTE(ha, reg++);
}
addr++;
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static void
ql_2700_dt_wiob2(ql_adapter_state_t *ha, ql_dt_wiob2_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
uint16_t data;
uint8_t *reg = (uint8_t *)ha->iobase + entry->pci_offset;
QL_PRINT_7(ha, "started, addr=%xh, data=%x%02xh, pci_offset=%xhh, "
"bank_sel_offset=%xh, reg_bank=%xh\n", entry->addr, entry->data_h,
entry->data_l, entry->pci_offset, entry->bank_sel_offset,
entry->reg_bank);
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done\n");
return;
}
if (dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=0\n");
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return;
}
data = CHAR_TO_SHORT(entry->data_l, entry->data_h);
WRT32_IO_REG(ha, io_base_addr, entry->addr);
WRT_REG_DWORD(ha, ha->iobase + entry->bank_sel_offset, entry->reg_bank);
WRT_REG_WORD(ha, reg, data);
QL_PRINT_7(ha, "done\n");
}
static int
ql_2700_dt_rpci(ql_adapter_state_t *ha, ql_dt_rpci_t *entry, uint8_t *dbuff,
uint8_t *dbuff_end)
{
int esize;
uint32_t i;
uint8_t *bp = dbuff;
uint8_t *reg = (uint8_t *)ha->iobase + entry->addr;
QL_PRINT_7(ha, "started, addr=%xh, reg=%ph\n", entry->addr,
(void *)reg);
esize = 4;
esize += 4;
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
*bp++ = LSB(LSW(entry->addr));
*bp++ = MSB(LSW(entry->addr));
*bp++ = LSB(MSW(entry->addr));
*bp++ = MSB(MSW(entry->addr));
for (i = 0; i < 4; i++) {
*bp++ = RD_REG_BYTE(ha, reg++);
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static void
ql_2700_dt_wpci(ql_adapter_state_t *ha, ql_dt_wpci_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
uint8_t *reg = (uint8_t *)ha->iobase + entry->addr;
QL_PRINT_7(ha, "started, addr=%xh, data=%xh, reg=%ph\n",
entry->addr, entry->data, (void *)reg);
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done\n");
return;
}
if (dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=0\n");
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return;
}
WRT_REG_DWORD(ha, reg, entry->data);
QL_PRINT_7(ha, "done\n");
}
static int
ql_2700_dt_rram(ql_adapter_state_t *ha, ql_dt_rram_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize, rval;
uint32_t start = entry->start_addr;
uint32_t end = entry->end_addr;
QL_PRINT_7(ha, "started, buf=%ph, ram_area=%xh, start_addr=%xh, "
"end_addr=%xh\n", (void *)dbuff, entry->ram_area,
entry->start_addr, entry->end_addr);
if (entry->ram_area == 2) {
end = ha->fw_ext_memory_end;
} else if (entry->ram_area == 3) {
start = ha->fw_shared_ram_start;
end = ha->fw_shared_ram_end;
} else if (entry->ram_area == 4) {
start = ha->fw_ddr_ram_start;
end = ha->fw_ddr_ram_end;
} else if (entry->ram_area != 1) {
EL(ha, "skipped, unknown RAM_AREA %d\n", entry->ram_area);
start = 0;
end = 0;
}
esize = end > start ? end - start : 0;
if (esize) {
esize = (esize + 1) * 4;
}
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize == 0 || esize + dbuff >= dbuff_end) {
if (esize != 0) {
EL(ha, "skipped, no buffer space, needed=%xh\n",
esize);
} else {
QL_PRINT_7(ha, "skipped, no ram_area=%xh, start=%xh, "
"end=%xh\n", entry->ram_area, start, end);
}
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
entry->end_addr = end;
entry->start_addr = start;
if ((rval = ql_2700_dump_ram(ha, MBC_DUMP_RAM_EXTENDED,
start, esize / 4, dbuff)) != QL_SUCCESS) {
EL(ha, "dump_ram failed, rval=%xh, addr=%xh, len=%xh, "
"esize=0\n", rval, start, esize / 4);
return (0);
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static int
ql_2700_dt_gque(ql_adapter_state_t *ha, ql_dt_gque_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize;
uint32_t cnt, q_cnt, e_cnt, i;
uint8_t *bp = dbuff, *dp;
QL_PRINT_7(ha, "started, buf=%ph, num_queues=%xh, queue_type=%xh\n",
(void *)dbuff, entry->num_queues, entry->queue_type);
if (entry->queue_type == 1) {
ql_request_q_t *req_q;
e_cnt = ha->rsp_queues_cnt > 1 ? 2 : 1;
esize = e_cnt * 2;
esize += e_cnt * 2;
esize += ha->req_q[0]->req_entry_cnt * REQUEST_ENTRY_SIZE;
if (e_cnt > 1) {
esize += ha->req_q[1]->req_entry_cnt *
REQUEST_ENTRY_SIZE;
}
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
entry->num_queues = e_cnt;
for (q_cnt = 0; q_cnt < entry->num_queues; q_cnt++) {
req_q = q_cnt == 0 ? ha->req_q[0] : ha->req_q[1];
e_cnt = req_q->req_entry_cnt;
dp = req_q->req_ring.bp;
*bp++ = LSB(q_cnt);
*bp++ = MSB(q_cnt);
*bp++ = LSB(e_cnt);
*bp++ = MSB(e_cnt);
for (cnt = 0; cnt < e_cnt; cnt++) {
for (i = 0; i < REQUEST_ENTRY_SIZE; i++) {
*bp++ = *dp++;
}
}
}
} else if (entry->queue_type == 2) {
ql_response_q_t *rsp_q;
e_cnt = ha->rsp_queues_cnt;
esize = e_cnt * 2;
esize += e_cnt * 2;
for (q_cnt = 0; q_cnt < ha->rsp_queues_cnt; q_cnt++) {
rsp_q = ha->rsp_queues[q_cnt];
esize += rsp_q->rsp_entry_cnt * RESPONSE_ENTRY_SIZE;
}
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped2, no buffer space, needed=%xh\n",
esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
entry->num_queues = e_cnt;
for (q_cnt = 0; q_cnt < entry->num_queues; q_cnt++) {
rsp_q = ha->rsp_queues[q_cnt];
e_cnt = rsp_q->rsp_entry_cnt;
dp = rsp_q->rsp_ring.bp;
*bp++ = LSB(q_cnt);
*bp++ = MSB(q_cnt);
*bp++ = LSB(e_cnt);
*bp++ = MSB(e_cnt);
for (cnt = 0; cnt < e_cnt; cnt++) {
for (i = 0; i < RESPONSE_ENTRY_SIZE; i++) {
*bp++ = *dp++;
}
}
}
} else if (entry->queue_type == 3) {
QL_PRINT_7(ha, "skipped, no ATIO queue, esize=0\n");
if (dbuff != NULL) {
entry->num_queues = 0;
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
return (0);
} else {
EL(ha, "skipped, unknown queue_type %d, esize=0\n",
entry->queue_type);
if (dbuff != NULL) {
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
return (0);
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static int
ql_2700_dt_gfce(ql_adapter_state_t *ha, ql_dt_gfce_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
QL_PRINT_7(ha, "started\n");
QL_PRINT_7(ha, "skipped, not supported, esize=0\n");
if (dbuff != NULL) {
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
return (0);
}
static void
ql_2700_dt_prisc(ql_adapter_state_t *ha, ql_dt_prisc_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
clock_t timer;
QL_PRINT_7(ha, "started\n");
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done\n");
return;
}
if (dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=0\n");
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return;
}
if ((RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0) {
WRT32_IO_REG(ha, hccr, HC24_PAUSE_RISC);
for (timer = 30000;
(RD32_IO_REG(ha, risc2host) & RH_RISC_PAUSED) == 0;
timer--) {
if (timer) {
drv_usecwait(100);
if (timer % 10000 == 0) {
EL(ha, "risc pause %d\n", timer);
}
} else {
EL(ha, "risc pause timeout\n");
break;
}
}
}
QL_PRINT_7(ha, "done\n");
}
static void
ql_2700_dt_rrisc(ql_adapter_state_t *ha, ql_dt_rrisc_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
clock_t timer;
QL_PRINT_7(ha, "started\n");
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done\n");
return;
}
if (dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=0\n");
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return;
}
WRT32_IO_REG(ha, ctrl_status, DMA_SHUTDOWN);
for (timer = 0; timer < 30000; timer++) {
if (!(RD32_IO_REG(ha, ctrl_status) & DMA_ACTIVE)) {
break;
}
drv_usecwait(100);
}
WRT32_IO_REG(ha, ctrl_status, ISP_RESET);
drv_usecwait(200);
for (timer = 30000; timer; timer--) {
ha->rom_status = RD16_IO_REG(ha, mailbox_out[0]);
if ((ha->rom_status & MBS_ROM_STATUS_MASK) != MBS_ROM_BUSY) {
break;
}
drv_usecwait(100);
}
for (timer = 30000; timer; timer--) {
if (!(RD32_IO_REG(ha, ctrl_status) & ISP_RESET)) {
break;
}
drv_usecwait(100);
}
ADAPTER_STATE_LOCK(ha);
ha->flags &= ~FIRMWARE_UP;
ADAPTER_STATE_UNLOCK(ha);
QL_PRINT_7(ha, "done\n");
}
static void
ql_2700_dt_dint(ql_adapter_state_t *ha, ql_dt_dint_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
QL_PRINT_7(ha, "started, pci_offset=%xh, data=%xh\n",
entry->pci_offset, entry->data);
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done\n");
return;
}
if (dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=0\n");
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return;
}
ql_pci_config_put32(ha, entry->pci_offset, entry->data);
QL_PRINT_7(ha, "done\n");
}
static int
ql_2700_dt_ghbd(ql_adapter_state_t *ha, ql_dt_ghbd_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
QL_PRINT_7(ha, "started\n");
QL_PRINT_7(ha, "skipped, not supported\n");
if (dbuff != NULL) {
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
return (0);
}
static int
ql_2700_dt_scra(ql_adapter_state_t *ha, ql_dt_scra_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
QL_PRINT_7(ha, "started\n");
QL_PRINT_7(ha, "skipped, not supported, esize=0\n");
if (dbuff != NULL) {
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
return (0);
}
static int
ql_2700_dt_rrreg(ql_adapter_state_t *ha, ql_dt_rrreg_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize;
uint32_t i;
uint8_t *bp = dbuff;
uint8_t *reg = (uint8_t *)ha->iobase + 0xc4;
uint32_t addr = entry->addr;
uint32_t cnt = entry->count;
QL_PRINT_7(ha, "started, buf=%ph, addr=%xh, count=%xh\n",
(void *)dbuff, entry->addr, entry->count);
esize = cnt * 4;
esize += cnt * 4;
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
WRT32_IO_REG(ha, io_base_addr, 0x40);
while (cnt--) {
WRT_REG_DWORD(ha, ha->iobase + 0xc0, addr | 0x80000000);
*bp++ = LSB(LSW(addr));
*bp++ = MSB(LSW(addr));
*bp++ = LSB(MSW(addr));
*bp++ = MSB(MSW(addr));
for (i = 0; i < 4; i++) {
*bp++ = RD_REG_BYTE(ha, reg + i);
}
addr += 4;
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static void
ql_2700_dt_wrreg(ql_adapter_state_t *ha, ql_dt_wrreg_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
QL_PRINT_7(ha, "started, addr=%xh, data=%xh\n", entry->addr,
entry->data);
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done\n");
return;
}
if (dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=0\n");
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return;
}
WRT32_IO_REG(ha, io_base_addr, 0x40);
WRT_REG_DWORD(ha, ha->iobase + 0xc4, entry->data);
WRT_REG_DWORD(ha, ha->iobase + 0xc0, entry->addr);
QL_PRINT_7(ha, "done\n");
}
static int
ql_2700_dt_rrram(ql_adapter_state_t *ha, ql_dt_rrram_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int rval, esize;
QL_PRINT_7(ha, "started, buf=%ph, addr=%xh, count=%xh\n",
(void *)dbuff, entry->addr, entry->count);
esize = entry->count * 4;
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
if ((rval = ql_2700_dump_ram(ha, MBC_MPI_RAM, entry->addr,
entry->count, dbuff)) != QL_SUCCESS) {
EL(ha, "dump_ram failed, rval=%xh, addr=%xh, len=%xh, "
"esize=0\n", rval, entry->addr, entry->count);
return (0);
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static int
ql_2700_dt_rpcic(ql_adapter_state_t *ha, ql_dt_rpcic_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize;
uint32_t i;
uint8_t *bp = dbuff;
uint32_t addr = entry->addr;
uint32_t cnt = entry->count;
QL_PRINT_7(ha, "started, buf=%ph, addr=%xh, count=%xh\n",
(void *)dbuff, entry->addr, entry->count);
esize = cnt * 4;
esize += cnt * 4;
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
while (cnt--) {
*bp++ = LSB(LSW(addr));
*bp++ = MSB(LSW(addr));
*bp++ = LSB(MSW(addr));
*bp++ = MSB(MSW(addr));
for (i = 0; i < 4; i++) {
*bp++ = ql_pci_config_get8(ha, addr++);
}
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static int
ql_2700_dt_gques(ql_adapter_state_t *ha, ql_dt_gques_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize;
uint32_t q_cnt, e_cnt, data;
uint8_t *bp = dbuff;
QL_PRINT_7(ha, "started, buf=%ph, num_queues=%xh, queue_type=%xh\n",
(void *)dbuff, entry->num_queues, entry->queue_type);
if (entry->queue_type == 1) {
ql_request_q_t *req_q;
e_cnt = ha->rsp_queues_cnt > 1 ? 2 : 1;
esize = e_cnt * 2;
esize += e_cnt * 2;
esize += SHADOW_ENTRY_SIZE;
if (e_cnt > 1) {
esize += SHADOW_ENTRY_SIZE;
}
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
entry->num_queues = e_cnt;
for (q_cnt = 0; q_cnt < entry->num_queues; q_cnt++) {
req_q = q_cnt == 0 ? ha->req_q[0] : ha->req_q[1];
e_cnt = 1;
data = ddi_get32(req_q->req_ring.acc_handle,
req_q->req_out_shadow_ptr);
*bp++ = LSB(q_cnt);
*bp++ = MSB(q_cnt);
*bp++ = LSB(e_cnt);
*bp++ = MSB(e_cnt);
*bp++ = LSB(LSW(data));
*bp++ = MSB(LSW(data));
*bp++ = LSB(MSW(data));
*bp++ = MSB(MSW(data));
}
} else if (entry->queue_type == 2) {
ql_response_q_t *rsp_q;
e_cnt = ha->rsp_queues_cnt;
esize = e_cnt * 2;
esize += e_cnt * 2;
for (q_cnt = 0; q_cnt < ha->rsp_queues_cnt; q_cnt++) {
esize += SHADOW_ENTRY_SIZE;
}
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped2, no buffer space, needed=%xh\n",
esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
entry->num_queues = e_cnt;
for (q_cnt = 0; q_cnt < entry->num_queues; q_cnt++) {
rsp_q = ha->rsp_queues[q_cnt];
e_cnt = 1;
data = ddi_get32(rsp_q->rsp_ring.acc_handle,
rsp_q->rsp_in_shadow_ptr);
*bp++ = LSB(q_cnt);
*bp++ = MSB(q_cnt);
*bp++ = LSB(e_cnt);
*bp++ = MSB(e_cnt);
*bp++ = LSB(LSW(data));
*bp++ = MSB(LSW(data));
*bp++ = LSB(MSW(data));
*bp++ = MSB(MSW(data));
}
} else if (entry->queue_type == 3) {
EL(ha, "skipped, no ATIO queue, esize=0\n");
if (dbuff != NULL) {
entry->num_queues = 0;
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
return (0);
} else {
EL(ha, "skipped, unknown queue_type %d, esize=0\n",
entry->queue_type);
if (dbuff != NULL) {
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
}
return (0);
}
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static int
ql_2700_dt_wdmp(ql_adapter_state_t *ha, ql_dt_wdmp_t *entry,
uint8_t *dbuff, uint8_t *dbuff_end)
{
int esize;
uint8_t *bp = dbuff;
uint32_t data, cnt = entry->length, *dp = entry->data;
QL_PRINT_7(ha, "started, buf=%ph, length=%xh\n",
(void *)dbuff, entry->length);
esize = cnt;
if (dbuff == NULL) {
QL_PRINT_7(ha, "null buf done, esize=%xh\n", esize);
return (esize);
}
if (esize + dbuff >= dbuff_end) {
EL(ha, "skipped, no buffer space, needed=%xh\n", esize);
entry->h.driver_flags = (uint8_t)
(entry->h.driver_flags | SKIPPED_FLAG);
return (0);
}
while (cnt--) {
data = *dp++;
*bp++ = LSB(LSW(data));
*bp++ = MSB(LSW(data));
*bp++ = LSB(MSW(data));
*bp++ = MSB(MSW(data));
}
QL_PRINT_7(ha, "%s\n", dbuff);
QL_PRINT_7(ha, "done, esize=%xh\n", esize);
return (esize);
}
static int
ql_2700_dump_ram(ql_adapter_state_t *ha, uint16_t cmd, uint32_t risc_address,
uint32_t len, uint8_t *bp)
{
dma_mem_t mem;
uint32_t i, stat, timer;
uint8_t *dp;
int rval = QL_SUCCESS;
QL_PRINT_7(ha, "started, cmd=%xh, risc_address=%xh, len=%xh, "
"bp=%ph\n", cmd, risc_address, len, (void *)bp);
mem.size = len * 4;
mem.type = LITTLE_ENDIAN_DMA;
mem.max_cookie_count = 1;
mem.alignment = 8;
if ((rval = ql_alloc_phys(ha, &mem, KM_SLEEP)) != QL_SUCCESS) {
EL(ha, "alloc status=%xh\n", rval);
return (rval);
}
WRT16_IO_REG(ha, mailbox_in[0], cmd);
WRT16_IO_REG(ha, mailbox_in[1], LSW(risc_address));
WRT16_IO_REG(ha, mailbox_in[2], MSW(LSD(mem.cookie.dmac_laddress)));
WRT16_IO_REG(ha, mailbox_in[3], LSW(LSD(mem.cookie.dmac_laddress)));
WRT16_IO_REG(ha, mailbox_in[4], MSW(len));
WRT16_IO_REG(ha, mailbox_in[5], LSW(len));
WRT16_IO_REG(ha, mailbox_in[6], MSW(MSD(mem.cookie.dmac_laddress)));
WRT16_IO_REG(ha, mailbox_in[7], LSW(MSD(mem.cookie.dmac_laddress)));
WRT16_IO_REG(ha, mailbox_in[8], MSW(risc_address));
if (cmd == MBC_MPI_RAM) {
WRT16_IO_REG(ha, mailbox_in[9], BIT_0);
}
WRT32_IO_REG(ha, hccr, HC24_SET_HOST_INT);
for (timer = 6000000; timer && rval == QL_SUCCESS; timer--) {
stat = RD32_IO_REG(ha, risc2host);
if (stat & RH_RISC_INT) {
stat &= 0xff;
if ((stat == 1) || (stat == 0x10)) {
break;
} else if ((stat == 2) || (stat == 0x11)) {
rval = RD16_IO_REG(ha, mailbox_out[0]);
break;
}
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
}
drv_usecwait(5);
}
WRT32_IO_REG(ha, hccr, HC24_CLR_RISC_INT);
if (timer == 0) {
QL_PRINT_7(ha, "timeout addr=%xh\n", risc_address);
rval = QL_FUNCTION_TIMEOUT;
} else {
(void) ddi_dma_sync(mem.dma_handle, 0, 0, DDI_DMA_SYNC_FORCPU);
dp = mem.bp;
for (i = 0; i < mem.size; i++) {
*bp++ = *dp++;
}
}
ql_free_phys(ha, &mem);
QL_PRINT_7(ha, "done\n");
return (rval);
}