162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2008-2009 USI Co., Ltd.
562306a36Sopenharmony_ci * All rights reserved.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
862306a36Sopenharmony_ci * modification, are permitted provided that the following conditions
962306a36Sopenharmony_ci * are met:
1062306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
1162306a36Sopenharmony_ci *    notice, this list of conditions, and the following disclaimer,
1262306a36Sopenharmony_ci *    without modification.
1362306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1462306a36Sopenharmony_ci *    substantially similar to the "NO WARRANTY" disclaimer below
1562306a36Sopenharmony_ci *    ("Disclaimer") and any redistribution must be conditioned upon
1662306a36Sopenharmony_ci *    including a substantially similar Disclaimer requirement for further
1762306a36Sopenharmony_ci *    binary redistribution.
1862306a36Sopenharmony_ci * 3. Neither the names of the above-listed copyright holders nor the names
1962306a36Sopenharmony_ci *    of any contributors may be used to endorse or promote products derived
2062306a36Sopenharmony_ci *    from this software without specific prior written permission.
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * Alternatively, this software may be distributed under the terms of the
2362306a36Sopenharmony_ci * GNU General Public License ("GPL") version 2 as published by the Free
2462306a36Sopenharmony_ci * Software Foundation.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * NO WARRANTY
2762306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2862306a36Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2962306a36Sopenharmony_ci * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
3062306a36Sopenharmony_ci * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3162306a36Sopenharmony_ci * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3262306a36Sopenharmony_ci * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3362306a36Sopenharmony_ci * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3462306a36Sopenharmony_ci * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
3562306a36Sopenharmony_ci * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
3662306a36Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3762306a36Sopenharmony_ci * POSSIBILITY OF SUCH DAMAGES.
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci #include <linux/slab.h>
4162306a36Sopenharmony_ci #include "pm8001_sas.h"
4262306a36Sopenharmony_ci #include "pm8001_hwi.h"
4362306a36Sopenharmony_ci #include "pm8001_chips.h"
4462306a36Sopenharmony_ci #include "pm8001_ctl.h"
4562306a36Sopenharmony_ci #include "pm80xx_tracepoints.h"
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci * read_main_config_table - read the configure table and save it.
4962306a36Sopenharmony_ci * @pm8001_ha: our hba card information
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_cistatic void read_main_config_table(struct pm8001_hba_info *pm8001_ha)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
5462306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.signature	=
5562306a36Sopenharmony_ci				pm8001_mr32(address, 0x00);
5662306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev =
5762306a36Sopenharmony_ci				pm8001_mr32(address, 0x04);
5862306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev	=
5962306a36Sopenharmony_ci				pm8001_mr32(address, 0x08);
6062306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io	=
6162306a36Sopenharmony_ci				pm8001_mr32(address, 0x0C);
6262306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl	=
6362306a36Sopenharmony_ci				pm8001_mr32(address, 0x10);
6462306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag =
6562306a36Sopenharmony_ci				pm8001_mr32(address, 0x14);
6662306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.gst_offset	=
6762306a36Sopenharmony_ci				pm8001_mr32(address, 0x18);
6862306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.inbound_queue_offset =
6962306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_IBQ_OFFSET);
7062306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_queue_offset =
7162306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_OBQ_OFFSET);
7262306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.hda_mode_flag	=
7362306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_HDA_FLAGS_OFFSET);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* read analog Setting offset from the configuration table */
7662306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.anolog_setup_table_offset =
7762306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_ANALOG_SETUP_OFFSET);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	/* read Error Dump Offset and Length */
8062306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_offset0 =
8162306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_OFFSET);
8262306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_length0 =
8362306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_LENGTH);
8462306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_offset1 =
8562306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_OFFSET);
8662306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_length1 =
8762306a36Sopenharmony_ci		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_LENGTH);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/**
9162306a36Sopenharmony_ci * read_general_status_table - read the general status table and save it.
9262306a36Sopenharmony_ci * @pm8001_ha: our hba card information
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cistatic void read_general_status_table(struct pm8001_hba_info *pm8001_ha)
9562306a36Sopenharmony_ci{
9662306a36Sopenharmony_ci	void __iomem *address = pm8001_ha->general_stat_tbl_addr;
9762306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.gst_len_mpistate	=
9862306a36Sopenharmony_ci				pm8001_mr32(address, 0x00);
9962306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.iq_freeze_state0	=
10062306a36Sopenharmony_ci				pm8001_mr32(address, 0x04);
10162306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.iq_freeze_state1	=
10262306a36Sopenharmony_ci				pm8001_mr32(address, 0x08);
10362306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.msgu_tcnt		=
10462306a36Sopenharmony_ci				pm8001_mr32(address, 0x0C);
10562306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.iop_tcnt		=
10662306a36Sopenharmony_ci				pm8001_mr32(address, 0x10);
10762306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.rsvd		=
10862306a36Sopenharmony_ci				pm8001_mr32(address, 0x14);
10962306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[0]	=
11062306a36Sopenharmony_ci				pm8001_mr32(address, 0x18);
11162306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[1]	=
11262306a36Sopenharmony_ci				pm8001_mr32(address, 0x1C);
11362306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[2]	=
11462306a36Sopenharmony_ci				pm8001_mr32(address, 0x20);
11562306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[3]	=
11662306a36Sopenharmony_ci				pm8001_mr32(address, 0x24);
11762306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[4]	=
11862306a36Sopenharmony_ci				pm8001_mr32(address, 0x28);
11962306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[5]	=
12062306a36Sopenharmony_ci				pm8001_mr32(address, 0x2C);
12162306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[6]	=
12262306a36Sopenharmony_ci				pm8001_mr32(address, 0x30);
12362306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[7]	=
12462306a36Sopenharmony_ci				pm8001_mr32(address, 0x34);
12562306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.gpio_input_val	=
12662306a36Sopenharmony_ci				pm8001_mr32(address, 0x38);
12762306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.rsvd1[0]		=
12862306a36Sopenharmony_ci				pm8001_mr32(address, 0x3C);
12962306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.rsvd1[1]		=
13062306a36Sopenharmony_ci				pm8001_mr32(address, 0x40);
13162306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[0]	=
13262306a36Sopenharmony_ci				pm8001_mr32(address, 0x44);
13362306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[1]	=
13462306a36Sopenharmony_ci				pm8001_mr32(address, 0x48);
13562306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[2]	=
13662306a36Sopenharmony_ci				pm8001_mr32(address, 0x4C);
13762306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[3]	=
13862306a36Sopenharmony_ci				pm8001_mr32(address, 0x50);
13962306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[4]	=
14062306a36Sopenharmony_ci				pm8001_mr32(address, 0x54);
14162306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[5]	=
14262306a36Sopenharmony_ci				pm8001_mr32(address, 0x58);
14362306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[6]	=
14462306a36Sopenharmony_ci				pm8001_mr32(address, 0x5C);
14562306a36Sopenharmony_ci	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[7]	=
14662306a36Sopenharmony_ci				pm8001_mr32(address, 0x60);
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/**
15062306a36Sopenharmony_ci * read_inbnd_queue_table - read the inbound queue table and save it.
15162306a36Sopenharmony_ci * @pm8001_ha: our hba card information
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_cistatic void read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	int i;
15662306a36Sopenharmony_ci	void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
15762306a36Sopenharmony_ci	for (i = 0; i < PM8001_MAX_INB_NUM; i++) {
15862306a36Sopenharmony_ci		u32 offset = i * 0x20;
15962306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].pi_pci_bar =
16062306a36Sopenharmony_ci		      get_pci_bar_index(pm8001_mr32(address, (offset + 0x14)));
16162306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].pi_offset =
16262306a36Sopenharmony_ci			pm8001_mr32(address, (offset + 0x18));
16362306a36Sopenharmony_ci	}
16462306a36Sopenharmony_ci}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci/**
16762306a36Sopenharmony_ci * read_outbnd_queue_table - read the outbound queue table and save it.
16862306a36Sopenharmony_ci * @pm8001_ha: our hba card information
16962306a36Sopenharmony_ci */
17062306a36Sopenharmony_cistatic void read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	int i;
17362306a36Sopenharmony_ci	void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
17462306a36Sopenharmony_ci	for (i = 0; i < PM8001_MAX_OUTB_NUM; i++) {
17562306a36Sopenharmony_ci		u32 offset = i * 0x24;
17662306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].ci_pci_bar =
17762306a36Sopenharmony_ci		      get_pci_bar_index(pm8001_mr32(address, (offset + 0x14)));
17862306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].ci_offset =
17962306a36Sopenharmony_ci			pm8001_mr32(address, (offset + 0x18));
18062306a36Sopenharmony_ci	}
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/**
18462306a36Sopenharmony_ci * init_default_table_values - init the default table.
18562306a36Sopenharmony_ci * @pm8001_ha: our hba card information
18662306a36Sopenharmony_ci */
18762306a36Sopenharmony_cistatic void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	int i;
19062306a36Sopenharmony_ci	u32 offsetib, offsetob;
19162306a36Sopenharmony_ci	void __iomem *addressib = pm8001_ha->inbnd_q_tbl_addr;
19262306a36Sopenharmony_ci	void __iomem *addressob = pm8001_ha->outbnd_q_tbl_addr;
19362306a36Sopenharmony_ci	u32 ib_offset = pm8001_ha->ib_offset;
19462306a36Sopenharmony_ci	u32 ob_offset = pm8001_ha->ob_offset;
19562306a36Sopenharmony_ci	u32 ci_offset = pm8001_ha->ci_offset;
19662306a36Sopenharmony_ci	u32 pi_offset = pm8001_ha->pi_offset;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.inbound_q_nppd_hppd		= 0;
19962306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid0_3	= 0;
20062306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid4_7	= 0;
20162306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid0_3	= 0;
20262306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid4_7	= 0;
20362306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ITNexus_event_pid0_3 =
20462306a36Sopenharmony_ci									 0;
20562306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ITNexus_event_pid4_7 =
20662306a36Sopenharmony_ci									 0;
20762306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ssp_event_pid0_3 = 0;
20862306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ssp_event_pid4_7 = 0;
20962306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_smp_event_pid0_3 = 0;
21062306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_smp_event_pid4_7 = 0;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_event_log_addr		=
21362306a36Sopenharmony_ci		pm8001_ha->memoryMap.region[AAP1].phys_addr_hi;
21462306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_event_log_addr		=
21562306a36Sopenharmony_ci		pm8001_ha->memoryMap.region[AAP1].phys_addr_lo;
21662306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_size		=
21762306a36Sopenharmony_ci		PM8001_EVENT_LOG_SIZE;
21862306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_option		= 0x01;
21962306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_iop_event_log_addr	=
22062306a36Sopenharmony_ci		pm8001_ha->memoryMap.region[IOP].phys_addr_hi;
22162306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_iop_event_log_addr	=
22262306a36Sopenharmony_ci		pm8001_ha->memoryMap.region[IOP].phys_addr_lo;
22362306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_size		=
22462306a36Sopenharmony_ci		PM8001_EVENT_LOG_SIZE;
22562306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_option		= 0x01;
22662306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_interrupt		= 0x01;
22762306a36Sopenharmony_ci	for (i = 0; i < pm8001_ha->max_q_num; i++) {
22862306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt	=
22962306a36Sopenharmony_ci			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30);
23062306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].upper_base_addr	=
23162306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_hi;
23262306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].lower_base_addr	=
23362306a36Sopenharmony_ci		pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_lo;
23462306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].base_virt		=
23562306a36Sopenharmony_ci		  (u8 *)pm8001_ha->memoryMap.region[ib_offset + i].virt_ptr;
23662306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].total_length		=
23762306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ib_offset + i].total_len;
23862306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].ci_upper_base_addr	=
23962306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_hi;
24062306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].ci_lower_base_addr	=
24162306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_lo;
24262306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].ci_virt		=
24362306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ci_offset + i].virt_ptr;
24462306a36Sopenharmony_ci		pm8001_write_32(pm8001_ha->inbnd_q_tbl[i].ci_virt, 0, 0);
24562306a36Sopenharmony_ci		offsetib = i * 0x20;
24662306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].pi_pci_bar		=
24762306a36Sopenharmony_ci			get_pci_bar_index(pm8001_mr32(addressib,
24862306a36Sopenharmony_ci				(offsetib + 0x14)));
24962306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].pi_offset		=
25062306a36Sopenharmony_ci			pm8001_mr32(addressib, (offsetib + 0x18));
25162306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].producer_idx		= 0;
25262306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[i].consumer_index	= 0;
25362306a36Sopenharmony_ci	}
25462306a36Sopenharmony_ci	for (i = 0; i < pm8001_ha->max_q_num; i++) {
25562306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].element_size_cnt	=
25662306a36Sopenharmony_ci			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30);
25762306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].upper_base_addr	=
25862306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_hi;
25962306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].lower_base_addr	=
26062306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_lo;
26162306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].base_virt		=
26262306a36Sopenharmony_ci		  (u8 *)pm8001_ha->memoryMap.region[ob_offset + i].virt_ptr;
26362306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].total_length		=
26462306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[ob_offset + i].total_len;
26562306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].pi_upper_base_addr	=
26662306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_hi;
26762306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].pi_lower_base_addr	=
26862306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_lo;
26962306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].interrup_vec_cnt_delay	=
27062306a36Sopenharmony_ci			0 | (10 << 16) | (i << 24);
27162306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].pi_virt		=
27262306a36Sopenharmony_ci			pm8001_ha->memoryMap.region[pi_offset + i].virt_ptr;
27362306a36Sopenharmony_ci		pm8001_write_32(pm8001_ha->outbnd_q_tbl[i].pi_virt, 0, 0);
27462306a36Sopenharmony_ci		offsetob = i * 0x24;
27562306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].ci_pci_bar		=
27662306a36Sopenharmony_ci			get_pci_bar_index(pm8001_mr32(addressob,
27762306a36Sopenharmony_ci			offsetob + 0x14));
27862306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].ci_offset		=
27962306a36Sopenharmony_ci			pm8001_mr32(addressob, (offsetob + 0x18));
28062306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].consumer_idx		= 0;
28162306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[i].producer_index	= 0;
28262306a36Sopenharmony_ci	}
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci/**
28662306a36Sopenharmony_ci * update_main_config_table - update the main default table to the HBA.
28762306a36Sopenharmony_ci * @pm8001_ha: our hba card information
28862306a36Sopenharmony_ci */
28962306a36Sopenharmony_cistatic void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
29262306a36Sopenharmony_ci	pm8001_mw32(address, 0x24,
29362306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.inbound_q_nppd_hppd);
29462306a36Sopenharmony_ci	pm8001_mw32(address, 0x28,
29562306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid0_3);
29662306a36Sopenharmony_ci	pm8001_mw32(address, 0x2C,
29762306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid4_7);
29862306a36Sopenharmony_ci	pm8001_mw32(address, 0x30,
29962306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid0_3);
30062306a36Sopenharmony_ci	pm8001_mw32(address, 0x34,
30162306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid4_7);
30262306a36Sopenharmony_ci	pm8001_mw32(address, 0x38,
30362306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.
30462306a36Sopenharmony_ci					outbound_tgt_ITNexus_event_pid0_3);
30562306a36Sopenharmony_ci	pm8001_mw32(address, 0x3C,
30662306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.
30762306a36Sopenharmony_ci					outbound_tgt_ITNexus_event_pid4_7);
30862306a36Sopenharmony_ci	pm8001_mw32(address, 0x40,
30962306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.
31062306a36Sopenharmony_ci					outbound_tgt_ssp_event_pid0_3);
31162306a36Sopenharmony_ci	pm8001_mw32(address, 0x44,
31262306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.
31362306a36Sopenharmony_ci					outbound_tgt_ssp_event_pid4_7);
31462306a36Sopenharmony_ci	pm8001_mw32(address, 0x48,
31562306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.
31662306a36Sopenharmony_ci					outbound_tgt_smp_event_pid0_3);
31762306a36Sopenharmony_ci	pm8001_mw32(address, 0x4C,
31862306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.
31962306a36Sopenharmony_ci					outbound_tgt_smp_event_pid4_7);
32062306a36Sopenharmony_ci	pm8001_mw32(address, 0x50,
32162306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_event_log_addr);
32262306a36Sopenharmony_ci	pm8001_mw32(address, 0x54,
32362306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_event_log_addr);
32462306a36Sopenharmony_ci	pm8001_mw32(address, 0x58,
32562306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_size);
32662306a36Sopenharmony_ci	pm8001_mw32(address, 0x5C,
32762306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_option);
32862306a36Sopenharmony_ci	pm8001_mw32(address, 0x60,
32962306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_iop_event_log_addr);
33062306a36Sopenharmony_ci	pm8001_mw32(address, 0x64,
33162306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_iop_event_log_addr);
33262306a36Sopenharmony_ci	pm8001_mw32(address, 0x68,
33362306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_size);
33462306a36Sopenharmony_ci	pm8001_mw32(address, 0x6C,
33562306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_option);
33662306a36Sopenharmony_ci	pm8001_mw32(address, 0x70,
33762306a36Sopenharmony_ci		pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_interrupt);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci/**
34162306a36Sopenharmony_ci * update_inbnd_queue_table - update the inbound queue table to the HBA.
34262306a36Sopenharmony_ci * @pm8001_ha: our hba card information
34362306a36Sopenharmony_ci * @number: entry in the queue
34462306a36Sopenharmony_ci */
34562306a36Sopenharmony_cistatic void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
34662306a36Sopenharmony_ci				     int number)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
34962306a36Sopenharmony_ci	u16 offset = number * 0x20;
35062306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x00,
35162306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt);
35262306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x04,
35362306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[number].upper_base_addr);
35462306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x08,
35562306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[number].lower_base_addr);
35662306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x0C,
35762306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr);
35862306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x10,
35962306a36Sopenharmony_ci		pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr);
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/**
36362306a36Sopenharmony_ci * update_outbnd_queue_table - update the outbound queue table to the HBA.
36462306a36Sopenharmony_ci * @pm8001_ha: our hba card information
36562306a36Sopenharmony_ci * @number: entry in the queue
36662306a36Sopenharmony_ci */
36762306a36Sopenharmony_cistatic void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
36862306a36Sopenharmony_ci				      int number)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
37162306a36Sopenharmony_ci	u16 offset = number * 0x24;
37262306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x00,
37362306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[number].element_size_cnt);
37462306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x04,
37562306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[number].upper_base_addr);
37662306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x08,
37762306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[number].lower_base_addr);
37862306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x0C,
37962306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr);
38062306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x10,
38162306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr);
38262306a36Sopenharmony_ci	pm8001_mw32(address, offset + 0x1C,
38362306a36Sopenharmony_ci		pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay);
38462306a36Sopenharmony_ci}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci/**
38762306a36Sopenharmony_ci * pm8001_bar4_shift - function is called to shift BAR base address
38862306a36Sopenharmony_ci * @pm8001_ha : our hba card information
38962306a36Sopenharmony_ci * @shiftValue : shifting value in memory bar.
39062306a36Sopenharmony_ci */
39162306a36Sopenharmony_ciint pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	u32 regVal;
39462306a36Sopenharmony_ci	unsigned long start;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* program the inbound AXI translation Lower Address */
39762306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW, shiftValue);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	/* confirm the setting is written */
40062306a36Sopenharmony_ci	start = jiffies + HZ; /* 1 sec */
40162306a36Sopenharmony_ci	do {
40262306a36Sopenharmony_ci		regVal = pm8001_cr32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW);
40362306a36Sopenharmony_ci	} while ((regVal != shiftValue) && time_before(jiffies, start));
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (regVal != shiftValue) {
40662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, INIT,
40762306a36Sopenharmony_ci			   "TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW = 0x%x\n",
40862306a36Sopenharmony_ci			   regVal);
40962306a36Sopenharmony_ci		return -1;
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci	return 0;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/**
41562306a36Sopenharmony_ci * mpi_set_phys_g3_with_ssc
41662306a36Sopenharmony_ci * @pm8001_ha: our hba card information
41762306a36Sopenharmony_ci * @SSCbit: set SSCbit to 0 to disable all phys ssc; 1 to enable all phys ssc.
41862306a36Sopenharmony_ci */
41962306a36Sopenharmony_cistatic void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
42062306a36Sopenharmony_ci				     u32 SSCbit)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	u32 offset, i;
42362306a36Sopenharmony_ci	unsigned long flags;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci#define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
42662306a36Sopenharmony_ci#define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
42762306a36Sopenharmony_ci#define SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET 0x1074
42862306a36Sopenharmony_ci#define SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET 0x1074
42962306a36Sopenharmony_ci#define PHY_G3_WITHOUT_SSC_BIT_SHIFT 12
43062306a36Sopenharmony_ci#define PHY_G3_WITH_SSC_BIT_SHIFT 13
43162306a36Sopenharmony_ci#define SNW3_PHY_CAPABILITIES_PARITY 31
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci   /*
43462306a36Sopenharmony_ci    * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
43562306a36Sopenharmony_ci    * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
43662306a36Sopenharmony_ci    */
43762306a36Sopenharmony_ci	spin_lock_irqsave(&pm8001_ha->lock, flags);
43862306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha,
43962306a36Sopenharmony_ci				SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
44062306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
44162306a36Sopenharmony_ci		return;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
44562306a36Sopenharmony_ci		offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i;
44662306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci	/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
44962306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha,
45062306a36Sopenharmony_ci				SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
45162306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
45262306a36Sopenharmony_ci		return;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci	for (i = 4; i < 8; i++) {
45562306a36Sopenharmony_ci		offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
45662306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci	/*************************************************************
45962306a36Sopenharmony_ci	Change the SSC upspreading value to 0x0 so that upspreading is disabled.
46062306a36Sopenharmony_ci	Device MABC SMOD0 Controls
46162306a36Sopenharmony_ci	Address: (via MEMBASE-III):
46262306a36Sopenharmony_ci	Using shifted destination address 0x0_0000: with Offset 0xD8
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	31:28 R/W Reserved Do not change
46562306a36Sopenharmony_ci	27:24 R/W SAS_SMOD_SPRDUP 0000
46662306a36Sopenharmony_ci	23:20 R/W SAS_SMOD_SPRDDN 0000
46762306a36Sopenharmony_ci	19:0  R/W  Reserved Do not change
46862306a36Sopenharmony_ci	Upon power-up this register will read as 0x8990c016,
46962306a36Sopenharmony_ci	and I would like you to change the SAS_SMOD_SPRDUP bits to 0b0000
47062306a36Sopenharmony_ci	so that the written value will be 0x8090c016.
47162306a36Sopenharmony_ci	This will ensure only down-spreading SSC is enabled on the SPC.
47262306a36Sopenharmony_ci	*************************************************************/
47362306a36Sopenharmony_ci	pm8001_cr32(pm8001_ha, 2, 0xd8);
47462306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/*set the shifted destination address to 0x0 to avoid error operation */
47762306a36Sopenharmony_ci	pm8001_bar4_shift(pm8001_ha, 0x0);
47862306a36Sopenharmony_ci	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
47962306a36Sopenharmony_ci	return;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/**
48362306a36Sopenharmony_ci * mpi_set_open_retry_interval_reg
48462306a36Sopenharmony_ci * @pm8001_ha: our hba card information
48562306a36Sopenharmony_ci * @interval: interval time for each OPEN_REJECT (RETRY). The units are in 1us.
48662306a36Sopenharmony_ci */
48762306a36Sopenharmony_cistatic void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
48862306a36Sopenharmony_ci					    u32 interval)
48962306a36Sopenharmony_ci{
49062306a36Sopenharmony_ci	u32 offset;
49162306a36Sopenharmony_ci	u32 value;
49262306a36Sopenharmony_ci	u32 i;
49362306a36Sopenharmony_ci	unsigned long flags;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci#define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
49662306a36Sopenharmony_ci#define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
49762306a36Sopenharmony_ci#define OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET 0x30B4
49862306a36Sopenharmony_ci#define OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET 0x30B4
49962306a36Sopenharmony_ci#define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
50262306a36Sopenharmony_ci	spin_lock_irqsave(&pm8001_ha->lock, flags);
50362306a36Sopenharmony_ci	/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
50462306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha,
50562306a36Sopenharmony_ci			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
50662306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
50762306a36Sopenharmony_ci		return;
50862306a36Sopenharmony_ci	}
50962306a36Sopenharmony_ci	for (i = 0; i < 4; i++) {
51062306a36Sopenharmony_ci		offset = OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET + 0x4000 * i;
51162306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 2, offset, value);
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha,
51562306a36Sopenharmony_ci			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
51662306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
51762306a36Sopenharmony_ci		return;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci	for (i = 4; i < 8; i++) {
52062306a36Sopenharmony_ci		offset = OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
52162306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 2, offset, value);
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci	/*set the shifted destination address to 0x0 to avoid error operation */
52462306a36Sopenharmony_ci	pm8001_bar4_shift(pm8001_ha, 0x0);
52562306a36Sopenharmony_ci	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
52662306a36Sopenharmony_ci	return;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * mpi_init_check - check firmware initialization status.
53162306a36Sopenharmony_ci * @pm8001_ha: our hba card information
53262306a36Sopenharmony_ci */
53362306a36Sopenharmony_cistatic int mpi_init_check(struct pm8001_hba_info *pm8001_ha)
53462306a36Sopenharmony_ci{
53562306a36Sopenharmony_ci	u32 max_wait_count;
53662306a36Sopenharmony_ci	u32 value;
53762306a36Sopenharmony_ci	u32 gst_len_mpistate;
53862306a36Sopenharmony_ci	/* Write bit0=1 to Inbound DoorBell Register to tell the SPC FW the
53962306a36Sopenharmony_ci	table is updated */
54062306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_UPDATE);
54162306a36Sopenharmony_ci	/* wait until Inbound DoorBell Clear Register toggled */
54262306a36Sopenharmony_ci	max_wait_count = 1 * 1000 * 1000;/* 1 sec */
54362306a36Sopenharmony_ci	do {
54462306a36Sopenharmony_ci		udelay(1);
54562306a36Sopenharmony_ci		value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
54662306a36Sopenharmony_ci		value &= SPC_MSGU_CFG_TABLE_UPDATE;
54762306a36Sopenharmony_ci	} while ((value != 0) && (--max_wait_count));
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (!max_wait_count)
55062306a36Sopenharmony_ci		return -1;
55162306a36Sopenharmony_ci	/* check the MPI-State for initialization */
55262306a36Sopenharmony_ci	gst_len_mpistate =
55362306a36Sopenharmony_ci		pm8001_mr32(pm8001_ha->general_stat_tbl_addr,
55462306a36Sopenharmony_ci		GST_GSTLEN_MPIS_OFFSET);
55562306a36Sopenharmony_ci	if (GST_MPI_STATE_INIT != (gst_len_mpistate & GST_MPI_STATE_MASK))
55662306a36Sopenharmony_ci		return -1;
55762306a36Sopenharmony_ci	/* check MPI Initialization error */
55862306a36Sopenharmony_ci	gst_len_mpistate = gst_len_mpistate >> 16;
55962306a36Sopenharmony_ci	if (0x0000 != gst_len_mpistate)
56062306a36Sopenharmony_ci		return -1;
56162306a36Sopenharmony_ci	return 0;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci/**
56562306a36Sopenharmony_ci * check_fw_ready - The LLDD check if the FW is ready, if not, return error.
56662306a36Sopenharmony_ci * @pm8001_ha: our hba card information
56762306a36Sopenharmony_ci */
56862306a36Sopenharmony_cistatic int check_fw_ready(struct pm8001_hba_info *pm8001_ha)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	u32 value, value1;
57162306a36Sopenharmony_ci	u32 max_wait_count;
57262306a36Sopenharmony_ci	/* check error state */
57362306a36Sopenharmony_ci	value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
57462306a36Sopenharmony_ci	value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
57562306a36Sopenharmony_ci	/* check AAP error */
57662306a36Sopenharmony_ci	if (SCRATCH_PAD1_ERR == (value & SCRATCH_PAD_STATE_MASK)) {
57762306a36Sopenharmony_ci		/* error state */
57862306a36Sopenharmony_ci		value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
57962306a36Sopenharmony_ci		return -1;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* check IOP error */
58362306a36Sopenharmony_ci	if (SCRATCH_PAD2_ERR == (value1 & SCRATCH_PAD_STATE_MASK)) {
58462306a36Sopenharmony_ci		/* error state */
58562306a36Sopenharmony_ci		value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
58662306a36Sopenharmony_ci		return -1;
58762306a36Sopenharmony_ci	}
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	/* bit 4-31 of scratch pad1 should be zeros if it is not
59062306a36Sopenharmony_ci	in error state*/
59162306a36Sopenharmony_ci	if (value & SCRATCH_PAD1_STATE_MASK) {
59262306a36Sopenharmony_ci		/* error case */
59362306a36Sopenharmony_ci		pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
59462306a36Sopenharmony_ci		return -1;
59562306a36Sopenharmony_ci	}
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	/* bit 2, 4-31 of scratch pad2 should be zeros if it is not
59862306a36Sopenharmony_ci	in error state */
59962306a36Sopenharmony_ci	if (value1 & SCRATCH_PAD2_STATE_MASK) {
60062306a36Sopenharmony_ci		/* error case */
60162306a36Sopenharmony_ci		return -1;
60262306a36Sopenharmony_ci	}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	max_wait_count = 1 * 1000 * 1000;/* 1 sec timeout */
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	/* wait until scratch pad 1 and 2 registers in ready state  */
60762306a36Sopenharmony_ci	do {
60862306a36Sopenharmony_ci		udelay(1);
60962306a36Sopenharmony_ci		value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)
61062306a36Sopenharmony_ci			& SCRATCH_PAD1_RDY;
61162306a36Sopenharmony_ci		value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)
61262306a36Sopenharmony_ci			& SCRATCH_PAD2_RDY;
61362306a36Sopenharmony_ci		if ((--max_wait_count) == 0)
61462306a36Sopenharmony_ci			return -1;
61562306a36Sopenharmony_ci	} while ((value != SCRATCH_PAD1_RDY) || (value1 != SCRATCH_PAD2_RDY));
61662306a36Sopenharmony_ci	return 0;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_cistatic void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
62062306a36Sopenharmony_ci{
62162306a36Sopenharmony_ci	void __iomem *base_addr;
62262306a36Sopenharmony_ci	u32	value;
62362306a36Sopenharmony_ci	u32	offset;
62462306a36Sopenharmony_ci	u32	pcibar;
62562306a36Sopenharmony_ci	u32	pcilogic;
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	value = pm8001_cr32(pm8001_ha, 0, 0x44);
62862306a36Sopenharmony_ci	offset = value & 0x03FFFFFF;
62962306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 Offset: %x\n", offset);
63062306a36Sopenharmony_ci	pcilogic = (value & 0xFC000000) >> 26;
63162306a36Sopenharmony_ci	pcibar = get_pci_bar_index(pcilogic);
63262306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar);
63362306a36Sopenharmony_ci	pm8001_ha->main_cfg_tbl_addr = base_addr =
63462306a36Sopenharmony_ci		pm8001_ha->io_mem[pcibar].memvirtaddr + offset;
63562306a36Sopenharmony_ci	pm8001_ha->general_stat_tbl_addr =
63662306a36Sopenharmony_ci		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x18);
63762306a36Sopenharmony_ci	pm8001_ha->inbnd_q_tbl_addr =
63862306a36Sopenharmony_ci		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C);
63962306a36Sopenharmony_ci	pm8001_ha->outbnd_q_tbl_addr =
64062306a36Sopenharmony_ci		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x20);
64162306a36Sopenharmony_ci}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci/**
64462306a36Sopenharmony_ci * pm8001_chip_init - the main init function that initialize whole PM8001 chip.
64562306a36Sopenharmony_ci * @pm8001_ha: our hba card information
64662306a36Sopenharmony_ci */
64762306a36Sopenharmony_cistatic int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	u32 i = 0;
65062306a36Sopenharmony_ci	u16 deviceid;
65162306a36Sopenharmony_ci	pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
65262306a36Sopenharmony_ci	/* 8081 controllers need BAR shift to access MPI space
65362306a36Sopenharmony_ci	* as this is shared with BIOS data */
65462306a36Sopenharmony_ci	if (deviceid == 0x8081 || deviceid == 0x0042) {
65562306a36Sopenharmony_ci		if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
65662306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
65762306a36Sopenharmony_ci				   "Shift Bar4 to 0x%x failed\n",
65862306a36Sopenharmony_ci				   GSM_SM_BASE);
65962306a36Sopenharmony_ci			return -1;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci	/* check the firmware status */
66362306a36Sopenharmony_ci	if (-1 == check_fw_ready(pm8001_ha)) {
66462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n");
66562306a36Sopenharmony_ci		return -EBUSY;
66662306a36Sopenharmony_ci	}
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci	/* Initialize pci space address eg: mpi offset */
66962306a36Sopenharmony_ci	init_pci_device_addresses(pm8001_ha);
67062306a36Sopenharmony_ci	init_default_table_values(pm8001_ha);
67162306a36Sopenharmony_ci	read_main_config_table(pm8001_ha);
67262306a36Sopenharmony_ci	read_general_status_table(pm8001_ha);
67362306a36Sopenharmony_ci	read_inbnd_queue_table(pm8001_ha);
67462306a36Sopenharmony_ci	read_outbnd_queue_table(pm8001_ha);
67562306a36Sopenharmony_ci	/* update main config table ,inbound table and outbound table */
67662306a36Sopenharmony_ci	update_main_config_table(pm8001_ha);
67762306a36Sopenharmony_ci	for (i = 0; i < pm8001_ha->max_q_num; i++)
67862306a36Sopenharmony_ci		update_inbnd_queue_table(pm8001_ha, i);
67962306a36Sopenharmony_ci	for (i = 0; i < pm8001_ha->max_q_num; i++)
68062306a36Sopenharmony_ci		update_outbnd_queue_table(pm8001_ha, i);
68162306a36Sopenharmony_ci	/* 8081 controller donot require these operations */
68262306a36Sopenharmony_ci	if (deviceid != 0x8081 && deviceid != 0x0042) {
68362306a36Sopenharmony_ci		mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
68462306a36Sopenharmony_ci		/* 7->130ms, 34->500ms, 119->1.5s */
68562306a36Sopenharmony_ci		mpi_set_open_retry_interval_reg(pm8001_ha, 119);
68662306a36Sopenharmony_ci	}
68762306a36Sopenharmony_ci	/* notify firmware update finished and check initialization status */
68862306a36Sopenharmony_ci	if (0 == mpi_init_check(pm8001_ha)) {
68962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n");
69062306a36Sopenharmony_ci	} else
69162306a36Sopenharmony_ci		return -EBUSY;
69262306a36Sopenharmony_ci	/*This register is a 16-bit timer with a resolution of 1us. This is the
69362306a36Sopenharmony_ci	timer used for interrupt delay/coalescing in the PCIe Application Layer.
69462306a36Sopenharmony_ci	Zero is not a valid value. A value of 1 in the register will cause the
69562306a36Sopenharmony_ci	interrupts to be normal. A value greater than 1 will cause coalescing
69662306a36Sopenharmony_ci	delays.*/
69762306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, 0x0033c0, 0x1);
69862306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, 0x0033c4, 0x0);
69962306a36Sopenharmony_ci	return 0;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic void pm8001_chip_post_init(struct pm8001_hba_info *pm8001_ha)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	u32 max_wait_count;
70962306a36Sopenharmony_ci	u32 value;
71062306a36Sopenharmony_ci	u32 gst_len_mpistate;
71162306a36Sopenharmony_ci	u16 deviceid;
71262306a36Sopenharmony_ci	pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
71362306a36Sopenharmony_ci	if (deviceid == 0x8081 || deviceid == 0x0042) {
71462306a36Sopenharmony_ci		if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
71562306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
71662306a36Sopenharmony_ci				   "Shift Bar4 to 0x%x failed\n",
71762306a36Sopenharmony_ci				   GSM_SM_BASE);
71862306a36Sopenharmony_ci			return -1;
71962306a36Sopenharmony_ci		}
72062306a36Sopenharmony_ci	}
72162306a36Sopenharmony_ci	init_pci_device_addresses(pm8001_ha);
72262306a36Sopenharmony_ci	/* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the
72362306a36Sopenharmony_ci	table is stop */
72462306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_RESET);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	/* wait until Inbound DoorBell Clear Register toggled */
72762306a36Sopenharmony_ci	max_wait_count = 1 * 1000 * 1000;/* 1 sec */
72862306a36Sopenharmony_ci	do {
72962306a36Sopenharmony_ci		udelay(1);
73062306a36Sopenharmony_ci		value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
73162306a36Sopenharmony_ci		value &= SPC_MSGU_CFG_TABLE_RESET;
73262306a36Sopenharmony_ci	} while ((value != 0) && (--max_wait_count));
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_ci	if (!max_wait_count) {
73562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=0x%x\n",
73662306a36Sopenharmony_ci			   value);
73762306a36Sopenharmony_ci		return -1;
73862306a36Sopenharmony_ci	}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	/* check the MPI-State for termination in progress */
74162306a36Sopenharmony_ci	/* wait until Inbound DoorBell Clear Register toggled */
74262306a36Sopenharmony_ci	max_wait_count = 1 * 1000 * 1000;  /* 1 sec */
74362306a36Sopenharmony_ci	do {
74462306a36Sopenharmony_ci		udelay(1);
74562306a36Sopenharmony_ci		gst_len_mpistate =
74662306a36Sopenharmony_ci			pm8001_mr32(pm8001_ha->general_stat_tbl_addr,
74762306a36Sopenharmony_ci			GST_GSTLEN_MPIS_OFFSET);
74862306a36Sopenharmony_ci		if (GST_MPI_STATE_UNINIT ==
74962306a36Sopenharmony_ci			(gst_len_mpistate & GST_MPI_STATE_MASK))
75062306a36Sopenharmony_ci			break;
75162306a36Sopenharmony_ci	} while (--max_wait_count);
75262306a36Sopenharmony_ci	if (!max_wait_count) {
75362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, " TIME OUT MPI State = 0x%x\n",
75462306a36Sopenharmony_ci			   gst_len_mpistate & GST_MPI_STATE_MASK);
75562306a36Sopenharmony_ci		return -1;
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci	return 0;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci/**
76162306a36Sopenharmony_ci * soft_reset_ready_check - Function to check FW is ready for soft reset.
76262306a36Sopenharmony_ci * @pm8001_ha: our hba card information
76362306a36Sopenharmony_ci */
76462306a36Sopenharmony_cistatic u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
76562306a36Sopenharmony_ci{
76662306a36Sopenharmony_ci	u32 regVal, regVal1, regVal2;
76762306a36Sopenharmony_ci	if (mpi_uninit_check(pm8001_ha) != 0) {
76862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "MPI state is not ready\n");
76962306a36Sopenharmony_ci		return -1;
77062306a36Sopenharmony_ci	}
77162306a36Sopenharmony_ci	/* read the scratch pad 2 register bit 2 */
77262306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)
77362306a36Sopenharmony_ci		& SCRATCH_PAD2_FWRDY_RST;
77462306a36Sopenharmony_ci	if (regVal == SCRATCH_PAD2_FWRDY_RST) {
77562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, INIT, "Firmware is ready for reset.\n");
77662306a36Sopenharmony_ci	} else {
77762306a36Sopenharmony_ci		unsigned long flags;
77862306a36Sopenharmony_ci		/* Trigger NMI twice via RB6 */
77962306a36Sopenharmony_ci		spin_lock_irqsave(&pm8001_ha->lock, flags);
78062306a36Sopenharmony_ci		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
78162306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
78262306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
78362306a36Sopenharmony_ci				   "Shift Bar4 to 0x%x failed\n",
78462306a36Sopenharmony_ci				   RB6_ACCESS_REG);
78562306a36Sopenharmony_ci			return -1;
78662306a36Sopenharmony_ci		}
78762306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
78862306a36Sopenharmony_ci			RB6_MAGIC_NUMBER_RST);
78962306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, RB6_MAGIC_NUMBER_RST);
79062306a36Sopenharmony_ci		/* wait for 100 ms */
79162306a36Sopenharmony_ci		mdelay(100);
79262306a36Sopenharmony_ci		regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) &
79362306a36Sopenharmony_ci			SCRATCH_PAD2_FWRDY_RST;
79462306a36Sopenharmony_ci		if (regVal != SCRATCH_PAD2_FWRDY_RST) {
79562306a36Sopenharmony_ci			regVal1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
79662306a36Sopenharmony_ci			regVal2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
79762306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:MSGU_SCRATCH_PAD1=0x%x, MSGU_SCRATCH_PAD2=0x%x\n",
79862306a36Sopenharmony_ci				   regVal1, regVal2);
79962306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
80062306a36Sopenharmony_ci				   "SCRATCH_PAD0 value = 0x%x\n",
80162306a36Sopenharmony_ci				   pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0));
80262306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
80362306a36Sopenharmony_ci				   "SCRATCH_PAD3 value = 0x%x\n",
80462306a36Sopenharmony_ci				   pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3));
80562306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
80662306a36Sopenharmony_ci			return -1;
80762306a36Sopenharmony_ci		}
80862306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
80962306a36Sopenharmony_ci	}
81062306a36Sopenharmony_ci	return 0;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci/**
81462306a36Sopenharmony_ci * pm8001_chip_soft_rst - soft reset the PM8001 chip, so that the clear all
81562306a36Sopenharmony_ci * the FW register status to the originated status.
81662306a36Sopenharmony_ci * @pm8001_ha: our hba card information
81762306a36Sopenharmony_ci */
81862306a36Sopenharmony_cistatic int
81962306a36Sopenharmony_cipm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
82062306a36Sopenharmony_ci{
82162306a36Sopenharmony_ci	u32	regVal, toggleVal;
82262306a36Sopenharmony_ci	u32	max_wait_count;
82362306a36Sopenharmony_ci	u32	regVal1, regVal2, regVal3;
82462306a36Sopenharmony_ci	u32	signature = 0x252acbcd; /* for host scratch pad0 */
82562306a36Sopenharmony_ci	unsigned long flags;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	/* step1: Check FW is ready for soft reset */
82862306a36Sopenharmony_ci	if (soft_reset_ready_check(pm8001_ha) != 0) {
82962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "FW is not ready\n");
83062306a36Sopenharmony_ci		return -1;
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	/* step 2: clear NMI status register on AAP1 and IOP, write the same
83462306a36Sopenharmony_ci	value to clear */
83562306a36Sopenharmony_ci	/* map 0x60000 to BAR4(0x20), BAR2(win) */
83662306a36Sopenharmony_ci	spin_lock_irqsave(&pm8001_ha->lock, flags);
83762306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
83862306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
83962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
84062306a36Sopenharmony_ci			   MBIC_AAP1_ADDR_BASE);
84162306a36Sopenharmony_ci		return -1;
84262306a36Sopenharmony_ci	}
84362306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP);
84462306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "MBIC - NMI Enable VPE0 (IOP)= 0x%x\n",
84562306a36Sopenharmony_ci		   regVal);
84662306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
84762306a36Sopenharmony_ci	/* map 0x70000 to BAR4(0x20), BAR2(win) */
84862306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
84962306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
85062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
85162306a36Sopenharmony_ci			   MBIC_IOP_ADDR_BASE);
85262306a36Sopenharmony_ci		return -1;
85362306a36Sopenharmony_ci	}
85462306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1);
85562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "MBIC - NMI Enable VPE0 (AAP1)= 0x%x\n",
85662306a36Sopenharmony_ci		   regVal);
85762306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1, 0x0);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE);
86062306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "PCIE -Event Interrupt Enable = 0x%x\n",
86162306a36Sopenharmony_ci		   regVal);
86262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE, 0x0);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT);
86562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "PCIE - Event Interrupt  = 0x%x\n",
86662306a36Sopenharmony_ci		   regVal);
86762306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT, regVal);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE);
87062306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "PCIE -Error Interrupt Enable = 0x%x\n",
87162306a36Sopenharmony_ci		   regVal);
87262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE, 0x0);
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT);
87562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "PCIE - Error Interrupt = 0x%x\n", regVal);
87662306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT, regVal);
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	/* read the scratch pad 1 register bit 2 */
87962306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)
88062306a36Sopenharmony_ci		& SCRATCH_PAD1_RST;
88162306a36Sopenharmony_ci	toggleVal = regVal ^ SCRATCH_PAD1_RST;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	/* set signature in host scratch pad0 register to tell SPC that the
88462306a36Sopenharmony_ci	host performs the soft reset */
88562306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0, signature);
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci	/* read required registers for confirmming */
88862306a36Sopenharmony_ci	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
88962306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
89062306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
89162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
89262306a36Sopenharmony_ci			   GSM_ADDR_BASE);
89362306a36Sopenharmony_ci		return -1;
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
89662306a36Sopenharmony_ci		   "GSM 0x0(0x00007b88)-GSM Configuration and Reset = 0x%x\n",
89762306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ci	/* step 3: host read GSM Configuration and Reset register */
90062306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET);
90162306a36Sopenharmony_ci	/* Put those bits to low */
90262306a36Sopenharmony_ci	/* GSM XCBI offset = 0x70 0000
90362306a36Sopenharmony_ci	0x00 Bit 13 COM_SLV_SW_RSTB 1
90462306a36Sopenharmony_ci	0x00 Bit 12 QSSP_SW_RSTB 1
90562306a36Sopenharmony_ci	0x00 Bit 11 RAAE_SW_RSTB 1
90662306a36Sopenharmony_ci	0x00 Bit 9 RB_1_SW_RSTB 1
90762306a36Sopenharmony_ci	0x00 Bit 8 SM_SW_RSTB 1
90862306a36Sopenharmony_ci	*/
90962306a36Sopenharmony_ci	regVal &= ~(0x00003b00);
91062306a36Sopenharmony_ci	/* host write GSM Configuration and Reset register */
91162306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal);
91262306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
91362306a36Sopenharmony_ci		   "GSM 0x0 (0x00007b88 ==> 0x00004088) - GSM Configuration and Reset is set to = 0x%x\n",
91462306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	/* step 4: */
91762306a36Sopenharmony_ci	/* disable GSM - Read Address Parity Check */
91862306a36Sopenharmony_ci	regVal1 = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK);
91962306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
92062306a36Sopenharmony_ci		   "GSM 0x700038 - Read Address Parity Check Enable = 0x%x\n",
92162306a36Sopenharmony_ci		   regVal1);
92262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, 0x0);
92362306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
92462306a36Sopenharmony_ci		   "GSM 0x700038 - Read Address Parity Check Enable is set to = 0x%x\n",
92562306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK));
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	/* disable GSM - Write Address Parity Check */
92862306a36Sopenharmony_ci	regVal2 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK);
92962306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
93062306a36Sopenharmony_ci		   "GSM 0x700040 - Write Address Parity Check Enable = 0x%x\n",
93162306a36Sopenharmony_ci		   regVal2);
93262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, 0x0);
93362306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
93462306a36Sopenharmony_ci		   "GSM 0x700040 - Write Address Parity Check Enable is set to = 0x%x\n",
93562306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK));
93662306a36Sopenharmony_ci
93762306a36Sopenharmony_ci	/* disable GSM - Write Data Parity Check */
93862306a36Sopenharmony_ci	regVal3 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK);
93962306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "GSM 0x300048 - Write Data Parity Check Enable = 0x%x\n",
94062306a36Sopenharmony_ci		   regVal3);
94162306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, 0x0);
94262306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
94362306a36Sopenharmony_ci		   "GSM 0x300048 - Write Data Parity Check Enable is set to = 0x%x\n",
94462306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK));
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/* step 5: delay 10 usec */
94762306a36Sopenharmony_ci	udelay(10);
94862306a36Sopenharmony_ci	/* step 5-b: set GPIO-0 output control to tristate anyway */
94962306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
95062306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
95162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, INIT, "Shift Bar4 to 0x%x failed\n",
95262306a36Sopenharmony_ci			   GPIO_ADDR_BASE);
95362306a36Sopenharmony_ci		return -1;
95462306a36Sopenharmony_ci	}
95562306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET);
95662306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "GPIO Output Control Register: = 0x%x\n",
95762306a36Sopenharmony_ci		   regVal);
95862306a36Sopenharmony_ci	/* set GPIO-0 output control to tri-state */
95962306a36Sopenharmony_ci	regVal &= 0xFFFFFFFC;
96062306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET, regVal);
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	/* Step 6: Reset the IOP and AAP1 */
96362306a36Sopenharmony_ci	/* map 0x00000 to BAR4(0x20), BAR2(win) */
96462306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
96562306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
96662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "SPC Shift Bar4 to 0x%x failed\n",
96762306a36Sopenharmony_ci			   SPC_TOP_LEVEL_ADDR_BASE);
96862306a36Sopenharmony_ci		return -1;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
97162306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "Top Register before resetting IOP/AAP1:= 0x%x\n",
97262306a36Sopenharmony_ci		   regVal);
97362306a36Sopenharmony_ci	regVal &= ~(SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS);
97462306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	/* step 7: Reset the BDMA/OSSP */
97762306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
97862306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "Top Register before resetting BDMA/OSSP: = 0x%x\n",
97962306a36Sopenharmony_ci		   regVal);
98062306a36Sopenharmony_ci	regVal &= ~(SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP);
98162306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	/* step 8: delay 10 usec */
98462306a36Sopenharmony_ci	udelay(10);
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci	/* step 9: bring the BDMA and OSSP out of reset */
98762306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
98862306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
98962306a36Sopenharmony_ci		   "Top Register before bringing up BDMA/OSSP:= 0x%x\n",
99062306a36Sopenharmony_ci		   regVal);
99162306a36Sopenharmony_ci	regVal |= (SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP);
99262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	/* step 10: delay 10 usec */
99562306a36Sopenharmony_ci	udelay(10);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	/* step 11: reads and sets the GSM Configuration and Reset Register */
99862306a36Sopenharmony_ci	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
99962306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
100062306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
100162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "SPC Shift Bar4 to 0x%x failed\n",
100262306a36Sopenharmony_ci			   GSM_ADDR_BASE);
100362306a36Sopenharmony_ci		return -1;
100462306a36Sopenharmony_ci	}
100562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
100662306a36Sopenharmony_ci		   "GSM 0x0 (0x00007b88)-GSM Configuration and Reset = 0x%x\n",
100762306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
100862306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET);
100962306a36Sopenharmony_ci	/* Put those bits to high */
101062306a36Sopenharmony_ci	/* GSM XCBI offset = 0x70 0000
101162306a36Sopenharmony_ci	0x00 Bit 13 COM_SLV_SW_RSTB 1
101262306a36Sopenharmony_ci	0x00 Bit 12 QSSP_SW_RSTB 1
101362306a36Sopenharmony_ci	0x00 Bit 11 RAAE_SW_RSTB 1
101462306a36Sopenharmony_ci	0x00 Bit 9   RB_1_SW_RSTB 1
101562306a36Sopenharmony_ci	0x00 Bit 8   SM_SW_RSTB 1
101662306a36Sopenharmony_ci	*/
101762306a36Sopenharmony_ci	regVal |= (GSM_CONFIG_RESET_VALUE);
101862306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal);
101962306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "GSM (0x00004088 ==> 0x00007b88) - GSM Configuration and Reset is set to = 0x%x\n",
102062306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	/* step 12: Restore GSM - Read Address Parity Check */
102362306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK);
102462306a36Sopenharmony_ci	/* just for debugging */
102562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
102662306a36Sopenharmony_ci		   "GSM 0x700038 - Read Address Parity Check Enable = 0x%x\n",
102762306a36Sopenharmony_ci		   regVal);
102862306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, regVal1);
102962306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "GSM 0x700038 - Read Address Parity Check Enable is set to = 0x%x\n",
103062306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK));
103162306a36Sopenharmony_ci	/* Restore GSM - Write Address Parity Check */
103262306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK);
103362306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, regVal2);
103462306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
103562306a36Sopenharmony_ci		   "GSM 0x700040 - Write Address Parity Check Enable is set to = 0x%x\n",
103662306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK));
103762306a36Sopenharmony_ci	/* Restore GSM - Write Data Parity Check */
103862306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK);
103962306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, regVal3);
104062306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
104162306a36Sopenharmony_ci		   "GSM 0x700048 - Write Data Parity Check Enable is set to = 0x%x\n",
104262306a36Sopenharmony_ci		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK));
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	/* step 13: bring the IOP and AAP1 out of reset */
104562306a36Sopenharmony_ci	/* map 0x00000 to BAR4(0x20), BAR2(win) */
104662306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
104762306a36Sopenharmony_ci		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
104862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
104962306a36Sopenharmony_ci			   SPC_TOP_LEVEL_ADDR_BASE);
105062306a36Sopenharmony_ci		return -1;
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
105362306a36Sopenharmony_ci	regVal |= (SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS);
105462306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	/* step 14: delay 10 usec - Normal Mode */
105762306a36Sopenharmony_ci	udelay(10);
105862306a36Sopenharmony_ci	/* check Soft Reset Normal mode or Soft Reset HDA mode */
105962306a36Sopenharmony_ci	if (signature == SPC_SOFT_RESET_SIGNATURE) {
106062306a36Sopenharmony_ci		/* step 15 (Normal Mode): wait until scratch pad1 register
106162306a36Sopenharmony_ci		bit 2 toggled */
106262306a36Sopenharmony_ci		max_wait_count = 2 * 1000 * 1000;/* 2 sec */
106362306a36Sopenharmony_ci		do {
106462306a36Sopenharmony_ci			udelay(1);
106562306a36Sopenharmony_ci			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) &
106662306a36Sopenharmony_ci				SCRATCH_PAD1_RST;
106762306a36Sopenharmony_ci		} while ((regVal != toggleVal) && (--max_wait_count));
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		if (!max_wait_count) {
107062306a36Sopenharmony_ci			regVal = pm8001_cr32(pm8001_ha, 0,
107162306a36Sopenharmony_ci				MSGU_SCRATCH_PAD_1);
107262306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT : ToggleVal 0x%x,MSGU_SCRATCH_PAD1 = 0x%x\n",
107362306a36Sopenharmony_ci				   toggleVal, regVal);
107462306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
107562306a36Sopenharmony_ci				   "SCRATCH_PAD0 value = 0x%x\n",
107662306a36Sopenharmony_ci				   pm8001_cr32(pm8001_ha, 0,
107762306a36Sopenharmony_ci					       MSGU_SCRATCH_PAD_0));
107862306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
107962306a36Sopenharmony_ci				   "SCRATCH_PAD2 value = 0x%x\n",
108062306a36Sopenharmony_ci				   pm8001_cr32(pm8001_ha, 0,
108162306a36Sopenharmony_ci					       MSGU_SCRATCH_PAD_2));
108262306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
108362306a36Sopenharmony_ci				   "SCRATCH_PAD3 value = 0x%x\n",
108462306a36Sopenharmony_ci				   pm8001_cr32(pm8001_ha, 0,
108562306a36Sopenharmony_ci					       MSGU_SCRATCH_PAD_3));
108662306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
108762306a36Sopenharmony_ci			return -1;
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci		/* step 16 (Normal) - Clear ODMR and ODCR */
109162306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
109262306a36Sopenharmony_ci		pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci		/* step 17 (Normal Mode): wait for the FW and IOP to get
109562306a36Sopenharmony_ci		ready - 1 sec timeout */
109662306a36Sopenharmony_ci		/* Wait for the SPC Configuration Table to be ready */
109762306a36Sopenharmony_ci		if (check_fw_ready(pm8001_ha) == -1) {
109862306a36Sopenharmony_ci			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
109962306a36Sopenharmony_ci			/* return error if MPI Configuration Table not ready */
110062306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, INIT,
110162306a36Sopenharmony_ci				   "FW not ready SCRATCH_PAD1 = 0x%x\n",
110262306a36Sopenharmony_ci				   regVal);
110362306a36Sopenharmony_ci			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
110462306a36Sopenharmony_ci			/* return error if MPI Configuration Table not ready */
110562306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, INIT,
110662306a36Sopenharmony_ci				   "FW not ready SCRATCH_PAD2 = 0x%x\n",
110762306a36Sopenharmony_ci				   regVal);
110862306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, INIT,
110962306a36Sopenharmony_ci				   "SCRATCH_PAD0 value = 0x%x\n",
111062306a36Sopenharmony_ci				   pm8001_cr32(pm8001_ha, 0,
111162306a36Sopenharmony_ci					       MSGU_SCRATCH_PAD_0));
111262306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, INIT,
111362306a36Sopenharmony_ci				   "SCRATCH_PAD3 value = 0x%x\n",
111462306a36Sopenharmony_ci				   pm8001_cr32(pm8001_ha, 0,
111562306a36Sopenharmony_ci					       MSGU_SCRATCH_PAD_3));
111662306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
111762306a36Sopenharmony_ci			return -1;
111862306a36Sopenharmony_ci		}
111962306a36Sopenharmony_ci	}
112062306a36Sopenharmony_ci	pm8001_bar4_shift(pm8001_ha, 0);
112162306a36Sopenharmony_ci	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "SPC soft reset Complete\n");
112462306a36Sopenharmony_ci	return 0;
112562306a36Sopenharmony_ci}
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_cistatic void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
112862306a36Sopenharmony_ci{
112962306a36Sopenharmony_ci	u32 i;
113062306a36Sopenharmony_ci	u32 regVal;
113162306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "chip reset start\n");
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	/* do SPC chip reset. */
113462306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET);
113562306a36Sopenharmony_ci	regVal &= ~(SPC_REG_RESET_DEVICE);
113662306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/* delay 10 usec */
113962306a36Sopenharmony_ci	udelay(10);
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	/* bring chip reset out of reset */
114262306a36Sopenharmony_ci	regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET);
114362306a36Sopenharmony_ci	regVal |= SPC_REG_RESET_DEVICE;
114462306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	/* delay 10 usec */
114762306a36Sopenharmony_ci	udelay(10);
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	/* wait for 20 msec until the firmware gets reloaded */
115062306a36Sopenharmony_ci	i = 20;
115162306a36Sopenharmony_ci	do {
115262306a36Sopenharmony_ci		mdelay(1);
115362306a36Sopenharmony_ci	} while ((--i) != 0);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "chip reset finished\n");
115662306a36Sopenharmony_ci}
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci/**
115962306a36Sopenharmony_ci * pm8001_chip_iounmap - which mapped when initialized.
116062306a36Sopenharmony_ci * @pm8001_ha: our hba card information
116162306a36Sopenharmony_ci */
116262306a36Sopenharmony_civoid pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha)
116362306a36Sopenharmony_ci{
116462306a36Sopenharmony_ci	s8 bar, logical = 0;
116562306a36Sopenharmony_ci	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
116662306a36Sopenharmony_ci		/*
116762306a36Sopenharmony_ci		** logical BARs for SPC:
116862306a36Sopenharmony_ci		** bar 0 and 1 - logical BAR0
116962306a36Sopenharmony_ci		** bar 2 and 3 - logical BAR1
117062306a36Sopenharmony_ci		** bar4 - logical BAR2
117162306a36Sopenharmony_ci		** bar5 - logical BAR3
117262306a36Sopenharmony_ci		** Skip the appropriate assignments:
117362306a36Sopenharmony_ci		*/
117462306a36Sopenharmony_ci		if ((bar == 1) || (bar == 3))
117562306a36Sopenharmony_ci			continue;
117662306a36Sopenharmony_ci		if (pm8001_ha->io_mem[logical].memvirtaddr) {
117762306a36Sopenharmony_ci			iounmap(pm8001_ha->io_mem[logical].memvirtaddr);
117862306a36Sopenharmony_ci			logical++;
117962306a36Sopenharmony_ci		}
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci#ifndef PM8001_USE_MSIX
118462306a36Sopenharmony_ci/**
118562306a36Sopenharmony_ci * pm8001_chip_intx_interrupt_enable - enable PM8001 chip interrupt
118662306a36Sopenharmony_ci * @pm8001_ha: our hba card information
118762306a36Sopenharmony_ci */
118862306a36Sopenharmony_cistatic void
118962306a36Sopenharmony_cipm8001_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha)
119062306a36Sopenharmony_ci{
119162306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);
119262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
119362306a36Sopenharmony_ci}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci/**
119662306a36Sopenharmony_ci * pm8001_chip_intx_interrupt_disable - disable PM8001 chip interrupt
119762306a36Sopenharmony_ci * @pm8001_ha: our hba card information
119862306a36Sopenharmony_ci */
119962306a36Sopenharmony_cistatic void
120062306a36Sopenharmony_cipm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha)
120162306a36Sopenharmony_ci{
120262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL);
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci#else
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci/**
120862306a36Sopenharmony_ci * pm8001_chip_msix_interrupt_enable - enable PM8001 chip interrupt
120962306a36Sopenharmony_ci * @pm8001_ha: our hba card information
121062306a36Sopenharmony_ci * @int_vec_idx: interrupt number to enable
121162306a36Sopenharmony_ci */
121262306a36Sopenharmony_cistatic void
121362306a36Sopenharmony_cipm8001_chip_msix_interrupt_enable(struct pm8001_hba_info *pm8001_ha,
121462306a36Sopenharmony_ci	u32 int_vec_idx)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	u32 msi_index;
121762306a36Sopenharmony_ci	u32 value;
121862306a36Sopenharmony_ci	msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
121962306a36Sopenharmony_ci	msi_index += MSIX_TABLE_BASE;
122062306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_ENABLE);
122162306a36Sopenharmony_ci	value = (1 << int_vec_idx);
122262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0,  MSGU_ODCR, value);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci/**
122762306a36Sopenharmony_ci * pm8001_chip_msix_interrupt_disable - disable PM8001 chip interrupt
122862306a36Sopenharmony_ci * @pm8001_ha: our hba card information
122962306a36Sopenharmony_ci * @int_vec_idx: interrupt number to disable
123062306a36Sopenharmony_ci */
123162306a36Sopenharmony_cistatic void
123262306a36Sopenharmony_cipm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha,
123362306a36Sopenharmony_ci	u32 int_vec_idx)
123462306a36Sopenharmony_ci{
123562306a36Sopenharmony_ci	u32 msi_index;
123662306a36Sopenharmony_ci	msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
123762306a36Sopenharmony_ci	msi_index += MSIX_TABLE_BASE;
123862306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, 0,  msi_index, MSIX_INTERRUPT_DISABLE);
123962306a36Sopenharmony_ci}
124062306a36Sopenharmony_ci#endif
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci/**
124362306a36Sopenharmony_ci * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
124462306a36Sopenharmony_ci * @pm8001_ha: our hba card information
124562306a36Sopenharmony_ci * @vec: unused
124662306a36Sopenharmony_ci */
124762306a36Sopenharmony_cistatic void
124862306a36Sopenharmony_cipm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec)
124962306a36Sopenharmony_ci{
125062306a36Sopenharmony_ci#ifdef PM8001_USE_MSIX
125162306a36Sopenharmony_ci	pm8001_chip_msix_interrupt_enable(pm8001_ha, 0);
125262306a36Sopenharmony_ci#else
125362306a36Sopenharmony_ci	pm8001_chip_intx_interrupt_enable(pm8001_ha);
125462306a36Sopenharmony_ci#endif
125562306a36Sopenharmony_ci}
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci/**
125862306a36Sopenharmony_ci * pm8001_chip_interrupt_disable - disable PM8001 chip interrupt
125962306a36Sopenharmony_ci * @pm8001_ha: our hba card information
126062306a36Sopenharmony_ci * @vec: unused
126162306a36Sopenharmony_ci */
126262306a36Sopenharmony_cistatic void
126362306a36Sopenharmony_cipm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci#ifdef PM8001_USE_MSIX
126662306a36Sopenharmony_ci	pm8001_chip_msix_interrupt_disable(pm8001_ha, 0);
126762306a36Sopenharmony_ci#else
126862306a36Sopenharmony_ci	pm8001_chip_intx_interrupt_disable(pm8001_ha);
126962306a36Sopenharmony_ci#endif
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_ci/**
127362306a36Sopenharmony_ci * pm8001_mpi_msg_free_get - get the free message buffer for transfer
127462306a36Sopenharmony_ci * inbound queue.
127562306a36Sopenharmony_ci * @circularQ: the inbound queue  we want to transfer to HBA.
127662306a36Sopenharmony_ci * @messageSize: the message size of this transfer, normally it is 64 bytes
127762306a36Sopenharmony_ci * @messagePtr: the pointer to message.
127862306a36Sopenharmony_ci */
127962306a36Sopenharmony_ciint pm8001_mpi_msg_free_get(struct inbound_queue_table *circularQ,
128062306a36Sopenharmony_ci			    u16 messageSize, void **messagePtr)
128162306a36Sopenharmony_ci{
128262306a36Sopenharmony_ci	u32 offset, consumer_index;
128362306a36Sopenharmony_ci	struct mpi_msg_hdr *msgHeader;
128462306a36Sopenharmony_ci	u8 bcCount = 1; /* only support single buffer */
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	/* Checks is the requested message size can be allocated in this queue*/
128762306a36Sopenharmony_ci	if (messageSize > IOMB_SIZE_SPCV) {
128862306a36Sopenharmony_ci		*messagePtr = NULL;
128962306a36Sopenharmony_ci		return -1;
129062306a36Sopenharmony_ci	}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	/* Stores the new consumer index */
129362306a36Sopenharmony_ci	consumer_index = pm8001_read_32(circularQ->ci_virt);
129462306a36Sopenharmony_ci	circularQ->consumer_index = cpu_to_le32(consumer_index);
129562306a36Sopenharmony_ci	if (((circularQ->producer_idx + bcCount) % PM8001_MPI_QUEUE) ==
129662306a36Sopenharmony_ci		le32_to_cpu(circularQ->consumer_index)) {
129762306a36Sopenharmony_ci		*messagePtr = NULL;
129862306a36Sopenharmony_ci		return -1;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci	/* get memory IOMB buffer address */
130162306a36Sopenharmony_ci	offset = circularQ->producer_idx * messageSize;
130262306a36Sopenharmony_ci	/* increment to next bcCount element */
130362306a36Sopenharmony_ci	circularQ->producer_idx = (circularQ->producer_idx + bcCount)
130462306a36Sopenharmony_ci				% PM8001_MPI_QUEUE;
130562306a36Sopenharmony_ci	/* Adds that distance to the base of the region virtual address plus
130662306a36Sopenharmony_ci	the message header size*/
130762306a36Sopenharmony_ci	msgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt	+ offset);
130862306a36Sopenharmony_ci	*messagePtr = ((void *)msgHeader) + sizeof(struct mpi_msg_hdr);
130962306a36Sopenharmony_ci	return 0;
131062306a36Sopenharmony_ci}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci/**
131362306a36Sopenharmony_ci * pm8001_mpi_build_cmd- build the message queue for transfer, update the PI to
131462306a36Sopenharmony_ci * FW to tell the fw to get this message from IOMB.
131562306a36Sopenharmony_ci * @pm8001_ha: our hba card information
131662306a36Sopenharmony_ci * @q_index: the index in the inbound queue we want to transfer to HBA.
131762306a36Sopenharmony_ci * @opCode: the operation code represents commands which LLDD and fw recognized.
131862306a36Sopenharmony_ci * @payload: the command payload of each operation command.
131962306a36Sopenharmony_ci * @nb: size in bytes of the command payload
132062306a36Sopenharmony_ci * @responseQueue: queue to interrupt on w/ command response (if any)
132162306a36Sopenharmony_ci */
132262306a36Sopenharmony_ciint pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
132362306a36Sopenharmony_ci			 u32 q_index, u32 opCode, void *payload, size_t nb,
132462306a36Sopenharmony_ci			 u32 responseQueue)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	u32 Header = 0, hpriority = 0, bc = 1, category = 0x02;
132762306a36Sopenharmony_ci	void *pMessage;
132862306a36Sopenharmony_ci	unsigned long flags;
132962306a36Sopenharmony_ci	struct inbound_queue_table *circularQ = &pm8001_ha->inbnd_q_tbl[q_index];
133062306a36Sopenharmony_ci	int rv;
133162306a36Sopenharmony_ci	u32 htag = le32_to_cpu(*(__le32 *)payload);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	trace_pm80xx_mpi_build_cmd(pm8001_ha->id, opCode, htag, q_index,
133462306a36Sopenharmony_ci		circularQ->producer_idx, le32_to_cpu(circularQ->consumer_index));
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (WARN_ON(q_index >= pm8001_ha->max_q_num))
133762306a36Sopenharmony_ci		return -EINVAL;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	spin_lock_irqsave(&circularQ->iq_lock, flags);
134062306a36Sopenharmony_ci	rv = pm8001_mpi_msg_free_get(circularQ, pm8001_ha->iomb_size,
134162306a36Sopenharmony_ci			&pMessage);
134262306a36Sopenharmony_ci	if (rv < 0) {
134362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "No free mpi buffer\n");
134462306a36Sopenharmony_ci		rv = -ENOMEM;
134562306a36Sopenharmony_ci		goto done;
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	if (nb > (pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr)))
134962306a36Sopenharmony_ci		nb = pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr);
135062306a36Sopenharmony_ci	memcpy(pMessage, payload, nb);
135162306a36Sopenharmony_ci	if (nb + sizeof(struct mpi_msg_hdr) < pm8001_ha->iomb_size)
135262306a36Sopenharmony_ci		memset(pMessage + nb, 0, pm8001_ha->iomb_size -
135362306a36Sopenharmony_ci				(nb + sizeof(struct mpi_msg_hdr)));
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_ci	/*Build the header*/
135662306a36Sopenharmony_ci	Header = ((1 << 31) | (hpriority << 30) | ((bc & 0x1f) << 24)
135762306a36Sopenharmony_ci		| ((responseQueue & 0x3F) << 16)
135862306a36Sopenharmony_ci		| ((category & 0xF) << 12) | (opCode & 0xFFF));
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	pm8001_write_32((pMessage - 4), 0, cpu_to_le32(Header));
136162306a36Sopenharmony_ci	/*Update the PI to the firmware*/
136262306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, circularQ->pi_pci_bar,
136362306a36Sopenharmony_ci		circularQ->pi_offset, circularQ->producer_idx);
136462306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, DEVIO,
136562306a36Sopenharmony_ci		   "INB Q %x OPCODE:%x , UPDATED PI=%d CI=%d\n",
136662306a36Sopenharmony_ci		   responseQueue, opCode, circularQ->producer_idx,
136762306a36Sopenharmony_ci		   circularQ->consumer_index);
136862306a36Sopenharmony_cidone:
136962306a36Sopenharmony_ci	spin_unlock_irqrestore(&circularQ->iq_lock, flags);
137062306a36Sopenharmony_ci	return rv;
137162306a36Sopenharmony_ci}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ciu32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg,
137462306a36Sopenharmony_ci			    struct outbound_queue_table *circularQ, u8 bc)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	u32 producer_index;
137762306a36Sopenharmony_ci	struct mpi_msg_hdr *msgHeader;
137862306a36Sopenharmony_ci	struct mpi_msg_hdr *pOutBoundMsgHeader;
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	msgHeader = (struct mpi_msg_hdr *)(pMsg - sizeof(struct mpi_msg_hdr));
138162306a36Sopenharmony_ci	pOutBoundMsgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt +
138262306a36Sopenharmony_ci				circularQ->consumer_idx * pm8001_ha->iomb_size);
138362306a36Sopenharmony_ci	if (pOutBoundMsgHeader != msgHeader) {
138462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL,
138562306a36Sopenharmony_ci			   "consumer_idx = %d msgHeader = %p\n",
138662306a36Sopenharmony_ci			   circularQ->consumer_idx, msgHeader);
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_ci		/* Update the producer index from SPC */
138962306a36Sopenharmony_ci		producer_index = pm8001_read_32(circularQ->pi_virt);
139062306a36Sopenharmony_ci		circularQ->producer_index = cpu_to_le32(producer_index);
139162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL,
139262306a36Sopenharmony_ci			   "consumer_idx = %d producer_index = %dmsgHeader = %p\n",
139362306a36Sopenharmony_ci			   circularQ->consumer_idx,
139462306a36Sopenharmony_ci			   circularQ->producer_index, msgHeader);
139562306a36Sopenharmony_ci		return 0;
139662306a36Sopenharmony_ci	}
139762306a36Sopenharmony_ci	/* free the circular queue buffer elements associated with the message*/
139862306a36Sopenharmony_ci	circularQ->consumer_idx = (circularQ->consumer_idx + bc)
139962306a36Sopenharmony_ci				% PM8001_MPI_QUEUE;
140062306a36Sopenharmony_ci	/* update the CI of outbound queue */
140162306a36Sopenharmony_ci	pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, circularQ->ci_offset,
140262306a36Sopenharmony_ci		circularQ->consumer_idx);
140362306a36Sopenharmony_ci	/* Update the producer index from SPC*/
140462306a36Sopenharmony_ci	producer_index = pm8001_read_32(circularQ->pi_virt);
140562306a36Sopenharmony_ci	circularQ->producer_index = cpu_to_le32(producer_index);
140662306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, IO, " CI=%d PI=%d\n",
140762306a36Sopenharmony_ci		   circularQ->consumer_idx, circularQ->producer_index);
140862306a36Sopenharmony_ci	return 0;
140962306a36Sopenharmony_ci}
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci/**
141262306a36Sopenharmony_ci * pm8001_mpi_msg_consume- get the MPI message from outbound queue
141362306a36Sopenharmony_ci * message table.
141462306a36Sopenharmony_ci * @pm8001_ha: our hba card information
141562306a36Sopenharmony_ci * @circularQ: the outbound queue  table.
141662306a36Sopenharmony_ci * @messagePtr1: the message contents of this outbound message.
141762306a36Sopenharmony_ci * @pBC: the message size.
141862306a36Sopenharmony_ci */
141962306a36Sopenharmony_ciu32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
142062306a36Sopenharmony_ci			   struct outbound_queue_table *circularQ,
142162306a36Sopenharmony_ci			   void **messagePtr1, u8 *pBC)
142262306a36Sopenharmony_ci{
142362306a36Sopenharmony_ci	struct mpi_msg_hdr	*msgHeader;
142462306a36Sopenharmony_ci	__le32	msgHeader_tmp;
142562306a36Sopenharmony_ci	u32 header_tmp;
142662306a36Sopenharmony_ci	do {
142762306a36Sopenharmony_ci		/* If there are not-yet-delivered messages ... */
142862306a36Sopenharmony_ci		if (le32_to_cpu(circularQ->producer_index)
142962306a36Sopenharmony_ci			!= circularQ->consumer_idx) {
143062306a36Sopenharmony_ci			/*Get the pointer to the circular queue buffer element*/
143162306a36Sopenharmony_ci			msgHeader = (struct mpi_msg_hdr *)
143262306a36Sopenharmony_ci				(circularQ->base_virt +
143362306a36Sopenharmony_ci				circularQ->consumer_idx * pm8001_ha->iomb_size);
143462306a36Sopenharmony_ci			/* read header */
143562306a36Sopenharmony_ci			header_tmp = pm8001_read_32(msgHeader);
143662306a36Sopenharmony_ci			msgHeader_tmp = cpu_to_le32(header_tmp);
143762306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, DEVIO,
143862306a36Sopenharmony_ci				   "outbound opcode msgheader:%x ci=%d pi=%d\n",
143962306a36Sopenharmony_ci				   msgHeader_tmp, circularQ->consumer_idx,
144062306a36Sopenharmony_ci				   circularQ->producer_index);
144162306a36Sopenharmony_ci			if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) {
144262306a36Sopenharmony_ci				if (OPC_OUB_SKIP_ENTRY !=
144362306a36Sopenharmony_ci					(le32_to_cpu(msgHeader_tmp) & 0xfff)) {
144462306a36Sopenharmony_ci					*messagePtr1 =
144562306a36Sopenharmony_ci						((u8 *)msgHeader) +
144662306a36Sopenharmony_ci						sizeof(struct mpi_msg_hdr);
144762306a36Sopenharmony_ci					*pBC = (u8)((le32_to_cpu(msgHeader_tmp)
144862306a36Sopenharmony_ci						>> 24) & 0x1f);
144962306a36Sopenharmony_ci					pm8001_dbg(pm8001_ha, IO,
145062306a36Sopenharmony_ci						   ": CI=%d PI=%d msgHeader=%x\n",
145162306a36Sopenharmony_ci						   circularQ->consumer_idx,
145262306a36Sopenharmony_ci						   circularQ->producer_index,
145362306a36Sopenharmony_ci						   msgHeader_tmp);
145462306a36Sopenharmony_ci					return MPI_IO_STATUS_SUCCESS;
145562306a36Sopenharmony_ci				} else {
145662306a36Sopenharmony_ci					circularQ->consumer_idx =
145762306a36Sopenharmony_ci						(circularQ->consumer_idx +
145862306a36Sopenharmony_ci						((le32_to_cpu(msgHeader_tmp)
145962306a36Sopenharmony_ci						 >> 24) & 0x1f))
146062306a36Sopenharmony_ci							% PM8001_MPI_QUEUE;
146162306a36Sopenharmony_ci					msgHeader_tmp = 0;
146262306a36Sopenharmony_ci					pm8001_write_32(msgHeader, 0, 0);
146362306a36Sopenharmony_ci					/* update the CI of outbound queue */
146462306a36Sopenharmony_ci					pm8001_cw32(pm8001_ha,
146562306a36Sopenharmony_ci						circularQ->ci_pci_bar,
146662306a36Sopenharmony_ci						circularQ->ci_offset,
146762306a36Sopenharmony_ci						circularQ->consumer_idx);
146862306a36Sopenharmony_ci				}
146962306a36Sopenharmony_ci			} else {
147062306a36Sopenharmony_ci				circularQ->consumer_idx =
147162306a36Sopenharmony_ci					(circularQ->consumer_idx +
147262306a36Sopenharmony_ci					((le32_to_cpu(msgHeader_tmp) >> 24) &
147362306a36Sopenharmony_ci					0x1f)) % PM8001_MPI_QUEUE;
147462306a36Sopenharmony_ci				msgHeader_tmp = 0;
147562306a36Sopenharmony_ci				pm8001_write_32(msgHeader, 0, 0);
147662306a36Sopenharmony_ci				/* update the CI of outbound queue */
147762306a36Sopenharmony_ci				pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar,
147862306a36Sopenharmony_ci					circularQ->ci_offset,
147962306a36Sopenharmony_ci					circularQ->consumer_idx);
148062306a36Sopenharmony_ci				return MPI_IO_STATUS_FAIL;
148162306a36Sopenharmony_ci			}
148262306a36Sopenharmony_ci		} else {
148362306a36Sopenharmony_ci			u32 producer_index;
148462306a36Sopenharmony_ci			void *pi_virt = circularQ->pi_virt;
148562306a36Sopenharmony_ci			/* spurious interrupt during setup if
148662306a36Sopenharmony_ci			 * kexec-ing and driver doing a doorbell access
148762306a36Sopenharmony_ci			 * with the pre-kexec oq interrupt setup
148862306a36Sopenharmony_ci			 */
148962306a36Sopenharmony_ci			if (!pi_virt)
149062306a36Sopenharmony_ci				break;
149162306a36Sopenharmony_ci			/* Update the producer index from SPC */
149262306a36Sopenharmony_ci			producer_index = pm8001_read_32(pi_virt);
149362306a36Sopenharmony_ci			circularQ->producer_index = cpu_to_le32(producer_index);
149462306a36Sopenharmony_ci		}
149562306a36Sopenharmony_ci	} while (le32_to_cpu(circularQ->producer_index) !=
149662306a36Sopenharmony_ci		circularQ->consumer_idx);
149762306a36Sopenharmony_ci	/* while we don't have any more not-yet-delivered message */
149862306a36Sopenharmony_ci	/* report empty */
149962306a36Sopenharmony_ci	return MPI_IO_STATUS_BUSY;
150062306a36Sopenharmony_ci}
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_civoid pm8001_work_fn(struct work_struct *work)
150362306a36Sopenharmony_ci{
150462306a36Sopenharmony_ci	struct pm8001_work *pw = container_of(work, struct pm8001_work, work);
150562306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
150662306a36Sopenharmony_ci	struct domain_device *dev;
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	/*
150962306a36Sopenharmony_ci	 * So far, all users of this stash an associated structure here.
151062306a36Sopenharmony_ci	 * If we get here, and this pointer is null, then the action
151162306a36Sopenharmony_ci	 * was cancelled. This nullification happens when the device
151262306a36Sopenharmony_ci	 * goes away.
151362306a36Sopenharmony_ci	 */
151462306a36Sopenharmony_ci	if (pw->handler != IO_FATAL_ERROR) {
151562306a36Sopenharmony_ci		pm8001_dev = pw->data; /* Most stash device structure */
151662306a36Sopenharmony_ci		if ((pm8001_dev == NULL)
151762306a36Sopenharmony_ci		 || ((pw->handler != IO_XFER_ERROR_BREAK)
151862306a36Sopenharmony_ci			 && (pm8001_dev->dev_type == SAS_PHY_UNUSED))) {
151962306a36Sopenharmony_ci			kfree(pw);
152062306a36Sopenharmony_ci			return;
152162306a36Sopenharmony_ci		}
152262306a36Sopenharmony_ci	}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	switch (pw->handler) {
152562306a36Sopenharmony_ci	case IO_XFER_ERROR_BREAK:
152662306a36Sopenharmony_ci	{	/* This one stashes the sas_task instead */
152762306a36Sopenharmony_ci		struct sas_task *t = (struct sas_task *)pm8001_dev;
152862306a36Sopenharmony_ci		struct pm8001_ccb_info *ccb;
152962306a36Sopenharmony_ci		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
153062306a36Sopenharmony_ci		unsigned long flags, flags1;
153162306a36Sopenharmony_ci		struct task_status_struct *ts;
153262306a36Sopenharmony_ci		int i;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci		if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
153562306a36Sopenharmony_ci			break; /* Task still on lu */
153662306a36Sopenharmony_ci		spin_lock_irqsave(&pm8001_ha->lock, flags);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci		spin_lock_irqsave(&t->task_state_lock, flags1);
153962306a36Sopenharmony_ci		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
154062306a36Sopenharmony_ci			spin_unlock_irqrestore(&t->task_state_lock, flags1);
154162306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
154262306a36Sopenharmony_ci			break; /* Task got completed by another */
154362306a36Sopenharmony_ci		}
154462306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags1);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci		/* Search for a possible ccb that matches the task */
154762306a36Sopenharmony_ci		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
154862306a36Sopenharmony_ci			ccb = &pm8001_ha->ccb_info[i];
154962306a36Sopenharmony_ci			if ((ccb->ccb_tag != PM8001_INVALID_TAG) &&
155062306a36Sopenharmony_ci			    (ccb->task == t))
155162306a36Sopenharmony_ci				break;
155262306a36Sopenharmony_ci		}
155362306a36Sopenharmony_ci		if (!ccb) {
155462306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
155562306a36Sopenharmony_ci			break; /* Task got freed by another */
155662306a36Sopenharmony_ci		}
155762306a36Sopenharmony_ci		ts = &t->task_status;
155862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
155962306a36Sopenharmony_ci		/* Force the midlayer to retry */
156062306a36Sopenharmony_ci		ts->stat = SAS_QUEUE_FULL;
156162306a36Sopenharmony_ci		pm8001_dev = ccb->device;
156262306a36Sopenharmony_ci		if (pm8001_dev)
156362306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
156462306a36Sopenharmony_ci		spin_lock_irqsave(&t->task_state_lock, flags1);
156562306a36Sopenharmony_ci		t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
156662306a36Sopenharmony_ci		t->task_state_flags |= SAS_TASK_STATE_DONE;
156762306a36Sopenharmony_ci		if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
156862306a36Sopenharmony_ci			spin_unlock_irqrestore(&t->task_state_lock, flags1);
156962306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
157062306a36Sopenharmony_ci				   t, pw->handler, ts->resp, ts->stat);
157162306a36Sopenharmony_ci			pm8001_ccb_task_free(pm8001_ha, ccb);
157262306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
157362306a36Sopenharmony_ci		} else {
157462306a36Sopenharmony_ci			spin_unlock_irqrestore(&t->task_state_lock, flags1);
157562306a36Sopenharmony_ci			pm8001_ccb_task_free(pm8001_ha, ccb);
157662306a36Sopenharmony_ci			mb();/* in order to force CPU ordering */
157762306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
157862306a36Sopenharmony_ci			t->task_done(t);
157962306a36Sopenharmony_ci		}
158062306a36Sopenharmony_ci	}	break;
158162306a36Sopenharmony_ci	case IO_XFER_OPEN_RETRY_TIMEOUT:
158262306a36Sopenharmony_ci	{	/* This one stashes the sas_task instead */
158362306a36Sopenharmony_ci		struct sas_task *t = (struct sas_task *)pm8001_dev;
158462306a36Sopenharmony_ci		struct pm8001_ccb_info *ccb;
158562306a36Sopenharmony_ci		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
158662306a36Sopenharmony_ci		unsigned long flags, flags1;
158762306a36Sopenharmony_ci		int i, ret = 0;
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci		ret = pm8001_query_task(t);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci		if (ret == TMF_RESP_FUNC_SUCC)
159462306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, IO, "...Task on lu\n");
159562306a36Sopenharmony_ci		else if (ret == TMF_RESP_FUNC_COMPLETE)
159662306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, IO, "...Task NOT on lu\n");
159762306a36Sopenharmony_ci		else
159862306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, DEVIO, "...query task failed!!!\n");
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci		spin_lock_irqsave(&pm8001_ha->lock, flags);
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci		spin_lock_irqsave(&t->task_state_lock, flags1);
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
160562306a36Sopenharmony_ci			spin_unlock_irqrestore(&t->task_state_lock, flags1);
160662306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
160762306a36Sopenharmony_ci			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
160862306a36Sopenharmony_ci				(void)pm8001_abort_task(t);
160962306a36Sopenharmony_ci			break; /* Task got completed by another */
161062306a36Sopenharmony_ci		}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags1);
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci		/* Search for a possible ccb that matches the task */
161562306a36Sopenharmony_ci		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
161662306a36Sopenharmony_ci			ccb = &pm8001_ha->ccb_info[i];
161762306a36Sopenharmony_ci			if ((ccb->ccb_tag != PM8001_INVALID_TAG) &&
161862306a36Sopenharmony_ci			    (ccb->task == t))
161962306a36Sopenharmony_ci				break;
162062306a36Sopenharmony_ci		}
162162306a36Sopenharmony_ci		if (!ccb) {
162262306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
162362306a36Sopenharmony_ci			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
162462306a36Sopenharmony_ci				(void)pm8001_abort_task(t);
162562306a36Sopenharmony_ci			break; /* Task got freed by another */
162662306a36Sopenharmony_ci		}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci		pm8001_dev = ccb->device;
162962306a36Sopenharmony_ci		dev = pm8001_dev->sas_device;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci		switch (ret) {
163262306a36Sopenharmony_ci		case TMF_RESP_FUNC_SUCC: /* task on lu */
163362306a36Sopenharmony_ci			ccb->open_retry = 1; /* Snub completion */
163462306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
163562306a36Sopenharmony_ci			ret = pm8001_abort_task(t);
163662306a36Sopenharmony_ci			ccb->open_retry = 0;
163762306a36Sopenharmony_ci			switch (ret) {
163862306a36Sopenharmony_ci			case TMF_RESP_FUNC_SUCC:
163962306a36Sopenharmony_ci			case TMF_RESP_FUNC_COMPLETE:
164062306a36Sopenharmony_ci				break;
164162306a36Sopenharmony_ci			default: /* device misbehavior */
164262306a36Sopenharmony_ci				ret = TMF_RESP_FUNC_FAILED;
164362306a36Sopenharmony_ci				pm8001_dbg(pm8001_ha, IO, "...Reset phy\n");
164462306a36Sopenharmony_ci				pm8001_I_T_nexus_reset(dev);
164562306a36Sopenharmony_ci				break;
164662306a36Sopenharmony_ci			}
164762306a36Sopenharmony_ci			break;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci		case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
165062306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
165162306a36Sopenharmony_ci			/* Do we need to abort the task locally? */
165262306a36Sopenharmony_ci			break;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci		default: /* device misbehavior */
165562306a36Sopenharmony_ci			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
165662306a36Sopenharmony_ci			ret = TMF_RESP_FUNC_FAILED;
165762306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, IO, "...Reset phy\n");
165862306a36Sopenharmony_ci			pm8001_I_T_nexus_reset(dev);
165962306a36Sopenharmony_ci		}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ci		if (ret == TMF_RESP_FUNC_FAILED)
166262306a36Sopenharmony_ci			t = NULL;
166362306a36Sopenharmony_ci		pm8001_open_reject_retry(pm8001_ha, t, pm8001_dev);
166462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "...Complete\n");
166562306a36Sopenharmony_ci	}	break;
166662306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
166762306a36Sopenharmony_ci		dev = pm8001_dev->sas_device;
166862306a36Sopenharmony_ci		pm8001_I_T_nexus_event_handler(dev);
166962306a36Sopenharmony_ci		break;
167062306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
167162306a36Sopenharmony_ci		dev = pm8001_dev->sas_device;
167262306a36Sopenharmony_ci		pm8001_I_T_nexus_reset(dev);
167362306a36Sopenharmony_ci		break;
167462306a36Sopenharmony_ci	case IO_DS_IN_ERROR:
167562306a36Sopenharmony_ci		dev = pm8001_dev->sas_device;
167662306a36Sopenharmony_ci		pm8001_I_T_nexus_reset(dev);
167762306a36Sopenharmony_ci		break;
167862306a36Sopenharmony_ci	case IO_DS_NON_OPERATIONAL:
167962306a36Sopenharmony_ci		dev = pm8001_dev->sas_device;
168062306a36Sopenharmony_ci		pm8001_I_T_nexus_reset(dev);
168162306a36Sopenharmony_ci		break;
168262306a36Sopenharmony_ci	case IO_FATAL_ERROR:
168362306a36Sopenharmony_ci	{
168462306a36Sopenharmony_ci		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
168562306a36Sopenharmony_ci		struct pm8001_ccb_info *ccb;
168662306a36Sopenharmony_ci		struct task_status_struct *ts;
168762306a36Sopenharmony_ci		struct sas_task *task;
168862306a36Sopenharmony_ci		int i;
168962306a36Sopenharmony_ci		u32 device_id;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
169262306a36Sopenharmony_ci			ccb = &pm8001_ha->ccb_info[i];
169362306a36Sopenharmony_ci			task = ccb->task;
169462306a36Sopenharmony_ci			ts = &task->task_status;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci			if (task != NULL) {
169762306a36Sopenharmony_ci				dev = task->dev;
169862306a36Sopenharmony_ci				if (!dev) {
169962306a36Sopenharmony_ci					pm8001_dbg(pm8001_ha, FAIL,
170062306a36Sopenharmony_ci						"dev is NULL\n");
170162306a36Sopenharmony_ci					continue;
170262306a36Sopenharmony_ci				}
170362306a36Sopenharmony_ci				/*complete sas task and update to top layer */
170462306a36Sopenharmony_ci				pm8001_ccb_task_free(pm8001_ha, ccb);
170562306a36Sopenharmony_ci				ts->resp = SAS_TASK_COMPLETE;
170662306a36Sopenharmony_ci				task->task_done(task);
170762306a36Sopenharmony_ci			} else if (ccb->ccb_tag != PM8001_INVALID_TAG) {
170862306a36Sopenharmony_ci				/* complete the internal commands/non-sas task */
170962306a36Sopenharmony_ci				pm8001_dev = ccb->device;
171062306a36Sopenharmony_ci				if (pm8001_dev->dcompletion) {
171162306a36Sopenharmony_ci					complete(pm8001_dev->dcompletion);
171262306a36Sopenharmony_ci					pm8001_dev->dcompletion = NULL;
171362306a36Sopenharmony_ci				}
171462306a36Sopenharmony_ci				complete(pm8001_ha->nvmd_completion);
171562306a36Sopenharmony_ci				pm8001_ccb_free(pm8001_ha, ccb);
171662306a36Sopenharmony_ci			}
171762306a36Sopenharmony_ci		}
171862306a36Sopenharmony_ci		/* Deregister all the device ids  */
171962306a36Sopenharmony_ci		for (i = 0; i < PM8001_MAX_DEVICES; i++) {
172062306a36Sopenharmony_ci			pm8001_dev = &pm8001_ha->devices[i];
172162306a36Sopenharmony_ci			device_id = pm8001_dev->device_id;
172262306a36Sopenharmony_ci			if (device_id) {
172362306a36Sopenharmony_ci				PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
172462306a36Sopenharmony_ci				pm8001_free_dev(pm8001_dev);
172562306a36Sopenharmony_ci			}
172662306a36Sopenharmony_ci		}
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci	break;
172962306a36Sopenharmony_ci	case IO_XFER_ERROR_ABORTED_NCQ_MODE:
173062306a36Sopenharmony_ci	{
173162306a36Sopenharmony_ci		dev = pm8001_dev->sas_device;
173262306a36Sopenharmony_ci		sas_ata_device_link_abort(dev, false);
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci	break;
173562306a36Sopenharmony_ci	}
173662306a36Sopenharmony_ci	kfree(pw);
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ciint pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data,
174062306a36Sopenharmony_ci			       int handler)
174162306a36Sopenharmony_ci{
174262306a36Sopenharmony_ci	struct pm8001_work *pw;
174362306a36Sopenharmony_ci	int ret = 0;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC);
174662306a36Sopenharmony_ci	if (pw) {
174762306a36Sopenharmony_ci		pw->pm8001_ha = pm8001_ha;
174862306a36Sopenharmony_ci		pw->data = data;
174962306a36Sopenharmony_ci		pw->handler = handler;
175062306a36Sopenharmony_ci		INIT_WORK(&pw->work, pm8001_work_fn);
175162306a36Sopenharmony_ci		queue_work(pm8001_wq, &pw->work);
175262306a36Sopenharmony_ci	} else
175362306a36Sopenharmony_ci		ret = -ENOMEM;
175462306a36Sopenharmony_ci
175562306a36Sopenharmony_ci	return ret;
175662306a36Sopenharmony_ci}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci/**
175962306a36Sopenharmony_ci * mpi_ssp_completion- process the event that FW response to the SSP request.
176062306a36Sopenharmony_ci * @pm8001_ha: our hba card information
176162306a36Sopenharmony_ci * @piomb: the message contents of this outbound message.
176262306a36Sopenharmony_ci *
176362306a36Sopenharmony_ci * When FW has completed a ssp request for example a IO request, after it has
176462306a36Sopenharmony_ci * filled the SG data with the data, it will trigger this event representing
176562306a36Sopenharmony_ci * that he has finished the job; please check the corresponding buffer.
176662306a36Sopenharmony_ci * So we will tell the caller who maybe waiting the result to tell upper layer
176762306a36Sopenharmony_ci * that the task has been finished.
176862306a36Sopenharmony_ci */
176962306a36Sopenharmony_cistatic void
177062306a36Sopenharmony_cimpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
177162306a36Sopenharmony_ci{
177262306a36Sopenharmony_ci	struct sas_task *t;
177362306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
177462306a36Sopenharmony_ci	unsigned long flags;
177562306a36Sopenharmony_ci	u32 status;
177662306a36Sopenharmony_ci	u32 param;
177762306a36Sopenharmony_ci	u32 tag;
177862306a36Sopenharmony_ci	struct ssp_completion_resp *psspPayload;
177962306a36Sopenharmony_ci	struct task_status_struct *ts;
178062306a36Sopenharmony_ci	struct ssp_response_iu *iu;
178162306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
178262306a36Sopenharmony_ci	psspPayload = (struct ssp_completion_resp *)(piomb + 4);
178362306a36Sopenharmony_ci	status = le32_to_cpu(psspPayload->status);
178462306a36Sopenharmony_ci	tag = le32_to_cpu(psspPayload->tag);
178562306a36Sopenharmony_ci	ccb = &pm8001_ha->ccb_info[tag];
178662306a36Sopenharmony_ci	if ((status == IO_ABORTED) && ccb->open_retry) {
178762306a36Sopenharmony_ci		/* Being completed by another */
178862306a36Sopenharmony_ci		ccb->open_retry = 0;
178962306a36Sopenharmony_ci		return;
179062306a36Sopenharmony_ci	}
179162306a36Sopenharmony_ci	pm8001_dev = ccb->device;
179262306a36Sopenharmony_ci	param = le32_to_cpu(psspPayload->param);
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	t = ccb->task;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	if (status && status != IO_UNDERFLOW)
179762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", status);
179862306a36Sopenharmony_ci	if (unlikely(!t || !t->lldd_task || !t->dev))
179962306a36Sopenharmony_ci		return;
180062306a36Sopenharmony_ci	ts = &t->task_status;
180162306a36Sopenharmony_ci	/* Print sas address of IO failed device */
180262306a36Sopenharmony_ci	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
180362306a36Sopenharmony_ci		(status != IO_UNDERFLOW))
180462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "SAS Address of IO Failure Drive:%016llx\n",
180562306a36Sopenharmony_ci			   SAS_ADDR(t->dev->sas_addr));
180662306a36Sopenharmony_ci
180762306a36Sopenharmony_ci	if (status)
180862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IOERR,
180962306a36Sopenharmony_ci			   "status:0x%x, tag:0x%x, task:0x%p\n",
181062306a36Sopenharmony_ci			   status, tag, t);
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	switch (status) {
181362306a36Sopenharmony_ci	case IO_SUCCESS:
181462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS,param = %d\n",
181562306a36Sopenharmony_ci			   param);
181662306a36Sopenharmony_ci		if (param == 0) {
181762306a36Sopenharmony_ci			ts->resp = SAS_TASK_COMPLETE;
181862306a36Sopenharmony_ci			ts->stat = SAS_SAM_STAT_GOOD;
181962306a36Sopenharmony_ci		} else {
182062306a36Sopenharmony_ci			ts->resp = SAS_TASK_COMPLETE;
182162306a36Sopenharmony_ci			ts->stat = SAS_PROTO_RESPONSE;
182262306a36Sopenharmony_ci			ts->residual = param;
182362306a36Sopenharmony_ci			iu = &psspPayload->ssp_resp_iu;
182462306a36Sopenharmony_ci			sas_ssp_task_response(pm8001_ha->dev, t, iu);
182562306a36Sopenharmony_ci		}
182662306a36Sopenharmony_ci		if (pm8001_dev)
182762306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
182862306a36Sopenharmony_ci		break;
182962306a36Sopenharmony_ci	case IO_ABORTED:
183062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n");
183162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
183262306a36Sopenharmony_ci		ts->stat = SAS_ABORTED_TASK;
183362306a36Sopenharmony_ci		break;
183462306a36Sopenharmony_ci	case IO_UNDERFLOW:
183562306a36Sopenharmony_ci		/* SSP Completion with error */
183662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW,param = %d\n",
183762306a36Sopenharmony_ci			   param);
183862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
183962306a36Sopenharmony_ci		ts->stat = SAS_DATA_UNDERRUN;
184062306a36Sopenharmony_ci		ts->residual = param;
184162306a36Sopenharmony_ci		if (pm8001_dev)
184262306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
184362306a36Sopenharmony_ci		break;
184462306a36Sopenharmony_ci	case IO_NO_DEVICE:
184562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
184662306a36Sopenharmony_ci		ts->resp = SAS_TASK_UNDELIVERED;
184762306a36Sopenharmony_ci		ts->stat = SAS_PHY_DOWN;
184862306a36Sopenharmony_ci		break;
184962306a36Sopenharmony_ci	case IO_XFER_ERROR_BREAK:
185062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
185162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
185262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
185362306a36Sopenharmony_ci		/* Force the midlayer to retry */
185462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
185562306a36Sopenharmony_ci		break;
185662306a36Sopenharmony_ci	case IO_XFER_ERROR_PHY_NOT_READY:
185762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
185862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
185962306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
186062306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
186162306a36Sopenharmony_ci		break;
186262306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
186362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
186462306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
186562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
186662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
186762306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_EPROTO;
186862306a36Sopenharmony_ci		break;
186962306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
187062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
187162306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
187262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
187362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
187462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
187562306a36Sopenharmony_ci		break;
187662306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BREAK:
187762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
187862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
187962306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
188062306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
188162306a36Sopenharmony_ci		break;
188262306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
188362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
188462306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
188562306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
188662306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
188762306a36Sopenharmony_ci		if (!t->uldd_task)
188862306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
188962306a36Sopenharmony_ci				pm8001_dev,
189062306a36Sopenharmony_ci				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
189162306a36Sopenharmony_ci		break;
189262306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
189362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
189462306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
189562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
189662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
189762306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
189862306a36Sopenharmony_ci		break;
189962306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
190062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
190162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
190262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
190362306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
190462306a36Sopenharmony_ci		break;
190562306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
190662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
190762306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
190862306a36Sopenharmony_ci		ts->resp = SAS_TASK_UNDELIVERED;
190962306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
191062306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
191162306a36Sopenharmony_ci		break;
191262306a36Sopenharmony_ci	case IO_XFER_ERROR_NAK_RECEIVED:
191362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
191462306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
191562306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
191662306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
191762306a36Sopenharmony_ci		break;
191862306a36Sopenharmony_ci	case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
191962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
192062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
192162306a36Sopenharmony_ci		ts->stat = SAS_NAK_R_ERR;
192262306a36Sopenharmony_ci		break;
192362306a36Sopenharmony_ci	case IO_XFER_ERROR_DMA:
192462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n");
192562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
192662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
192762306a36Sopenharmony_ci		break;
192862306a36Sopenharmony_ci	case IO_XFER_OPEN_RETRY_TIMEOUT:
192962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
193062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
193162306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
193262306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
193362306a36Sopenharmony_ci		break;
193462306a36Sopenharmony_ci	case IO_XFER_ERROR_OFFSET_MISMATCH:
193562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
193662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
193762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
193862306a36Sopenharmony_ci		break;
193962306a36Sopenharmony_ci	case IO_PORT_IN_RESET:
194062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
194162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
194262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
194362306a36Sopenharmony_ci		break;
194462306a36Sopenharmony_ci	case IO_DS_NON_OPERATIONAL:
194562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
194662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
194762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
194862306a36Sopenharmony_ci		if (!t->uldd_task)
194962306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
195062306a36Sopenharmony_ci				pm8001_dev,
195162306a36Sopenharmony_ci				IO_DS_NON_OPERATIONAL);
195262306a36Sopenharmony_ci		break;
195362306a36Sopenharmony_ci	case IO_DS_IN_RECOVERY:
195462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n");
195562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
195662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
195762306a36Sopenharmony_ci		break;
195862306a36Sopenharmony_ci	case IO_TM_TAG_NOT_FOUND:
195962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_TM_TAG_NOT_FOUND\n");
196062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
196162306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
196262306a36Sopenharmony_ci		break;
196362306a36Sopenharmony_ci	case IO_SSP_EXT_IU_ZERO_LEN_ERROR:
196462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_SSP_EXT_IU_ZERO_LEN_ERROR\n");
196562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
196662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
196762306a36Sopenharmony_ci		break;
196862306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
196962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
197062306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
197162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
197262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
197362306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
197462306a36Sopenharmony_ci		break;
197562306a36Sopenharmony_ci	default:
197662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
197762306a36Sopenharmony_ci		/* not allowed case. Therefore, return failed status */
197862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
197962306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
198062306a36Sopenharmony_ci		break;
198162306a36Sopenharmony_ci	}
198262306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, IO, "scsi_status = %x\n",
198362306a36Sopenharmony_ci		   psspPayload->ssp_resp_iu.status);
198462306a36Sopenharmony_ci	spin_lock_irqsave(&t->task_state_lock, flags);
198562306a36Sopenharmony_ci	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
198662306a36Sopenharmony_ci	t->task_state_flags |= SAS_TASK_STATE_DONE;
198762306a36Sopenharmony_ci	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
198862306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
198962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
199062306a36Sopenharmony_ci			   t, status, ts->resp, ts->stat);
199162306a36Sopenharmony_ci		pm8001_ccb_task_free(pm8001_ha, ccb);
199262306a36Sopenharmony_ci	} else {
199362306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
199462306a36Sopenharmony_ci		pm8001_ccb_task_free(pm8001_ha, ccb);
199562306a36Sopenharmony_ci		mb();/* in order to force CPU ordering */
199662306a36Sopenharmony_ci		t->task_done(t);
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci/*See the comments for mpi_ssp_completion */
200162306a36Sopenharmony_cistatic void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
200262306a36Sopenharmony_ci{
200362306a36Sopenharmony_ci	struct sas_task *t;
200462306a36Sopenharmony_ci	unsigned long flags;
200562306a36Sopenharmony_ci	struct task_status_struct *ts;
200662306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
200762306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
200862306a36Sopenharmony_ci	struct ssp_event_resp *psspPayload =
200962306a36Sopenharmony_ci		(struct ssp_event_resp *)(piomb + 4);
201062306a36Sopenharmony_ci	u32 event = le32_to_cpu(psspPayload->event);
201162306a36Sopenharmony_ci	u32 tag = le32_to_cpu(psspPayload->tag);
201262306a36Sopenharmony_ci	u32 port_id = le32_to_cpu(psspPayload->port_id);
201362306a36Sopenharmony_ci	u32 dev_id = le32_to_cpu(psspPayload->device_id);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	ccb = &pm8001_ha->ccb_info[tag];
201662306a36Sopenharmony_ci	t = ccb->task;
201762306a36Sopenharmony_ci	pm8001_dev = ccb->device;
201862306a36Sopenharmony_ci	if (event)
201962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", event);
202062306a36Sopenharmony_ci	if (unlikely(!t || !t->lldd_task || !t->dev))
202162306a36Sopenharmony_ci		return;
202262306a36Sopenharmony_ci	ts = &t->task_status;
202362306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, DEVIO, "port_id = %x,device_id = %x\n",
202462306a36Sopenharmony_ci		   port_id, dev_id);
202562306a36Sopenharmony_ci	switch (event) {
202662306a36Sopenharmony_ci	case IO_OVERFLOW:
202762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
202862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
202962306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
203062306a36Sopenharmony_ci		ts->residual = 0;
203162306a36Sopenharmony_ci		if (pm8001_dev)
203262306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
203362306a36Sopenharmony_ci		break;
203462306a36Sopenharmony_ci	case IO_XFER_ERROR_BREAK:
203562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
203662306a36Sopenharmony_ci		pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK);
203762306a36Sopenharmony_ci		return;
203862306a36Sopenharmony_ci	case IO_XFER_ERROR_PHY_NOT_READY:
203962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
204062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
204162306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
204262306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
204362306a36Sopenharmony_ci		break;
204462306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
204562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
204662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
204762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
204862306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_EPROTO;
204962306a36Sopenharmony_ci		break;
205062306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
205162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
205262306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
205362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
205462306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
205562306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
205662306a36Sopenharmony_ci		break;
205762306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BREAK:
205862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
205962306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
206062306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
206162306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
206262306a36Sopenharmony_ci		break;
206362306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
206462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
206562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
206662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
206762306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
206862306a36Sopenharmony_ci		if (!t->uldd_task)
206962306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
207062306a36Sopenharmony_ci				pm8001_dev,
207162306a36Sopenharmony_ci				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
207262306a36Sopenharmony_ci		break;
207362306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
207462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
207562306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
207662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
207762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
207862306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
207962306a36Sopenharmony_ci		break;
208062306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
208162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
208262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
208362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
208462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
208562306a36Sopenharmony_ci		break;
208662306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
208762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
208862306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
208962306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
209062306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
209162306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
209262306a36Sopenharmony_ci		break;
209362306a36Sopenharmony_ci	case IO_XFER_ERROR_NAK_RECEIVED:
209462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
209562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
209662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
209762306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
209862306a36Sopenharmony_ci		break;
209962306a36Sopenharmony_ci	case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
210062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
210162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
210262306a36Sopenharmony_ci		ts->stat = SAS_NAK_R_ERR;
210362306a36Sopenharmony_ci		break;
210462306a36Sopenharmony_ci	case IO_XFER_OPEN_RETRY_TIMEOUT:
210562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
210662306a36Sopenharmony_ci		pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT);
210762306a36Sopenharmony_ci		return;
210862306a36Sopenharmony_ci	case IO_XFER_ERROR_UNEXPECTED_PHASE:
210962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n");
211062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
211162306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
211262306a36Sopenharmony_ci		break;
211362306a36Sopenharmony_ci	case IO_XFER_ERROR_XFER_RDY_OVERRUN:
211462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n");
211562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
211662306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
211762306a36Sopenharmony_ci		break;
211862306a36Sopenharmony_ci	case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
211962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
212062306a36Sopenharmony_ci			   "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n");
212162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
212262306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
212362306a36Sopenharmony_ci		break;
212462306a36Sopenharmony_ci	case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT:
212562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
212662306a36Sopenharmony_ci			   "IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n");
212762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
212862306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
212962306a36Sopenharmony_ci		break;
213062306a36Sopenharmony_ci	case IO_XFER_ERROR_OFFSET_MISMATCH:
213162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
213262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
213362306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
213462306a36Sopenharmony_ci		break;
213562306a36Sopenharmony_ci	case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
213662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
213762306a36Sopenharmony_ci			   "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n");
213862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
213962306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
214062306a36Sopenharmony_ci		break;
214162306a36Sopenharmony_ci	case IO_XFER_CMD_FRAME_ISSUED:
214262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n");
214362306a36Sopenharmony_ci		return;
214462306a36Sopenharmony_ci	default:
214562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event);
214662306a36Sopenharmony_ci		/* not allowed case. Therefore, return failed status */
214762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
214862306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
214962306a36Sopenharmony_ci		break;
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci	spin_lock_irqsave(&t->task_state_lock, flags);
215262306a36Sopenharmony_ci	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
215362306a36Sopenharmony_ci	t->task_state_flags |= SAS_TASK_STATE_DONE;
215462306a36Sopenharmony_ci	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
215562306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
215662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
215762306a36Sopenharmony_ci			   t, event, ts->resp, ts->stat);
215862306a36Sopenharmony_ci		pm8001_ccb_task_free(pm8001_ha, ccb);
215962306a36Sopenharmony_ci	} else {
216062306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
216162306a36Sopenharmony_ci		pm8001_ccb_task_free(pm8001_ha, ccb);
216262306a36Sopenharmony_ci		mb();/* in order to force CPU ordering */
216362306a36Sopenharmony_ci		t->task_done(t);
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci/*See the comments for mpi_ssp_completion */
216862306a36Sopenharmony_cistatic void
216962306a36Sopenharmony_cimpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
217062306a36Sopenharmony_ci{
217162306a36Sopenharmony_ci	struct sas_task *t;
217262306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
217362306a36Sopenharmony_ci	u32 param;
217462306a36Sopenharmony_ci	u32 status;
217562306a36Sopenharmony_ci	u32 tag;
217662306a36Sopenharmony_ci	int i, j;
217762306a36Sopenharmony_ci	u8 sata_addr_low[4];
217862306a36Sopenharmony_ci	u32 temp_sata_addr_low;
217962306a36Sopenharmony_ci	u8 sata_addr_hi[4];
218062306a36Sopenharmony_ci	u32 temp_sata_addr_hi;
218162306a36Sopenharmony_ci	struct sata_completion_resp *psataPayload;
218262306a36Sopenharmony_ci	struct task_status_struct *ts;
218362306a36Sopenharmony_ci	struct ata_task_resp *resp ;
218462306a36Sopenharmony_ci	u32 *sata_resp;
218562306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
218662306a36Sopenharmony_ci	unsigned long flags;
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	psataPayload = (struct sata_completion_resp *)(piomb + 4);
218962306a36Sopenharmony_ci	status = le32_to_cpu(psataPayload->status);
219062306a36Sopenharmony_ci	param = le32_to_cpu(psataPayload->param);
219162306a36Sopenharmony_ci	tag = le32_to_cpu(psataPayload->tag);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	ccb = &pm8001_ha->ccb_info[tag];
219462306a36Sopenharmony_ci	t = ccb->task;
219562306a36Sopenharmony_ci	pm8001_dev = ccb->device;
219662306a36Sopenharmony_ci
219762306a36Sopenharmony_ci	if (t) {
219862306a36Sopenharmony_ci		if (t->dev && (t->dev->lldd_dev))
219962306a36Sopenharmony_ci			pm8001_dev = t->dev->lldd_dev;
220062306a36Sopenharmony_ci	} else {
220162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n",
220262306a36Sopenharmony_ci			   ccb->ccb_tag);
220362306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
220462306a36Sopenharmony_ci		return;
220562306a36Sopenharmony_ci	}
220662306a36Sopenharmony_ci
220762306a36Sopenharmony_ci	if (pm8001_dev && unlikely(!t || !t->lldd_task || !t->dev)) {
220862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n");
220962306a36Sopenharmony_ci		return;
221062306a36Sopenharmony_ci	}
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci	ts = &t->task_status;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	if (status)
221562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IOERR,
221662306a36Sopenharmony_ci			   "status:0x%x, tag:0x%x, task::0x%p\n",
221762306a36Sopenharmony_ci			   status, tag, t);
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	/* Print sas address of IO failed device */
222062306a36Sopenharmony_ci	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
222162306a36Sopenharmony_ci		(status != IO_UNDERFLOW)) {
222262306a36Sopenharmony_ci		if (!((t->dev->parent) &&
222362306a36Sopenharmony_ci			(dev_is_expander(t->dev->parent->dev_type)))) {
222462306a36Sopenharmony_ci			for (i = 0, j = 4; j <= 7 && i <= 3; i++, j++)
222562306a36Sopenharmony_ci				sata_addr_low[i] = pm8001_ha->sas_addr[j];
222662306a36Sopenharmony_ci			for (i = 0, j = 0; j <= 3 && i <= 3; i++, j++)
222762306a36Sopenharmony_ci				sata_addr_hi[i] = pm8001_ha->sas_addr[j];
222862306a36Sopenharmony_ci			memcpy(&temp_sata_addr_low, sata_addr_low,
222962306a36Sopenharmony_ci				sizeof(sata_addr_low));
223062306a36Sopenharmony_ci			memcpy(&temp_sata_addr_hi, sata_addr_hi,
223162306a36Sopenharmony_ci				sizeof(sata_addr_hi));
223262306a36Sopenharmony_ci			temp_sata_addr_hi = (((temp_sata_addr_hi >> 24) & 0xff)
223362306a36Sopenharmony_ci						|((temp_sata_addr_hi << 8) &
223462306a36Sopenharmony_ci						0xff0000) |
223562306a36Sopenharmony_ci						((temp_sata_addr_hi >> 8)
223662306a36Sopenharmony_ci						& 0xff00) |
223762306a36Sopenharmony_ci						((temp_sata_addr_hi << 24) &
223862306a36Sopenharmony_ci						0xff000000));
223962306a36Sopenharmony_ci			temp_sata_addr_low = ((((temp_sata_addr_low >> 24)
224062306a36Sopenharmony_ci						& 0xff) |
224162306a36Sopenharmony_ci						((temp_sata_addr_low << 8)
224262306a36Sopenharmony_ci						& 0xff0000) |
224362306a36Sopenharmony_ci						((temp_sata_addr_low >> 8)
224462306a36Sopenharmony_ci						& 0xff00) |
224562306a36Sopenharmony_ci						((temp_sata_addr_low << 24)
224662306a36Sopenharmony_ci						& 0xff000000)) +
224762306a36Sopenharmony_ci						pm8001_dev->attached_phy +
224862306a36Sopenharmony_ci						0x10);
224962306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
225062306a36Sopenharmony_ci				   "SAS Address of IO Failure Drive:%08x%08x\n",
225162306a36Sopenharmony_ci				   temp_sata_addr_hi,
225262306a36Sopenharmony_ci				   temp_sata_addr_low);
225362306a36Sopenharmony_ci		} else {
225462306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, FAIL,
225562306a36Sopenharmony_ci				   "SAS Address of IO Failure Drive:%016llx\n",
225662306a36Sopenharmony_ci				   SAS_ADDR(t->dev->sas_addr));
225762306a36Sopenharmony_ci		}
225862306a36Sopenharmony_ci	}
225962306a36Sopenharmony_ci	switch (status) {
226062306a36Sopenharmony_ci	case IO_SUCCESS:
226162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
226262306a36Sopenharmony_ci		if (param == 0) {
226362306a36Sopenharmony_ci			ts->resp = SAS_TASK_COMPLETE;
226462306a36Sopenharmony_ci			ts->stat = SAS_SAM_STAT_GOOD;
226562306a36Sopenharmony_ci		} else {
226662306a36Sopenharmony_ci			u8 len;
226762306a36Sopenharmony_ci			ts->resp = SAS_TASK_COMPLETE;
226862306a36Sopenharmony_ci			ts->stat = SAS_PROTO_RESPONSE;
226962306a36Sopenharmony_ci			ts->residual = param;
227062306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, IO,
227162306a36Sopenharmony_ci				   "SAS_PROTO_RESPONSE len = %d\n",
227262306a36Sopenharmony_ci				   param);
227362306a36Sopenharmony_ci			sata_resp = &psataPayload->sata_resp[0];
227462306a36Sopenharmony_ci			resp = (struct ata_task_resp *)ts->buf;
227562306a36Sopenharmony_ci			if (t->ata_task.dma_xfer == 0 &&
227662306a36Sopenharmony_ci			    t->data_dir == DMA_FROM_DEVICE) {
227762306a36Sopenharmony_ci				len = sizeof(struct pio_setup_fis);
227862306a36Sopenharmony_ci				pm8001_dbg(pm8001_ha, IO,
227962306a36Sopenharmony_ci					   "PIO read len = %d\n", len);
228062306a36Sopenharmony_ci			} else if (t->ata_task.use_ncq &&
228162306a36Sopenharmony_ci				   t->data_dir != DMA_NONE) {
228262306a36Sopenharmony_ci				len = sizeof(struct set_dev_bits_fis);
228362306a36Sopenharmony_ci				pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n",
228462306a36Sopenharmony_ci					   len);
228562306a36Sopenharmony_ci			} else {
228662306a36Sopenharmony_ci				len = sizeof(struct dev_to_host_fis);
228762306a36Sopenharmony_ci				pm8001_dbg(pm8001_ha, IO, "other len = %d\n",
228862306a36Sopenharmony_ci					   len);
228962306a36Sopenharmony_ci			}
229062306a36Sopenharmony_ci			if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
229162306a36Sopenharmony_ci				resp->frame_len = len;
229262306a36Sopenharmony_ci				memcpy(&resp->ending_fis[0], sata_resp, len);
229362306a36Sopenharmony_ci				ts->buf_valid_size = sizeof(*resp);
229462306a36Sopenharmony_ci			} else
229562306a36Sopenharmony_ci				pm8001_dbg(pm8001_ha, IO,
229662306a36Sopenharmony_ci					   "response too large\n");
229762306a36Sopenharmony_ci		}
229862306a36Sopenharmony_ci		if (pm8001_dev)
229962306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
230062306a36Sopenharmony_ci		break;
230162306a36Sopenharmony_ci	case IO_ABORTED:
230262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n");
230362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
230462306a36Sopenharmony_ci		ts->stat = SAS_ABORTED_TASK;
230562306a36Sopenharmony_ci		if (pm8001_dev)
230662306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
230762306a36Sopenharmony_ci		break;
230862306a36Sopenharmony_ci		/* following cases are to do cases */
230962306a36Sopenharmony_ci	case IO_UNDERFLOW:
231062306a36Sopenharmony_ci		/* SATA Completion with error */
231162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW param = %d\n", param);
231262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
231362306a36Sopenharmony_ci		ts->stat = SAS_DATA_UNDERRUN;
231462306a36Sopenharmony_ci		ts->residual =  param;
231562306a36Sopenharmony_ci		if (pm8001_dev)
231662306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
231762306a36Sopenharmony_ci		break;
231862306a36Sopenharmony_ci	case IO_NO_DEVICE:
231962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
232062306a36Sopenharmony_ci		ts->resp = SAS_TASK_UNDELIVERED;
232162306a36Sopenharmony_ci		ts->stat = SAS_PHY_DOWN;
232262306a36Sopenharmony_ci		if (pm8001_dev)
232362306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
232462306a36Sopenharmony_ci		break;
232562306a36Sopenharmony_ci	case IO_XFER_ERROR_BREAK:
232662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
232762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
232862306a36Sopenharmony_ci		ts->stat = SAS_INTERRUPTED;
232962306a36Sopenharmony_ci		if (pm8001_dev)
233062306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
233162306a36Sopenharmony_ci		break;
233262306a36Sopenharmony_ci	case IO_XFER_ERROR_PHY_NOT_READY:
233362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
233462306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
233562306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
233662306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
233762306a36Sopenharmony_ci		if (pm8001_dev)
233862306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
233962306a36Sopenharmony_ci		break;
234062306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
234162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
234262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
234362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
234462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_EPROTO;
234562306a36Sopenharmony_ci		if (pm8001_dev)
234662306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
234762306a36Sopenharmony_ci		break;
234862306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
234962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
235062306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
235162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
235262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
235362306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
235462306a36Sopenharmony_ci		if (pm8001_dev)
235562306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
235662306a36Sopenharmony_ci		break;
235762306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BREAK:
235862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
235962306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
236062306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
236162306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
236262306a36Sopenharmony_ci		if (pm8001_dev)
236362306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
236462306a36Sopenharmony_ci		break;
236562306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
236662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
236762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
236862306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
236962306a36Sopenharmony_ci		if (!t->uldd_task) {
237062306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
237162306a36Sopenharmony_ci				pm8001_dev,
237262306a36Sopenharmony_ci				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
237362306a36Sopenharmony_ci			ts->resp = SAS_TASK_UNDELIVERED;
237462306a36Sopenharmony_ci			ts->stat = SAS_QUEUE_FULL;
237562306a36Sopenharmony_ci			pm8001_ccb_task_free_done(pm8001_ha, ccb);
237662306a36Sopenharmony_ci			return;
237762306a36Sopenharmony_ci		}
237862306a36Sopenharmony_ci		break;
237962306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
238062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
238162306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
238262306a36Sopenharmony_ci		ts->resp = SAS_TASK_UNDELIVERED;
238362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
238462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
238562306a36Sopenharmony_ci		if (!t->uldd_task) {
238662306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
238762306a36Sopenharmony_ci				pm8001_dev,
238862306a36Sopenharmony_ci				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
238962306a36Sopenharmony_ci			ts->resp = SAS_TASK_UNDELIVERED;
239062306a36Sopenharmony_ci			ts->stat = SAS_QUEUE_FULL;
239162306a36Sopenharmony_ci			pm8001_ccb_task_free_done(pm8001_ha, ccb);
239262306a36Sopenharmony_ci			return;
239362306a36Sopenharmony_ci		}
239462306a36Sopenharmony_ci		break;
239562306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
239662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
239762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
239862306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
239962306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
240062306a36Sopenharmony_ci		if (pm8001_dev)
240162306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
240262306a36Sopenharmony_ci		break;
240362306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
240462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n");
240562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
240662306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
240762306a36Sopenharmony_ci		if (!t->uldd_task) {
240862306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
240962306a36Sopenharmony_ci				pm8001_dev,
241062306a36Sopenharmony_ci				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
241162306a36Sopenharmony_ci			ts->resp = SAS_TASK_UNDELIVERED;
241262306a36Sopenharmony_ci			ts->stat = SAS_QUEUE_FULL;
241362306a36Sopenharmony_ci			pm8001_ccb_task_free_done(pm8001_ha, ccb);
241462306a36Sopenharmony_ci			return;
241562306a36Sopenharmony_ci		}
241662306a36Sopenharmony_ci		break;
241762306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
241862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
241962306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
242062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
242162306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
242262306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
242362306a36Sopenharmony_ci		if (pm8001_dev)
242462306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
242562306a36Sopenharmony_ci		break;
242662306a36Sopenharmony_ci	case IO_XFER_ERROR_NAK_RECEIVED:
242762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
242862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
242962306a36Sopenharmony_ci		ts->stat = SAS_NAK_R_ERR;
243062306a36Sopenharmony_ci		if (pm8001_dev)
243162306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
243262306a36Sopenharmony_ci		break;
243362306a36Sopenharmony_ci	case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
243462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
243562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
243662306a36Sopenharmony_ci		ts->stat = SAS_NAK_R_ERR;
243762306a36Sopenharmony_ci		if (pm8001_dev)
243862306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
243962306a36Sopenharmony_ci		break;
244062306a36Sopenharmony_ci	case IO_XFER_ERROR_DMA:
244162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n");
244262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
244362306a36Sopenharmony_ci		ts->stat = SAS_ABORTED_TASK;
244462306a36Sopenharmony_ci		if (pm8001_dev)
244562306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
244662306a36Sopenharmony_ci		break;
244762306a36Sopenharmony_ci	case IO_XFER_ERROR_SATA_LINK_TIMEOUT:
244862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_SATA_LINK_TIMEOUT\n");
244962306a36Sopenharmony_ci		ts->resp = SAS_TASK_UNDELIVERED;
245062306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
245162306a36Sopenharmony_ci		if (pm8001_dev)
245262306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
245362306a36Sopenharmony_ci		break;
245462306a36Sopenharmony_ci	case IO_XFER_ERROR_REJECTED_NCQ_MODE:
245562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n");
245662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
245762306a36Sopenharmony_ci		ts->stat = SAS_DATA_UNDERRUN;
245862306a36Sopenharmony_ci		if (pm8001_dev)
245962306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
246062306a36Sopenharmony_ci		break;
246162306a36Sopenharmony_ci	case IO_XFER_OPEN_RETRY_TIMEOUT:
246262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
246362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
246462306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
246562306a36Sopenharmony_ci		if (pm8001_dev)
246662306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
246762306a36Sopenharmony_ci		break;
246862306a36Sopenharmony_ci	case IO_PORT_IN_RESET:
246962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
247062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
247162306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
247262306a36Sopenharmony_ci		if (pm8001_dev)
247362306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
247462306a36Sopenharmony_ci		break;
247562306a36Sopenharmony_ci	case IO_DS_NON_OPERATIONAL:
247662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
247762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
247862306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
247962306a36Sopenharmony_ci		if (!t->uldd_task) {
248062306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha, pm8001_dev,
248162306a36Sopenharmony_ci				    IO_DS_NON_OPERATIONAL);
248262306a36Sopenharmony_ci			ts->resp = SAS_TASK_UNDELIVERED;
248362306a36Sopenharmony_ci			ts->stat = SAS_QUEUE_FULL;
248462306a36Sopenharmony_ci			pm8001_ccb_task_free_done(pm8001_ha, ccb);
248562306a36Sopenharmony_ci			return;
248662306a36Sopenharmony_ci		}
248762306a36Sopenharmony_ci		break;
248862306a36Sopenharmony_ci	case IO_DS_IN_RECOVERY:
248962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "  IO_DS_IN_RECOVERY\n");
249062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
249162306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
249262306a36Sopenharmony_ci		if (pm8001_dev)
249362306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
249462306a36Sopenharmony_ci		break;
249562306a36Sopenharmony_ci	case IO_DS_IN_ERROR:
249662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_ERROR\n");
249762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
249862306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
249962306a36Sopenharmony_ci		if (!t->uldd_task) {
250062306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha, pm8001_dev,
250162306a36Sopenharmony_ci				    IO_DS_IN_ERROR);
250262306a36Sopenharmony_ci			ts->resp = SAS_TASK_UNDELIVERED;
250362306a36Sopenharmony_ci			ts->stat = SAS_QUEUE_FULL;
250462306a36Sopenharmony_ci			pm8001_ccb_task_free_done(pm8001_ha, ccb);
250562306a36Sopenharmony_ci			return;
250662306a36Sopenharmony_ci		}
250762306a36Sopenharmony_ci		break;
250862306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
250962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
251062306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
251162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
251262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
251362306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
251462306a36Sopenharmony_ci		if (pm8001_dev)
251562306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
251662306a36Sopenharmony_ci		break;
251762306a36Sopenharmony_ci	default:
251862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
251962306a36Sopenharmony_ci		/* not allowed case. Therefore, return failed status */
252062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
252162306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
252262306a36Sopenharmony_ci		if (pm8001_dev)
252362306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
252462306a36Sopenharmony_ci		break;
252562306a36Sopenharmony_ci	}
252662306a36Sopenharmony_ci	spin_lock_irqsave(&t->task_state_lock, flags);
252762306a36Sopenharmony_ci	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
252862306a36Sopenharmony_ci	t->task_state_flags |= SAS_TASK_STATE_DONE;
252962306a36Sopenharmony_ci	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
253062306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
253162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL,
253262306a36Sopenharmony_ci			   "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
253362306a36Sopenharmony_ci			   t, status, ts->resp, ts->stat);
253462306a36Sopenharmony_ci		pm8001_ccb_task_free(pm8001_ha, ccb);
253562306a36Sopenharmony_ci	} else {
253662306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
253762306a36Sopenharmony_ci		pm8001_ccb_task_free_done(pm8001_ha, ccb);
253862306a36Sopenharmony_ci	}
253962306a36Sopenharmony_ci}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci/*See the comments for mpi_ssp_completion */
254262306a36Sopenharmony_cistatic void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
254362306a36Sopenharmony_ci{
254462306a36Sopenharmony_ci	struct sas_task *t;
254562306a36Sopenharmony_ci	struct task_status_struct *ts;
254662306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
254762306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
254862306a36Sopenharmony_ci	struct sata_event_resp *psataPayload =
254962306a36Sopenharmony_ci		(struct sata_event_resp *)(piomb + 4);
255062306a36Sopenharmony_ci	u32 event = le32_to_cpu(psataPayload->event);
255162306a36Sopenharmony_ci	u32 tag = le32_to_cpu(psataPayload->tag);
255262306a36Sopenharmony_ci	u32 port_id = le32_to_cpu(psataPayload->port_id);
255362306a36Sopenharmony_ci	u32 dev_id = le32_to_cpu(psataPayload->device_id);
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	if (event)
255662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	/* Check if this is NCQ error */
255962306a36Sopenharmony_ci	if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) {
256062306a36Sopenharmony_ci		/* find device using device id */
256162306a36Sopenharmony_ci		pm8001_dev = pm8001_find_dev(pm8001_ha, dev_id);
256262306a36Sopenharmony_ci		if (pm8001_dev)
256362306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
256462306a36Sopenharmony_ci				pm8001_dev,
256562306a36Sopenharmony_ci				IO_XFER_ERROR_ABORTED_NCQ_MODE);
256662306a36Sopenharmony_ci		return;
256762306a36Sopenharmony_ci	}
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci	ccb = &pm8001_ha->ccb_info[tag];
257062306a36Sopenharmony_ci	t = ccb->task;
257162306a36Sopenharmony_ci	pm8001_dev = ccb->device;
257262306a36Sopenharmony_ci	if (event)
257362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "sata IO status 0x%x\n", event);
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_ci	if (unlikely(!t)) {
257662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n",
257762306a36Sopenharmony_ci			   ccb->ccb_tag);
257862306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
257962306a36Sopenharmony_ci		return;
258062306a36Sopenharmony_ci	}
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	if (unlikely(!t->lldd_task || !t->dev))
258362306a36Sopenharmony_ci		return;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	ts = &t->task_status;
258662306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, DEVIO,
258762306a36Sopenharmony_ci		   "port_id:0x%x, device_id:0x%x, tag:0x%x, event:0x%x\n",
258862306a36Sopenharmony_ci		   port_id, dev_id, tag, event);
258962306a36Sopenharmony_ci	switch (event) {
259062306a36Sopenharmony_ci	case IO_OVERFLOW:
259162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
259262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
259362306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
259462306a36Sopenharmony_ci		ts->residual = 0;
259562306a36Sopenharmony_ci		break;
259662306a36Sopenharmony_ci	case IO_XFER_ERROR_BREAK:
259762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
259862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
259962306a36Sopenharmony_ci		ts->stat = SAS_INTERRUPTED;
260062306a36Sopenharmony_ci		break;
260162306a36Sopenharmony_ci	case IO_XFER_ERROR_PHY_NOT_READY:
260262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
260362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
260462306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
260562306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
260662306a36Sopenharmony_ci		break;
260762306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
260862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
260962306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
261062306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
261162306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_EPROTO;
261262306a36Sopenharmony_ci		break;
261362306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
261462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
261562306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
261662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
261762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
261862306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
261962306a36Sopenharmony_ci		break;
262062306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BREAK:
262162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
262262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
262362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
262462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
262562306a36Sopenharmony_ci		break;
262662306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
262762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
262862306a36Sopenharmony_ci		ts->resp = SAS_TASK_UNDELIVERED;
262962306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
263062306a36Sopenharmony_ci		if (!t->uldd_task) {
263162306a36Sopenharmony_ci			pm8001_handle_event(pm8001_ha,
263262306a36Sopenharmony_ci				pm8001_dev,
263362306a36Sopenharmony_ci				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
263462306a36Sopenharmony_ci			ts->resp = SAS_TASK_COMPLETE;
263562306a36Sopenharmony_ci			ts->stat = SAS_QUEUE_FULL;
263662306a36Sopenharmony_ci			return;
263762306a36Sopenharmony_ci		}
263862306a36Sopenharmony_ci		break;
263962306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
264062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
264162306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
264262306a36Sopenharmony_ci		ts->resp = SAS_TASK_UNDELIVERED;
264362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
264462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
264562306a36Sopenharmony_ci		break;
264662306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
264762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
264862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
264962306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
265062306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
265162306a36Sopenharmony_ci		break;
265262306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
265362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
265462306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
265562306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
265662306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
265762306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
265862306a36Sopenharmony_ci		break;
265962306a36Sopenharmony_ci	case IO_XFER_ERROR_NAK_RECEIVED:
266062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
266162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
266262306a36Sopenharmony_ci		ts->stat = SAS_NAK_R_ERR;
266362306a36Sopenharmony_ci		break;
266462306a36Sopenharmony_ci	case IO_XFER_ERROR_PEER_ABORTED:
266562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PEER_ABORTED\n");
266662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
266762306a36Sopenharmony_ci		ts->stat = SAS_NAK_R_ERR;
266862306a36Sopenharmony_ci		break;
266962306a36Sopenharmony_ci	case IO_XFER_ERROR_REJECTED_NCQ_MODE:
267062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n");
267162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
267262306a36Sopenharmony_ci		ts->stat = SAS_DATA_UNDERRUN;
267362306a36Sopenharmony_ci		break;
267462306a36Sopenharmony_ci	case IO_XFER_OPEN_RETRY_TIMEOUT:
267562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
267662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
267762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
267862306a36Sopenharmony_ci		break;
267962306a36Sopenharmony_ci	case IO_XFER_ERROR_UNEXPECTED_PHASE:
268062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n");
268162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
268262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
268362306a36Sopenharmony_ci		break;
268462306a36Sopenharmony_ci	case IO_XFER_ERROR_XFER_RDY_OVERRUN:
268562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n");
268662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
268762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
268862306a36Sopenharmony_ci		break;
268962306a36Sopenharmony_ci	case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
269062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
269162306a36Sopenharmony_ci			   "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n");
269262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
269362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
269462306a36Sopenharmony_ci		break;
269562306a36Sopenharmony_ci	case IO_XFER_ERROR_OFFSET_MISMATCH:
269662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
269762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
269862306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
269962306a36Sopenharmony_ci		break;
270062306a36Sopenharmony_ci	case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
270162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
270262306a36Sopenharmony_ci			   "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n");
270362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
270462306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
270562306a36Sopenharmony_ci		break;
270662306a36Sopenharmony_ci	case IO_XFER_CMD_FRAME_ISSUED:
270762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n");
270862306a36Sopenharmony_ci		break;
270962306a36Sopenharmony_ci	case IO_XFER_PIO_SETUP_ERROR:
271062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_PIO_SETUP_ERROR\n");
271162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
271262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
271362306a36Sopenharmony_ci		break;
271462306a36Sopenharmony_ci	default:
271562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event);
271662306a36Sopenharmony_ci		/* not allowed case. Therefore, return failed status */
271762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
271862306a36Sopenharmony_ci		ts->stat = SAS_OPEN_TO;
271962306a36Sopenharmony_ci		break;
272062306a36Sopenharmony_ci	}
272162306a36Sopenharmony_ci}
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci/*See the comments for mpi_ssp_completion */
272462306a36Sopenharmony_cistatic void
272562306a36Sopenharmony_cimpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
272662306a36Sopenharmony_ci{
272762306a36Sopenharmony_ci	struct sas_task *t;
272862306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
272962306a36Sopenharmony_ci	unsigned long flags;
273062306a36Sopenharmony_ci	u32 status;
273162306a36Sopenharmony_ci	u32 tag;
273262306a36Sopenharmony_ci	struct smp_completion_resp *psmpPayload;
273362306a36Sopenharmony_ci	struct task_status_struct *ts;
273462306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci	psmpPayload = (struct smp_completion_resp *)(piomb + 4);
273762306a36Sopenharmony_ci	status = le32_to_cpu(psmpPayload->status);
273862306a36Sopenharmony_ci	tag = le32_to_cpu(psmpPayload->tag);
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	ccb = &pm8001_ha->ccb_info[tag];
274162306a36Sopenharmony_ci	t = ccb->task;
274262306a36Sopenharmony_ci	ts = &t->task_status;
274362306a36Sopenharmony_ci	pm8001_dev = ccb->device;
274462306a36Sopenharmony_ci	if (status) {
274562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "smp IO status 0x%x\n", status);
274662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IOERR,
274762306a36Sopenharmony_ci			   "status:0x%x, tag:0x%x, task:0x%p\n",
274862306a36Sopenharmony_ci			   status, tag, t);
274962306a36Sopenharmony_ci	}
275062306a36Sopenharmony_ci	if (unlikely(!t || !t->lldd_task || !t->dev))
275162306a36Sopenharmony_ci		return;
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci	switch (status) {
275462306a36Sopenharmony_ci	case IO_SUCCESS:
275562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
275662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
275762306a36Sopenharmony_ci		ts->stat = SAS_SAM_STAT_GOOD;
275862306a36Sopenharmony_ci		if (pm8001_dev)
275962306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
276062306a36Sopenharmony_ci		break;
276162306a36Sopenharmony_ci	case IO_ABORTED:
276262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB\n");
276362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
276462306a36Sopenharmony_ci		ts->stat = SAS_ABORTED_TASK;
276562306a36Sopenharmony_ci		if (pm8001_dev)
276662306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
276762306a36Sopenharmony_ci		break;
276862306a36Sopenharmony_ci	case IO_OVERFLOW:
276962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
277062306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
277162306a36Sopenharmony_ci		ts->stat = SAS_DATA_OVERRUN;
277262306a36Sopenharmony_ci		ts->residual = 0;
277362306a36Sopenharmony_ci		if (pm8001_dev)
277462306a36Sopenharmony_ci			atomic_dec(&pm8001_dev->running_req);
277562306a36Sopenharmony_ci		break;
277662306a36Sopenharmony_ci	case IO_NO_DEVICE:
277762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
277862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
277962306a36Sopenharmony_ci		ts->stat = SAS_PHY_DOWN;
278062306a36Sopenharmony_ci		break;
278162306a36Sopenharmony_ci	case IO_ERROR_HW_TIMEOUT:
278262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n");
278362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
278462306a36Sopenharmony_ci		ts->stat = SAS_SAM_STAT_BUSY;
278562306a36Sopenharmony_ci		break;
278662306a36Sopenharmony_ci	case IO_XFER_ERROR_BREAK:
278762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
278862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
278962306a36Sopenharmony_ci		ts->stat = SAS_SAM_STAT_BUSY;
279062306a36Sopenharmony_ci		break;
279162306a36Sopenharmony_ci	case IO_XFER_ERROR_PHY_NOT_READY:
279262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
279362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
279462306a36Sopenharmony_ci		ts->stat = SAS_SAM_STAT_BUSY;
279562306a36Sopenharmony_ci		break;
279662306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
279762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
279862306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
279962306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
280062306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
280162306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
280262306a36Sopenharmony_ci		break;
280362306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
280462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
280562306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
280662306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
280762306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
280862306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
280962306a36Sopenharmony_ci		break;
281062306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BREAK:
281162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
281262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
281362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
281462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
281562306a36Sopenharmony_ci		break;
281662306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
281762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
281862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
281962306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
282062306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
282162306a36Sopenharmony_ci		pm8001_handle_event(pm8001_ha,
282262306a36Sopenharmony_ci				pm8001_dev,
282362306a36Sopenharmony_ci				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
282462306a36Sopenharmony_ci		break;
282562306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
282662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
282762306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
282862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
282962306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
283062306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
283162306a36Sopenharmony_ci		break;
283262306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
283362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
283462306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
283562306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
283662306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
283762306a36Sopenharmony_ci		break;
283862306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
283962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
284062306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
284162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
284262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
284362306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
284462306a36Sopenharmony_ci		break;
284562306a36Sopenharmony_ci	case IO_XFER_ERROR_RX_FRAME:
284662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_RX_FRAME\n");
284762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
284862306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
284962306a36Sopenharmony_ci		break;
285062306a36Sopenharmony_ci	case IO_XFER_OPEN_RETRY_TIMEOUT:
285162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
285262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
285362306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
285462306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
285562306a36Sopenharmony_ci		break;
285662306a36Sopenharmony_ci	case IO_ERROR_INTERNAL_SMP_RESOURCE:
285762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_ERROR_INTERNAL_SMP_RESOURCE\n");
285862306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
285962306a36Sopenharmony_ci		ts->stat = SAS_QUEUE_FULL;
286062306a36Sopenharmony_ci		break;
286162306a36Sopenharmony_ci	case IO_PORT_IN_RESET:
286262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
286362306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
286462306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
286562306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
286662306a36Sopenharmony_ci		break;
286762306a36Sopenharmony_ci	case IO_DS_NON_OPERATIONAL:
286862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
286962306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
287062306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
287162306a36Sopenharmony_ci		break;
287262306a36Sopenharmony_ci	case IO_DS_IN_RECOVERY:
287362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n");
287462306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
287562306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
287662306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
287762306a36Sopenharmony_ci		break;
287862306a36Sopenharmony_ci	case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
287962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO,
288062306a36Sopenharmony_ci			   "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
288162306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
288262306a36Sopenharmony_ci		ts->stat = SAS_OPEN_REJECT;
288362306a36Sopenharmony_ci		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
288462306a36Sopenharmony_ci		break;
288562306a36Sopenharmony_ci	default:
288662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
288762306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
288862306a36Sopenharmony_ci		ts->stat = SAS_DEV_NO_RESPONSE;
288962306a36Sopenharmony_ci		/* not allowed case. Therefore, return failed status */
289062306a36Sopenharmony_ci		break;
289162306a36Sopenharmony_ci	}
289262306a36Sopenharmony_ci	spin_lock_irqsave(&t->task_state_lock, flags);
289362306a36Sopenharmony_ci	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
289462306a36Sopenharmony_ci	t->task_state_flags |= SAS_TASK_STATE_DONE;
289562306a36Sopenharmony_ci	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
289662306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
289762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n",
289862306a36Sopenharmony_ci			   t, status, ts->resp, ts->stat);
289962306a36Sopenharmony_ci		pm8001_ccb_task_free(pm8001_ha, ccb);
290062306a36Sopenharmony_ci	} else {
290162306a36Sopenharmony_ci		spin_unlock_irqrestore(&t->task_state_lock, flags);
290262306a36Sopenharmony_ci		pm8001_ccb_task_free_done(pm8001_ha, ccb);
290362306a36Sopenharmony_ci	}
290462306a36Sopenharmony_ci}
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_civoid pm8001_mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha,
290762306a36Sopenharmony_ci		void *piomb)
290862306a36Sopenharmony_ci{
290962306a36Sopenharmony_ci	struct set_dev_state_resp *pPayload =
291062306a36Sopenharmony_ci		(struct set_dev_state_resp *)(piomb + 4);
291162306a36Sopenharmony_ci	u32 tag = le32_to_cpu(pPayload->tag);
291262306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
291362306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev = ccb->device;
291462306a36Sopenharmony_ci	u32 status = le32_to_cpu(pPayload->status);
291562306a36Sopenharmony_ci	u32 device_id = le32_to_cpu(pPayload->device_id);
291662306a36Sopenharmony_ci	u8 pds = le32_to_cpu(pPayload->pds_nds) & PDS_BITS;
291762306a36Sopenharmony_ci	u8 nds = le32_to_cpu(pPayload->pds_nds) & NDS_BITS;
291862306a36Sopenharmony_ci
291962306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG,
292062306a36Sopenharmony_ci		   "Set device id = 0x%x state from 0x%x to 0x%x status = 0x%x!\n",
292162306a36Sopenharmony_ci		   device_id, pds, nds, status);
292262306a36Sopenharmony_ci	complete(pm8001_dev->setds_completion);
292362306a36Sopenharmony_ci	pm8001_ccb_free(pm8001_ha, ccb);
292462306a36Sopenharmony_ci}
292562306a36Sopenharmony_ci
292662306a36Sopenharmony_civoid pm8001_mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
292762306a36Sopenharmony_ci{
292862306a36Sopenharmony_ci	struct get_nvm_data_resp *pPayload =
292962306a36Sopenharmony_ci		(struct get_nvm_data_resp *)(piomb + 4);
293062306a36Sopenharmony_ci	u32 tag = le32_to_cpu(pPayload->tag);
293162306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
293262306a36Sopenharmony_ci	u32 dlen_status = le32_to_cpu(pPayload->dlen_status);
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci	complete(pm8001_ha->nvmd_completion);
293562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG, "Set nvm data complete!\n");
293662306a36Sopenharmony_ci	if ((dlen_status & NVMD_STAT) != 0) {
293762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "Set nvm data error %x\n",
293862306a36Sopenharmony_ci				dlen_status);
293962306a36Sopenharmony_ci	}
294062306a36Sopenharmony_ci	pm8001_ccb_free(pm8001_ha, ccb);
294162306a36Sopenharmony_ci}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_civoid
294462306a36Sopenharmony_cipm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
294562306a36Sopenharmony_ci{
294662306a36Sopenharmony_ci	struct fw_control_ex    *fw_control_context;
294762306a36Sopenharmony_ci	struct get_nvm_data_resp *pPayload =
294862306a36Sopenharmony_ci		(struct get_nvm_data_resp *)(piomb + 4);
294962306a36Sopenharmony_ci	u32 tag = le32_to_cpu(pPayload->tag);
295062306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
295162306a36Sopenharmony_ci	u32 dlen_status = le32_to_cpu(pPayload->dlen_status);
295262306a36Sopenharmony_ci	u32 ir_tds_bn_dps_das_nvm =
295362306a36Sopenharmony_ci		le32_to_cpu(pPayload->ir_tda_bn_dps_das_nvm);
295462306a36Sopenharmony_ci	void *virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr;
295562306a36Sopenharmony_ci	fw_control_context = ccb->fw_control_context;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG, "Get nvm data complete!\n");
295862306a36Sopenharmony_ci	if ((dlen_status & NVMD_STAT) != 0) {
295962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "Get nvm data error %x\n",
296062306a36Sopenharmony_ci				dlen_status);
296162306a36Sopenharmony_ci		complete(pm8001_ha->nvmd_completion);
296262306a36Sopenharmony_ci		/* We should free tag during failure also, the tag is not being
296362306a36Sopenharmony_ci		 * freed by requesting path anywhere.
296462306a36Sopenharmony_ci		 */
296562306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
296662306a36Sopenharmony_ci		return;
296762306a36Sopenharmony_ci	}
296862306a36Sopenharmony_ci	if (ir_tds_bn_dps_das_nvm & IPMode) {
296962306a36Sopenharmony_ci		/* indirect mode - IR bit set */
297062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "Get NVMD success, IR=1\n");
297162306a36Sopenharmony_ci		if ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == TWI_DEVICE) {
297262306a36Sopenharmony_ci			if (ir_tds_bn_dps_das_nvm == 0x80a80200) {
297362306a36Sopenharmony_ci				memcpy(pm8001_ha->sas_addr,
297462306a36Sopenharmony_ci				      ((u8 *)virt_addr + 4),
297562306a36Sopenharmony_ci				       SAS_ADDR_SIZE);
297662306a36Sopenharmony_ci				pm8001_dbg(pm8001_ha, MSG, "Get SAS address from VPD successfully!\n");
297762306a36Sopenharmony_ci			}
297862306a36Sopenharmony_ci		} else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == C_SEEPROM)
297962306a36Sopenharmony_ci			|| ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == VPD_FLASH) ||
298062306a36Sopenharmony_ci			((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == EXPAN_ROM)) {
298162306a36Sopenharmony_ci				;
298262306a36Sopenharmony_ci		} else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == AAP1_RDUMP)
298362306a36Sopenharmony_ci			|| ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == IOP_RDUMP)) {
298462306a36Sopenharmony_ci			;
298562306a36Sopenharmony_ci		} else {
298662306a36Sopenharmony_ci			/* Should not be happened*/
298762306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, MSG,
298862306a36Sopenharmony_ci				   "(IR=1)Wrong Device type 0x%x\n",
298962306a36Sopenharmony_ci				   ir_tds_bn_dps_das_nvm);
299062306a36Sopenharmony_ci		}
299162306a36Sopenharmony_ci	} else /* direct mode */{
299262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
299362306a36Sopenharmony_ci			   "Get NVMD success, IR=0, dataLen=%d\n",
299462306a36Sopenharmony_ci			   (dlen_status & NVMD_LEN) >> 24);
299562306a36Sopenharmony_ci	}
299662306a36Sopenharmony_ci	/* Though fw_control_context is freed below, usrAddr still needs
299762306a36Sopenharmony_ci	 * to be updated as this holds the response to the request function
299862306a36Sopenharmony_ci	 */
299962306a36Sopenharmony_ci	memcpy(fw_control_context->usrAddr,
300062306a36Sopenharmony_ci		pm8001_ha->memoryMap.region[NVMD].virt_ptr,
300162306a36Sopenharmony_ci		fw_control_context->len);
300262306a36Sopenharmony_ci	kfree(ccb->fw_control_context);
300362306a36Sopenharmony_ci	/* To avoid race condition, complete should be
300462306a36Sopenharmony_ci	 * called after the message is copied to
300562306a36Sopenharmony_ci	 * fw_control_context->usrAddr
300662306a36Sopenharmony_ci	 */
300762306a36Sopenharmony_ci	complete(pm8001_ha->nvmd_completion);
300862306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG, "Get nvmd data complete!\n");
300962306a36Sopenharmony_ci	pm8001_ccb_free(pm8001_ha, ccb);
301062306a36Sopenharmony_ci}
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ciint pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb)
301362306a36Sopenharmony_ci{
301462306a36Sopenharmony_ci	u32 tag;
301562306a36Sopenharmony_ci	struct local_phy_ctl_resp *pPayload =
301662306a36Sopenharmony_ci		(struct local_phy_ctl_resp *)(piomb + 4);
301762306a36Sopenharmony_ci	u32 status = le32_to_cpu(pPayload->status);
301862306a36Sopenharmony_ci	u32 phy_id = le32_to_cpu(pPayload->phyop_phyid) & ID_BITS;
301962306a36Sopenharmony_ci	u32 phy_op = le32_to_cpu(pPayload->phyop_phyid) & OP_BITS;
302062306a36Sopenharmony_ci	tag = le32_to_cpu(pPayload->tag);
302162306a36Sopenharmony_ci	if (status != 0) {
302262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
302362306a36Sopenharmony_ci			   "%x phy execute %x phy op failed!\n",
302462306a36Sopenharmony_ci			   phy_id, phy_op);
302562306a36Sopenharmony_ci	} else {
302662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
302762306a36Sopenharmony_ci			   "%x phy execute %x phy op success!\n",
302862306a36Sopenharmony_ci			   phy_id, phy_op);
302962306a36Sopenharmony_ci		pm8001_ha->phy[phy_id].reset_success = true;
303062306a36Sopenharmony_ci	}
303162306a36Sopenharmony_ci	if (pm8001_ha->phy[phy_id].enable_completion) {
303262306a36Sopenharmony_ci		complete(pm8001_ha->phy[phy_id].enable_completion);
303362306a36Sopenharmony_ci		pm8001_ha->phy[phy_id].enable_completion = NULL;
303462306a36Sopenharmony_ci	}
303562306a36Sopenharmony_ci	pm8001_tag_free(pm8001_ha, tag);
303662306a36Sopenharmony_ci	return 0;
303762306a36Sopenharmony_ci}
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci/**
304062306a36Sopenharmony_ci * pm8001_bytes_dmaed - one of the interface function communication with libsas
304162306a36Sopenharmony_ci * @pm8001_ha: our hba card information
304262306a36Sopenharmony_ci * @i: which phy that received the event.
304362306a36Sopenharmony_ci *
304462306a36Sopenharmony_ci * when HBA driver received the identify done event or initiate FIS received
304562306a36Sopenharmony_ci * event(for SATA), it will invoke this function to notify the sas layer that
304662306a36Sopenharmony_ci * the sas toplogy has formed, please discover the whole sas domain,
304762306a36Sopenharmony_ci * while receive a broadcast(change) primitive just tell the sas
304862306a36Sopenharmony_ci * layer to discover the changed domain rather than the whole domain.
304962306a36Sopenharmony_ci */
305062306a36Sopenharmony_civoid pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i)
305162306a36Sopenharmony_ci{
305262306a36Sopenharmony_ci	struct pm8001_phy *phy = &pm8001_ha->phy[i];
305362306a36Sopenharmony_ci	struct asd_sas_phy *sas_phy = &phy->sas_phy;
305462306a36Sopenharmony_ci	if (!phy->phy_attached)
305562306a36Sopenharmony_ci		return;
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci	if (phy->phy_type & PORT_TYPE_SAS) {
305862306a36Sopenharmony_ci		struct sas_identify_frame *id;
305962306a36Sopenharmony_ci		id = (struct sas_identify_frame *)phy->frame_rcvd;
306062306a36Sopenharmony_ci		id->dev_type = phy->identify.device_type;
306162306a36Sopenharmony_ci		id->initiator_bits = SAS_PROTOCOL_ALL;
306262306a36Sopenharmony_ci		id->target_bits = phy->identify.target_port_protocols;
306362306a36Sopenharmony_ci	} else if (phy->phy_type & PORT_TYPE_SATA) {
306462306a36Sopenharmony_ci		/*Nothing*/
306562306a36Sopenharmony_ci	}
306662306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG, "phy %d byte dmaded.\n", i);
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_ci	sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
306962306a36Sopenharmony_ci	sas_notify_port_event(sas_phy, PORTE_BYTES_DMAED, GFP_ATOMIC);
307062306a36Sopenharmony_ci}
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci/* Get the link rate speed  */
307362306a36Sopenharmony_civoid pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate)
307462306a36Sopenharmony_ci{
307562306a36Sopenharmony_ci	struct sas_phy *sas_phy = phy->sas_phy.phy;
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci	switch (link_rate) {
307862306a36Sopenharmony_ci	case PHY_SPEED_120:
307962306a36Sopenharmony_ci		phy->sas_phy.linkrate = SAS_LINK_RATE_12_0_GBPS;
308062306a36Sopenharmony_ci		break;
308162306a36Sopenharmony_ci	case PHY_SPEED_60:
308262306a36Sopenharmony_ci		phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
308362306a36Sopenharmony_ci		break;
308462306a36Sopenharmony_ci	case PHY_SPEED_30:
308562306a36Sopenharmony_ci		phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
308662306a36Sopenharmony_ci		break;
308762306a36Sopenharmony_ci	case PHY_SPEED_15:
308862306a36Sopenharmony_ci		phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
308962306a36Sopenharmony_ci		break;
309062306a36Sopenharmony_ci	}
309162306a36Sopenharmony_ci	sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
309262306a36Sopenharmony_ci	sas_phy->maximum_linkrate_hw = phy->maximum_linkrate;
309362306a36Sopenharmony_ci	sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
309462306a36Sopenharmony_ci	sas_phy->maximum_linkrate = phy->maximum_linkrate;
309562306a36Sopenharmony_ci	sas_phy->minimum_linkrate = phy->minimum_linkrate;
309662306a36Sopenharmony_ci}
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci/**
309962306a36Sopenharmony_ci * pm8001_get_attached_sas_addr - extract/generate attached SAS address
310062306a36Sopenharmony_ci * @phy: pointer to asd_phy
310162306a36Sopenharmony_ci * @sas_addr: pointer to buffer where the SAS address is to be written
310262306a36Sopenharmony_ci *
310362306a36Sopenharmony_ci * This function extracts the SAS address from an IDENTIFY frame
310462306a36Sopenharmony_ci * received.  If OOB is SATA, then a SAS address is generated from the
310562306a36Sopenharmony_ci * HA tables.
310662306a36Sopenharmony_ci *
310762306a36Sopenharmony_ci * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
310862306a36Sopenharmony_ci * buffer.
310962306a36Sopenharmony_ci */
311062306a36Sopenharmony_civoid pm8001_get_attached_sas_addr(struct pm8001_phy *phy,
311162306a36Sopenharmony_ci	u8 *sas_addr)
311262306a36Sopenharmony_ci{
311362306a36Sopenharmony_ci	if (phy->sas_phy.frame_rcvd[0] == 0x34
311462306a36Sopenharmony_ci		&& phy->sas_phy.oob_mode == SATA_OOB_MODE) {
311562306a36Sopenharmony_ci		struct pm8001_hba_info *pm8001_ha = phy->sas_phy.ha->lldd_ha;
311662306a36Sopenharmony_ci		/* FIS device-to-host */
311762306a36Sopenharmony_ci		u64 addr = be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr);
311862306a36Sopenharmony_ci		addr += phy->sas_phy.id;
311962306a36Sopenharmony_ci		*(__be64 *)sas_addr = cpu_to_be64(addr);
312062306a36Sopenharmony_ci	} else {
312162306a36Sopenharmony_ci		struct sas_identify_frame *idframe =
312262306a36Sopenharmony_ci			(void *) phy->sas_phy.frame_rcvd;
312362306a36Sopenharmony_ci		memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE);
312462306a36Sopenharmony_ci	}
312562306a36Sopenharmony_ci}
312662306a36Sopenharmony_ci
312762306a36Sopenharmony_ci/**
312862306a36Sopenharmony_ci * pm8001_hw_event_ack_req- For PM8001,some events need to acknowage to FW.
312962306a36Sopenharmony_ci * @pm8001_ha: our hba card information
313062306a36Sopenharmony_ci * @Qnum: the outbound queue message number.
313162306a36Sopenharmony_ci * @SEA: source of event to ack
313262306a36Sopenharmony_ci * @port_id: port id.
313362306a36Sopenharmony_ci * @phyId: phy id.
313462306a36Sopenharmony_ci * @param0: parameter 0.
313562306a36Sopenharmony_ci * @param1: parameter 1.
313662306a36Sopenharmony_ci */
313762306a36Sopenharmony_cistatic void pm8001_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha,
313862306a36Sopenharmony_ci	u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, u32 param1)
313962306a36Sopenharmony_ci{
314062306a36Sopenharmony_ci	struct hw_event_ack_req	 payload;
314162306a36Sopenharmony_ci	u32 opc = OPC_INB_SAS_HW_EVENT_ACK;
314262306a36Sopenharmony_ci
314362306a36Sopenharmony_ci	memset((u8 *)&payload, 0, sizeof(payload));
314462306a36Sopenharmony_ci	payload.tag = cpu_to_le32(1);
314562306a36Sopenharmony_ci	payload.sea_phyid_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) |
314662306a36Sopenharmony_ci		((phyId & 0x0F) << 4) | (port_id & 0x0F));
314762306a36Sopenharmony_ci	payload.param0 = cpu_to_le32(param0);
314862306a36Sopenharmony_ci	payload.param1 = cpu_to_le32(param1);
314962306a36Sopenharmony_ci
315062306a36Sopenharmony_ci	pm8001_mpi_build_cmd(pm8001_ha, Qnum, opc, &payload, sizeof(payload), 0);
315162306a36Sopenharmony_ci}
315262306a36Sopenharmony_ci
315362306a36Sopenharmony_cistatic int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
315462306a36Sopenharmony_ci	u32 phyId, u32 phy_op);
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci/**
315762306a36Sopenharmony_ci * hw_event_sas_phy_up -FW tells me a SAS phy up event.
315862306a36Sopenharmony_ci * @pm8001_ha: our hba card information
315962306a36Sopenharmony_ci * @piomb: IO message buffer
316062306a36Sopenharmony_ci */
316162306a36Sopenharmony_cistatic void
316262306a36Sopenharmony_cihw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
316362306a36Sopenharmony_ci{
316462306a36Sopenharmony_ci	struct hw_event_resp *pPayload =
316562306a36Sopenharmony_ci		(struct hw_event_resp *)(piomb + 4);
316662306a36Sopenharmony_ci	u32 lr_evt_status_phyid_portid =
316762306a36Sopenharmony_ci		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
316862306a36Sopenharmony_ci	u8 link_rate =
316962306a36Sopenharmony_ci		(u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
317062306a36Sopenharmony_ci	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
317162306a36Sopenharmony_ci	u8 phy_id =
317262306a36Sopenharmony_ci		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
317362306a36Sopenharmony_ci	u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
317462306a36Sopenharmony_ci	u8 portstate = (u8)(npip_portstate & 0x0000000F);
317562306a36Sopenharmony_ci	struct pm8001_port *port = &pm8001_ha->port[port_id];
317662306a36Sopenharmony_ci	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
317762306a36Sopenharmony_ci	unsigned long flags;
317862306a36Sopenharmony_ci	u8 deviceType = pPayload->sas_identify.dev_type;
317962306a36Sopenharmony_ci	phy->port = port;
318062306a36Sopenharmony_ci	port->port_id = port_id;
318162306a36Sopenharmony_ci	port->port_state =  portstate;
318262306a36Sopenharmony_ci	phy->phy_state = PHY_STATE_LINK_UP_SPC;
318362306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG,
318462306a36Sopenharmony_ci		   "HW_EVENT_SAS_PHY_UP port id = %d, phy id = %d\n",
318562306a36Sopenharmony_ci		   port_id, phy_id);
318662306a36Sopenharmony_ci
318762306a36Sopenharmony_ci	switch (deviceType) {
318862306a36Sopenharmony_ci	case SAS_PHY_UNUSED:
318962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "device type no device.\n");
319062306a36Sopenharmony_ci		break;
319162306a36Sopenharmony_ci	case SAS_END_DEVICE:
319262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "end device.\n");
319362306a36Sopenharmony_ci		pm8001_chip_phy_ctl_req(pm8001_ha, phy_id,
319462306a36Sopenharmony_ci			PHY_NOTIFY_ENABLE_SPINUP);
319562306a36Sopenharmony_ci		port->port_attached = 1;
319662306a36Sopenharmony_ci		pm8001_get_lrate_mode(phy, link_rate);
319762306a36Sopenharmony_ci		break;
319862306a36Sopenharmony_ci	case SAS_EDGE_EXPANDER_DEVICE:
319962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "expander device.\n");
320062306a36Sopenharmony_ci		port->port_attached = 1;
320162306a36Sopenharmony_ci		pm8001_get_lrate_mode(phy, link_rate);
320262306a36Sopenharmony_ci		break;
320362306a36Sopenharmony_ci	case SAS_FANOUT_EXPANDER_DEVICE:
320462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "fanout expander device.\n");
320562306a36Sopenharmony_ci		port->port_attached = 1;
320662306a36Sopenharmony_ci		pm8001_get_lrate_mode(phy, link_rate);
320762306a36Sopenharmony_ci		break;
320862306a36Sopenharmony_ci	default:
320962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "unknown device type(%x)\n",
321062306a36Sopenharmony_ci			   deviceType);
321162306a36Sopenharmony_ci		break;
321262306a36Sopenharmony_ci	}
321362306a36Sopenharmony_ci	phy->phy_type |= PORT_TYPE_SAS;
321462306a36Sopenharmony_ci	phy->identify.device_type = deviceType;
321562306a36Sopenharmony_ci	phy->phy_attached = 1;
321662306a36Sopenharmony_ci	if (phy->identify.device_type == SAS_END_DEVICE)
321762306a36Sopenharmony_ci		phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
321862306a36Sopenharmony_ci	else if (phy->identify.device_type != SAS_PHY_UNUSED)
321962306a36Sopenharmony_ci		phy->identify.target_port_protocols = SAS_PROTOCOL_SMP;
322062306a36Sopenharmony_ci	phy->sas_phy.oob_mode = SAS_OOB_MODE;
322162306a36Sopenharmony_ci	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
322262306a36Sopenharmony_ci	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
322362306a36Sopenharmony_ci	memcpy(phy->frame_rcvd, &pPayload->sas_identify,
322462306a36Sopenharmony_ci		sizeof(struct sas_identify_frame)-4);
322562306a36Sopenharmony_ci	phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4;
322662306a36Sopenharmony_ci	pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
322762306a36Sopenharmony_ci	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
322862306a36Sopenharmony_ci	if (pm8001_ha->flags == PM8001F_RUN_TIME)
322962306a36Sopenharmony_ci		mdelay(200);/*delay a moment to wait disk to spinup*/
323062306a36Sopenharmony_ci	pm8001_bytes_dmaed(pm8001_ha, phy_id);
323162306a36Sopenharmony_ci}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci/**
323462306a36Sopenharmony_ci * hw_event_sata_phy_up -FW tells me a SATA phy up event.
323562306a36Sopenharmony_ci * @pm8001_ha: our hba card information
323662306a36Sopenharmony_ci * @piomb: IO message buffer
323762306a36Sopenharmony_ci */
323862306a36Sopenharmony_cistatic void
323962306a36Sopenharmony_cihw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
324062306a36Sopenharmony_ci{
324162306a36Sopenharmony_ci	struct hw_event_resp *pPayload =
324262306a36Sopenharmony_ci		(struct hw_event_resp *)(piomb + 4);
324362306a36Sopenharmony_ci	u32 lr_evt_status_phyid_portid =
324462306a36Sopenharmony_ci		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
324562306a36Sopenharmony_ci	u8 link_rate =
324662306a36Sopenharmony_ci		(u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
324762306a36Sopenharmony_ci	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
324862306a36Sopenharmony_ci	u8 phy_id =
324962306a36Sopenharmony_ci		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
325062306a36Sopenharmony_ci	u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
325162306a36Sopenharmony_ci	u8 portstate = (u8)(npip_portstate & 0x0000000F);
325262306a36Sopenharmony_ci	struct pm8001_port *port = &pm8001_ha->port[port_id];
325362306a36Sopenharmony_ci	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
325462306a36Sopenharmony_ci	unsigned long flags;
325562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, DEVIO, "HW_EVENT_SATA_PHY_UP port id = %d, phy id = %d\n",
325662306a36Sopenharmony_ci		   port_id, phy_id);
325762306a36Sopenharmony_ci	phy->port = port;
325862306a36Sopenharmony_ci	port->port_id = port_id;
325962306a36Sopenharmony_ci	port->port_state =  portstate;
326062306a36Sopenharmony_ci	phy->phy_state = PHY_STATE_LINK_UP_SPC;
326162306a36Sopenharmony_ci	port->port_attached = 1;
326262306a36Sopenharmony_ci	pm8001_get_lrate_mode(phy, link_rate);
326362306a36Sopenharmony_ci	phy->phy_type |= PORT_TYPE_SATA;
326462306a36Sopenharmony_ci	phy->phy_attached = 1;
326562306a36Sopenharmony_ci	phy->sas_phy.oob_mode = SATA_OOB_MODE;
326662306a36Sopenharmony_ci	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
326762306a36Sopenharmony_ci	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
326862306a36Sopenharmony_ci	memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4),
326962306a36Sopenharmony_ci		sizeof(struct dev_to_host_fis));
327062306a36Sopenharmony_ci	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
327162306a36Sopenharmony_ci	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
327262306a36Sopenharmony_ci	phy->identify.device_type = SAS_SATA_DEV;
327362306a36Sopenharmony_ci	pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
327462306a36Sopenharmony_ci	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
327562306a36Sopenharmony_ci	pm8001_bytes_dmaed(pm8001_ha, phy_id);
327662306a36Sopenharmony_ci}
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci/**
327962306a36Sopenharmony_ci * hw_event_phy_down -we should notify the libsas the phy is down.
328062306a36Sopenharmony_ci * @pm8001_ha: our hba card information
328162306a36Sopenharmony_ci * @piomb: IO message buffer
328262306a36Sopenharmony_ci */
328362306a36Sopenharmony_cistatic void
328462306a36Sopenharmony_cihw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
328562306a36Sopenharmony_ci{
328662306a36Sopenharmony_ci	struct hw_event_resp *pPayload =
328762306a36Sopenharmony_ci		(struct hw_event_resp *)(piomb + 4);
328862306a36Sopenharmony_ci	u32 lr_evt_status_phyid_portid =
328962306a36Sopenharmony_ci		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
329062306a36Sopenharmony_ci	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
329162306a36Sopenharmony_ci	u8 phy_id =
329262306a36Sopenharmony_ci		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
329362306a36Sopenharmony_ci	u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
329462306a36Sopenharmony_ci	u8 portstate = (u8)(npip_portstate & 0x0000000F);
329562306a36Sopenharmony_ci	struct pm8001_port *port = &pm8001_ha->port[port_id];
329662306a36Sopenharmony_ci	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
329762306a36Sopenharmony_ci	port->port_state =  portstate;
329862306a36Sopenharmony_ci	phy->phy_type = 0;
329962306a36Sopenharmony_ci	phy->identify.device_type = 0;
330062306a36Sopenharmony_ci	phy->phy_attached = 0;
330162306a36Sopenharmony_ci	memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE);
330262306a36Sopenharmony_ci	switch (portstate) {
330362306a36Sopenharmony_ci	case PORT_VALID:
330462306a36Sopenharmony_ci		break;
330562306a36Sopenharmony_ci	case PORT_INVALID:
330662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, " PortInvalid portID %d\n",
330762306a36Sopenharmony_ci			   port_id);
330862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
330962306a36Sopenharmony_ci			   " Last phy Down and port invalid\n");
331062306a36Sopenharmony_ci		port->port_attached = 0;
331162306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
331262306a36Sopenharmony_ci			port_id, phy_id, 0, 0);
331362306a36Sopenharmony_ci		break;
331462306a36Sopenharmony_ci	case PORT_IN_RESET:
331562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, " Port In Reset portID %d\n",
331662306a36Sopenharmony_ci			   port_id);
331762306a36Sopenharmony_ci		break;
331862306a36Sopenharmony_ci	case PORT_NOT_ESTABLISHED:
331962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
332062306a36Sopenharmony_ci			   " phy Down and PORT_NOT_ESTABLISHED\n");
332162306a36Sopenharmony_ci		port->port_attached = 0;
332262306a36Sopenharmony_ci		break;
332362306a36Sopenharmony_ci	case PORT_LOSTCOMM:
332462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, " phy Down and PORT_LOSTCOMM\n");
332562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
332662306a36Sopenharmony_ci			   " Last phy Down and port invalid\n");
332762306a36Sopenharmony_ci		port->port_attached = 0;
332862306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
332962306a36Sopenharmony_ci			port_id, phy_id, 0, 0);
333062306a36Sopenharmony_ci		break;
333162306a36Sopenharmony_ci	default:
333262306a36Sopenharmony_ci		port->port_attached = 0;
333362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, " phy Down and(default) = %x\n",
333462306a36Sopenharmony_ci			   portstate);
333562306a36Sopenharmony_ci		break;
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	}
333862306a36Sopenharmony_ci}
333962306a36Sopenharmony_ci
334062306a36Sopenharmony_ci/**
334162306a36Sopenharmony_ci * pm8001_mpi_reg_resp -process register device ID response.
334262306a36Sopenharmony_ci * @pm8001_ha: our hba card information
334362306a36Sopenharmony_ci * @piomb: IO message buffer
334462306a36Sopenharmony_ci *
334562306a36Sopenharmony_ci * when sas layer find a device it will notify LLDD, then the driver register
334662306a36Sopenharmony_ci * the domain device to FW, this event is the return device ID which the FW
334762306a36Sopenharmony_ci * has assigned, from now, inter-communication with FW is no longer using the
334862306a36Sopenharmony_ci * SAS address, use device ID which FW assigned.
334962306a36Sopenharmony_ci */
335062306a36Sopenharmony_ciint pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
335162306a36Sopenharmony_ci{
335262306a36Sopenharmony_ci	u32 status;
335362306a36Sopenharmony_ci	u32 device_id;
335462306a36Sopenharmony_ci	u32 htag;
335562306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
335662306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
335762306a36Sopenharmony_ci	struct dev_reg_resp *registerRespPayload =
335862306a36Sopenharmony_ci		(struct dev_reg_resp *)(piomb + 4);
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	htag = le32_to_cpu(registerRespPayload->tag);
336162306a36Sopenharmony_ci	ccb = &pm8001_ha->ccb_info[htag];
336262306a36Sopenharmony_ci	pm8001_dev = ccb->device;
336362306a36Sopenharmony_ci	status = le32_to_cpu(registerRespPayload->status);
336462306a36Sopenharmony_ci	device_id = le32_to_cpu(registerRespPayload->device_id);
336562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT,
336662306a36Sopenharmony_ci		   "register device status %d phy_id 0x%x device_id %d\n",
336762306a36Sopenharmony_ci		   status, pm8001_dev->attached_phy, device_id);
336862306a36Sopenharmony_ci	switch (status) {
336962306a36Sopenharmony_ci	case DEVREG_SUCCESS:
337062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "DEVREG_SUCCESS\n");
337162306a36Sopenharmony_ci		pm8001_dev->device_id = device_id;
337262306a36Sopenharmony_ci		break;
337362306a36Sopenharmony_ci	case DEVREG_FAILURE_OUT_OF_RESOURCE:
337462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "DEVREG_FAILURE_OUT_OF_RESOURCE\n");
337562306a36Sopenharmony_ci		break;
337662306a36Sopenharmony_ci	case DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED:
337762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
337862306a36Sopenharmony_ci			   "DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED\n");
337962306a36Sopenharmony_ci		break;
338062306a36Sopenharmony_ci	case DEVREG_FAILURE_INVALID_PHY_ID:
338162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "DEVREG_FAILURE_INVALID_PHY_ID\n");
338262306a36Sopenharmony_ci		break;
338362306a36Sopenharmony_ci	case DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED:
338462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
338562306a36Sopenharmony_ci			   "DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED\n");
338662306a36Sopenharmony_ci		break;
338762306a36Sopenharmony_ci	case DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE:
338862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
338962306a36Sopenharmony_ci			   "DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE\n");
339062306a36Sopenharmony_ci		break;
339162306a36Sopenharmony_ci	case DEVREG_FAILURE_PORT_NOT_VALID_STATE:
339262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
339362306a36Sopenharmony_ci			   "DEVREG_FAILURE_PORT_NOT_VALID_STATE\n");
339462306a36Sopenharmony_ci		break;
339562306a36Sopenharmony_ci	case DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID:
339662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
339762306a36Sopenharmony_ci			   "DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID\n");
339862306a36Sopenharmony_ci		break;
339962306a36Sopenharmony_ci	default:
340062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
340162306a36Sopenharmony_ci			   "DEVREG_FAILURE_DEVICE_TYPE_NOT_SUPPORTED\n");
340262306a36Sopenharmony_ci		break;
340362306a36Sopenharmony_ci	}
340462306a36Sopenharmony_ci	complete(pm8001_dev->dcompletion);
340562306a36Sopenharmony_ci	pm8001_ccb_free(pm8001_ha, ccb);
340662306a36Sopenharmony_ci	return 0;
340762306a36Sopenharmony_ci}
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ciint pm8001_mpi_dereg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
341062306a36Sopenharmony_ci{
341162306a36Sopenharmony_ci	u32 status;
341262306a36Sopenharmony_ci	u32 device_id;
341362306a36Sopenharmony_ci	struct dev_reg_resp *registerRespPayload =
341462306a36Sopenharmony_ci		(struct dev_reg_resp *)(piomb + 4);
341562306a36Sopenharmony_ci
341662306a36Sopenharmony_ci	status = le32_to_cpu(registerRespPayload->status);
341762306a36Sopenharmony_ci	device_id = le32_to_cpu(registerRespPayload->device_id);
341862306a36Sopenharmony_ci	if (status != 0)
341962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
342062306a36Sopenharmony_ci			   " deregister device failed ,status = %x, device_id = %x\n",
342162306a36Sopenharmony_ci			   status, device_id);
342262306a36Sopenharmony_ci	return 0;
342362306a36Sopenharmony_ci}
342462306a36Sopenharmony_ci
342562306a36Sopenharmony_ci/**
342662306a36Sopenharmony_ci * pm8001_mpi_fw_flash_update_resp - Response from FW for flash update command.
342762306a36Sopenharmony_ci * @pm8001_ha: our hba card information
342862306a36Sopenharmony_ci * @piomb: IO message buffer
342962306a36Sopenharmony_ci */
343062306a36Sopenharmony_ciint pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
343162306a36Sopenharmony_ci		void *piomb)
343262306a36Sopenharmony_ci{
343362306a36Sopenharmony_ci	u32 status;
343462306a36Sopenharmony_ci	struct fw_flash_Update_resp *ppayload =
343562306a36Sopenharmony_ci		(struct fw_flash_Update_resp *)(piomb + 4);
343662306a36Sopenharmony_ci	u32 tag = le32_to_cpu(ppayload->tag);
343762306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
343862306a36Sopenharmony_ci
343962306a36Sopenharmony_ci	status = le32_to_cpu(ppayload->status);
344062306a36Sopenharmony_ci	switch (status) {
344162306a36Sopenharmony_ci	case FLASH_UPDATE_COMPLETE_PENDING_REBOOT:
344262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
344362306a36Sopenharmony_ci			   ": FLASH_UPDATE_COMPLETE_PENDING_REBOOT\n");
344462306a36Sopenharmony_ci		break;
344562306a36Sopenharmony_ci	case FLASH_UPDATE_IN_PROGRESS:
344662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_IN_PROGRESS\n");
344762306a36Sopenharmony_ci		break;
344862306a36Sopenharmony_ci	case FLASH_UPDATE_HDR_ERR:
344962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_HDR_ERR\n");
345062306a36Sopenharmony_ci		break;
345162306a36Sopenharmony_ci	case FLASH_UPDATE_OFFSET_ERR:
345262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_OFFSET_ERR\n");
345362306a36Sopenharmony_ci		break;
345462306a36Sopenharmony_ci	case FLASH_UPDATE_CRC_ERR:
345562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_CRC_ERR\n");
345662306a36Sopenharmony_ci		break;
345762306a36Sopenharmony_ci	case FLASH_UPDATE_LENGTH_ERR:
345862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_LENGTH_ERR\n");
345962306a36Sopenharmony_ci		break;
346062306a36Sopenharmony_ci	case FLASH_UPDATE_HW_ERR:
346162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_HW_ERR\n");
346262306a36Sopenharmony_ci		break;
346362306a36Sopenharmony_ci	case FLASH_UPDATE_DNLD_NOT_SUPPORTED:
346462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
346562306a36Sopenharmony_ci			   ": FLASH_UPDATE_DNLD_NOT_SUPPORTED\n");
346662306a36Sopenharmony_ci		break;
346762306a36Sopenharmony_ci	case FLASH_UPDATE_DISABLED:
346862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_DISABLED\n");
346962306a36Sopenharmony_ci		break;
347062306a36Sopenharmony_ci	default:
347162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "No matched status = %d\n",
347262306a36Sopenharmony_ci			   status);
347362306a36Sopenharmony_ci		break;
347462306a36Sopenharmony_ci	}
347562306a36Sopenharmony_ci	kfree(ccb->fw_control_context);
347662306a36Sopenharmony_ci	pm8001_ccb_free(pm8001_ha, ccb);
347762306a36Sopenharmony_ci	complete(pm8001_ha->nvmd_completion);
347862306a36Sopenharmony_ci	return 0;
347962306a36Sopenharmony_ci}
348062306a36Sopenharmony_ci
348162306a36Sopenharmony_ciint pm8001_mpi_general_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
348262306a36Sopenharmony_ci{
348362306a36Sopenharmony_ci	u32 status;
348462306a36Sopenharmony_ci	int i;
348562306a36Sopenharmony_ci	struct general_event_resp *pPayload =
348662306a36Sopenharmony_ci		(struct general_event_resp *)(piomb + 4);
348762306a36Sopenharmony_ci	status = le32_to_cpu(pPayload->status);
348862306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG, " status = 0x%x\n", status);
348962306a36Sopenharmony_ci	for (i = 0; i < GENERAL_EVENT_PAYLOAD; i++)
349062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "inb_IOMB_payload[0x%x] 0x%x,\n",
349162306a36Sopenharmony_ci			   i,
349262306a36Sopenharmony_ci			   pPayload->inb_IOMB_payload[i]);
349362306a36Sopenharmony_ci	return 0;
349462306a36Sopenharmony_ci}
349562306a36Sopenharmony_ci
349662306a36Sopenharmony_ciint pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
349762306a36Sopenharmony_ci{
349862306a36Sopenharmony_ci	struct sas_task *t;
349962306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
350062306a36Sopenharmony_ci	unsigned long flags;
350162306a36Sopenharmony_ci	u32 status ;
350262306a36Sopenharmony_ci	u32 tag, scp;
350362306a36Sopenharmony_ci	struct task_status_struct *ts;
350462306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev;
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci	struct task_abort_resp *pPayload =
350762306a36Sopenharmony_ci		(struct task_abort_resp *)(piomb + 4);
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci	status = le32_to_cpu(pPayload->status);
351062306a36Sopenharmony_ci	tag = le32_to_cpu(pPayload->tag);
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	scp = le32_to_cpu(pPayload->scp);
351362306a36Sopenharmony_ci	ccb = &pm8001_ha->ccb_info[tag];
351462306a36Sopenharmony_ci	t = ccb->task;
351562306a36Sopenharmony_ci	pm8001_dev = ccb->device; /* retrieve device */
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci	if (!t)	{
351862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, " TASK NULL. RETURNING !!!\n");
351962306a36Sopenharmony_ci		return -1;
352062306a36Sopenharmony_ci	}
352162306a36Sopenharmony_ci
352262306a36Sopenharmony_ci	if (t->task_proto == SAS_PROTOCOL_INTERNAL_ABORT)
352362306a36Sopenharmony_ci		atomic_dec(&pm8001_dev->running_req);
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	ts = &t->task_status;
352662306a36Sopenharmony_ci	if (status != 0)
352762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, FAIL, "task abort failed status 0x%x ,tag = 0x%x, scp= 0x%x\n",
352862306a36Sopenharmony_ci			   status, tag, scp);
352962306a36Sopenharmony_ci	switch (status) {
353062306a36Sopenharmony_ci	case IO_SUCCESS:
353162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, EH, "IO_SUCCESS\n");
353262306a36Sopenharmony_ci		ts->resp = SAS_TASK_COMPLETE;
353362306a36Sopenharmony_ci		ts->stat = SAS_SAM_STAT_GOOD;
353462306a36Sopenharmony_ci		break;
353562306a36Sopenharmony_ci	case IO_NOT_VALID:
353662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, EH, "IO_NOT_VALID\n");
353762306a36Sopenharmony_ci		ts->resp = TMF_RESP_FUNC_FAILED;
353862306a36Sopenharmony_ci		break;
353962306a36Sopenharmony_ci	}
354062306a36Sopenharmony_ci	spin_lock_irqsave(&t->task_state_lock, flags);
354162306a36Sopenharmony_ci	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
354262306a36Sopenharmony_ci	t->task_state_flags |= SAS_TASK_STATE_DONE;
354362306a36Sopenharmony_ci	spin_unlock_irqrestore(&t->task_state_lock, flags);
354462306a36Sopenharmony_ci	pm8001_ccb_task_free(pm8001_ha, ccb);
354562306a36Sopenharmony_ci	mb();
354662306a36Sopenharmony_ci
354762306a36Sopenharmony_ci	t->task_done(t);
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci	return 0;
355062306a36Sopenharmony_ci}
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci/**
355362306a36Sopenharmony_ci * mpi_hw_event -The hw event has come.
355462306a36Sopenharmony_ci * @pm8001_ha: our hba card information
355562306a36Sopenharmony_ci * @piomb: IO message buffer
355662306a36Sopenharmony_ci */
355762306a36Sopenharmony_cistatic int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
355862306a36Sopenharmony_ci{
355962306a36Sopenharmony_ci	unsigned long flags;
356062306a36Sopenharmony_ci	struct hw_event_resp *pPayload =
356162306a36Sopenharmony_ci		(struct hw_event_resp *)(piomb + 4);
356262306a36Sopenharmony_ci	u32 lr_evt_status_phyid_portid =
356362306a36Sopenharmony_ci		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
356462306a36Sopenharmony_ci	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
356562306a36Sopenharmony_ci	u8 phy_id =
356662306a36Sopenharmony_ci		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
356762306a36Sopenharmony_ci	u16 eventType =
356862306a36Sopenharmony_ci		(u16)((lr_evt_status_phyid_portid & 0x00FFFF00) >> 8);
356962306a36Sopenharmony_ci	u8 status =
357062306a36Sopenharmony_ci		(u8)((lr_evt_status_phyid_portid & 0x0F000000) >> 24);
357162306a36Sopenharmony_ci	struct sas_ha_struct *sas_ha = pm8001_ha->sas;
357262306a36Sopenharmony_ci	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
357362306a36Sopenharmony_ci	struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
357462306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, DEVIO,
357562306a36Sopenharmony_ci		   "SPC HW event for portid:%d, phyid:%d, event:%x, status:%x\n",
357662306a36Sopenharmony_ci		   port_id, phy_id, eventType, status);
357762306a36Sopenharmony_ci	switch (eventType) {
357862306a36Sopenharmony_ci	case HW_EVENT_PHY_START_STATUS:
357962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS status = %x\n",
358062306a36Sopenharmony_ci			   status);
358162306a36Sopenharmony_ci		if (status == 0)
358262306a36Sopenharmony_ci			phy->phy_state = 1;
358362306a36Sopenharmony_ci
358462306a36Sopenharmony_ci		if (pm8001_ha->flags == PM8001F_RUN_TIME &&
358562306a36Sopenharmony_ci				phy->enable_completion != NULL) {
358662306a36Sopenharmony_ci			complete(phy->enable_completion);
358762306a36Sopenharmony_ci			phy->enable_completion = NULL;
358862306a36Sopenharmony_ci		}
358962306a36Sopenharmony_ci		break;
359062306a36Sopenharmony_ci	case HW_EVENT_SAS_PHY_UP:
359162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS\n");
359262306a36Sopenharmony_ci		hw_event_sas_phy_up(pm8001_ha, piomb);
359362306a36Sopenharmony_ci		break;
359462306a36Sopenharmony_ci	case HW_EVENT_SATA_PHY_UP:
359562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_PHY_UP\n");
359662306a36Sopenharmony_ci		hw_event_sata_phy_up(pm8001_ha, piomb);
359762306a36Sopenharmony_ci		break;
359862306a36Sopenharmony_ci	case HW_EVENT_PHY_STOP_STATUS:
359962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_STOP_STATUS status = %x\n",
360062306a36Sopenharmony_ci			   status);
360162306a36Sopenharmony_ci		if (status == 0)
360262306a36Sopenharmony_ci			phy->phy_state = 0;
360362306a36Sopenharmony_ci		break;
360462306a36Sopenharmony_ci	case HW_EVENT_SATA_SPINUP_HOLD:
360562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_SPINUP_HOLD\n");
360662306a36Sopenharmony_ci		sas_notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD,
360762306a36Sopenharmony_ci			GFP_ATOMIC);
360862306a36Sopenharmony_ci		break;
360962306a36Sopenharmony_ci	case HW_EVENT_PHY_DOWN:
361062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n");
361162306a36Sopenharmony_ci		sas_notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL,
361262306a36Sopenharmony_ci			GFP_ATOMIC);
361362306a36Sopenharmony_ci		phy->phy_attached = 0;
361462306a36Sopenharmony_ci		phy->phy_state = 0;
361562306a36Sopenharmony_ci		hw_event_phy_down(pm8001_ha, piomb);
361662306a36Sopenharmony_ci		break;
361762306a36Sopenharmony_ci	case HW_EVENT_PORT_INVALID:
361862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_INVALID\n");
361962306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
362062306a36Sopenharmony_ci		phy->phy_attached = 0;
362162306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
362262306a36Sopenharmony_ci			GFP_ATOMIC);
362362306a36Sopenharmony_ci		break;
362462306a36Sopenharmony_ci	/* the broadcast change primitive received, tell the LIBSAS this event
362562306a36Sopenharmony_ci	to revalidate the sas domain*/
362662306a36Sopenharmony_ci	case HW_EVENT_BROADCAST_CHANGE:
362762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_CHANGE\n");
362862306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_BROADCAST_CHANGE,
362962306a36Sopenharmony_ci			port_id, phy_id, 1, 0);
363062306a36Sopenharmony_ci		spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
363162306a36Sopenharmony_ci		sas_phy->sas_prim = HW_EVENT_BROADCAST_CHANGE;
363262306a36Sopenharmony_ci		spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
363362306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
363462306a36Sopenharmony_ci			GFP_ATOMIC);
363562306a36Sopenharmony_ci		break;
363662306a36Sopenharmony_ci	case HW_EVENT_PHY_ERROR:
363762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_ERROR\n");
363862306a36Sopenharmony_ci		sas_phy_disconnected(&phy->sas_phy);
363962306a36Sopenharmony_ci		phy->phy_attached = 0;
364062306a36Sopenharmony_ci		sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR, GFP_ATOMIC);
364162306a36Sopenharmony_ci		break;
364262306a36Sopenharmony_ci	case HW_EVENT_BROADCAST_EXP:
364362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_EXP\n");
364462306a36Sopenharmony_ci		spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
364562306a36Sopenharmony_ci		sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP;
364662306a36Sopenharmony_ci		spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
364762306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
364862306a36Sopenharmony_ci			GFP_ATOMIC);
364962306a36Sopenharmony_ci		break;
365062306a36Sopenharmony_ci	case HW_EVENT_LINK_ERR_INVALID_DWORD:
365162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
365262306a36Sopenharmony_ci			   "HW_EVENT_LINK_ERR_INVALID_DWORD\n");
365362306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0,
365462306a36Sopenharmony_ci			HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0);
365562306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
365662306a36Sopenharmony_ci		phy->phy_attached = 0;
365762306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
365862306a36Sopenharmony_ci			GFP_ATOMIC);
365962306a36Sopenharmony_ci		break;
366062306a36Sopenharmony_ci	case HW_EVENT_LINK_ERR_DISPARITY_ERROR:
366162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
366262306a36Sopenharmony_ci			   "HW_EVENT_LINK_ERR_DISPARITY_ERROR\n");
366362306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0,
366462306a36Sopenharmony_ci			HW_EVENT_LINK_ERR_DISPARITY_ERROR,
366562306a36Sopenharmony_ci			port_id, phy_id, 0, 0);
366662306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
366762306a36Sopenharmony_ci		phy->phy_attached = 0;
366862306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
366962306a36Sopenharmony_ci			GFP_ATOMIC);
367062306a36Sopenharmony_ci		break;
367162306a36Sopenharmony_ci	case HW_EVENT_LINK_ERR_CODE_VIOLATION:
367262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
367362306a36Sopenharmony_ci			   "HW_EVENT_LINK_ERR_CODE_VIOLATION\n");
367462306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0,
367562306a36Sopenharmony_ci			HW_EVENT_LINK_ERR_CODE_VIOLATION,
367662306a36Sopenharmony_ci			port_id, phy_id, 0, 0);
367762306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
367862306a36Sopenharmony_ci		phy->phy_attached = 0;
367962306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
368062306a36Sopenharmony_ci			GFP_ATOMIC);
368162306a36Sopenharmony_ci		break;
368262306a36Sopenharmony_ci	case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH:
368362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
368462306a36Sopenharmony_ci			   "HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n");
368562306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0,
368662306a36Sopenharmony_ci			HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH,
368762306a36Sopenharmony_ci			port_id, phy_id, 0, 0);
368862306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
368962306a36Sopenharmony_ci		phy->phy_attached = 0;
369062306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
369162306a36Sopenharmony_ci			GFP_ATOMIC);
369262306a36Sopenharmony_ci		break;
369362306a36Sopenharmony_ci	case HW_EVENT_MALFUNCTION:
369462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_MALFUNCTION\n");
369562306a36Sopenharmony_ci		break;
369662306a36Sopenharmony_ci	case HW_EVENT_BROADCAST_SES:
369762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n");
369862306a36Sopenharmony_ci		spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
369962306a36Sopenharmony_ci		sas_phy->sas_prim = HW_EVENT_BROADCAST_SES;
370062306a36Sopenharmony_ci		spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
370162306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
370262306a36Sopenharmony_ci			GFP_ATOMIC);
370362306a36Sopenharmony_ci		break;
370462306a36Sopenharmony_ci	case HW_EVENT_INBOUND_CRC_ERROR:
370562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_INBOUND_CRC_ERROR\n");
370662306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0,
370762306a36Sopenharmony_ci			HW_EVENT_INBOUND_CRC_ERROR,
370862306a36Sopenharmony_ci			port_id, phy_id, 0, 0);
370962306a36Sopenharmony_ci		break;
371062306a36Sopenharmony_ci	case HW_EVENT_HARD_RESET_RECEIVED:
371162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_HARD_RESET_RECEIVED\n");
371262306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_HARD_RESET, GFP_ATOMIC);
371362306a36Sopenharmony_ci		break;
371462306a36Sopenharmony_ci	case HW_EVENT_ID_FRAME_TIMEOUT:
371562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_ID_FRAME_TIMEOUT\n");
371662306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
371762306a36Sopenharmony_ci		phy->phy_attached = 0;
371862306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
371962306a36Sopenharmony_ci			GFP_ATOMIC);
372062306a36Sopenharmony_ci		break;
372162306a36Sopenharmony_ci	case HW_EVENT_LINK_ERR_PHY_RESET_FAILED:
372262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
372362306a36Sopenharmony_ci			   "HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n");
372462306a36Sopenharmony_ci		pm8001_hw_event_ack_req(pm8001_ha, 0,
372562306a36Sopenharmony_ci			HW_EVENT_LINK_ERR_PHY_RESET_FAILED,
372662306a36Sopenharmony_ci			port_id, phy_id, 0, 0);
372762306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
372862306a36Sopenharmony_ci		phy->phy_attached = 0;
372962306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
373062306a36Sopenharmony_ci			GFP_ATOMIC);
373162306a36Sopenharmony_ci		break;
373262306a36Sopenharmony_ci	case HW_EVENT_PORT_RESET_TIMER_TMO:
373362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_TIMER_TMO\n");
373462306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
373562306a36Sopenharmony_ci		phy->phy_attached = 0;
373662306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
373762306a36Sopenharmony_ci			GFP_ATOMIC);
373862306a36Sopenharmony_ci		break;
373962306a36Sopenharmony_ci	case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
374062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
374162306a36Sopenharmony_ci			   "HW_EVENT_PORT_RECOVERY_TIMER_TMO\n");
374262306a36Sopenharmony_ci		sas_phy_disconnected(sas_phy);
374362306a36Sopenharmony_ci		phy->phy_attached = 0;
374462306a36Sopenharmony_ci		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
374562306a36Sopenharmony_ci			GFP_ATOMIC);
374662306a36Sopenharmony_ci		break;
374762306a36Sopenharmony_ci	case HW_EVENT_PORT_RECOVER:
374862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RECOVER\n");
374962306a36Sopenharmony_ci		break;
375062306a36Sopenharmony_ci	case HW_EVENT_PORT_RESET_COMPLETE:
375162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_COMPLETE\n");
375262306a36Sopenharmony_ci		break;
375362306a36Sopenharmony_ci	case EVENT_BROADCAST_ASYNCH_EVENT:
375462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n");
375562306a36Sopenharmony_ci		break;
375662306a36Sopenharmony_ci	default:
375762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO, "Unknown event type = %x\n",
375862306a36Sopenharmony_ci			   eventType);
375962306a36Sopenharmony_ci		break;
376062306a36Sopenharmony_ci	}
376162306a36Sopenharmony_ci	return 0;
376262306a36Sopenharmony_ci}
376362306a36Sopenharmony_ci
376462306a36Sopenharmony_ci/**
376562306a36Sopenharmony_ci * process_one_iomb - process one outbound Queue memory block
376662306a36Sopenharmony_ci * @pm8001_ha: our hba card information
376762306a36Sopenharmony_ci * @piomb: IO message buffer
376862306a36Sopenharmony_ci */
376962306a36Sopenharmony_cistatic void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
377062306a36Sopenharmony_ci{
377162306a36Sopenharmony_ci	__le32 pHeader = *(__le32 *)piomb;
377262306a36Sopenharmony_ci	u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
377362306a36Sopenharmony_ci
377462306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, MSG, "process_one_iomb:\n");
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	switch (opc) {
377762306a36Sopenharmony_ci	case OPC_OUB_ECHO:
377862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_ECHO\n");
377962306a36Sopenharmony_ci		break;
378062306a36Sopenharmony_ci	case OPC_OUB_HW_EVENT:
378162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_HW_EVENT\n");
378262306a36Sopenharmony_ci		mpi_hw_event(pm8001_ha, piomb);
378362306a36Sopenharmony_ci		break;
378462306a36Sopenharmony_ci	case OPC_OUB_SSP_COMP:
378562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_COMP\n");
378662306a36Sopenharmony_ci		mpi_ssp_completion(pm8001_ha, piomb);
378762306a36Sopenharmony_ci		break;
378862306a36Sopenharmony_ci	case OPC_OUB_SMP_COMP:
378962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_COMP\n");
379062306a36Sopenharmony_ci		mpi_smp_completion(pm8001_ha, piomb);
379162306a36Sopenharmony_ci		break;
379262306a36Sopenharmony_ci	case OPC_OUB_LOCAL_PHY_CNTRL:
379362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_LOCAL_PHY_CNTRL\n");
379462306a36Sopenharmony_ci		pm8001_mpi_local_phy_ctl(pm8001_ha, piomb);
379562306a36Sopenharmony_ci		break;
379662306a36Sopenharmony_ci	case OPC_OUB_DEV_REGIST:
379762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_REGIST\n");
379862306a36Sopenharmony_ci		pm8001_mpi_reg_resp(pm8001_ha, piomb);
379962306a36Sopenharmony_ci		break;
380062306a36Sopenharmony_ci	case OPC_OUB_DEREG_DEV:
380162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "unregister the device\n");
380262306a36Sopenharmony_ci		pm8001_mpi_dereg_resp(pm8001_ha, piomb);
380362306a36Sopenharmony_ci		break;
380462306a36Sopenharmony_ci	case OPC_OUB_GET_DEV_HANDLE:
380562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEV_HANDLE\n");
380662306a36Sopenharmony_ci		break;
380762306a36Sopenharmony_ci	case OPC_OUB_SATA_COMP:
380862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n");
380962306a36Sopenharmony_ci		mpi_sata_completion(pm8001_ha, piomb);
381062306a36Sopenharmony_ci		break;
381162306a36Sopenharmony_ci	case OPC_OUB_SATA_EVENT:
381262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n");
381362306a36Sopenharmony_ci		mpi_sata_event(pm8001_ha, piomb);
381462306a36Sopenharmony_ci		break;
381562306a36Sopenharmony_ci	case OPC_OUB_SSP_EVENT:
381662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n");
381762306a36Sopenharmony_ci		mpi_ssp_event(pm8001_ha, piomb);
381862306a36Sopenharmony_ci		break;
381962306a36Sopenharmony_ci	case OPC_OUB_DEV_HANDLE_ARRIV:
382062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_HANDLE_ARRIV\n");
382162306a36Sopenharmony_ci		/*This is for target*/
382262306a36Sopenharmony_ci		break;
382362306a36Sopenharmony_ci	case OPC_OUB_SSP_RECV_EVENT:
382462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_RECV_EVENT\n");
382562306a36Sopenharmony_ci		/*This is for target*/
382662306a36Sopenharmony_ci		break;
382762306a36Sopenharmony_ci	case OPC_OUB_DEV_INFO:
382862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_INFO\n");
382962306a36Sopenharmony_ci		break;
383062306a36Sopenharmony_ci	case OPC_OUB_FW_FLASH_UPDATE:
383162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_FW_FLASH_UPDATE\n");
383262306a36Sopenharmony_ci		pm8001_mpi_fw_flash_update_resp(pm8001_ha, piomb);
383362306a36Sopenharmony_ci		break;
383462306a36Sopenharmony_ci	case OPC_OUB_GPIO_RESPONSE:
383562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_RESPONSE\n");
383662306a36Sopenharmony_ci		break;
383762306a36Sopenharmony_ci	case OPC_OUB_GPIO_EVENT:
383862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_EVENT\n");
383962306a36Sopenharmony_ci		break;
384062306a36Sopenharmony_ci	case OPC_OUB_GENERAL_EVENT:
384162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GENERAL_EVENT\n");
384262306a36Sopenharmony_ci		pm8001_mpi_general_event(pm8001_ha, piomb);
384362306a36Sopenharmony_ci		break;
384462306a36Sopenharmony_ci	case OPC_OUB_SSP_ABORT_RSP:
384562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_ABORT_RSP\n");
384662306a36Sopenharmony_ci		pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
384762306a36Sopenharmony_ci		break;
384862306a36Sopenharmony_ci	case OPC_OUB_SATA_ABORT_RSP:
384962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_ABORT_RSP\n");
385062306a36Sopenharmony_ci		pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
385162306a36Sopenharmony_ci		break;
385262306a36Sopenharmony_ci	case OPC_OUB_SAS_DIAG_MODE_START_END:
385362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG,
385462306a36Sopenharmony_ci			   "OPC_OUB_SAS_DIAG_MODE_START_END\n");
385562306a36Sopenharmony_ci		break;
385662306a36Sopenharmony_ci	case OPC_OUB_SAS_DIAG_EXECUTE:
385762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_DIAG_EXECUTE\n");
385862306a36Sopenharmony_ci		break;
385962306a36Sopenharmony_ci	case OPC_OUB_GET_TIME_STAMP:
386062306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_TIME_STAMP\n");
386162306a36Sopenharmony_ci		break;
386262306a36Sopenharmony_ci	case OPC_OUB_SAS_HW_EVENT_ACK:
386362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_HW_EVENT_ACK\n");
386462306a36Sopenharmony_ci		break;
386562306a36Sopenharmony_ci	case OPC_OUB_PORT_CONTROL:
386662306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_PORT_CONTROL\n");
386762306a36Sopenharmony_ci		break;
386862306a36Sopenharmony_ci	case OPC_OUB_SMP_ABORT_RSP:
386962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_ABORT_RSP\n");
387062306a36Sopenharmony_ci		pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
387162306a36Sopenharmony_ci		break;
387262306a36Sopenharmony_ci	case OPC_OUB_GET_NVMD_DATA:
387362306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_NVMD_DATA\n");
387462306a36Sopenharmony_ci		pm8001_mpi_get_nvmd_resp(pm8001_ha, piomb);
387562306a36Sopenharmony_ci		break;
387662306a36Sopenharmony_ci	case OPC_OUB_SET_NVMD_DATA:
387762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_NVMD_DATA\n");
387862306a36Sopenharmony_ci		pm8001_mpi_set_nvmd_resp(pm8001_ha, piomb);
387962306a36Sopenharmony_ci		break;
388062306a36Sopenharmony_ci	case OPC_OUB_DEVICE_HANDLE_REMOVAL:
388162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEVICE_HANDLE_REMOVAL\n");
388262306a36Sopenharmony_ci		break;
388362306a36Sopenharmony_ci	case OPC_OUB_SET_DEVICE_STATE:
388462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEVICE_STATE\n");
388562306a36Sopenharmony_ci		pm8001_mpi_set_dev_state_resp(pm8001_ha, piomb);
388662306a36Sopenharmony_ci		break;
388762306a36Sopenharmony_ci	case OPC_OUB_GET_DEVICE_STATE:
388862306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEVICE_STATE\n");
388962306a36Sopenharmony_ci		break;
389062306a36Sopenharmony_ci	case OPC_OUB_SET_DEV_INFO:
389162306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n");
389262306a36Sopenharmony_ci		break;
389362306a36Sopenharmony_ci	case OPC_OUB_SAS_RE_INITIALIZE:
389462306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_RE_INITIALIZE\n");
389562306a36Sopenharmony_ci		break;
389662306a36Sopenharmony_ci	default:
389762306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, DEVIO,
389862306a36Sopenharmony_ci			   "Unknown outbound Queue IOMB OPC = %x\n",
389962306a36Sopenharmony_ci			   opc);
390062306a36Sopenharmony_ci		break;
390162306a36Sopenharmony_ci	}
390262306a36Sopenharmony_ci}
390362306a36Sopenharmony_ci
390462306a36Sopenharmony_cistatic int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
390562306a36Sopenharmony_ci{
390662306a36Sopenharmony_ci	struct outbound_queue_table *circularQ;
390762306a36Sopenharmony_ci	void *pMsg1 = NULL;
390862306a36Sopenharmony_ci	u8 bc;
390962306a36Sopenharmony_ci	u32 ret = MPI_IO_STATUS_FAIL;
391062306a36Sopenharmony_ci	unsigned long flags;
391162306a36Sopenharmony_ci
391262306a36Sopenharmony_ci	spin_lock_irqsave(&pm8001_ha->lock, flags);
391362306a36Sopenharmony_ci	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
391462306a36Sopenharmony_ci	do {
391562306a36Sopenharmony_ci		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
391662306a36Sopenharmony_ci		if (MPI_IO_STATUS_SUCCESS == ret) {
391762306a36Sopenharmony_ci			/* process the outbound message */
391862306a36Sopenharmony_ci			process_one_iomb(pm8001_ha, (void *)(pMsg1 - 4));
391962306a36Sopenharmony_ci			/* free the message from the outbound circular buffer */
392062306a36Sopenharmony_ci			pm8001_mpi_msg_free_set(pm8001_ha, pMsg1,
392162306a36Sopenharmony_ci							circularQ, bc);
392262306a36Sopenharmony_ci		}
392362306a36Sopenharmony_ci		if (MPI_IO_STATUS_BUSY == ret) {
392462306a36Sopenharmony_ci			/* Update the producer index from SPC */
392562306a36Sopenharmony_ci			circularQ->producer_index =
392662306a36Sopenharmony_ci				cpu_to_le32(pm8001_read_32(circularQ->pi_virt));
392762306a36Sopenharmony_ci			if (le32_to_cpu(circularQ->producer_index) ==
392862306a36Sopenharmony_ci				circularQ->consumer_idx)
392962306a36Sopenharmony_ci				/* OQ is empty */
393062306a36Sopenharmony_ci				break;
393162306a36Sopenharmony_ci		}
393262306a36Sopenharmony_ci	} while (1);
393362306a36Sopenharmony_ci	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
393462306a36Sopenharmony_ci	return ret;
393562306a36Sopenharmony_ci}
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci/* DMA_... to our direction translation. */
393862306a36Sopenharmony_cistatic const u8 data_dir_flags[] = {
393962306a36Sopenharmony_ci	[DMA_BIDIRECTIONAL]	= DATA_DIR_BYRECIPIENT,	/* UNSPECIFIED */
394062306a36Sopenharmony_ci	[DMA_TO_DEVICE]		= DATA_DIR_OUT,		/* OUTBOUND */
394162306a36Sopenharmony_ci	[DMA_FROM_DEVICE]	= DATA_DIR_IN,		/* INBOUND */
394262306a36Sopenharmony_ci	[DMA_NONE]		= DATA_DIR_NONE,	/* NO TRANSFER */
394362306a36Sopenharmony_ci};
394462306a36Sopenharmony_civoid
394562306a36Sopenharmony_cipm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd)
394662306a36Sopenharmony_ci{
394762306a36Sopenharmony_ci	int i;
394862306a36Sopenharmony_ci	struct scatterlist *sg;
394962306a36Sopenharmony_ci	struct pm8001_prd *buf_prd = prd;
395062306a36Sopenharmony_ci
395162306a36Sopenharmony_ci	for_each_sg(scatter, sg, nr, i) {
395262306a36Sopenharmony_ci		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
395362306a36Sopenharmony_ci		buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg));
395462306a36Sopenharmony_ci		buf_prd->im_len.e = 0;
395562306a36Sopenharmony_ci		buf_prd++;
395662306a36Sopenharmony_ci	}
395762306a36Sopenharmony_ci}
395862306a36Sopenharmony_ci
395962306a36Sopenharmony_cistatic void build_smp_cmd(u32 deviceID, __le32 hTag, struct smp_req *psmp_cmd)
396062306a36Sopenharmony_ci{
396162306a36Sopenharmony_ci	psmp_cmd->tag = hTag;
396262306a36Sopenharmony_ci	psmp_cmd->device_id = cpu_to_le32(deviceID);
396362306a36Sopenharmony_ci	psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1));
396462306a36Sopenharmony_ci}
396562306a36Sopenharmony_ci
396662306a36Sopenharmony_ci/**
396762306a36Sopenharmony_ci * pm8001_chip_smp_req - send a SMP task to FW
396862306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
396962306a36Sopenharmony_ci * @ccb: the ccb information this request used.
397062306a36Sopenharmony_ci */
397162306a36Sopenharmony_cistatic int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
397262306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb)
397362306a36Sopenharmony_ci{
397462306a36Sopenharmony_ci	int elem, rc;
397562306a36Sopenharmony_ci	struct sas_task *task = ccb->task;
397662306a36Sopenharmony_ci	struct domain_device *dev = task->dev;
397762306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev = dev->lldd_dev;
397862306a36Sopenharmony_ci	struct scatterlist *sg_req, *sg_resp;
397962306a36Sopenharmony_ci	u32 req_len, resp_len;
398062306a36Sopenharmony_ci	struct smp_req smp_cmd;
398162306a36Sopenharmony_ci	u32 opc;
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci	memset(&smp_cmd, 0, sizeof(smp_cmd));
398462306a36Sopenharmony_ci	/*
398562306a36Sopenharmony_ci	 * DMA-map SMP request, response buffers
398662306a36Sopenharmony_ci	 */
398762306a36Sopenharmony_ci	sg_req = &task->smp_task.smp_req;
398862306a36Sopenharmony_ci	elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE);
398962306a36Sopenharmony_ci	if (!elem)
399062306a36Sopenharmony_ci		return -ENOMEM;
399162306a36Sopenharmony_ci	req_len = sg_dma_len(sg_req);
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	sg_resp = &task->smp_task.smp_resp;
399462306a36Sopenharmony_ci	elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE);
399562306a36Sopenharmony_ci	if (!elem) {
399662306a36Sopenharmony_ci		rc = -ENOMEM;
399762306a36Sopenharmony_ci		goto err_out;
399862306a36Sopenharmony_ci	}
399962306a36Sopenharmony_ci	resp_len = sg_dma_len(sg_resp);
400062306a36Sopenharmony_ci	/* must be in dwords */
400162306a36Sopenharmony_ci	if ((req_len & 0x3) || (resp_len & 0x3)) {
400262306a36Sopenharmony_ci		rc = -EINVAL;
400362306a36Sopenharmony_ci		goto err_out_2;
400462306a36Sopenharmony_ci	}
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	opc = OPC_INB_SMP_REQUEST;
400762306a36Sopenharmony_ci	smp_cmd.tag = cpu_to_le32(ccb->ccb_tag);
400862306a36Sopenharmony_ci	smp_cmd.long_smp_req.long_req_addr =
400962306a36Sopenharmony_ci		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
401062306a36Sopenharmony_ci	smp_cmd.long_smp_req.long_req_size =
401162306a36Sopenharmony_ci		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);
401262306a36Sopenharmony_ci	smp_cmd.long_smp_req.long_resp_addr =
401362306a36Sopenharmony_ci		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));
401462306a36Sopenharmony_ci	smp_cmd.long_smp_req.long_resp_size =
401562306a36Sopenharmony_ci		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
401662306a36Sopenharmony_ci	build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd);
401762306a36Sopenharmony_ci	rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc,
401862306a36Sopenharmony_ci				  &smp_cmd, sizeof(smp_cmd), 0);
401962306a36Sopenharmony_ci	if (rc)
402062306a36Sopenharmony_ci		goto err_out_2;
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci	return 0;
402362306a36Sopenharmony_ci
402462306a36Sopenharmony_cierr_out_2:
402562306a36Sopenharmony_ci	dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1,
402662306a36Sopenharmony_ci			DMA_FROM_DEVICE);
402762306a36Sopenharmony_cierr_out:
402862306a36Sopenharmony_ci	dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1,
402962306a36Sopenharmony_ci			DMA_TO_DEVICE);
403062306a36Sopenharmony_ci	return rc;
403162306a36Sopenharmony_ci}
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci/**
403462306a36Sopenharmony_ci * pm8001_chip_ssp_io_req - send a SSP task to FW
403562306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
403662306a36Sopenharmony_ci * @ccb: the ccb information this request used.
403762306a36Sopenharmony_ci */
403862306a36Sopenharmony_cistatic int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
403962306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb)
404062306a36Sopenharmony_ci{
404162306a36Sopenharmony_ci	struct sas_task *task = ccb->task;
404262306a36Sopenharmony_ci	struct domain_device *dev = task->dev;
404362306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev = dev->lldd_dev;
404462306a36Sopenharmony_ci	struct ssp_ini_io_start_req ssp_cmd;
404562306a36Sopenharmony_ci	u32 tag = ccb->ccb_tag;
404662306a36Sopenharmony_ci	u64 phys_addr;
404762306a36Sopenharmony_ci	u32 opc = OPC_INB_SSPINIIOSTART;
404862306a36Sopenharmony_ci	memset(&ssp_cmd, 0, sizeof(ssp_cmd));
404962306a36Sopenharmony_ci	memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8);
405062306a36Sopenharmony_ci	ssp_cmd.dir_m_tlr =
405162306a36Sopenharmony_ci		cpu_to_le32(data_dir_flags[task->data_dir] << 8 | 0x0);/*0 for
405262306a36Sopenharmony_ci	SAS 1.1 compatible TLR*/
405362306a36Sopenharmony_ci	ssp_cmd.data_len = cpu_to_le32(task->total_xfer_len);
405462306a36Sopenharmony_ci	ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id);
405562306a36Sopenharmony_ci	ssp_cmd.tag = cpu_to_le32(tag);
405662306a36Sopenharmony_ci	ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7);
405762306a36Sopenharmony_ci	memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd,
405862306a36Sopenharmony_ci	       task->ssp_task.cmd->cmd_len);
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_ci	/* fill in PRD (scatter/gather) table, if any */
406162306a36Sopenharmony_ci	if (task->num_scatter > 1) {
406262306a36Sopenharmony_ci		pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
406362306a36Sopenharmony_ci		phys_addr = ccb->ccb_dma_handle;
406462306a36Sopenharmony_ci		ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(phys_addr));
406562306a36Sopenharmony_ci		ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(phys_addr));
406662306a36Sopenharmony_ci		ssp_cmd.esgl = cpu_to_le32(1<<31);
406762306a36Sopenharmony_ci	} else if (task->num_scatter == 1) {
406862306a36Sopenharmony_ci		u64 dma_addr = sg_dma_address(task->scatter);
406962306a36Sopenharmony_ci		ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr));
407062306a36Sopenharmony_ci		ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(dma_addr));
407162306a36Sopenharmony_ci		ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
407262306a36Sopenharmony_ci		ssp_cmd.esgl = 0;
407362306a36Sopenharmony_ci	} else if (task->num_scatter == 0) {
407462306a36Sopenharmony_ci		ssp_cmd.addr_low = 0;
407562306a36Sopenharmony_ci		ssp_cmd.addr_high = 0;
407662306a36Sopenharmony_ci		ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
407762306a36Sopenharmony_ci		ssp_cmd.esgl = 0;
407862306a36Sopenharmony_ci	}
407962306a36Sopenharmony_ci
408062306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &ssp_cmd,
408162306a36Sopenharmony_ci				    sizeof(ssp_cmd), 0);
408262306a36Sopenharmony_ci}
408362306a36Sopenharmony_ci
408462306a36Sopenharmony_cistatic int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
408562306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb)
408662306a36Sopenharmony_ci{
408762306a36Sopenharmony_ci	struct sas_task *task = ccb->task;
408862306a36Sopenharmony_ci	struct domain_device *dev = task->dev;
408962306a36Sopenharmony_ci	struct pm8001_device *pm8001_ha_dev = dev->lldd_dev;
409062306a36Sopenharmony_ci	u32 tag = ccb->ccb_tag;
409162306a36Sopenharmony_ci	struct sata_start_req sata_cmd;
409262306a36Sopenharmony_ci	u32 hdr_tag, ncg_tag = 0;
409362306a36Sopenharmony_ci	u64 phys_addr;
409462306a36Sopenharmony_ci	u32 ATAP = 0x0;
409562306a36Sopenharmony_ci	u32 dir, retfis = 0;
409662306a36Sopenharmony_ci	u32  opc = OPC_INB_SATA_HOST_OPSTART;
409762306a36Sopenharmony_ci
409862306a36Sopenharmony_ci	memset(&sata_cmd, 0, sizeof(sata_cmd));
409962306a36Sopenharmony_ci
410062306a36Sopenharmony_ci	if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) {
410162306a36Sopenharmony_ci		ATAP = 0x04;  /* no data*/
410262306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, IO, "no data\n");
410362306a36Sopenharmony_ci	} else if (likely(!task->ata_task.device_control_reg_update)) {
410462306a36Sopenharmony_ci		if (task->ata_task.use_ncq &&
410562306a36Sopenharmony_ci		    dev->sata_dev.class != ATA_DEV_ATAPI) {
410662306a36Sopenharmony_ci			ATAP = 0x07; /* FPDMA */
410762306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, IO, "FPDMA\n");
410862306a36Sopenharmony_ci		} else if (task->ata_task.dma_xfer) {
410962306a36Sopenharmony_ci			ATAP = 0x06; /* DMA */
411062306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, IO, "DMA\n");
411162306a36Sopenharmony_ci		} else {
411262306a36Sopenharmony_ci			ATAP = 0x05; /* PIO*/
411362306a36Sopenharmony_ci			pm8001_dbg(pm8001_ha, IO, "PIO\n");
411462306a36Sopenharmony_ci		}
411562306a36Sopenharmony_ci	}
411662306a36Sopenharmony_ci	if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) {
411762306a36Sopenharmony_ci		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
411862306a36Sopenharmony_ci		ncg_tag = hdr_tag;
411962306a36Sopenharmony_ci	}
412062306a36Sopenharmony_ci	dir = data_dir_flags[task->data_dir] << 8;
412162306a36Sopenharmony_ci	sata_cmd.tag = cpu_to_le32(tag);
412262306a36Sopenharmony_ci	sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
412362306a36Sopenharmony_ci	sata_cmd.data_len = cpu_to_le32(task->total_xfer_len);
412462306a36Sopenharmony_ci	if (task->ata_task.return_fis_on_success)
412562306a36Sopenharmony_ci		retfis = 1;
412662306a36Sopenharmony_ci	sata_cmd.retfis_ncqtag_atap_dir_m =
412762306a36Sopenharmony_ci		cpu_to_le32((retfis << 24) | ((ncg_tag & 0xff) << 16) |
412862306a36Sopenharmony_ci			    ((ATAP & 0x3f) << 10) | dir);
412962306a36Sopenharmony_ci	sata_cmd.sata_fis = task->ata_task.fis;
413062306a36Sopenharmony_ci	if (likely(!task->ata_task.device_control_reg_update))
413162306a36Sopenharmony_ci		sata_cmd.sata_fis.flags |= 0x80;/* C=1: update ATA cmd reg */
413262306a36Sopenharmony_ci	sata_cmd.sata_fis.flags &= 0xF0;/* PM_PORT field shall be 0 */
413362306a36Sopenharmony_ci	/* fill in PRD (scatter/gather) table, if any */
413462306a36Sopenharmony_ci	if (task->num_scatter > 1) {
413562306a36Sopenharmony_ci		pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
413662306a36Sopenharmony_ci		phys_addr = ccb->ccb_dma_handle;
413762306a36Sopenharmony_ci		sata_cmd.addr_low = lower_32_bits(phys_addr);
413862306a36Sopenharmony_ci		sata_cmd.addr_high = upper_32_bits(phys_addr);
413962306a36Sopenharmony_ci		sata_cmd.esgl = cpu_to_le32(1 << 31);
414062306a36Sopenharmony_ci	} else if (task->num_scatter == 1) {
414162306a36Sopenharmony_ci		u64 dma_addr = sg_dma_address(task->scatter);
414262306a36Sopenharmony_ci		sata_cmd.addr_low = lower_32_bits(dma_addr);
414362306a36Sopenharmony_ci		sata_cmd.addr_high = upper_32_bits(dma_addr);
414462306a36Sopenharmony_ci		sata_cmd.len = cpu_to_le32(task->total_xfer_len);
414562306a36Sopenharmony_ci		sata_cmd.esgl = 0;
414662306a36Sopenharmony_ci	} else if (task->num_scatter == 0) {
414762306a36Sopenharmony_ci		sata_cmd.addr_low = 0;
414862306a36Sopenharmony_ci		sata_cmd.addr_high = 0;
414962306a36Sopenharmony_ci		sata_cmd.len = cpu_to_le32(task->total_xfer_len);
415062306a36Sopenharmony_ci		sata_cmd.esgl = 0;
415162306a36Sopenharmony_ci	}
415262306a36Sopenharmony_ci
415362306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &sata_cmd,
415462306a36Sopenharmony_ci				    sizeof(sata_cmd), 0);
415562306a36Sopenharmony_ci}
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci/**
415862306a36Sopenharmony_ci * pm8001_chip_phy_start_req - start phy via PHY_START COMMAND
415962306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
416062306a36Sopenharmony_ci * @phy_id: the phy id which we wanted to start up.
416162306a36Sopenharmony_ci */
416262306a36Sopenharmony_cistatic int
416362306a36Sopenharmony_cipm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
416462306a36Sopenharmony_ci{
416562306a36Sopenharmony_ci	struct phy_start_req payload;
416662306a36Sopenharmony_ci	u32 tag = 0x01;
416762306a36Sopenharmony_ci	u32 opcode = OPC_INB_PHYSTART;
416862306a36Sopenharmony_ci
416962306a36Sopenharmony_ci	memset(&payload, 0, sizeof(payload));
417062306a36Sopenharmony_ci	payload.tag = cpu_to_le32(tag);
417162306a36Sopenharmony_ci	/*
417262306a36Sopenharmony_ci	 ** [0:7]   PHY Identifier
417362306a36Sopenharmony_ci	 ** [8:11]  link rate 1.5G, 3G, 6G
417462306a36Sopenharmony_ci	 ** [12:13] link mode 01b SAS mode; 10b SATA mode; 11b both
417562306a36Sopenharmony_ci	 ** [14]    0b disable spin up hold; 1b enable spin up hold
417662306a36Sopenharmony_ci	 */
417762306a36Sopenharmony_ci	payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
417862306a36Sopenharmony_ci		LINKMODE_AUTO |	LINKRATE_15 |
417962306a36Sopenharmony_ci		LINKRATE_30 | LINKRATE_60 | phy_id);
418062306a36Sopenharmony_ci	payload.sas_identify.dev_type = SAS_END_DEVICE;
418162306a36Sopenharmony_ci	payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL;
418262306a36Sopenharmony_ci	memcpy(payload.sas_identify.sas_addr,
418362306a36Sopenharmony_ci		&pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE);
418462306a36Sopenharmony_ci	payload.sas_identify.phy_id = phy_id;
418562306a36Sopenharmony_ci
418662306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload,
418762306a36Sopenharmony_ci				    sizeof(payload), 0);
418862306a36Sopenharmony_ci}
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci/**
419162306a36Sopenharmony_ci * pm8001_chip_phy_stop_req - start phy via PHY_STOP COMMAND
419262306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
419362306a36Sopenharmony_ci * @phy_id: the phy id which we wanted to start up.
419462306a36Sopenharmony_ci */
419562306a36Sopenharmony_cistatic int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
419662306a36Sopenharmony_ci				    u8 phy_id)
419762306a36Sopenharmony_ci{
419862306a36Sopenharmony_ci	struct phy_stop_req payload;
419962306a36Sopenharmony_ci	u32 tag = 0x01;
420062306a36Sopenharmony_ci	u32 opcode = OPC_INB_PHYSTOP;
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	memset(&payload, 0, sizeof(payload));
420362306a36Sopenharmony_ci	payload.tag = cpu_to_le32(tag);
420462306a36Sopenharmony_ci	payload.phy_id = cpu_to_le32(phy_id);
420562306a36Sopenharmony_ci
420662306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload,
420762306a36Sopenharmony_ci				    sizeof(payload), 0);
420862306a36Sopenharmony_ci}
420962306a36Sopenharmony_ci
421062306a36Sopenharmony_ci/*
421162306a36Sopenharmony_ci * see comments on pm8001_mpi_reg_resp.
421262306a36Sopenharmony_ci */
421362306a36Sopenharmony_cistatic int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
421462306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev, u32 flag)
421562306a36Sopenharmony_ci{
421662306a36Sopenharmony_ci	struct reg_dev_req payload;
421762306a36Sopenharmony_ci	u32	opc;
421862306a36Sopenharmony_ci	u32 stp_sspsmp_sata = 0x4;
421962306a36Sopenharmony_ci	u32 linkrate, phy_id;
422062306a36Sopenharmony_ci	int rc;
422162306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
422262306a36Sopenharmony_ci	u8 retryFlag = 0x1;
422362306a36Sopenharmony_ci	u16 firstBurstSize = 0;
422462306a36Sopenharmony_ci	u16 ITNT = 2000;
422562306a36Sopenharmony_ci	struct domain_device *dev = pm8001_dev->sas_device;
422662306a36Sopenharmony_ci	struct domain_device *parent_dev = dev->parent;
422762306a36Sopenharmony_ci	struct pm8001_port *port = dev->port->lldd_port;
422862306a36Sopenharmony_ci
422962306a36Sopenharmony_ci	memset(&payload, 0, sizeof(payload));
423062306a36Sopenharmony_ci	ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_dev, NULL);
423162306a36Sopenharmony_ci	if (!ccb)
423262306a36Sopenharmony_ci		return -SAS_QUEUE_FULL;
423362306a36Sopenharmony_ci
423462306a36Sopenharmony_ci	payload.tag = cpu_to_le32(ccb->ccb_tag);
423562306a36Sopenharmony_ci	if (flag == 1)
423662306a36Sopenharmony_ci		stp_sspsmp_sata = 0x02; /*direct attached sata */
423762306a36Sopenharmony_ci	else {
423862306a36Sopenharmony_ci		if (pm8001_dev->dev_type == SAS_SATA_DEV)
423962306a36Sopenharmony_ci			stp_sspsmp_sata = 0x00; /* stp*/
424062306a36Sopenharmony_ci		else if (pm8001_dev->dev_type == SAS_END_DEVICE ||
424162306a36Sopenharmony_ci			dev_is_expander(pm8001_dev->dev_type))
424262306a36Sopenharmony_ci			stp_sspsmp_sata = 0x01; /*ssp or smp*/
424362306a36Sopenharmony_ci	}
424462306a36Sopenharmony_ci	if (parent_dev && dev_is_expander(parent_dev->dev_type))
424562306a36Sopenharmony_ci		phy_id = parent_dev->ex_dev.ex_phy->phy_id;
424662306a36Sopenharmony_ci	else
424762306a36Sopenharmony_ci		phy_id = pm8001_dev->attached_phy;
424862306a36Sopenharmony_ci	opc = OPC_INB_REG_DEV;
424962306a36Sopenharmony_ci	linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ?
425062306a36Sopenharmony_ci			pm8001_dev->sas_device->linkrate : dev->port->linkrate;
425162306a36Sopenharmony_ci	payload.phyid_portid =
425262306a36Sopenharmony_ci		cpu_to_le32(((port->port_id) & 0x0F) |
425362306a36Sopenharmony_ci		((phy_id & 0x0F) << 4));
425462306a36Sopenharmony_ci	payload.dtype_dlr_retry = cpu_to_le32((retryFlag & 0x01) |
425562306a36Sopenharmony_ci		((linkrate & 0x0F) * 0x1000000) |
425662306a36Sopenharmony_ci		((stp_sspsmp_sata & 0x03) * 0x10000000));
425762306a36Sopenharmony_ci	payload.firstburstsize_ITNexustimeout =
425862306a36Sopenharmony_ci		cpu_to_le32(ITNT | (firstBurstSize * 0x10000));
425962306a36Sopenharmony_ci	memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
426062306a36Sopenharmony_ci		SAS_ADDR_SIZE);
426162306a36Sopenharmony_ci
426262306a36Sopenharmony_ci	rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
426362306a36Sopenharmony_ci				  sizeof(payload), 0);
426462306a36Sopenharmony_ci	if (rc)
426562306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
426662306a36Sopenharmony_ci
426762306a36Sopenharmony_ci	return rc;
426862306a36Sopenharmony_ci}
426962306a36Sopenharmony_ci
427062306a36Sopenharmony_ci/*
427162306a36Sopenharmony_ci * see comments on pm8001_mpi_reg_resp.
427262306a36Sopenharmony_ci */
427362306a36Sopenharmony_ciint pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha,
427462306a36Sopenharmony_ci	u32 device_id)
427562306a36Sopenharmony_ci{
427662306a36Sopenharmony_ci	struct dereg_dev_req payload;
427762306a36Sopenharmony_ci	u32 opc = OPC_INB_DEREG_DEV_HANDLE;
427862306a36Sopenharmony_ci
427962306a36Sopenharmony_ci	memset(&payload, 0, sizeof(payload));
428062306a36Sopenharmony_ci	payload.tag = cpu_to_le32(1);
428162306a36Sopenharmony_ci	payload.device_id = cpu_to_le32(device_id);
428262306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, INIT, "unregister device device_id %d\n",
428362306a36Sopenharmony_ci		   device_id);
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
428662306a36Sopenharmony_ci				    sizeof(payload), 0);
428762306a36Sopenharmony_ci}
428862306a36Sopenharmony_ci
428962306a36Sopenharmony_ci/**
429062306a36Sopenharmony_ci * pm8001_chip_phy_ctl_req - support the local phy operation
429162306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
429262306a36Sopenharmony_ci * @phyId: the phy id which we wanted to operate
429362306a36Sopenharmony_ci * @phy_op: the phy operation to request
429462306a36Sopenharmony_ci */
429562306a36Sopenharmony_cistatic int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
429662306a36Sopenharmony_ci	u32 phyId, u32 phy_op)
429762306a36Sopenharmony_ci{
429862306a36Sopenharmony_ci	struct local_phy_ctl_req payload;
429962306a36Sopenharmony_ci	u32 opc = OPC_INB_LOCAL_PHY_CONTROL;
430062306a36Sopenharmony_ci
430162306a36Sopenharmony_ci	memset(&payload, 0, sizeof(payload));
430262306a36Sopenharmony_ci	payload.tag = cpu_to_le32(1);
430362306a36Sopenharmony_ci	payload.phyop_phyid =
430462306a36Sopenharmony_ci		cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F));
430562306a36Sopenharmony_ci
430662306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
430762306a36Sopenharmony_ci				    sizeof(payload), 0);
430862306a36Sopenharmony_ci}
430962306a36Sopenharmony_ci
431062306a36Sopenharmony_cistatic u32 pm8001_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha)
431162306a36Sopenharmony_ci{
431262306a36Sopenharmony_ci#ifdef PM8001_USE_MSIX
431362306a36Sopenharmony_ci	return 1;
431462306a36Sopenharmony_ci#else
431562306a36Sopenharmony_ci	u32 value;
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_ci	value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR);
431862306a36Sopenharmony_ci	if (value)
431962306a36Sopenharmony_ci		return 1;
432062306a36Sopenharmony_ci	return 0;
432162306a36Sopenharmony_ci#endif
432262306a36Sopenharmony_ci}
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci/**
432562306a36Sopenharmony_ci * pm8001_chip_isr - PM8001 isr handler.
432662306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
432762306a36Sopenharmony_ci * @vec: IRQ number
432862306a36Sopenharmony_ci */
432962306a36Sopenharmony_cistatic irqreturn_t
433062306a36Sopenharmony_cipm8001_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)
433162306a36Sopenharmony_ci{
433262306a36Sopenharmony_ci	pm8001_chip_interrupt_disable(pm8001_ha, vec);
433362306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, DEVIO,
433462306a36Sopenharmony_ci		   "irq vec %d, ODMR:0x%x\n",
433562306a36Sopenharmony_ci		   vec, pm8001_cr32(pm8001_ha, 0, 0x30));
433662306a36Sopenharmony_ci	process_oq(pm8001_ha, vec);
433762306a36Sopenharmony_ci	pm8001_chip_interrupt_enable(pm8001_ha, vec);
433862306a36Sopenharmony_ci	return IRQ_HANDLED;
433962306a36Sopenharmony_ci}
434062306a36Sopenharmony_ci
434162306a36Sopenharmony_cistatic int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc,
434262306a36Sopenharmony_ci	u32 dev_id, enum sas_internal_abort type, u32 task_tag, u32 cmd_tag)
434362306a36Sopenharmony_ci{
434462306a36Sopenharmony_ci	struct task_abort_req task_abort;
434562306a36Sopenharmony_ci
434662306a36Sopenharmony_ci	memset(&task_abort, 0, sizeof(task_abort));
434762306a36Sopenharmony_ci	if (type == SAS_INTERNAL_ABORT_SINGLE) {
434862306a36Sopenharmony_ci		task_abort.abort_all = 0;
434962306a36Sopenharmony_ci		task_abort.device_id = cpu_to_le32(dev_id);
435062306a36Sopenharmony_ci		task_abort.tag_to_abort = cpu_to_le32(task_tag);
435162306a36Sopenharmony_ci	} else if (type == SAS_INTERNAL_ABORT_DEV) {
435262306a36Sopenharmony_ci		task_abort.abort_all = cpu_to_le32(1);
435362306a36Sopenharmony_ci		task_abort.device_id = cpu_to_le32(dev_id);
435462306a36Sopenharmony_ci	} else {
435562306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, EH, "unknown type (%d)\n", type);
435662306a36Sopenharmony_ci		return -EIO;
435762306a36Sopenharmony_ci	}
435862306a36Sopenharmony_ci
435962306a36Sopenharmony_ci	task_abort.tag = cpu_to_le32(cmd_tag);
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &task_abort,
436262306a36Sopenharmony_ci				    sizeof(task_abort), 0);
436362306a36Sopenharmony_ci}
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci/*
436662306a36Sopenharmony_ci * pm8001_chip_abort_task - SAS abort task when error or exception happened.
436762306a36Sopenharmony_ci */
436862306a36Sopenharmony_ciint pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha,
436962306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb)
437062306a36Sopenharmony_ci{
437162306a36Sopenharmony_ci	struct sas_task *task = ccb->task;
437262306a36Sopenharmony_ci	struct sas_internal_abort_task *abort = &task->abort_task;
437362306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev = ccb->device;
437462306a36Sopenharmony_ci	int rc = TMF_RESP_FUNC_FAILED;
437562306a36Sopenharmony_ci	u32 opc, device_id;
437662306a36Sopenharmony_ci
437762306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, EH, "cmd_tag = %x, abort task tag = 0x%x\n",
437862306a36Sopenharmony_ci		   ccb->ccb_tag, abort->tag);
437962306a36Sopenharmony_ci	if (pm8001_dev->dev_type == SAS_END_DEVICE)
438062306a36Sopenharmony_ci		opc = OPC_INB_SSP_ABORT;
438162306a36Sopenharmony_ci	else if (pm8001_dev->dev_type == SAS_SATA_DEV)
438262306a36Sopenharmony_ci		opc = OPC_INB_SATA_ABORT;
438362306a36Sopenharmony_ci	else
438462306a36Sopenharmony_ci		opc = OPC_INB_SMP_ABORT;/* SMP */
438562306a36Sopenharmony_ci	device_id = pm8001_dev->device_id;
438662306a36Sopenharmony_ci	rc = send_task_abort(pm8001_ha, opc, device_id, abort->type,
438762306a36Sopenharmony_ci			     abort->tag, ccb->ccb_tag);
438862306a36Sopenharmony_ci	if (rc != TMF_RESP_FUNC_COMPLETE)
438962306a36Sopenharmony_ci		pm8001_dbg(pm8001_ha, EH, "rc= %d\n", rc);
439062306a36Sopenharmony_ci	return rc;
439162306a36Sopenharmony_ci}
439262306a36Sopenharmony_ci
439362306a36Sopenharmony_ci/**
439462306a36Sopenharmony_ci * pm8001_chip_ssp_tm_req - built the task management command.
439562306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
439662306a36Sopenharmony_ci * @ccb: the ccb information.
439762306a36Sopenharmony_ci * @tmf: task management function.
439862306a36Sopenharmony_ci */
439962306a36Sopenharmony_ciint pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha,
440062306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb, struct sas_tmf_task *tmf)
440162306a36Sopenharmony_ci{
440262306a36Sopenharmony_ci	struct sas_task *task = ccb->task;
440362306a36Sopenharmony_ci	struct domain_device *dev = task->dev;
440462306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev = dev->lldd_dev;
440562306a36Sopenharmony_ci	u32 opc = OPC_INB_SSPINITMSTART;
440662306a36Sopenharmony_ci	struct ssp_ini_tm_start_req sspTMCmd;
440762306a36Sopenharmony_ci
440862306a36Sopenharmony_ci	memset(&sspTMCmd, 0, sizeof(sspTMCmd));
440962306a36Sopenharmony_ci	sspTMCmd.device_id = cpu_to_le32(pm8001_dev->device_id);
441062306a36Sopenharmony_ci	sspTMCmd.relate_tag = cpu_to_le32((u32)tmf->tag_of_task_to_be_managed);
441162306a36Sopenharmony_ci	sspTMCmd.tmf = cpu_to_le32(tmf->tmf);
441262306a36Sopenharmony_ci	memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8);
441362306a36Sopenharmony_ci	sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag);
441462306a36Sopenharmony_ci	if (pm8001_ha->chip_id != chip_8001)
441562306a36Sopenharmony_ci		sspTMCmd.ds_ads_m = cpu_to_le32(0x08);
441662306a36Sopenharmony_ci
441762306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &sspTMCmd,
441862306a36Sopenharmony_ci				    sizeof(sspTMCmd), 0);
441962306a36Sopenharmony_ci}
442062306a36Sopenharmony_ci
442162306a36Sopenharmony_ciint pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
442262306a36Sopenharmony_ci	void *payload)
442362306a36Sopenharmony_ci{
442462306a36Sopenharmony_ci	u32 opc = OPC_INB_GET_NVMD_DATA;
442562306a36Sopenharmony_ci	u32 nvmd_type;
442662306a36Sopenharmony_ci	int rc;
442762306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
442862306a36Sopenharmony_ci	struct get_nvm_data_req nvmd_req;
442962306a36Sopenharmony_ci	struct fw_control_ex *fw_control_context;
443062306a36Sopenharmony_ci	struct pm8001_ioctl_payload *ioctl_payload = payload;
443162306a36Sopenharmony_ci
443262306a36Sopenharmony_ci	nvmd_type = ioctl_payload->minor_function;
443362306a36Sopenharmony_ci	fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
443462306a36Sopenharmony_ci	if (!fw_control_context)
443562306a36Sopenharmony_ci		return -ENOMEM;
443662306a36Sopenharmony_ci	fw_control_context->usrAddr = (u8 *)ioctl_payload->func_specific;
443762306a36Sopenharmony_ci	fw_control_context->len = ioctl_payload->rd_length;
443862306a36Sopenharmony_ci	memset(&nvmd_req, 0, sizeof(nvmd_req));
443962306a36Sopenharmony_ci
444062306a36Sopenharmony_ci	ccb = pm8001_ccb_alloc(pm8001_ha, NULL, NULL);
444162306a36Sopenharmony_ci	if (!ccb) {
444262306a36Sopenharmony_ci		kfree(fw_control_context);
444362306a36Sopenharmony_ci		return -SAS_QUEUE_FULL;
444462306a36Sopenharmony_ci	}
444562306a36Sopenharmony_ci	ccb->fw_control_context = fw_control_context;
444662306a36Sopenharmony_ci
444762306a36Sopenharmony_ci	nvmd_req.tag = cpu_to_le32(ccb->ccb_tag);
444862306a36Sopenharmony_ci
444962306a36Sopenharmony_ci	switch (nvmd_type) {
445062306a36Sopenharmony_ci	case TWI_DEVICE: {
445162306a36Sopenharmony_ci		u32 twi_addr, twi_page_size;
445262306a36Sopenharmony_ci		twi_addr = 0xa8;
445362306a36Sopenharmony_ci		twi_page_size = 2;
445462306a36Sopenharmony_ci
445562306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
445662306a36Sopenharmony_ci			twi_page_size << 8 | TWI_DEVICE);
445762306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
445862306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
445962306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
446062306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
446162306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
446262306a36Sopenharmony_ci		break;
446362306a36Sopenharmony_ci	}
446462306a36Sopenharmony_ci	case C_SEEPROM: {
446562306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
446662306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
446762306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
446862306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
446962306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
447062306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
447162306a36Sopenharmony_ci		break;
447262306a36Sopenharmony_ci	}
447362306a36Sopenharmony_ci	case VPD_FLASH: {
447462306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
447562306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
447662306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
447762306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
447862306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
447962306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
448062306a36Sopenharmony_ci		break;
448162306a36Sopenharmony_ci	}
448262306a36Sopenharmony_ci	case EXPAN_ROM: {
448362306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
448462306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
448562306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
448662306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
448762306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
448862306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
448962306a36Sopenharmony_ci		break;
449062306a36Sopenharmony_ci	}
449162306a36Sopenharmony_ci	case IOP_RDUMP: {
449262306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | IOP_RDUMP);
449362306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
449462306a36Sopenharmony_ci		nvmd_req.vpd_offset = cpu_to_le32(ioctl_payload->offset);
449562306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
449662306a36Sopenharmony_ci		cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
449762306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
449862306a36Sopenharmony_ci		cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
449962306a36Sopenharmony_ci		break;
450062306a36Sopenharmony_ci	}
450162306a36Sopenharmony_ci	default:
450262306a36Sopenharmony_ci		break;
450362306a36Sopenharmony_ci	}
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &nvmd_req,
450662306a36Sopenharmony_ci				  sizeof(nvmd_req), 0);
450762306a36Sopenharmony_ci	if (rc) {
450862306a36Sopenharmony_ci		kfree(fw_control_context);
450962306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
451062306a36Sopenharmony_ci	}
451162306a36Sopenharmony_ci	return rc;
451262306a36Sopenharmony_ci}
451362306a36Sopenharmony_ci
451462306a36Sopenharmony_ciint pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
451562306a36Sopenharmony_ci	void *payload)
451662306a36Sopenharmony_ci{
451762306a36Sopenharmony_ci	u32 opc = OPC_INB_SET_NVMD_DATA;
451862306a36Sopenharmony_ci	u32 nvmd_type;
451962306a36Sopenharmony_ci	int rc;
452062306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
452162306a36Sopenharmony_ci	struct set_nvm_data_req nvmd_req;
452262306a36Sopenharmony_ci	struct fw_control_ex *fw_control_context;
452362306a36Sopenharmony_ci	struct pm8001_ioctl_payload *ioctl_payload = payload;
452462306a36Sopenharmony_ci
452562306a36Sopenharmony_ci	nvmd_type = ioctl_payload->minor_function;
452662306a36Sopenharmony_ci	fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
452762306a36Sopenharmony_ci	if (!fw_control_context)
452862306a36Sopenharmony_ci		return -ENOMEM;
452962306a36Sopenharmony_ci
453062306a36Sopenharmony_ci	memcpy(pm8001_ha->memoryMap.region[NVMD].virt_ptr,
453162306a36Sopenharmony_ci		&ioctl_payload->func_specific,
453262306a36Sopenharmony_ci		ioctl_payload->wr_length);
453362306a36Sopenharmony_ci	memset(&nvmd_req, 0, sizeof(nvmd_req));
453462306a36Sopenharmony_ci
453562306a36Sopenharmony_ci	ccb = pm8001_ccb_alloc(pm8001_ha, NULL, NULL);
453662306a36Sopenharmony_ci	if (!ccb) {
453762306a36Sopenharmony_ci		kfree(fw_control_context);
453862306a36Sopenharmony_ci		return -SAS_QUEUE_FULL;
453962306a36Sopenharmony_ci	}
454062306a36Sopenharmony_ci	ccb->fw_control_context = fw_control_context;
454162306a36Sopenharmony_ci
454262306a36Sopenharmony_ci	nvmd_req.tag = cpu_to_le32(ccb->ccb_tag);
454362306a36Sopenharmony_ci	switch (nvmd_type) {
454462306a36Sopenharmony_ci	case TWI_DEVICE: {
454562306a36Sopenharmony_ci		u32 twi_addr, twi_page_size;
454662306a36Sopenharmony_ci		twi_addr = 0xa8;
454762306a36Sopenharmony_ci		twi_page_size = 2;
454862306a36Sopenharmony_ci		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
454962306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
455062306a36Sopenharmony_ci			twi_page_size << 8 | TWI_DEVICE);
455162306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
455262306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
455362306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
455462306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
455562306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
455662306a36Sopenharmony_ci		break;
455762306a36Sopenharmony_ci	}
455862306a36Sopenharmony_ci	case C_SEEPROM:
455962306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
456062306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
456162306a36Sopenharmony_ci		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
456262306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
456362306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
456462306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
456562306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
456662306a36Sopenharmony_ci		break;
456762306a36Sopenharmony_ci	case VPD_FLASH:
456862306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
456962306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
457062306a36Sopenharmony_ci		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
457162306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
457262306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
457362306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
457462306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
457562306a36Sopenharmony_ci		break;
457662306a36Sopenharmony_ci	case EXPAN_ROM:
457762306a36Sopenharmony_ci		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
457862306a36Sopenharmony_ci		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
457962306a36Sopenharmony_ci		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
458062306a36Sopenharmony_ci		nvmd_req.resp_addr_hi =
458162306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
458262306a36Sopenharmony_ci		nvmd_req.resp_addr_lo =
458362306a36Sopenharmony_ci		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
458462306a36Sopenharmony_ci		break;
458562306a36Sopenharmony_ci	default:
458662306a36Sopenharmony_ci		break;
458762306a36Sopenharmony_ci	}
458862306a36Sopenharmony_ci
458962306a36Sopenharmony_ci	rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &nvmd_req,
459062306a36Sopenharmony_ci			sizeof(nvmd_req), 0);
459162306a36Sopenharmony_ci	if (rc) {
459262306a36Sopenharmony_ci		kfree(fw_control_context);
459362306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
459462306a36Sopenharmony_ci	}
459562306a36Sopenharmony_ci	return rc;
459662306a36Sopenharmony_ci}
459762306a36Sopenharmony_ci
459862306a36Sopenharmony_ci/**
459962306a36Sopenharmony_ci * pm8001_chip_fw_flash_update_build - support the firmware update operation
460062306a36Sopenharmony_ci * @pm8001_ha: our hba card information.
460162306a36Sopenharmony_ci * @fw_flash_updata_info: firmware flash update param
460262306a36Sopenharmony_ci * @tag: Tag to apply to the payload
460362306a36Sopenharmony_ci */
460462306a36Sopenharmony_ciint
460562306a36Sopenharmony_cipm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha,
460662306a36Sopenharmony_ci	void *fw_flash_updata_info, u32 tag)
460762306a36Sopenharmony_ci{
460862306a36Sopenharmony_ci	struct fw_flash_Update_req payload;
460962306a36Sopenharmony_ci	struct fw_flash_updata_info *info;
461062306a36Sopenharmony_ci	u32 opc = OPC_INB_FW_FLASH_UPDATE;
461162306a36Sopenharmony_ci
461262306a36Sopenharmony_ci	memset(&payload, 0, sizeof(struct fw_flash_Update_req));
461362306a36Sopenharmony_ci	info = fw_flash_updata_info;
461462306a36Sopenharmony_ci	payload.tag = cpu_to_le32(tag);
461562306a36Sopenharmony_ci	payload.cur_image_len = cpu_to_le32(info->cur_image_len);
461662306a36Sopenharmony_ci	payload.cur_image_offset = cpu_to_le32(info->cur_image_offset);
461762306a36Sopenharmony_ci	payload.total_image_len = cpu_to_le32(info->total_image_len);
461862306a36Sopenharmony_ci	payload.len = info->sgl.im_len.len ;
461962306a36Sopenharmony_ci	payload.sgl_addr_lo =
462062306a36Sopenharmony_ci		cpu_to_le32(lower_32_bits(le64_to_cpu(info->sgl.addr)));
462162306a36Sopenharmony_ci	payload.sgl_addr_hi =
462262306a36Sopenharmony_ci		cpu_to_le32(upper_32_bits(le64_to_cpu(info->sgl.addr)));
462362306a36Sopenharmony_ci
462462306a36Sopenharmony_ci	return pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
462562306a36Sopenharmony_ci				    sizeof(payload), 0);
462662306a36Sopenharmony_ci}
462762306a36Sopenharmony_ci
462862306a36Sopenharmony_ciint
462962306a36Sopenharmony_cipm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
463062306a36Sopenharmony_ci	void *payload)
463162306a36Sopenharmony_ci{
463262306a36Sopenharmony_ci	struct fw_flash_updata_info flash_update_info;
463362306a36Sopenharmony_ci	struct fw_control_info *fw_control;
463462306a36Sopenharmony_ci	struct fw_control_ex *fw_control_context;
463562306a36Sopenharmony_ci	int rc;
463662306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
463762306a36Sopenharmony_ci	void *buffer = pm8001_ha->memoryMap.region[FW_FLASH].virt_ptr;
463862306a36Sopenharmony_ci	dma_addr_t phys_addr = pm8001_ha->memoryMap.region[FW_FLASH].phys_addr;
463962306a36Sopenharmony_ci	struct pm8001_ioctl_payload *ioctl_payload = payload;
464062306a36Sopenharmony_ci
464162306a36Sopenharmony_ci	fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
464262306a36Sopenharmony_ci	if (!fw_control_context)
464362306a36Sopenharmony_ci		return -ENOMEM;
464462306a36Sopenharmony_ci	fw_control = (struct fw_control_info *)&ioctl_payload->func_specific;
464562306a36Sopenharmony_ci	pm8001_dbg(pm8001_ha, DEVIO,
464662306a36Sopenharmony_ci		   "dma fw_control context input length :%x\n",
464762306a36Sopenharmony_ci		   fw_control->len);
464862306a36Sopenharmony_ci	memcpy(buffer, fw_control->buffer, fw_control->len);
464962306a36Sopenharmony_ci	flash_update_info.sgl.addr = cpu_to_le64(phys_addr);
465062306a36Sopenharmony_ci	flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len);
465162306a36Sopenharmony_ci	flash_update_info.sgl.im_len.e = 0;
465262306a36Sopenharmony_ci	flash_update_info.cur_image_offset = fw_control->offset;
465362306a36Sopenharmony_ci	flash_update_info.cur_image_len = fw_control->len;
465462306a36Sopenharmony_ci	flash_update_info.total_image_len = fw_control->size;
465562306a36Sopenharmony_ci	fw_control_context->fw_control = fw_control;
465662306a36Sopenharmony_ci	fw_control_context->virtAddr = buffer;
465762306a36Sopenharmony_ci	fw_control_context->phys_addr = phys_addr;
465862306a36Sopenharmony_ci	fw_control_context->len = fw_control->len;
465962306a36Sopenharmony_ci
466062306a36Sopenharmony_ci	ccb = pm8001_ccb_alloc(pm8001_ha, NULL, NULL);
466162306a36Sopenharmony_ci	if (!ccb) {
466262306a36Sopenharmony_ci		kfree(fw_control_context);
466362306a36Sopenharmony_ci		return -SAS_QUEUE_FULL;
466462306a36Sopenharmony_ci	}
466562306a36Sopenharmony_ci	ccb->fw_control_context = fw_control_context;
466662306a36Sopenharmony_ci
466762306a36Sopenharmony_ci	rc = pm8001_chip_fw_flash_update_build(pm8001_ha, &flash_update_info,
466862306a36Sopenharmony_ci					       ccb->ccb_tag);
466962306a36Sopenharmony_ci	if (rc) {
467062306a36Sopenharmony_ci		kfree(fw_control_context);
467162306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
467262306a36Sopenharmony_ci	}
467362306a36Sopenharmony_ci
467462306a36Sopenharmony_ci	return rc;
467562306a36Sopenharmony_ci}
467662306a36Sopenharmony_ci
467762306a36Sopenharmony_cissize_t
467862306a36Sopenharmony_cipm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
467962306a36Sopenharmony_ci{
468062306a36Sopenharmony_ci	u32 value, rem, offset = 0, bar = 0;
468162306a36Sopenharmony_ci	u32 index, work_offset, dw_length;
468262306a36Sopenharmony_ci	u32 shift_value, gsm_base, gsm_dump_offset;
468362306a36Sopenharmony_ci	char *direct_data;
468462306a36Sopenharmony_ci	struct Scsi_Host *shost = class_to_shost(cdev);
468562306a36Sopenharmony_ci	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
468662306a36Sopenharmony_ci	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
468762306a36Sopenharmony_ci
468862306a36Sopenharmony_ci	direct_data = buf;
468962306a36Sopenharmony_ci	gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset;
469062306a36Sopenharmony_ci
469162306a36Sopenharmony_ci	/* check max is 1 Mbytes */
469262306a36Sopenharmony_ci	if ((length > 0x100000) || (gsm_dump_offset & 3) ||
469362306a36Sopenharmony_ci		((gsm_dump_offset + length) > 0x1000000))
469462306a36Sopenharmony_ci			return -EINVAL;
469562306a36Sopenharmony_ci
469662306a36Sopenharmony_ci	if (pm8001_ha->chip_id == chip_8001)
469762306a36Sopenharmony_ci		bar = 2;
469862306a36Sopenharmony_ci	else
469962306a36Sopenharmony_ci		bar = 1;
470062306a36Sopenharmony_ci
470162306a36Sopenharmony_ci	work_offset = gsm_dump_offset & 0xFFFF0000;
470262306a36Sopenharmony_ci	offset = gsm_dump_offset & 0x0000FFFF;
470362306a36Sopenharmony_ci	gsm_dump_offset = work_offset;
470462306a36Sopenharmony_ci	/* adjust length to dword boundary */
470562306a36Sopenharmony_ci	rem = length & 3;
470662306a36Sopenharmony_ci	dw_length = length >> 2;
470762306a36Sopenharmony_ci
470862306a36Sopenharmony_ci	for (index = 0; index < dw_length; index++) {
470962306a36Sopenharmony_ci		if ((work_offset + offset) & 0xFFFF0000) {
471062306a36Sopenharmony_ci			if (pm8001_ha->chip_id == chip_8001)
471162306a36Sopenharmony_ci				shift_value = ((gsm_dump_offset + offset) &
471262306a36Sopenharmony_ci						SHIFT_REG_64K_MASK);
471362306a36Sopenharmony_ci			else
471462306a36Sopenharmony_ci				shift_value = (((gsm_dump_offset + offset) &
471562306a36Sopenharmony_ci						SHIFT_REG_64K_MASK) >>
471662306a36Sopenharmony_ci						SHIFT_REG_BIT_SHIFT);
471762306a36Sopenharmony_ci
471862306a36Sopenharmony_ci			if (pm8001_ha->chip_id == chip_8001) {
471962306a36Sopenharmony_ci				gsm_base = GSM_BASE;
472062306a36Sopenharmony_ci				if (-1 == pm8001_bar4_shift(pm8001_ha,
472162306a36Sopenharmony_ci						(gsm_base + shift_value)))
472262306a36Sopenharmony_ci					return -EIO;
472362306a36Sopenharmony_ci			} else {
472462306a36Sopenharmony_ci				gsm_base = 0;
472562306a36Sopenharmony_ci				if (-1 == pm80xx_bar4_shift(pm8001_ha,
472662306a36Sopenharmony_ci						(gsm_base + shift_value)))
472762306a36Sopenharmony_ci					return -EIO;
472862306a36Sopenharmony_ci			}
472962306a36Sopenharmony_ci			gsm_dump_offset = (gsm_dump_offset + offset) &
473062306a36Sopenharmony_ci						0xFFFF0000;
473162306a36Sopenharmony_ci			work_offset = 0;
473262306a36Sopenharmony_ci			offset = offset & 0x0000FFFF;
473362306a36Sopenharmony_ci		}
473462306a36Sopenharmony_ci		value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
473562306a36Sopenharmony_ci						0x0000FFFF);
473662306a36Sopenharmony_ci		direct_data += sprintf(direct_data, "%08x ", value);
473762306a36Sopenharmony_ci		offset += 4;
473862306a36Sopenharmony_ci	}
473962306a36Sopenharmony_ci	if (rem != 0) {
474062306a36Sopenharmony_ci		value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
474162306a36Sopenharmony_ci						0x0000FFFF);
474262306a36Sopenharmony_ci		/* xfr for non_dw */
474362306a36Sopenharmony_ci		direct_data += sprintf(direct_data, "%08x ", value);
474462306a36Sopenharmony_ci	}
474562306a36Sopenharmony_ci	/* Shift back to BAR4 original address */
474662306a36Sopenharmony_ci	if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
474762306a36Sopenharmony_ci			return -EIO;
474862306a36Sopenharmony_ci	pm8001_ha->fatal_forensic_shift_offset += 1024;
474962306a36Sopenharmony_ci
475062306a36Sopenharmony_ci	if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
475162306a36Sopenharmony_ci		pm8001_ha->fatal_forensic_shift_offset = 0;
475262306a36Sopenharmony_ci	return direct_data - buf;
475362306a36Sopenharmony_ci}
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ciint
475662306a36Sopenharmony_cipm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
475762306a36Sopenharmony_ci	struct pm8001_device *pm8001_dev, u32 state)
475862306a36Sopenharmony_ci{
475962306a36Sopenharmony_ci	struct set_dev_state_req payload;
476062306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
476162306a36Sopenharmony_ci	int rc;
476262306a36Sopenharmony_ci	u32 opc = OPC_INB_SET_DEVICE_STATE;
476362306a36Sopenharmony_ci
476462306a36Sopenharmony_ci	memset(&payload, 0, sizeof(payload));
476562306a36Sopenharmony_ci
476662306a36Sopenharmony_ci	ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_dev, NULL);
476762306a36Sopenharmony_ci	if (!ccb)
476862306a36Sopenharmony_ci		return -SAS_QUEUE_FULL;
476962306a36Sopenharmony_ci
477062306a36Sopenharmony_ci	payload.tag = cpu_to_le32(ccb->ccb_tag);
477162306a36Sopenharmony_ci	payload.device_id = cpu_to_le32(pm8001_dev->device_id);
477262306a36Sopenharmony_ci	payload.nds = cpu_to_le32(state);
477362306a36Sopenharmony_ci
477462306a36Sopenharmony_ci	rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
477562306a36Sopenharmony_ci				  sizeof(payload), 0);
477662306a36Sopenharmony_ci	if (rc)
477762306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
477862306a36Sopenharmony_ci
477962306a36Sopenharmony_ci	return rc;
478062306a36Sopenharmony_ci}
478162306a36Sopenharmony_ci
478262306a36Sopenharmony_cistatic int
478362306a36Sopenharmony_cipm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
478462306a36Sopenharmony_ci{
478562306a36Sopenharmony_ci	struct sas_re_initialization_req payload;
478662306a36Sopenharmony_ci	struct pm8001_ccb_info *ccb;
478762306a36Sopenharmony_ci	int rc;
478862306a36Sopenharmony_ci	u32 opc = OPC_INB_SAS_RE_INITIALIZE;
478962306a36Sopenharmony_ci
479062306a36Sopenharmony_ci	memset(&payload, 0, sizeof(payload));
479162306a36Sopenharmony_ci
479262306a36Sopenharmony_ci	ccb = pm8001_ccb_alloc(pm8001_ha, NULL, NULL);
479362306a36Sopenharmony_ci	if (!ccb)
479462306a36Sopenharmony_ci		return -SAS_QUEUE_FULL;
479562306a36Sopenharmony_ci
479662306a36Sopenharmony_ci	payload.tag = cpu_to_le32(ccb->ccb_tag);
479762306a36Sopenharmony_ci	payload.SSAHOLT = cpu_to_le32(0xd << 25);
479862306a36Sopenharmony_ci	payload.sata_hol_tmo = cpu_to_le32(80);
479962306a36Sopenharmony_ci	payload.open_reject_cmdretries_data_retries = cpu_to_le32(0xff00ff);
480062306a36Sopenharmony_ci
480162306a36Sopenharmony_ci	rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
480262306a36Sopenharmony_ci				  sizeof(payload), 0);
480362306a36Sopenharmony_ci	if (rc)
480462306a36Sopenharmony_ci		pm8001_ccb_free(pm8001_ha, ccb);
480562306a36Sopenharmony_ci
480662306a36Sopenharmony_ci	return rc;
480762306a36Sopenharmony_ci}
480862306a36Sopenharmony_ci
480962306a36Sopenharmony_ciconst struct pm8001_dispatch pm8001_8001_dispatch = {
481062306a36Sopenharmony_ci	.name			= "pmc8001",
481162306a36Sopenharmony_ci	.chip_init		= pm8001_chip_init,
481262306a36Sopenharmony_ci	.chip_post_init		= pm8001_chip_post_init,
481362306a36Sopenharmony_ci	.chip_soft_rst		= pm8001_chip_soft_rst,
481462306a36Sopenharmony_ci	.chip_rst		= pm8001_hw_chip_rst,
481562306a36Sopenharmony_ci	.chip_iounmap		= pm8001_chip_iounmap,
481662306a36Sopenharmony_ci	.isr			= pm8001_chip_isr,
481762306a36Sopenharmony_ci	.is_our_interrupt	= pm8001_chip_is_our_interrupt,
481862306a36Sopenharmony_ci	.isr_process_oq		= process_oq,
481962306a36Sopenharmony_ci	.interrupt_enable 	= pm8001_chip_interrupt_enable,
482062306a36Sopenharmony_ci	.interrupt_disable	= pm8001_chip_interrupt_disable,
482162306a36Sopenharmony_ci	.make_prd		= pm8001_chip_make_sg,
482262306a36Sopenharmony_ci	.smp_req		= pm8001_chip_smp_req,
482362306a36Sopenharmony_ci	.ssp_io_req		= pm8001_chip_ssp_io_req,
482462306a36Sopenharmony_ci	.sata_req		= pm8001_chip_sata_req,
482562306a36Sopenharmony_ci	.phy_start_req		= pm8001_chip_phy_start_req,
482662306a36Sopenharmony_ci	.phy_stop_req		= pm8001_chip_phy_stop_req,
482762306a36Sopenharmony_ci	.reg_dev_req		= pm8001_chip_reg_dev_req,
482862306a36Sopenharmony_ci	.dereg_dev_req		= pm8001_chip_dereg_dev_req,
482962306a36Sopenharmony_ci	.phy_ctl_req		= pm8001_chip_phy_ctl_req,
483062306a36Sopenharmony_ci	.task_abort		= pm8001_chip_abort_task,
483162306a36Sopenharmony_ci	.ssp_tm_req		= pm8001_chip_ssp_tm_req,
483262306a36Sopenharmony_ci	.get_nvmd_req		= pm8001_chip_get_nvmd_req,
483362306a36Sopenharmony_ci	.set_nvmd_req		= pm8001_chip_set_nvmd_req,
483462306a36Sopenharmony_ci	.fw_flash_update_req	= pm8001_chip_fw_flash_update_req,
483562306a36Sopenharmony_ci	.set_dev_state_req	= pm8001_chip_set_dev_state_req,
483662306a36Sopenharmony_ci	.sas_re_init_req	= pm8001_chip_sas_re_initialization,
483762306a36Sopenharmony_ci	.fatal_errors		= pm80xx_fatal_errors,
483862306a36Sopenharmony_ci};
4839