pm8001_hwi.c 163.1 KB
Newer Older
J
jack wang 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/*
 * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver
 *
 * Copyright (c) 2008-2009 USI Co., Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 *
 */
40
 #include <linux/slab.h>
J
jack wang 已提交
41 42 43 44 45 46 47 48 49
 #include "pm8001_sas.h"
 #include "pm8001_hwi.h"
 #include "pm8001_chips.h"
 #include "pm8001_ctl.h"

/**
 * read_main_config_table - read the configure table and save it.
 * @pm8001_ha: our hba card information
 */
50
static void read_main_config_table(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
51 52
{
	void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
	pm8001_ha->main_cfg_tbl.pm8001_tbl.signature	=
				pm8001_mr32(address, 0x00);
	pm8001_ha->main_cfg_tbl.pm8001_tbl.interface_rev =
				pm8001_mr32(address, 0x04);
	pm8001_ha->main_cfg_tbl.pm8001_tbl.firmware_rev	=
				pm8001_mr32(address, 0x08);
	pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io	=
				pm8001_mr32(address, 0x0C);
	pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl	=
				pm8001_mr32(address, 0x10);
	pm8001_ha->main_cfg_tbl.pm8001_tbl.ctrl_cap_flag =
				pm8001_mr32(address, 0x14);
	pm8001_ha->main_cfg_tbl.pm8001_tbl.gst_offset	=
				pm8001_mr32(address, 0x18);
	pm8001_ha->main_cfg_tbl.pm8001_tbl.inbound_queue_offset =
68
		pm8001_mr32(address, MAIN_IBQ_OFFSET);
69
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_queue_offset =
70
		pm8001_mr32(address, MAIN_OBQ_OFFSET);
71
	pm8001_ha->main_cfg_tbl.pm8001_tbl.hda_mode_flag	=
J
jack wang 已提交
72 73 74
		pm8001_mr32(address, MAIN_HDA_FLAGS_OFFSET);

	/* read analog Setting offset from the configuration table */
75
	pm8001_ha->main_cfg_tbl.pm8001_tbl.anolog_setup_table_offset =
J
jack wang 已提交
76 77 78
		pm8001_mr32(address, MAIN_ANALOG_SETUP_OFFSET);

	/* read Error Dump Offset and Length */
79
	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_offset0 =
J
jack wang 已提交
80
		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_OFFSET);
81
	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_length0 =
J
jack wang 已提交
82
		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_LENGTH);
83
	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_offset1 =
J
jack wang 已提交
84
		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_OFFSET);
85
	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_dump_length1 =
J
jack wang 已提交
86 87 88 89 90 91 92
		pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_LENGTH);
}

/**
 * read_general_status_table - read the general status table and save it.
 * @pm8001_ha: our hba card information
 */
93
static void read_general_status_table(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
94 95
{
	void __iomem *address = pm8001_ha->general_stat_tbl_addr;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
	pm8001_ha->gs_tbl.pm8001_tbl.gst_len_mpistate	=
				pm8001_mr32(address, 0x00);
	pm8001_ha->gs_tbl.pm8001_tbl.iq_freeze_state0	=
				pm8001_mr32(address, 0x04);
	pm8001_ha->gs_tbl.pm8001_tbl.iq_freeze_state1	=
				pm8001_mr32(address, 0x08);
	pm8001_ha->gs_tbl.pm8001_tbl.msgu_tcnt		=
				pm8001_mr32(address, 0x0C);
	pm8001_ha->gs_tbl.pm8001_tbl.iop_tcnt		=
				pm8001_mr32(address, 0x10);
	pm8001_ha->gs_tbl.pm8001_tbl.rsvd		=
				pm8001_mr32(address, 0x14);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[0]	=
				pm8001_mr32(address, 0x18);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[1]	=
				pm8001_mr32(address, 0x1C);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[2]	=
				pm8001_mr32(address, 0x20);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[3]	=
				pm8001_mr32(address, 0x24);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[4]	=
				pm8001_mr32(address, 0x28);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[5]	=
				pm8001_mr32(address, 0x2C);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[6]	=
				pm8001_mr32(address, 0x30);
	pm8001_ha->gs_tbl.pm8001_tbl.phy_state[7]	=
				pm8001_mr32(address, 0x34);
	pm8001_ha->gs_tbl.pm8001_tbl.gpio_input_val	=
				pm8001_mr32(address, 0x38);
	pm8001_ha->gs_tbl.pm8001_tbl.rsvd1[0]		=
				pm8001_mr32(address, 0x3C);
	pm8001_ha->gs_tbl.pm8001_tbl.rsvd1[1]		=
				pm8001_mr32(address, 0x40);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[0]	=
				pm8001_mr32(address, 0x44);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[1]	=
				pm8001_mr32(address, 0x48);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[2]	=
				pm8001_mr32(address, 0x4C);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[3]	=
				pm8001_mr32(address, 0x50);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[4]	=
				pm8001_mr32(address, 0x54);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[5]	=
				pm8001_mr32(address, 0x58);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[6]	=
				pm8001_mr32(address, 0x5C);
	pm8001_ha->gs_tbl.pm8001_tbl.recover_err_info[7]	=
				pm8001_mr32(address, 0x60);
J
jack wang 已提交
146 147 148 149 150 151
}

/**
 * read_inbnd_queue_table - read the inbound queue table and save it.
 * @pm8001_ha: our hba card information
 */
152
static void read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
153 154 155
{
	int i;
	void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
156
	for (i = 0; i < PM8001_MAX_INB_NUM; i++) {
157
		u32 offset = i * 0x20;
J
jack wang 已提交
158 159 160 161 162 163 164 165 166 167 168
		pm8001_ha->inbnd_q_tbl[i].pi_pci_bar =
		      get_pci_bar_index(pm8001_mr32(address, (offset + 0x14)));
		pm8001_ha->inbnd_q_tbl[i].pi_offset =
			pm8001_mr32(address, (offset + 0x18));
	}
}

/**
 * read_outbnd_queue_table - read the outbound queue table and save it.
 * @pm8001_ha: our hba card information
 */
169
static void read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
170 171 172
{
	int i;
	void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
173
	for (i = 0; i < PM8001_MAX_OUTB_NUM; i++) {
J
jack wang 已提交
174 175 176 177 178 179 180 181 182 183 184 185
		u32 offset = i * 0x24;
		pm8001_ha->outbnd_q_tbl[i].ci_pci_bar =
		      get_pci_bar_index(pm8001_mr32(address, (offset + 0x14)));
		pm8001_ha->outbnd_q_tbl[i].ci_offset =
			pm8001_mr32(address, (offset + 0x18));
	}
}

/**
 * init_default_table_values - init the default table.
 * @pm8001_ha: our hba card information
 */
186
static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
187 188 189 190 191
{
	int i;
	u32 offsetib, offsetob;
	void __iomem *addressib = pm8001_ha->inbnd_q_tbl_addr;
	void __iomem *addressob = pm8001_ha->outbnd_q_tbl_addr;
192 193 194 195
	u32 ib_offset = pm8001_ha->ib_offset;
	u32 ob_offset = pm8001_ha->ob_offset;
	u32 ci_offset = pm8001_ha->ci_offset;
	u32 pi_offset = pm8001_ha->pi_offset;
J
jack wang 已提交
196

197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	pm8001_ha->main_cfg_tbl.pm8001_tbl.inbound_q_nppd_hppd		= 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid0_3	= 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid4_7	= 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid0_3	= 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid4_7	= 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ITNexus_event_pid0_3 =
									 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ITNexus_event_pid4_7 =
									 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ssp_event_pid0_3 = 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_ssp_event_pid4_7 = 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_smp_event_pid0_3 = 0;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_tgt_smp_event_pid4_7 = 0;

	pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_event_log_addr		=
J
jack wang 已提交
212
		pm8001_ha->memoryMap.region[AAP1].phys_addr_hi;
213
	pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_event_log_addr		=
J
jack wang 已提交
214
		pm8001_ha->memoryMap.region[AAP1].phys_addr_lo;
215 216 217 218
	pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_size		=
		PM8001_EVENT_LOG_SIZE;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_option		= 0x01;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_iop_event_log_addr	=
J
jack wang 已提交
219
		pm8001_ha->memoryMap.region[IOP].phys_addr_hi;
220
	pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_iop_event_log_addr	=
J
jack wang 已提交
221
		pm8001_ha->memoryMap.region[IOP].phys_addr_lo;
222 223 224 225
	pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_size		=
		PM8001_EVENT_LOG_SIZE;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_option		= 0x01;
	pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_interrupt		= 0x01;
226
	for (i = 0; i < pm8001_ha->max_q_num; i++) {
J
jack wang 已提交
227
		pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt	=
228
			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30);
J
jack wang 已提交
229
		pm8001_ha->inbnd_q_tbl[i].upper_base_addr	=
230
			pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_hi;
J
jack wang 已提交
231
		pm8001_ha->inbnd_q_tbl[i].lower_base_addr	=
232
		pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_lo;
J
jack wang 已提交
233
		pm8001_ha->inbnd_q_tbl[i].base_virt		=
234
		  (u8 *)pm8001_ha->memoryMap.region[ib_offset + i].virt_ptr;
J
jack wang 已提交
235
		pm8001_ha->inbnd_q_tbl[i].total_length		=
236
			pm8001_ha->memoryMap.region[ib_offset + i].total_len;
J
jack wang 已提交
237
		pm8001_ha->inbnd_q_tbl[i].ci_upper_base_addr	=
238
			pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_hi;
J
jack wang 已提交
239
		pm8001_ha->inbnd_q_tbl[i].ci_lower_base_addr	=
240
			pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_lo;
J
jack wang 已提交
241
		pm8001_ha->inbnd_q_tbl[i].ci_virt		=
242
			pm8001_ha->memoryMap.region[ci_offset + i].virt_ptr;
243
		pm8001_write_32(pm8001_ha->inbnd_q_tbl[i].ci_virt, 0, 0);
J
jack wang 已提交
244 245 246 247 248 249 250 251 252
		offsetib = i * 0x20;
		pm8001_ha->inbnd_q_tbl[i].pi_pci_bar		=
			get_pci_bar_index(pm8001_mr32(addressib,
				(offsetib + 0x14)));
		pm8001_ha->inbnd_q_tbl[i].pi_offset		=
			pm8001_mr32(addressib, (offsetib + 0x18));
		pm8001_ha->inbnd_q_tbl[i].producer_idx		= 0;
		pm8001_ha->inbnd_q_tbl[i].consumer_index	= 0;
	}
253
	for (i = 0; i < pm8001_ha->max_q_num; i++) {
J
jack wang 已提交
254
		pm8001_ha->outbnd_q_tbl[i].element_size_cnt	=
255
			PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30);
J
jack wang 已提交
256
		pm8001_ha->outbnd_q_tbl[i].upper_base_addr	=
257
			pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_hi;
J
jack wang 已提交
258
		pm8001_ha->outbnd_q_tbl[i].lower_base_addr	=
259
			pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_lo;
J
jack wang 已提交
260
		pm8001_ha->outbnd_q_tbl[i].base_virt		=
261
		  (u8 *)pm8001_ha->memoryMap.region[ob_offset + i].virt_ptr;
J
jack wang 已提交
262
		pm8001_ha->outbnd_q_tbl[i].total_length		=
263
			pm8001_ha->memoryMap.region[ob_offset + i].total_len;
J
jack wang 已提交
264
		pm8001_ha->outbnd_q_tbl[i].pi_upper_base_addr	=
265
			pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_hi;
J
jack wang 已提交
266
		pm8001_ha->outbnd_q_tbl[i].pi_lower_base_addr	=
267
			pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_lo;
J
jack wang 已提交
268
		pm8001_ha->outbnd_q_tbl[i].interrup_vec_cnt_delay	=
269
			0 | (10 << 16) | (i << 24);
J
jack wang 已提交
270
		pm8001_ha->outbnd_q_tbl[i].pi_virt		=
271
			pm8001_ha->memoryMap.region[pi_offset + i].virt_ptr;
272
		pm8001_write_32(pm8001_ha->outbnd_q_tbl[i].pi_virt, 0, 0);
J
jack wang 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
		offsetob = i * 0x24;
		pm8001_ha->outbnd_q_tbl[i].ci_pci_bar		=
			get_pci_bar_index(pm8001_mr32(addressob,
			offsetob + 0x14));
		pm8001_ha->outbnd_q_tbl[i].ci_offset		=
			pm8001_mr32(addressob, (offsetob + 0x18));
		pm8001_ha->outbnd_q_tbl[i].consumer_idx		= 0;
		pm8001_ha->outbnd_q_tbl[i].producer_index	= 0;
	}
}

/**
 * update_main_config_table - update the main default table to the HBA.
 * @pm8001_ha: our hba card information
 */
288
static void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
289 290 291
{
	void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
	pm8001_mw32(address, 0x24,
292
		pm8001_ha->main_cfg_tbl.pm8001_tbl.inbound_q_nppd_hppd);
J
jack wang 已提交
293
	pm8001_mw32(address, 0x28,
294
		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid0_3);
J
jack wang 已提交
295
	pm8001_mw32(address, 0x2C,
296
		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_hw_event_pid4_7);
J
jack wang 已提交
297
	pm8001_mw32(address, 0x30,
298
		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid0_3);
J
jack wang 已提交
299
	pm8001_mw32(address, 0x34,
300
		pm8001_ha->main_cfg_tbl.pm8001_tbl.outbound_ncq_event_pid4_7);
J
jack wang 已提交
301
	pm8001_mw32(address, 0x38,
302 303
		pm8001_ha->main_cfg_tbl.pm8001_tbl.
					outbound_tgt_ITNexus_event_pid0_3);
J
jack wang 已提交
304
	pm8001_mw32(address, 0x3C,
305 306
		pm8001_ha->main_cfg_tbl.pm8001_tbl.
					outbound_tgt_ITNexus_event_pid4_7);
J
jack wang 已提交
307
	pm8001_mw32(address, 0x40,
308 309
		pm8001_ha->main_cfg_tbl.pm8001_tbl.
					outbound_tgt_ssp_event_pid0_3);
J
jack wang 已提交
310
	pm8001_mw32(address, 0x44,
311 312
		pm8001_ha->main_cfg_tbl.pm8001_tbl.
					outbound_tgt_ssp_event_pid4_7);
J
jack wang 已提交
313
	pm8001_mw32(address, 0x48,
314 315
		pm8001_ha->main_cfg_tbl.pm8001_tbl.
					outbound_tgt_smp_event_pid0_3);
J
jack wang 已提交
316
	pm8001_mw32(address, 0x4C,
317 318
		pm8001_ha->main_cfg_tbl.pm8001_tbl.
					outbound_tgt_smp_event_pid4_7);
J
jack wang 已提交
319
	pm8001_mw32(address, 0x50,
320
		pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_event_log_addr);
J
jack wang 已提交
321
	pm8001_mw32(address, 0x54,
322 323 324 325 326
		pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_event_log_addr);
	pm8001_mw32(address, 0x58,
		pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_size);
	pm8001_mw32(address, 0x5C,
		pm8001_ha->main_cfg_tbl.pm8001_tbl.event_log_option);
J
jack wang 已提交
327
	pm8001_mw32(address, 0x60,
328
		pm8001_ha->main_cfg_tbl.pm8001_tbl.upper_iop_event_log_addr);
J
jack wang 已提交
329
	pm8001_mw32(address, 0x64,
330 331 332
		pm8001_ha->main_cfg_tbl.pm8001_tbl.lower_iop_event_log_addr);
	pm8001_mw32(address, 0x68,
		pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_size);
J
jack wang 已提交
333
	pm8001_mw32(address, 0x6C,
334
		pm8001_ha->main_cfg_tbl.pm8001_tbl.iop_event_log_option);
J
jack wang 已提交
335
	pm8001_mw32(address, 0x70,
336
		pm8001_ha->main_cfg_tbl.pm8001_tbl.fatal_err_interrupt);
J
jack wang 已提交
337 338 339 340 341
}

/**
 * update_inbnd_queue_table - update the inbound queue table to the HBA.
 * @pm8001_ha: our hba card information
342
 * @number: entry in the queue
J
jack wang 已提交
343
 */
344 345
static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
				     int number)
J
jack wang 已提交
346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
{
	void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
	u16 offset = number * 0x20;
	pm8001_mw32(address, offset + 0x00,
		pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt);
	pm8001_mw32(address, offset + 0x04,
		pm8001_ha->inbnd_q_tbl[number].upper_base_addr);
	pm8001_mw32(address, offset + 0x08,
		pm8001_ha->inbnd_q_tbl[number].lower_base_addr);
	pm8001_mw32(address, offset + 0x0C,
		pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr);
	pm8001_mw32(address, offset + 0x10,
		pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr);
}

/**
 * update_outbnd_queue_table - update the outbound queue table to the HBA.
 * @pm8001_ha: our hba card information
364
 * @number: entry in the queue
J
jack wang 已提交
365
 */
366 367
static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
				      int number)
J
jack wang 已提交
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
{
	void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
	u16 offset = number * 0x24;
	pm8001_mw32(address, offset + 0x00,
		pm8001_ha->outbnd_q_tbl[number].element_size_cnt);
	pm8001_mw32(address, offset + 0x04,
		pm8001_ha->outbnd_q_tbl[number].upper_base_addr);
	pm8001_mw32(address, offset + 0x08,
		pm8001_ha->outbnd_q_tbl[number].lower_base_addr);
	pm8001_mw32(address, offset + 0x0C,
		pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr);
	pm8001_mw32(address, offset + 0x10,
		pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr);
	pm8001_mw32(address, offset + 0x1C,
		pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay);
}

/**
386 387
 * pm8001_bar4_shift - function is called to shift BAR base address
 * @pm8001_ha : our hba card infomation
J
jack wang 已提交
388 389
 * @shiftValue : shifting value in memory bar.
 */
390
int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue)
J
jack wang 已提交
391 392
{
	u32 regVal;
393
	unsigned long start;
J
jack wang 已提交
394 395 396 397 398

	/* program the inbound AXI translation Lower Address */
	pm8001_cw32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW, shiftValue);

	/* confirm the setting is written */
399
	start = jiffies + HZ; /* 1 sec */
J
jack wang 已提交
400 401
	do {
		regVal = pm8001_cr32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW);
402
	} while ((regVal != shiftValue) && time_before(jiffies, start));
J
jack wang 已提交
403

404
	if (regVal != shiftValue) {
405 406 407
		pm8001_dbg(pm8001_ha, INIT,
			   "TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW = 0x%x\n",
			   regVal);
J
jack wang 已提交
408 409 410 411 412 413 414 415 416 417
		return -1;
	}
	return 0;
}

/**
 * mpi_set_phys_g3_with_ssc
 * @pm8001_ha: our hba card information
 * @SSCbit: set SSCbit to 0 to disable all phys ssc; 1 to enable all phys ssc.
 */
418 419
static void mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha,
				     u32 SSCbit)
J
jack wang 已提交
420
{
421
	u32 offset, i;
422
	unsigned long flags;
J
jack wang 已提交
423 424 425 426 427

#define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000
#define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000
#define SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET 0x1074
#define SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET 0x1074
428 429 430
#define PHY_G3_WITHOUT_SSC_BIT_SHIFT 12
#define PHY_G3_WITH_SSC_BIT_SHIFT 13
#define SNW3_PHY_CAPABILITIES_PARITY 31
J
jack wang 已提交
431 432 433 434 435

   /*
    * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3)
    * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7)
    */
436 437 438 439
	spin_lock_irqsave(&pm8001_ha->lock, flags);
	if (-1 == pm8001_bar4_shift(pm8001_ha,
				SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
440
		return;
441
	}
442

J
jack wang 已提交
443 444
	for (i = 0; i < 4; i++) {
		offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i;
445
		pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
J
jack wang 已提交
446 447
	}
	/* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */
448 449 450
	if (-1 == pm8001_bar4_shift(pm8001_ha,
				SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
451
		return;
452
	}
J
jack wang 已提交
453 454
	for (i = 4; i < 8; i++) {
		offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
455
		pm8001_cw32(pm8001_ha, 2, offset, 0x80001501);
J
jack wang 已提交
456
	}
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
	/*************************************************************
	Change the SSC upspreading value to 0x0 so that upspreading is disabled.
	Device MABC SMOD0 Controls
	Address: (via MEMBASE-III):
	Using shifted destination address 0x0_0000: with Offset 0xD8

	31:28 R/W Reserved Do not change
	27:24 R/W SAS_SMOD_SPRDUP 0000
	23:20 R/W SAS_SMOD_SPRDDN 0000
	19:0  R/W  Reserved Do not change
	Upon power-up this register will read as 0x8990c016,
	and I would like you to change the SAS_SMOD_SPRDUP bits to 0b0000
	so that the written value will be 0x8090c016.
	This will ensure only down-spreading SSC is enabled on the SPC.
	*************************************************************/
472
	pm8001_cr32(pm8001_ha, 2, 0xd8);
473
	pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016);
J
jack wang 已提交
474 475

	/*set the shifted destination address to 0x0 to avoid error operation */
476 477
	pm8001_bar4_shift(pm8001_ha, 0x0);
	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
478 479 480 481 482 483
	return;
}

/**
 * mpi_set_open_retry_interval_reg
 * @pm8001_ha: our hba card information
484
 * @interval: interval time for each OPEN_REJECT (RETRY). The units are in 1us.
J
jack wang 已提交
485
 */
486 487
static void mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha,
					    u32 interval)
J
jack wang 已提交
488 489 490 491
{
	u32 offset;
	u32 value;
	u32 i;
492
	unsigned long flags;
J
jack wang 已提交
493 494 495 496 497 498 499 500

#define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000
#define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000
#define OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET 0x30B4
#define OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET 0x30B4
#define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF

	value = interval & OPEN_RETRY_INTERVAL_REG_MASK;
501
	spin_lock_irqsave(&pm8001_ha->lock, flags);
J
jack wang 已提交
502
	/* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/
503 504 505
	if (-1 == pm8001_bar4_shift(pm8001_ha,
			     OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
506
		return;
507
	}
J
jack wang 已提交
508 509 510 511 512
	for (i = 0; i < 4; i++) {
		offset = OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET + 0x4000 * i;
		pm8001_cw32(pm8001_ha, 2, offset, value);
	}

513 514 515
	if (-1 == pm8001_bar4_shift(pm8001_ha,
			     OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
516
		return;
517
	}
J
jack wang 已提交
518 519 520 521 522
	for (i = 4; i < 8; i++) {
		offset = OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET + 0x4000 * (i-4);
		pm8001_cw32(pm8001_ha, 2, offset, value);
	}
	/*set the shifted destination address to 0x0 to avoid error operation */
523 524
	pm8001_bar4_shift(pm8001_ha, 0x0);
	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
	return;
}

/**
 * mpi_init_check - check firmware initialization status.
 * @pm8001_ha: our hba card information
 */
static int mpi_init_check(struct pm8001_hba_info *pm8001_ha)
{
	u32 max_wait_count;
	u32 value;
	u32 gst_len_mpistate;
	/* Write bit0=1 to Inbound DoorBell Register to tell the SPC FW the
	table is updated */
	pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_UPDATE);
	/* wait until Inbound DoorBell Clear Register toggled */
	max_wait_count = 1 * 1000 * 1000;/* 1 sec */
	do {
		udelay(1);
		value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
		value &= SPC_MSGU_CFG_TABLE_UPDATE;
	} while ((value != 0) && (--max_wait_count));

	if (!max_wait_count)
		return -1;
	/* check the MPI-State for initialization */
	gst_len_mpistate =
		pm8001_mr32(pm8001_ha->general_stat_tbl_addr,
		GST_GSTLEN_MPIS_OFFSET);
	if (GST_MPI_STATE_INIT != (gst_len_mpistate & GST_MPI_STATE_MASK))
		return -1;
	/* check MPI Initialization error */
	gst_len_mpistate = gst_len_mpistate >> 16;
	if (0x0000 != gst_len_mpistate)
		return -1;
	return 0;
}

/**
 * check_fw_ready - The LLDD check if the FW is ready, if not, return error.
 * @pm8001_ha: our hba card information
 */
static int check_fw_ready(struct pm8001_hba_info *pm8001_ha)
{
	u32 value, value1;
	u32 max_wait_count;
	/* check error state */
	value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
	value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
	/* check AAP error */
	if (SCRATCH_PAD1_ERR == (value & SCRATCH_PAD_STATE_MASK)) {
		/* error state */
		value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
		return -1;
	}

	/* check IOP error */
	if (SCRATCH_PAD2_ERR == (value1 & SCRATCH_PAD_STATE_MASK)) {
		/* error state */
		value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
		return -1;
	}

	/* bit 4-31 of scratch pad1 should be zeros if it is not
	in error state*/
	if (value & SCRATCH_PAD1_STATE_MASK) {
		/* error case */
		pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
		return -1;
	}

	/* bit 2, 4-31 of scratch pad2 should be zeros if it is not
	in error state */
	if (value1 & SCRATCH_PAD2_STATE_MASK) {
		/* error case */
		return -1;
	}

	max_wait_count = 1 * 1000 * 1000;/* 1 sec timeout */

	/* wait until scratch pad 1 and 2 registers in ready state  */
	do {
		udelay(1);
		value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)
			& SCRATCH_PAD1_RDY;
		value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)
			& SCRATCH_PAD2_RDY;
		if ((--max_wait_count) == 0)
			return -1;
	} while ((value != SCRATCH_PAD1_RDY) || (value1 != SCRATCH_PAD2_RDY));
	return 0;
}

static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
{
	void __iomem *base_addr;
	u32	value;
	u32	offset;
	u32	pcibar;
	u32	pcilogic;

	value = pm8001_cr32(pm8001_ha, 0, 0x44);
	offset = value & 0x03FFFFFF;
628
	pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 Offset: %x\n", offset);
J
jack wang 已提交
629 630
	pcilogic = (value & 0xFC000000) >> 26;
	pcibar = get_pci_bar_index(pcilogic);
631
	pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar);
J
jack wang 已提交
632 633 634 635 636 637 638 639 640 641 642 643 644 645
	pm8001_ha->main_cfg_tbl_addr = base_addr =
		pm8001_ha->io_mem[pcibar].memvirtaddr + offset;
	pm8001_ha->general_stat_tbl_addr =
		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x18);
	pm8001_ha->inbnd_q_tbl_addr =
		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C);
	pm8001_ha->outbnd_q_tbl_addr =
		base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x20);
}

/**
 * pm8001_chip_init - the main init function that initialize whole PM8001 chip.
 * @pm8001_ha: our hba card information
 */
646
static int pm8001_chip_init(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
647
{
648
	u32 i = 0;
649 650 651 652
	u16 deviceid;
	pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
	/* 8081 controllers need BAR shift to access MPI space
	* as this is shared with BIOS data */
653
	if (deviceid == 0x8081 || deviceid == 0x0042) {
654
		if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
655 656 657
			pm8001_dbg(pm8001_ha, FAIL,
				   "Shift Bar4 to 0x%x failed\n",
				   GSM_SM_BASE);
658 659 660
			return -1;
		}
	}
J
jack wang 已提交
661 662
	/* check the firmware status */
	if (-1 == check_fw_ready(pm8001_ha)) {
663
		pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n");
J
jack wang 已提交
664 665 666 667 668 669 670 671 672 673 674 675
		return -EBUSY;
	}

	/* Initialize pci space address eg: mpi offset */
	init_pci_device_addresses(pm8001_ha);
	init_default_table_values(pm8001_ha);
	read_main_config_table(pm8001_ha);
	read_general_status_table(pm8001_ha);
	read_inbnd_queue_table(pm8001_ha);
	read_outbnd_queue_table(pm8001_ha);
	/* update main config table ,inbound table and outbound table */
	update_main_config_table(pm8001_ha);
676
	for (i = 0; i < pm8001_ha->max_q_num; i++)
677
		update_inbnd_queue_table(pm8001_ha, i);
678
	for (i = 0; i < pm8001_ha->max_q_num; i++)
679
		update_outbnd_queue_table(pm8001_ha, i);
680
	/* 8081 controller donot require these operations */
681
	if (deviceid != 0x8081 && deviceid != 0x0042) {
682 683 684 685
		mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
		/* 7->130ms, 34->500ms, 119->1.5s */
		mpi_set_open_retry_interval_reg(pm8001_ha, 119);
	}
J
jack wang 已提交
686 687
	/* notify firmware update finished and check initialization status */
	if (0 == mpi_init_check(pm8001_ha)) {
688
		pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n");
J
jack wang 已提交
689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
	} else
		return -EBUSY;
	/*This register is a 16-bit timer with a resolution of 1us. This is the
	timer used for interrupt delay/coalescing in the PCIe Application Layer.
	Zero is not a valid value. A value of 1 in the register will cause the
	interrupts to be normal. A value greater than 1 will cause coalescing
	delays.*/
	pm8001_cw32(pm8001_ha, 1, 0x0033c0, 0x1);
	pm8001_cw32(pm8001_ha, 1, 0x0033c4, 0x0);
	return 0;
}

static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
{
	u32 max_wait_count;
	u32 value;
	u32 gst_len_mpistate;
706 707
	u16 deviceid;
	pci_read_config_word(pm8001_ha->pdev, PCI_DEVICE_ID, &deviceid);
708
	if (deviceid == 0x8081 || deviceid == 0x0042) {
709
		if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_SM_BASE)) {
710 711 712
			pm8001_dbg(pm8001_ha, FAIL,
				   "Shift Bar4 to 0x%x failed\n",
				   GSM_SM_BASE);
713 714 715
			return -1;
		}
	}
J
jack wang 已提交
716 717 718 719 720 721 722 723 724 725 726 727 728 729
	init_pci_device_addresses(pm8001_ha);
	/* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the
	table is stop */
	pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_RESET);

	/* wait until Inbound DoorBell Clear Register toggled */
	max_wait_count = 1 * 1000 * 1000;/* 1 sec */
	do {
		udelay(1);
		value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
		value &= SPC_MSGU_CFG_TABLE_RESET;
	} while ((value != 0) && (--max_wait_count));

	if (!max_wait_count) {
730 731
		pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=0x%x\n",
			   value);
J
jack wang 已提交
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
		return -1;
	}

	/* check the MPI-State for termination in progress */
	/* wait until Inbound DoorBell Clear Register toggled */
	max_wait_count = 1 * 1000 * 1000;  /* 1 sec */
	do {
		udelay(1);
		gst_len_mpistate =
			pm8001_mr32(pm8001_ha->general_stat_tbl_addr,
			GST_GSTLEN_MPIS_OFFSET);
		if (GST_MPI_STATE_UNINIT ==
			(gst_len_mpistate & GST_MPI_STATE_MASK))
			break;
	} while (--max_wait_count);
	if (!max_wait_count) {
748 749
		pm8001_dbg(pm8001_ha, FAIL, " TIME OUT MPI State = 0x%x\n",
			   gst_len_mpistate & GST_MPI_STATE_MASK);
J
jack wang 已提交
750 751 752 753 754 755 756 757 758 759 760 761 762
		return -1;
	}
	return 0;
}

/**
 * soft_reset_ready_check - Function to check FW is ready for soft reset.
 * @pm8001_ha: our hba card information
 */
static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha)
{
	u32 regVal, regVal1, regVal2;
	if (mpi_uninit_check(pm8001_ha) != 0) {
763
		pm8001_dbg(pm8001_ha, FAIL, "MPI state is not ready\n");
J
jack wang 已提交
764 765 766 767 768 769
		return -1;
	}
	/* read the scratch pad 2 register bit 2 */
	regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)
		& SCRATCH_PAD2_FWRDY_RST;
	if (regVal == SCRATCH_PAD2_FWRDY_RST) {
770
		pm8001_dbg(pm8001_ha, INIT, "Firmware is ready for reset.\n");
J
jack wang 已提交
771
	} else {
772 773 774 775 776
		unsigned long flags;
		/* Trigger NMI twice via RB6 */
		spin_lock_irqsave(&pm8001_ha->lock, flags);
		if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) {
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
777 778 779
			pm8001_dbg(pm8001_ha, FAIL,
				   "Shift Bar4 to 0x%x failed\n",
				   RB6_ACCESS_REG);
J
jack wang 已提交
780 781 782 783 784 785 786 787 788 789 790 791
			return -1;
		}
		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET,
			RB6_MAGIC_NUMBER_RST);
		pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, RB6_MAGIC_NUMBER_RST);
		/* wait for 100 ms */
		mdelay(100);
		regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) &
			SCRATCH_PAD2_FWRDY_RST;
		if (regVal != SCRATCH_PAD2_FWRDY_RST) {
			regVal1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
			regVal2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
792 793 794 795 796 797 798 799
			pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:MSGU_SCRATCH_PAD1=0x%x, MSGU_SCRATCH_PAD2=0x%x\n",
				   regVal1, regVal2);
			pm8001_dbg(pm8001_ha, FAIL,
				   "SCRATCH_PAD0 value = 0x%x\n",
				   pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0));
			pm8001_dbg(pm8001_ha, FAIL,
				   "SCRATCH_PAD3 value = 0x%x\n",
				   pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3));
800
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
801 802
			return -1;
		}
803
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
804 805 806 807 808 809 810 811 812 813
	}
	return 0;
}

/**
 * pm8001_chip_soft_rst - soft reset the PM8001 chip, so that the clear all
 * the FW register status to the originated status.
 * @pm8001_ha: our hba card information
 */
static int
814
pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
815 816 817 818
{
	u32	regVal, toggleVal;
	u32	max_wait_count;
	u32	regVal1, regVal2, regVal3;
819
	u32	signature = 0x252acbcd; /* for host scratch pad0 */
820
	unsigned long flags;
J
jack wang 已提交
821 822 823

	/* step1: Check FW is ready for soft reset */
	if (soft_reset_ready_check(pm8001_ha) != 0) {
824
		pm8001_dbg(pm8001_ha, FAIL, "FW is not ready\n");
J
jack wang 已提交
825 826 827 828 829 830
		return -1;
	}

	/* step 2: clear NMI status register on AAP1 and IOP, write the same
	value to clear */
	/* map 0x60000 to BAR4(0x20), BAR2(win) */
831 832 833
	spin_lock_irqsave(&pm8001_ha->lock, flags);
	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
834 835
		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
			   MBIC_AAP1_ADDR_BASE);
J
jack wang 已提交
836 837 838
		return -1;
	}
	regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP);
839 840
	pm8001_dbg(pm8001_ha, INIT, "MBIC - NMI Enable VPE0 (IOP)= 0x%x\n",
		   regVal);
J
jack wang 已提交
841 842
	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0);
	/* map 0x70000 to BAR4(0x20), BAR2(win) */
843 844
	if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
845 846
		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
			   MBIC_IOP_ADDR_BASE);
J
jack wang 已提交
847 848 849
		return -1;
	}
	regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1);
850 851
	pm8001_dbg(pm8001_ha, INIT, "MBIC - NMI Enable VPE0 (AAP1)= 0x%x\n",
		   regVal);
J
jack wang 已提交
852 853 854
	pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1, 0x0);

	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE);
855 856
	pm8001_dbg(pm8001_ha, INIT, "PCIE -Event Interrupt Enable = 0x%x\n",
		   regVal);
J
jack wang 已提交
857 858 859
	pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE, 0x0);

	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT);
860 861
	pm8001_dbg(pm8001_ha, INIT, "PCIE - Event Interrupt  = 0x%x\n",
		   regVal);
J
jack wang 已提交
862 863 864
	pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT, regVal);

	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE);
865 866
	pm8001_dbg(pm8001_ha, INIT, "PCIE -Error Interrupt Enable = 0x%x\n",
		   regVal);
J
jack wang 已提交
867 868 869
	pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE, 0x0);

	regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT);
870
	pm8001_dbg(pm8001_ha, INIT, "PCIE - Error Interrupt = 0x%x\n", regVal);
J
jack wang 已提交
871 872 873 874 875 876 877 878 879 880 881 882 883
	pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT, regVal);

	/* read the scratch pad 1 register bit 2 */
	regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)
		& SCRATCH_PAD1_RST;
	toggleVal = regVal ^ SCRATCH_PAD1_RST;

	/* set signature in host scratch pad0 register to tell SPC that the
	host performs the soft reset */
	pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0, signature);

	/* read required registers for confirmming */
	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
884 885
	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
886 887
		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
			   GSM_ADDR_BASE);
J
jack wang 已提交
888 889
		return -1;
	}
890 891 892
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x0(0x00007b88)-GSM Configuration and Reset = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
J
jack wang 已提交
893 894 895 896 897 898 899 900 901 902 903 904 905 906

	/* step 3: host read GSM Configuration and Reset register */
	regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET);
	/* Put those bits to low */
	/* GSM XCBI offset = 0x70 0000
	0x00 Bit 13 COM_SLV_SW_RSTB 1
	0x00 Bit 12 QSSP_SW_RSTB 1
	0x00 Bit 11 RAAE_SW_RSTB 1
	0x00 Bit 9 RB_1_SW_RSTB 1
	0x00 Bit 8 SM_SW_RSTB 1
	*/
	regVal &= ~(0x00003b00);
	/* host write GSM Configuration and Reset register */
	pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal);
907 908 909
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x0 (0x00007b88 ==> 0x00004088) - GSM Configuration and Reset is set to = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
J
jack wang 已提交
910 911 912 913

	/* step 4: */
	/* disable GSM - Read Address Parity Check */
	regVal1 = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK);
914 915 916
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x700038 - Read Address Parity Check Enable = 0x%x\n",
		   regVal1);
J
jack wang 已提交
917
	pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, 0x0);
918 919 920
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x700038 - Read Address Parity Check Enable is set to = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK));
J
jack wang 已提交
921 922 923

	/* disable GSM - Write Address Parity Check */
	regVal2 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK);
924 925 926
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x700040 - Write Address Parity Check Enable = 0x%x\n",
		   regVal2);
J
jack wang 已提交
927
	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, 0x0);
928 929 930
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x700040 - Write Address Parity Check Enable is set to = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK));
J
jack wang 已提交
931 932 933

	/* disable GSM - Write Data Parity Check */
	regVal3 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK);
934 935
	pm8001_dbg(pm8001_ha, INIT, "GSM 0x300048 - Write Data Parity Check Enable = 0x%x\n",
		   regVal3);
J
jack wang 已提交
936
	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, 0x0);
937 938 939
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x300048 - Write Data Parity Check Enable is set to = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK));
J
jack wang 已提交
940 941 942 943

	/* step 5: delay 10 usec */
	udelay(10);
	/* step 5-b: set GPIO-0 output control to tristate anyway */
944 945
	if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
946 947
		pm8001_dbg(pm8001_ha, INIT, "Shift Bar4 to 0x%x failed\n",
			   GPIO_ADDR_BASE);
J
jack wang 已提交
948 949 950
		return -1;
	}
	regVal = pm8001_cr32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET);
951 952
	pm8001_dbg(pm8001_ha, INIT, "GPIO Output Control Register: = 0x%x\n",
		   regVal);
J
jack wang 已提交
953 954 955 956 957 958
	/* set GPIO-0 output control to tri-state */
	regVal &= 0xFFFFFFFC;
	pm8001_cw32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET, regVal);

	/* Step 6: Reset the IOP and AAP1 */
	/* map 0x00000 to BAR4(0x20), BAR2(win) */
959 960
	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
961 962
		pm8001_dbg(pm8001_ha, FAIL, "SPC Shift Bar4 to 0x%x failed\n",
			   SPC_TOP_LEVEL_ADDR_BASE);
J
jack wang 已提交
963 964 965
		return -1;
	}
	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
966 967
	pm8001_dbg(pm8001_ha, INIT, "Top Register before resetting IOP/AAP1:= 0x%x\n",
		   regVal);
J
jack wang 已提交
968 969 970 971 972
	regVal &= ~(SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS);
	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);

	/* step 7: Reset the BDMA/OSSP */
	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
973 974
	pm8001_dbg(pm8001_ha, INIT, "Top Register before resetting BDMA/OSSP: = 0x%x\n",
		   regVal);
J
jack wang 已提交
975 976 977 978 979 980 981 982
	regVal &= ~(SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP);
	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);

	/* step 8: delay 10 usec */
	udelay(10);

	/* step 9: bring the BDMA and OSSP out of reset */
	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
983 984 985
	pm8001_dbg(pm8001_ha, INIT,
		   "Top Register before bringing up BDMA/OSSP:= 0x%x\n",
		   regVal);
J
jack wang 已提交
986 987 988 989 990 991 992 993
	regVal |= (SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP);
	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);

	/* step 10: delay 10 usec */
	udelay(10);

	/* step 11: reads and sets the GSM Configuration and Reset Register */
	/* map 0x0700000 to BAR4(0x20), BAR2(win) */
994 995
	if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
996 997
		pm8001_dbg(pm8001_ha, FAIL, "SPC Shift Bar4 to 0x%x failed\n",
			   GSM_ADDR_BASE);
J
jack wang 已提交
998 999
		return -1;
	}
1000 1001 1002
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x0 (0x00007b88)-GSM Configuration and Reset = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
J
jack wang 已提交
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
	regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET);
	/* Put those bits to high */
	/* GSM XCBI offset = 0x70 0000
	0x00 Bit 13 COM_SLV_SW_RSTB 1
	0x00 Bit 12 QSSP_SW_RSTB 1
	0x00 Bit 11 RAAE_SW_RSTB 1
	0x00 Bit 9   RB_1_SW_RSTB 1
	0x00 Bit 8   SM_SW_RSTB 1
	*/
	regVal |= (GSM_CONFIG_RESET_VALUE);
	pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal);
1014 1015
	pm8001_dbg(pm8001_ha, INIT, "GSM (0x00004088 ==> 0x00007b88) - GSM Configuration and Reset is set to = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET));
J
jack wang 已提交
1016 1017 1018 1019

	/* step 12: Restore GSM - Read Address Parity Check */
	regVal = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK);
	/* just for debugging */
1020 1021 1022
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x700038 - Read Address Parity Check Enable = 0x%x\n",
		   regVal);
J
jack wang 已提交
1023
	pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, regVal1);
1024 1025
	pm8001_dbg(pm8001_ha, INIT, "GSM 0x700038 - Read Address Parity Check Enable is set to = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK));
J
jack wang 已提交
1026 1027 1028
	/* Restore GSM - Write Address Parity Check */
	regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK);
	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, regVal2);
1029 1030 1031
	pm8001_dbg(pm8001_ha, INIT,
		   "GSM 0x700040 - Write Address Parity Check Enable is set to = 0x%x\n",
		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK));
J
jack wang 已提交
1032 1033 1034
	/* Restore GSM - Write Data Parity Check */
	regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK);
	pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, regVal3);
1035
	pm8001_dbg(pm8001_ha, INIT,
1036
		   "GSM 0x700048 - Write Data Parity Check Enable is set to = 0x%x\n",
1037
		   pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK));
J
jack wang 已提交
1038 1039 1040

	/* step 13: bring the IOP and AAP1 out of reset */
	/* map 0x00000 to BAR4(0x20), BAR2(win) */
1041 1042
	if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) {
		spin_unlock_irqrestore(&pm8001_ha->lock, flags);
1043 1044
		pm8001_dbg(pm8001_ha, FAIL, "Shift Bar4 to 0x%x failed\n",
			   SPC_TOP_LEVEL_ADDR_BASE);
J
jack wang 已提交
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066
		return -1;
	}
	regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET);
	regVal |= (SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS);
	pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal);

	/* step 14: delay 10 usec - Normal Mode */
	udelay(10);
	/* check Soft Reset Normal mode or Soft Reset HDA mode */
	if (signature == SPC_SOFT_RESET_SIGNATURE) {
		/* step 15 (Normal Mode): wait until scratch pad1 register
		bit 2 toggled */
		max_wait_count = 2 * 1000 * 1000;/* 2 sec */
		do {
			udelay(1);
			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) &
				SCRATCH_PAD1_RST;
		} while ((regVal != toggleVal) && (--max_wait_count));

		if (!max_wait_count) {
			regVal = pm8001_cr32(pm8001_ha, 0,
				MSGU_SCRATCH_PAD_1);
1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
			pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT : ToggleVal 0x%x,MSGU_SCRATCH_PAD1 = 0x%x\n",
				   toggleVal, regVal);
			pm8001_dbg(pm8001_ha, FAIL,
				   "SCRATCH_PAD0 value = 0x%x\n",
				   pm8001_cr32(pm8001_ha, 0,
					       MSGU_SCRATCH_PAD_0));
			pm8001_dbg(pm8001_ha, FAIL,
				   "SCRATCH_PAD2 value = 0x%x\n",
				   pm8001_cr32(pm8001_ha, 0,
					       MSGU_SCRATCH_PAD_2));
			pm8001_dbg(pm8001_ha, FAIL,
				   "SCRATCH_PAD3 value = 0x%x\n",
				   pm8001_cr32(pm8001_ha, 0,
					       MSGU_SCRATCH_PAD_3));
1081
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
			return -1;
		}

		/* step 16 (Normal) - Clear ODMR and ODCR */
		pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
		pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);

		/* step 17 (Normal Mode): wait for the FW and IOP to get
		ready - 1 sec timeout */
		/* Wait for the SPC Configuration Table to be ready */
		if (check_fw_ready(pm8001_ha) == -1) {
			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
			/* return error if MPI Configuration Table not ready */
1095 1096 1097
			pm8001_dbg(pm8001_ha, INIT,
				   "FW not ready SCRATCH_PAD1 = 0x%x\n",
				   regVal);
J
jack wang 已提交
1098 1099
			regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
			/* return error if MPI Configuration Table not ready */
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110
			pm8001_dbg(pm8001_ha, INIT,
				   "FW not ready SCRATCH_PAD2 = 0x%x\n",
				   regVal);
			pm8001_dbg(pm8001_ha, INIT,
				   "SCRATCH_PAD0 value = 0x%x\n",
				   pm8001_cr32(pm8001_ha, 0,
					       MSGU_SCRATCH_PAD_0));
			pm8001_dbg(pm8001_ha, INIT,
				   "SCRATCH_PAD3 value = 0x%x\n",
				   pm8001_cr32(pm8001_ha, 0,
					       MSGU_SCRATCH_PAD_3));
1111
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
1112 1113 1114
			return -1;
		}
	}
1115 1116
	pm8001_bar4_shift(pm8001_ha, 0);
	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
1117

1118
	pm8001_dbg(pm8001_ha, INIT, "SPC soft reset Complete\n");
J
jack wang 已提交
1119 1120 1121 1122 1123 1124 1125
	return 0;
}

static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
{
	u32 i;
	u32 regVal;
1126
	pm8001_dbg(pm8001_ha, INIT, "chip reset start\n");
J
jack wang 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149

	/* do SPC chip reset. */
	regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET);
	regVal &= ~(SPC_REG_RESET_DEVICE);
	pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal);

	/* delay 10 usec */
	udelay(10);

	/* bring chip reset out of reset */
	regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET);
	regVal |= SPC_REG_RESET_DEVICE;
	pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal);

	/* delay 10 usec */
	udelay(10);

	/* wait for 20 msec until the firmware gets reloaded */
	i = 20;
	do {
		mdelay(1);
	} while ((--i) != 0);

1150
	pm8001_dbg(pm8001_ha, INIT, "chip reset finished\n");
J
jack wang 已提交
1151 1152 1153
}

/**
1154
 * pm8001_chip_iounmap - which maped when initialized.
J
jack wang 已提交
1155 1156
 * @pm8001_ha: our hba card information
 */
1157
void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
1158 1159
{
	s8 bar, logical = 0;
1160
	for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
J
jack wang 已提交
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
		/*
		** logical BARs for SPC:
		** bar 0 and 1 - logical BAR0
		** bar 2 and 3 - logical BAR1
		** bar4 - logical BAR2
		** bar5 - logical BAR3
		** Skip the appropriate assignments:
		*/
		if ((bar == 1) || (bar == 3))
			continue;
		if (pm8001_ha->io_mem[logical].memvirtaddr) {
			iounmap(pm8001_ha->io_mem[logical].memvirtaddr);
			logical++;
		}
	}
}

1178
#ifndef PM8001_USE_MSIX
J
jack wang 已提交
1179
/**
1180
 * pm8001_chip_intx_interrupt_enable - enable PM8001 chip interrupt
J
jack wang 已提交
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
 * @pm8001_ha: our hba card information
 */
static void
pm8001_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha)
{
	pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL);
	pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL);
}

 /**
  * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt
  * @pm8001_ha: our hba card information
  */
static void
pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha)
{
	pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL);
}

1200 1201
#else

J
jack wang 已提交
1202 1203 1204
/**
 * pm8001_chip_msix_interrupt_enable - enable PM8001 chip interrupt
 * @pm8001_ha: our hba card information
1205
 * @int_vec_idx: interrupt number to enable
J
jack wang 已提交
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
 */
static void
pm8001_chip_msix_interrupt_enable(struct pm8001_hba_info *pm8001_ha,
	u32 int_vec_idx)
{
	u32 msi_index;
	u32 value;
	msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
	msi_index += MSIX_TABLE_BASE;
	pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_ENABLE);
	value = (1 << int_vec_idx);
	pm8001_cw32(pm8001_ha, 0,  MSGU_ODCR, value);

}

/**
 * pm8001_chip_msix_interrupt_disable - disable PM8001 chip interrupt
 * @pm8001_ha: our hba card information
1224
 * @int_vec_idx: interrupt number to disable
J
jack wang 已提交
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
 */
static void
pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha,
	u32 int_vec_idx)
{
	u32 msi_index;
	msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE;
	msi_index += MSIX_TABLE_BASE;
	pm8001_cw32(pm8001_ha, 0,  msi_index, MSIX_INTERRUPT_DISABLE);
}
1235
#endif
1236

J
jack wang 已提交
1237 1238 1239
/**
 * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt
 * @pm8001_ha: our hba card information
1240
 * @vec: unused
J
jack wang 已提交
1241 1242
 */
static void
1243
pm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec)
J
jack wang 已提交
1244 1245 1246
{
#ifdef PM8001_USE_MSIX
	pm8001_chip_msix_interrupt_enable(pm8001_ha, 0);
1247
#else
J
jack wang 已提交
1248
	pm8001_chip_intx_interrupt_enable(pm8001_ha);
1249
#endif
J
jack wang 已提交
1250 1251 1252
}

/**
1253
 * pm8001_chip_interrupt_disable - disable PM8001 chip interrupt
J
jack wang 已提交
1254
 * @pm8001_ha: our hba card information
1255
 * @vec: unused
J
jack wang 已提交
1256 1257
 */
static void
1258
pm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec)
J
jack wang 已提交
1259 1260 1261
{
#ifdef PM8001_USE_MSIX
	pm8001_chip_msix_interrupt_disable(pm8001_ha, 0);
1262
#else
J
jack wang 已提交
1263
	pm8001_chip_intx_interrupt_disable(pm8001_ha);
1264
#endif
J
jack wang 已提交
1265 1266 1267
}

/**
1268 1269
 * pm8001_mpi_msg_free_get - get the free message buffer for transfer
 * inbound queue.
J
jack wang 已提交
1270 1271 1272 1273
 * @circularQ: the inbound queue  we want to transfer to HBA.
 * @messageSize: the message size of this transfer, normally it is 64 bytes
 * @messagePtr: the pointer to message.
 */
1274
int pm8001_mpi_msg_free_get(struct inbound_queue_table *circularQ,
J
jack wang 已提交
1275 1276 1277 1278 1279 1280 1281
			    u16 messageSize, void **messagePtr)
{
	u32 offset, consumer_index;
	struct mpi_msg_hdr *msgHeader;
	u8 bcCount = 1; /* only support single buffer */

	/* Checks is the requested message size can be allocated in this queue*/
1282
	if (messageSize > IOMB_SIZE_SPCV) {
J
jack wang 已提交
1283 1284 1285 1286 1287 1288 1289
		*messagePtr = NULL;
		return -1;
	}

	/* Stores the new consumer index */
	consumer_index = pm8001_read_32(circularQ->ci_virt);
	circularQ->consumer_index = cpu_to_le32(consumer_index);
1290
	if (((circularQ->producer_idx + bcCount) % PM8001_MPI_QUEUE) ==
1291
		le32_to_cpu(circularQ->consumer_index)) {
J
jack wang 已提交
1292 1293 1294 1295
		*messagePtr = NULL;
		return -1;
	}
	/* get memory IOMB buffer address */
1296
	offset = circularQ->producer_idx * messageSize;
J
jack wang 已提交
1297
	/* increment to next bcCount element */
1298 1299
	circularQ->producer_idx = (circularQ->producer_idx + bcCount)
				% PM8001_MPI_QUEUE;
J
jack wang 已提交
1300 1301 1302 1303 1304 1305 1306 1307
	/* Adds that distance to the base of the region virtual address plus
	the message header size*/
	msgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt	+ offset);
	*messagePtr = ((void *)msgHeader) + sizeof(struct mpi_msg_hdr);
	return 0;
}

/**
1308 1309
 * pm8001_mpi_build_cmd- build the message queue for transfer, update the PI to
 * FW to tell the fw to get this message from IOMB.
J
jack wang 已提交
1310 1311 1312 1313
 * @pm8001_ha: our hba card information
 * @circularQ: the inbound queue we want to transfer to HBA.
 * @opCode: the operation code represents commands which LLDD and fw recognized.
 * @payload: the command payload of each operation command.
1314 1315
 * @nb: size in bytes of the command payload
 * @responseQueue: queue to interrupt on w/ command response (if any)
J
jack wang 已提交
1316
 */
1317
int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha,
J
jack wang 已提交
1318
			 struct inbound_queue_table *circularQ,
1319 1320
			 u32 opCode, void *payload, size_t nb,
			 u32 responseQueue)
J
jack wang 已提交
1321 1322 1323
{
	u32 Header = 0, hpriority = 0, bc = 1, category = 0x02;
	void *pMessage;
1324 1325 1326 1327 1328 1329 1330 1331 1332
	unsigned long flags;
	int q_index = circularQ - pm8001_ha->inbnd_q_tbl;
	int rv = -1;

	WARN_ON(q_index >= PM8001_MAX_INB_NUM);
	spin_lock_irqsave(&circularQ->iq_lock, flags);
	rv = pm8001_mpi_msg_free_get(circularQ, pm8001_ha->iomb_size,
			&pMessage);
	if (rv < 0) {
1333
		pm8001_dbg(pm8001_ha, IO, "No free mpi buffer\n");
1334 1335
		rv = -ENOMEM;
		goto done;
J
jack wang 已提交
1336
	}
1337 1338 1339 1340 1341 1342 1343

	if (nb > (pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr)))
		nb = pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr);
	memcpy(pMessage, payload, nb);
	if (nb + sizeof(struct mpi_msg_hdr) < pm8001_ha->iomb_size)
		memset(pMessage + nb, 0, pm8001_ha->iomb_size -
				(nb + sizeof(struct mpi_msg_hdr)));
J
jack wang 已提交
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353

	/*Build the header*/
	Header = ((1 << 31) | (hpriority << 30) | ((bc & 0x1f) << 24)
		| ((responseQueue & 0x3F) << 16)
		| ((category & 0xF) << 12) | (opCode & 0xFFF));

	pm8001_write_32((pMessage - 4), 0, cpu_to_le32(Header));
	/*Update the PI to the firmware*/
	pm8001_cw32(pm8001_ha, circularQ->pi_pci_bar,
		circularQ->pi_offset, circularQ->producer_idx);
1354 1355 1356 1357
	pm8001_dbg(pm8001_ha, DEVIO,
		   "INB Q %x OPCODE:%x , UPDATED PI=%d CI=%d\n",
		   responseQueue, opCode, circularQ->producer_idx,
		   circularQ->consumer_index);
1358 1359 1360
done:
	spin_unlock_irqrestore(&circularQ->iq_lock, flags);
	return rv;
J
jack wang 已提交
1361 1362
}

1363
u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg,
J
jack wang 已提交
1364 1365 1366
			    struct outbound_queue_table *circularQ, u8 bc)
{
	u32 producer_index;
1367 1368 1369 1370 1371
	struct mpi_msg_hdr *msgHeader;
	struct mpi_msg_hdr *pOutBoundMsgHeader;

	msgHeader = (struct mpi_msg_hdr *)(pMsg - sizeof(struct mpi_msg_hdr));
	pOutBoundMsgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt +
1372
				circularQ->consumer_idx * pm8001_ha->iomb_size);
1373
	if (pOutBoundMsgHeader != msgHeader) {
1374 1375 1376
		pm8001_dbg(pm8001_ha, FAIL,
			   "consumer_idx = %d msgHeader = %p\n",
			   circularQ->consumer_idx, msgHeader);
1377 1378 1379 1380

		/* Update the producer index from SPC */
		producer_index = pm8001_read_32(circularQ->pi_virt);
		circularQ->producer_index = cpu_to_le32(producer_index);
1381 1382 1383 1384
		pm8001_dbg(pm8001_ha, FAIL,
			   "consumer_idx = %d producer_index = %dmsgHeader = %p\n",
			   circularQ->consumer_idx,
			   circularQ->producer_index, msgHeader);
1385 1386
		return 0;
	}
J
jack wang 已提交
1387
	/* free the circular queue buffer elements associated with the message*/
1388 1389
	circularQ->consumer_idx = (circularQ->consumer_idx + bc)
				% PM8001_MPI_QUEUE;
J
jack wang 已提交
1390 1391 1392 1393 1394 1395
	/* update the CI of outbound queue */
	pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, circularQ->ci_offset,
		circularQ->consumer_idx);
	/* Update the producer index from SPC*/
	producer_index = pm8001_read_32(circularQ->pi_virt);
	circularQ->producer_index = cpu_to_le32(producer_index);
1396 1397
	pm8001_dbg(pm8001_ha, IO, " CI=%d PI=%d\n",
		   circularQ->consumer_idx, circularQ->producer_index);
J
jack wang 已提交
1398 1399 1400 1401
	return 0;
}

/**
1402 1403
 * pm8001_mpi_msg_consume- get the MPI message from outbound queue
 * message table.
J
jack wang 已提交
1404 1405 1406 1407 1408
 * @pm8001_ha: our hba card information
 * @circularQ: the outbound queue  table.
 * @messagePtr1: the message contents of this outbound message.
 * @pBC: the message size.
 */
1409
u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha,
J
jack wang 已提交
1410 1411 1412 1413 1414 1415 1416 1417
			   struct outbound_queue_table *circularQ,
			   void **messagePtr1, u8 *pBC)
{
	struct mpi_msg_hdr	*msgHeader;
	__le32	msgHeader_tmp;
	u32 header_tmp;
	do {
		/* If there are not-yet-delivered messages ... */
1418 1419
		if (le32_to_cpu(circularQ->producer_index)
			!= circularQ->consumer_idx) {
J
jack wang 已提交
1420 1421 1422
			/*Get the pointer to the circular queue buffer element*/
			msgHeader = (struct mpi_msg_hdr *)
				(circularQ->base_virt +
1423
				circularQ->consumer_idx * pm8001_ha->iomb_size);
J
jack wang 已提交
1424 1425 1426
			/* read header */
			header_tmp = pm8001_read_32(msgHeader);
			msgHeader_tmp = cpu_to_le32(header_tmp);
1427 1428 1429 1430
			pm8001_dbg(pm8001_ha, DEVIO,
				   "outbound opcode msgheader:%x ci=%d pi=%d\n",
				   msgHeader_tmp, circularQ->consumer_idx,
				   circularQ->producer_index);
1431
			if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) {
J
jack wang 已提交
1432
				if (OPC_OUB_SKIP_ENTRY !=
1433
					(le32_to_cpu(msgHeader_tmp) & 0xfff)) {
J
jack wang 已提交
1434 1435 1436
					*messagePtr1 =
						((u8 *)msgHeader) +
						sizeof(struct mpi_msg_hdr);
1437 1438
					*pBC = (u8)((le32_to_cpu(msgHeader_tmp)
						>> 24) & 0x1f);
1439 1440 1441 1442 1443
					pm8001_dbg(pm8001_ha, IO,
						   ": CI=%d PI=%d msgHeader=%x\n",
						   circularQ->consumer_idx,
						   circularQ->producer_index,
						   msgHeader_tmp);
J
jack wang 已提交
1444 1445 1446 1447
					return MPI_IO_STATUS_SUCCESS;
				} else {
					circularQ->consumer_idx =
						(circularQ->consumer_idx +
1448
						((le32_to_cpu(msgHeader_tmp)
1449 1450
						 >> 24) & 0x1f))
							% PM8001_MPI_QUEUE;
1451 1452
					msgHeader_tmp = 0;
					pm8001_write_32(msgHeader, 0, 0);
J
jack wang 已提交
1453 1454 1455 1456 1457 1458
					/* update the CI of outbound queue */
					pm8001_cw32(pm8001_ha,
						circularQ->ci_pci_bar,
						circularQ->ci_offset,
						circularQ->consumer_idx);
				}
1459 1460 1461
			} else {
				circularQ->consumer_idx =
					(circularQ->consumer_idx +
1462
					((le32_to_cpu(msgHeader_tmp) >> 24) &
1463
					0x1f)) % PM8001_MPI_QUEUE;
1464 1465 1466 1467 1468 1469
				msgHeader_tmp = 0;
				pm8001_write_32(msgHeader, 0, 0);
				/* update the CI of outbound queue */
				pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar,
					circularQ->ci_offset,
					circularQ->consumer_idx);
J
jack wang 已提交
1470
				return MPI_IO_STATUS_FAIL;
1471 1472 1473 1474
			}
		} else {
			u32 producer_index;
			void *pi_virt = circularQ->pi_virt;
1475 1476 1477 1478 1479 1480
			/* spurious interrupt during setup if
			 * kexec-ing and driver doing a doorbell access
			 * with the pre-kexec oq interrupt setup
			 */
			if (!pi_virt)
				break;
1481 1482 1483
			/* Update the producer index from SPC */
			producer_index = pm8001_read_32(pi_virt);
			circularQ->producer_index = cpu_to_le32(producer_index);
J
jack wang 已提交
1484
		}
1485 1486
	} while (le32_to_cpu(circularQ->producer_index) !=
		circularQ->consumer_idx);
J
jack wang 已提交
1487 1488 1489 1490 1491
	/* while we don't have any more not-yet-delivered message */
	/* report empty */
	return MPI_IO_STATUS_BUSY;
}

1492
void pm8001_work_fn(struct work_struct *work)
J
jack wang 已提交
1493
{
1494
	struct pm8001_work *pw = container_of(work, struct pm8001_work, work);
J
jack wang 已提交
1495
	struct pm8001_device *pm8001_dev;
1496
	struct domain_device *dev;
J
jack wang 已提交
1497

1498 1499 1500 1501 1502 1503
	/*
	 * So far, all users of this stash an associated structure here.
	 * If we get here, and this pointer is null, then the action
	 * was cancelled. This nullification happens when the device
	 * goes away.
	 */
1504 1505 1506 1507 1508 1509 1510 1511
	if (pw->handler != IO_FATAL_ERROR) {
		pm8001_dev = pw->data; /* Most stash device structure */
		if ((pm8001_dev == NULL)
		 || ((pw->handler != IO_XFER_ERROR_BREAK)
			 && (pm8001_dev->dev_type == SAS_PHY_UNUSED))) {
			kfree(pw);
			return;
		}
1512 1513
	}

1514
	switch (pw->handler) {
1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553
	case IO_XFER_ERROR_BREAK:
	{	/* This one stashes the sas_task instead */
		struct sas_task *t = (struct sas_task *)pm8001_dev;
		u32 tag;
		struct pm8001_ccb_info *ccb;
		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
		unsigned long flags, flags1;
		struct task_status_struct *ts;
		int i;

		if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC)
			break; /* Task still on lu */
		spin_lock_irqsave(&pm8001_ha->lock, flags);

		spin_lock_irqsave(&t->task_state_lock, flags1);
		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
			spin_unlock_irqrestore(&t->task_state_lock, flags1);
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			break; /* Task got completed by another */
		}
		spin_unlock_irqrestore(&t->task_state_lock, flags1);

		/* Search for a possible ccb that matches the task */
		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
			ccb = &pm8001_ha->ccb_info[i];
			tag = ccb->ccb_tag;
			if ((tag != 0xFFFFFFFF) && (ccb->task == t))
				break;
		}
		if (!ccb) {
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			break; /* Task got freed by another */
		}
		ts = &t->task_status;
		ts->resp = SAS_TASK_COMPLETE;
		/* Force the midlayer to retry */
		ts->stat = SAS_QUEUE_FULL;
		pm8001_dev = ccb->device;
		if (pm8001_dev)
V
Viswas G 已提交
1554
			atomic_dec(&pm8001_dev->running_req);
1555 1556 1557 1558 1559 1560
		spin_lock_irqsave(&t->task_state_lock, flags1);
		t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
		t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
		t->task_state_flags |= SAS_TASK_STATE_DONE;
		if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
			spin_unlock_irqrestore(&t->task_state_lock, flags1);
1561 1562
			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",
				   t, pw->handler, ts->resp, ts->stat);
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581
			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
		} else {
			spin_unlock_irqrestore(&t->task_state_lock, flags1);
			pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
			mb();/* in order to force CPU ordering */
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			t->task_done(t);
		}
	}	break;
	case IO_XFER_OPEN_RETRY_TIMEOUT:
	{	/* This one stashes the sas_task instead */
		struct sas_task *t = (struct sas_task *)pm8001_dev;
		u32 tag;
		struct pm8001_ccb_info *ccb;
		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
		unsigned long flags, flags1;
		int i, ret = 0;

1582
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
1583 1584 1585

		ret = pm8001_query_task(t);

1586 1587 1588 1589 1590 1591
		if (ret == TMF_RESP_FUNC_SUCC)
			pm8001_dbg(pm8001_ha, IO, "...Task on lu\n");
		else if (ret == TMF_RESP_FUNC_COMPLETE)
			pm8001_dbg(pm8001_ha, IO, "...Task NOT on lu\n");
		else
			pm8001_dbg(pm8001_ha, DEVIO, "...query task failed!!!\n");
1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635

		spin_lock_irqsave(&pm8001_ha->lock, flags);

		spin_lock_irqsave(&t->task_state_lock, flags1);

		if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) {
			spin_unlock_irqrestore(&t->task_state_lock, flags1);
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
				(void)pm8001_abort_task(t);
			break; /* Task got completed by another */
		}

		spin_unlock_irqrestore(&t->task_state_lock, flags1);

		/* Search for a possible ccb that matches the task */
		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
			ccb = &pm8001_ha->ccb_info[i];
			tag = ccb->ccb_tag;
			if ((tag != 0xFFFFFFFF) && (ccb->task == t))
				break;
		}
		if (!ccb) {
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */
				(void)pm8001_abort_task(t);
			break; /* Task got freed by another */
		}

		pm8001_dev = ccb->device;
		dev = pm8001_dev->sas_device;

		switch (ret) {
		case TMF_RESP_FUNC_SUCC: /* task on lu */
			ccb->open_retry = 1; /* Snub completion */
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			ret = pm8001_abort_task(t);
			ccb->open_retry = 0;
			switch (ret) {
			case TMF_RESP_FUNC_SUCC:
			case TMF_RESP_FUNC_COMPLETE:
				break;
			default: /* device misbehavior */
				ret = TMF_RESP_FUNC_FAILED;
1636
				pm8001_dbg(pm8001_ha, IO, "...Reset phy\n");
1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649
				pm8001_I_T_nexus_reset(dev);
				break;
			}
			break;

		case TMF_RESP_FUNC_COMPLETE: /* task not on lu */
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			/* Do we need to abort the task locally? */
			break;

		default: /* device misbehavior */
			spin_unlock_irqrestore(&pm8001_ha->lock, flags);
			ret = TMF_RESP_FUNC_FAILED;
1650
			pm8001_dbg(pm8001_ha, IO, "...Reset phy\n");
1651 1652 1653 1654 1655 1656
			pm8001_I_T_nexus_reset(dev);
		}

		if (ret == TMF_RESP_FUNC_FAILED)
			t = NULL;
		pm8001_open_reject_retry(pm8001_ha, t, pm8001_dev);
1657
		pm8001_dbg(pm8001_ha, IO, "...Complete\n");
1658
	}	break;
J
jack wang 已提交
1659 1660
	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
		dev = pm8001_dev->sas_device;
1661
		pm8001_I_T_nexus_event_handler(dev);
J
jack wang 已提交
1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674
		break;
	case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
		dev = pm8001_dev->sas_device;
		pm8001_I_T_nexus_reset(dev);
		break;
	case IO_DS_IN_ERROR:
		dev = pm8001_dev->sas_device;
		pm8001_I_T_nexus_reset(dev);
		break;
	case IO_DS_NON_OPERATIONAL:
		dev = pm8001_dev->sas_device;
		pm8001_I_T_nexus_reset(dev);
		break;
1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726
	case IO_FATAL_ERROR:
	{
		struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha;
		struct pm8001_ccb_info *ccb;
		struct task_status_struct *ts;
		struct sas_task *task;
		int i;
		u32 tag, device_id;

		for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) {
			ccb = &pm8001_ha->ccb_info[i];
			task = ccb->task;
			ts = &task->task_status;
			tag = ccb->ccb_tag;
			/* check if tag is NULL */
			if (!tag) {
				pm8001_dbg(pm8001_ha, FAIL,
					"tag Null\n");
				continue;
			}
			if (task != NULL) {
				dev = task->dev;
				if (!dev) {
					pm8001_dbg(pm8001_ha, FAIL,
						"dev is NULL\n");
					continue;
				}
				/*complete sas task and update to top layer */
				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
				ts->resp = SAS_TASK_COMPLETE;
				task->task_done(task);
			} else if (tag != 0xFFFFFFFF) {
				/* complete the internal commands/non-sas task */
				pm8001_dev = ccb->device;
				if (pm8001_dev->dcompletion) {
					complete(pm8001_dev->dcompletion);
					pm8001_dev->dcompletion = NULL;
				}
				complete(pm8001_ha->nvmd_completion);
				pm8001_tag_free(pm8001_ha, tag);
			}
		}
		/* Deregister all the device ids  */
		for (i = 0; i < PM8001_MAX_DEVICES; i++) {
			pm8001_dev = &pm8001_ha->devices[i];
			device_id = pm8001_dev->device_id;
			if (device_id) {
				PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id);
				pm8001_free_dev(pm8001_dev);
			}
		}
	}	break;
J
jack wang 已提交
1727
	}
1728
	kfree(pw);
J
jack wang 已提交
1729 1730
}

1731
int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data,
J
jack wang 已提交
1732 1733
			       int handler)
{
1734
	struct pm8001_work *pw;
J
jack wang 已提交
1735 1736
	int ret = 0;

1737 1738 1739 1740 1741 1742 1743
	pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC);
	if (pw) {
		pw->pm8001_ha = pm8001_ha;
		pw->data = data;
		pw->handler = handler;
		INIT_WORK(&pw->work, pm8001_work_fn);
		queue_work(pm8001_wq, &pw->work);
J
jack wang 已提交
1744 1745 1746 1747 1748 1749
	} else
		ret = -ENOMEM;

	return ret;
}

1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762
static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha,
		struct pm8001_device *pm8001_ha_dev)
{
	int res;
	u32 ccb_tag;
	struct pm8001_ccb_info *ccb;
	struct sas_task *task = NULL;
	struct task_abort_req task_abort;
	struct inbound_queue_table *circularQ;
	u32 opc = OPC_INB_SATA_ABORT;
	int ret;

	if (!pm8001_ha_dev) {
1763
		pm8001_dbg(pm8001_ha, FAIL, "dev is null\n");
1764 1765 1766 1767 1768 1769
		return;
	}

	task = sas_alloc_slow_task(GFP_ATOMIC);

	if (!task) {
1770
		pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task\n");
1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791
		return;
	}

	task->task_done = pm8001_task_done;

	res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
	if (res)
		return;

	ccb = &pm8001_ha->ccb_info[ccb_tag];
	ccb->device = pm8001_ha_dev;
	ccb->ccb_tag = ccb_tag;
	ccb->task = task;

	circularQ = &pm8001_ha->inbnd_q_tbl[0];

	memset(&task_abort, 0, sizeof(task_abort));
	task_abort.abort_all = cpu_to_le32(1);
	task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
	task_abort.tag = cpu_to_le32(ccb_tag);

1792 1793
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort,
			sizeof(task_abort), 0);
T
Tomas Henzl 已提交
1794 1795
	if (ret)
		pm8001_tag_free(pm8001_ha, ccb_tag);
1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814

}

static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha,
		struct pm8001_device *pm8001_ha_dev)
{
	struct sata_start_req sata_cmd;
	int res;
	u32 ccb_tag;
	struct pm8001_ccb_info *ccb;
	struct sas_task *task = NULL;
	struct host_to_dev_fis fis;
	struct domain_device *dev;
	struct inbound_queue_table *circularQ;
	u32 opc = OPC_INB_SATA_HOST_OPSTART;

	task = sas_alloc_slow_task(GFP_ATOMIC);

	if (!task) {
1815
		pm8001_dbg(pm8001_ha, FAIL, "cannot allocate task !!!\n");
1816 1817 1818 1819 1820 1821
		return;
	}
	task->task_done = pm8001_task_done;

	res = pm8001_tag_alloc(pm8001_ha, &ccb_tag);
	if (res) {
T
Tomas Henzl 已提交
1822
		sas_free_task(task);
1823
		pm8001_dbg(pm8001_ha, FAIL, "cannot allocate tag !!!\n");
1824 1825 1826 1827 1828 1829 1830 1831
		return;
	}

	/* allocate domain device by ourselves as libsas
	 * is not going to provide any
	*/
	dev = kzalloc(sizeof(struct domain_device), GFP_ATOMIC);
	if (!dev) {
T
Tomas Henzl 已提交
1832 1833
		sas_free_task(task);
		pm8001_tag_free(pm8001_ha, ccb_tag);
1834 1835
		pm8001_dbg(pm8001_ha, FAIL,
			   "Domain device cannot be allocated\n");
1836 1837
		return;
	}
T
Tomas Henzl 已提交
1838 1839
	task->dev = dev;
	task->dev->lldd_dev = pm8001_ha_dev;
1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863

	ccb = &pm8001_ha->ccb_info[ccb_tag];
	ccb->device = pm8001_ha_dev;
	ccb->ccb_tag = ccb_tag;
	ccb->task = task;
	pm8001_ha_dev->id |= NCQ_READ_LOG_FLAG;
	pm8001_ha_dev->id |= NCQ_2ND_RLE_FLAG;

	memset(&sata_cmd, 0, sizeof(sata_cmd));
	circularQ = &pm8001_ha->inbnd_q_tbl[0];

	/* construct read log FIS */
	memset(&fis, 0, sizeof(struct host_to_dev_fis));
	fis.fis_type = 0x27;
	fis.flags = 0x80;
	fis.command = ATA_CMD_READ_LOG_EXT;
	fis.lbal = 0x10;
	fis.sector_count = 0x1;

	sata_cmd.tag = cpu_to_le32(ccb_tag);
	sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
	sata_cmd.ncqtag_atap_dir_m |= ((0x1 << 7) | (0x5 << 9));
	memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis));

1864 1865
	res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd,
			sizeof(sata_cmd), 0);
T
Tomas Henzl 已提交
1866 1867 1868 1869 1870
	if (res) {
		sas_free_task(task);
		pm8001_tag_free(pm8001_ha, ccb_tag);
		kfree(dev);
	}
1871 1872
}

J
jack wang 已提交
1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883
/**
 * mpi_ssp_completion- process the event that FW response to the SSP request.
 * @pm8001_ha: our hba card information
 * @piomb: the message contents of this outbound message.
 *
 * When FW has completed a ssp request for example a IO request, after it has
 * filled the SG data with the data, it will trigger this event represent
 * that he has finished the job,please check the coresponding buffer.
 * So we will tell the caller who maybe waiting the result to tell upper layer
 * that the task has been finished.
 */
1884
static void
L
Luo Jiaxing 已提交
1885
mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
{
	struct sas_task *t;
	struct pm8001_ccb_info *ccb;
	unsigned long flags;
	u32 status;
	u32 param;
	u32 tag;
	struct ssp_completion_resp *psspPayload;
	struct task_status_struct *ts;
	struct ssp_response_iu *iu;
	struct pm8001_device *pm8001_dev;
	psspPayload = (struct ssp_completion_resp *)(piomb + 4);
	status = le32_to_cpu(psspPayload->status);
	tag = le32_to_cpu(psspPayload->tag);
	ccb = &pm8001_ha->ccb_info[tag];
1901 1902 1903 1904 1905
	if ((status == IO_ABORTED) && ccb->open_retry) {
		/* Being completed by another */
		ccb->open_retry = 0;
		return;
	}
J
jack wang 已提交
1906 1907 1908 1909 1910
	pm8001_dev = ccb->device;
	param = le32_to_cpu(psspPayload->param);

	t = ccb->task;

1911
	if (status && status != IO_UNDERFLOW)
1912
		pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", status);
J
jack wang 已提交
1913
	if (unlikely(!t || !t->lldd_task || !t->dev))
1914
		return;
J
jack wang 已提交
1915
	ts = &t->task_status;
1916 1917 1918
	/* Print sas address of IO failed device */
	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
		(status != IO_UNDERFLOW))
1919 1920
		pm8001_dbg(pm8001_ha, FAIL, "SAS Address of IO Failure Drive:%016llx\n",
			   SAS_ADDR(t->dev->sas_addr));
1921

1922
	if (status)
1923 1924 1925
		pm8001_dbg(pm8001_ha, IOERR,
			   "status:0x%x, tag:0x%x, task:0x%p\n",
			   status, tag, t);
1926

J
jack wang 已提交
1927 1928
	switch (status) {
	case IO_SUCCESS:
1929 1930
		pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS,param = %d\n",
			   param);
J
jack wang 已提交
1931 1932
		if (param == 0) {
			ts->resp = SAS_TASK_COMPLETE;
1933
			ts->stat = SAS_SAM_STAT_GOOD;
J
jack wang 已提交
1934 1935 1936 1937 1938 1939 1940 1941
		} else {
			ts->resp = SAS_TASK_COMPLETE;
			ts->stat = SAS_PROTO_RESPONSE;
			ts->residual = param;
			iu = &psspPayload->ssp_resp_iu;
			sas_ssp_task_response(pm8001_ha->dev, t, iu);
		}
		if (pm8001_dev)
V
Viswas G 已提交
1942
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
1943 1944
		break;
	case IO_ABORTED:
1945
		pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n");
J
jack wang 已提交
1946 1947 1948 1949 1950
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_ABORTED_TASK;
		break;
	case IO_UNDERFLOW:
		/* SSP Completion with error */
1951 1952
		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW,param = %d\n",
			   param);
J
jack wang 已提交
1953 1954 1955 1956
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_UNDERRUN;
		ts->residual = param;
		if (pm8001_dev)
V
Viswas G 已提交
1957
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
1958 1959
		break;
	case IO_NO_DEVICE:
1960
		pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
J
jack wang 已提交
1961 1962 1963 1964
		ts->resp = SAS_TASK_UNDELIVERED;
		ts->stat = SAS_PHY_DOWN;
		break;
	case IO_XFER_ERROR_BREAK:
1965
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
J
jack wang 已提交
1966 1967
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
1968 1969
		/* Force the midlayer to retry */
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
J
jack wang 已提交
1970 1971
		break;
	case IO_XFER_ERROR_PHY_NOT_READY:
1972
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
J
jack wang 已提交
1973 1974 1975 1976 1977
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
1978 1979
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
J
jack wang 已提交
1980 1981 1982 1983 1984
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_EPROTO;
		break;
	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
1985 1986
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
J
jack wang 已提交
1987 1988 1989 1990 1991
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		break;
	case IO_OPEN_CNX_ERROR_BREAK:
1992
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
J
jack wang 已提交
1993 1994
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
1995
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
J
jack wang 已提交
1996 1997
		break;
	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
1998
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
J
jack wang 已提交
1999 2000 2001 2002 2003 2004 2005 2006 2007
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		if (!t->uldd_task)
			pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
		break;
	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
2008 2009
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
J
jack wang 已提交
2010 2011 2012 2013 2014
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
		break;
	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
2015
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
J
jack wang 已提交
2016 2017 2018 2019 2020
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
		break;
	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
2021 2022
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
J
jack wang 已提交
2023 2024 2025 2026 2027
		ts->resp = SAS_TASK_UNDELIVERED;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
		break;
	case IO_XFER_ERROR_NAK_RECEIVED:
2028
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
J
jack wang 已提交
2029 2030
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
2031
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
J
jack wang 已提交
2032 2033
		break;
	case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
2034
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
J
jack wang 已提交
2035 2036 2037 2038
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_NAK_R_ERR;
		break;
	case IO_XFER_ERROR_DMA:
2039
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n");
J
jack wang 已提交
2040 2041 2042 2043
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		break;
	case IO_XFER_OPEN_RETRY_TIMEOUT:
2044
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
J
jack wang 已提交
2045 2046 2047 2048 2049
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	case IO_XFER_ERROR_OFFSET_MISMATCH:
2050
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
J
jack wang 已提交
2051 2052 2053 2054
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		break;
	case IO_PORT_IN_RESET:
2055
		pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
J
jack wang 已提交
2056 2057 2058 2059
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		break;
	case IO_DS_NON_OPERATIONAL:
2060
		pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
J
jack wang 已提交
2061 2062 2063 2064 2065 2066 2067 2068
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		if (!t->uldd_task)
			pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_DS_NON_OPERATIONAL);
		break;
	case IO_DS_IN_RECOVERY:
2069
		pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n");
J
jack wang 已提交
2070 2071 2072 2073
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		break;
	case IO_TM_TAG_NOT_FOUND:
2074
		pm8001_dbg(pm8001_ha, IO, "IO_TM_TAG_NOT_FOUND\n");
J
jack wang 已提交
2075 2076 2077 2078
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		break;
	case IO_SSP_EXT_IU_ZERO_LEN_ERROR:
2079
		pm8001_dbg(pm8001_ha, IO, "IO_SSP_EXT_IU_ZERO_LEN_ERROR\n");
J
jack wang 已提交
2080 2081 2082 2083
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		break;
	case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
2084 2085
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
J
jack wang 已提交
2086 2087 2088
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
2089
		break;
J
jack wang 已提交
2090
	default:
2091
		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
J
jack wang 已提交
2092 2093 2094 2095 2096
		/* not allowed case. Therefore, return failed status */
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		break;
	}
2097 2098
	pm8001_dbg(pm8001_ha, IO, "scsi_status = %x\n",
		   psspPayload->ssp_resp_iu.status);
J
jack wang 已提交
2099 2100 2101 2102 2103 2104
	spin_lock_irqsave(&t->task_state_lock, flags);
	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
	t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
	t->task_state_flags |= SAS_TASK_STATE_DONE;
	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
2105 2106
		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",
			   t, status, ts->resp, ts->stat);
J
jack wang 已提交
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
	} else {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
		mb();/* in order to force CPU ordering */
		t->task_done(t);
	}
}

/*See the comments for mpi_ssp_completion */
L
Luo Jiaxing 已提交
2117
static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
{
	struct sas_task *t;
	unsigned long flags;
	struct task_status_struct *ts;
	struct pm8001_ccb_info *ccb;
	struct pm8001_device *pm8001_dev;
	struct ssp_event_resp *psspPayload =
		(struct ssp_event_resp *)(piomb + 4);
	u32 event = le32_to_cpu(psspPayload->event);
	u32 tag = le32_to_cpu(psspPayload->tag);
	u32 port_id = le32_to_cpu(psspPayload->port_id);
	u32 dev_id = le32_to_cpu(psspPayload->device_id);

	ccb = &pm8001_ha->ccb_info[tag];
	t = ccb->task;
	pm8001_dev = ccb->device;
	if (event)
2135
		pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", event);
J
jack wang 已提交
2136
	if (unlikely(!t || !t->lldd_task || !t->dev))
2137
		return;
J
jack wang 已提交
2138
	ts = &t->task_status;
2139 2140
	pm8001_dbg(pm8001_ha, DEVIO, "port_id = %x,device_id = %x\n",
		   port_id, dev_id);
J
jack wang 已提交
2141 2142
	switch (event) {
	case IO_OVERFLOW:
2143
		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
J
jack wang 已提交
2144 2145 2146 2147
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		ts->residual = 0;
		if (pm8001_dev)
V
Viswas G 已提交
2148
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2149 2150
		break;
	case IO_XFER_ERROR_BREAK:
2151
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
2152 2153
		pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK);
		return;
J
jack wang 已提交
2154
	case IO_XFER_ERROR_PHY_NOT_READY:
2155
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
J
jack wang 已提交
2156 2157 2158 2159 2160
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
2161
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
J
jack wang 已提交
2162 2163 2164 2165 2166
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_EPROTO;
		break;
	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
2167 2168
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
J
jack wang 已提交
2169 2170 2171 2172 2173
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		break;
	case IO_OPEN_CNX_ERROR_BREAK:
2174
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
J
jack wang 已提交
2175 2176
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
2177
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
J
jack wang 已提交
2178 2179
		break;
	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
2180
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
J
jack wang 已提交
2181 2182 2183 2184 2185 2186 2187 2188 2189
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		if (!t->uldd_task)
			pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
		break;
	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
2190 2191
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
J
jack wang 已提交
2192 2193 2194 2195 2196
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
		break;
	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
2197
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
J
jack wang 已提交
2198 2199 2200 2201 2202
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
		break;
	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
2203 2204
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
J
jack wang 已提交
2205 2206 2207 2208 2209
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
		break;
	case IO_XFER_ERROR_NAK_RECEIVED:
2210
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
J
jack wang 已提交
2211 2212
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
2213
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
J
jack wang 已提交
2214 2215
		break;
	case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
2216
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
J
jack wang 已提交
2217 2218 2219 2220
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_NAK_R_ERR;
		break;
	case IO_XFER_OPEN_RETRY_TIMEOUT:
2221
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
2222 2223
		pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT);
		return;
J
jack wang 已提交
2224
	case IO_XFER_ERROR_UNEXPECTED_PHASE:
2225
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n");
J
jack wang 已提交
2226 2227 2228 2229
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		break;
	case IO_XFER_ERROR_XFER_RDY_OVERRUN:
2230
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n");
J
jack wang 已提交
2231 2232 2233 2234
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		break;
	case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
2235 2236
		pm8001_dbg(pm8001_ha, IO,
			   "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n");
J
jack wang 已提交
2237 2238 2239 2240
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		break;
	case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT:
2241 2242
		pm8001_dbg(pm8001_ha, IO,
			   "IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n");
J
jack wang 已提交
2243 2244 2245 2246
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		break;
	case IO_XFER_ERROR_OFFSET_MISMATCH:
2247
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
J
jack wang 已提交
2248 2249 2250 2251
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		break;
	case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
2252 2253
		pm8001_dbg(pm8001_ha, IO,
			   "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n");
J
jack wang 已提交
2254 2255 2256 2257
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		break;
	case IO_XFER_CMD_FRAME_ISSUED:
2258
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n");
2259
		return;
J
jack wang 已提交
2260
	default:
2261
		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event);
J
jack wang 已提交
2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272
		/* not allowed case. Therefore, return failed status */
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		break;
	}
	spin_lock_irqsave(&t->task_state_lock, flags);
	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
	t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
	t->task_state_flags |= SAS_TASK_STATE_DONE;
	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
2273 2274
		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",
			   t, event, ts->resp, ts->stat);
J
jack wang 已提交
2275 2276 2277 2278 2279 2280 2281 2282 2283 2284
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
	} else {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
		mb();/* in order to force CPU ordering */
		t->task_done(t);
	}
}

/*See the comments for mpi_ssp_completion */
2285
static void
J
jack wang 已提交
2286 2287 2288 2289 2290 2291 2292
mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
	struct sas_task *t;
	struct pm8001_ccb_info *ccb;
	u32 param;
	u32 status;
	u32 tag;
2293 2294 2295 2296 2297
	int i, j;
	u8 sata_addr_low[4];
	u32 temp_sata_addr_low;
	u8 sata_addr_hi[4];
	u32 temp_sata_addr_hi;
J
jack wang 已提交
2298 2299 2300 2301 2302
	struct sata_completion_resp *psataPayload;
	struct task_status_struct *ts;
	struct ata_task_resp *resp ;
	u32 *sata_resp;
	struct pm8001_device *pm8001_dev;
2303
	unsigned long flags;
J
jack wang 已提交
2304 2305 2306 2307 2308

	psataPayload = (struct sata_completion_resp *)(piomb + 4);
	status = le32_to_cpu(psataPayload->status);
	tag = le32_to_cpu(psataPayload->tag);

2309
	if (!tag) {
2310
		pm8001_dbg(pm8001_ha, FAIL, "tag null\n");
2311 2312
		return;
	}
J
jack wang 已提交
2313 2314
	ccb = &pm8001_ha->ccb_info[tag];
	param = le32_to_cpu(psataPayload->param);
2315 2316 2317 2318
	if (ccb) {
		t = ccb->task;
		pm8001_dev = ccb->device;
	} else {
2319
		pm8001_dbg(pm8001_ha, FAIL, "ccb null\n");
2320 2321 2322 2323 2324 2325 2326
		return;
	}

	if (t) {
		if (t->dev && (t->dev->lldd_dev))
			pm8001_dev = t->dev->lldd_dev;
	} else {
2327
		pm8001_dbg(pm8001_ha, FAIL, "task null\n");
2328 2329 2330 2331 2332
		return;
	}

	if ((pm8001_dev && !(pm8001_dev->id & NCQ_READ_LOG_FLAG))
		&& unlikely(!t || !t->lldd_task || !t->dev)) {
2333
		pm8001_dbg(pm8001_ha, FAIL, "task or dev null\n");
2334 2335 2336
		return;
	}

J
jack wang 已提交
2337
	ts = &t->task_status;
2338
	if (!ts) {
2339
		pm8001_dbg(pm8001_ha, FAIL, "ts null\n");
2340
		return;
2341
	}
2342 2343

	if (status)
2344 2345 2346
		pm8001_dbg(pm8001_ha, IOERR,
			   "status:0x%x, tag:0x%x, task::0x%p\n",
			   status, tag, t);
2347

2348 2349 2350 2351
	/* Print sas address of IO failed device */
	if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
		(status != IO_UNDERFLOW)) {
		if (!((t->dev->parent) &&
2352
			(dev_is_expander(t->dev->parent->dev_type)))) {
L
Luo Jiaxing 已提交
2353
			for (i = 0, j = 4; j <= 7 && i <= 3; i++, j++)
2354
				sata_addr_low[i] = pm8001_ha->sas_addr[j];
L
Luo Jiaxing 已提交
2355
			for (i = 0, j = 0; j <= 3 && i <= 3; i++, j++)
2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
				sata_addr_hi[i] = pm8001_ha->sas_addr[j];
			memcpy(&temp_sata_addr_low, sata_addr_low,
				sizeof(sata_addr_low));
			memcpy(&temp_sata_addr_hi, sata_addr_hi,
				sizeof(sata_addr_hi));
			temp_sata_addr_hi = (((temp_sata_addr_hi >> 24) & 0xff)
						|((temp_sata_addr_hi << 8) &
						0xff0000) |
						((temp_sata_addr_hi >> 8)
						& 0xff00) |
						((temp_sata_addr_hi << 24) &
						0xff000000));
			temp_sata_addr_low = ((((temp_sata_addr_low >> 24)
						& 0xff) |
						((temp_sata_addr_low << 8)
						& 0xff0000) |
						((temp_sata_addr_low >> 8)
						& 0xff00) |
						((temp_sata_addr_low << 24)
						& 0xff000000)) +
						pm8001_dev->attached_phy +
						0x10);
2378 2379 2380 2381
			pm8001_dbg(pm8001_ha, FAIL,
				   "SAS Address of IO Failure Drive:%08x%08x\n",
				   temp_sata_addr_hi,
				   temp_sata_addr_low);
2382
		} else {
2383 2384 2385
			pm8001_dbg(pm8001_ha, FAIL,
				   "SAS Address of IO Failure Drive:%016llx\n",
				   SAS_ADDR(t->dev->sas_addr));
2386 2387
		}
	}
J
jack wang 已提交
2388 2389
	switch (status) {
	case IO_SUCCESS:
2390
		pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
J
jack wang 已提交
2391 2392
		if (param == 0) {
			ts->resp = SAS_TASK_COMPLETE;
2393
			ts->stat = SAS_SAM_STAT_GOOD;
2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406
			/* check if response is for SEND READ LOG */
			if (pm8001_dev &&
				(pm8001_dev->id & NCQ_READ_LOG_FLAG)) {
				/* set new bit for abort_all */
				pm8001_dev->id |= NCQ_ABORT_ALL_FLAG;
				/* clear bit for read log */
				pm8001_dev->id = pm8001_dev->id & 0x7FFFFFFF;
				pm8001_send_abort_all(pm8001_ha, pm8001_dev);
				/* Free the tag */
				pm8001_tag_free(pm8001_ha, tag);
				sas_free_task(t);
				return;
			}
J
jack wang 已提交
2407 2408 2409 2410 2411
		} else {
			u8 len;
			ts->resp = SAS_TASK_COMPLETE;
			ts->stat = SAS_PROTO_RESPONSE;
			ts->residual = param;
2412 2413 2414
			pm8001_dbg(pm8001_ha, IO,
				   "SAS_PROTO_RESPONSE len = %d\n",
				   param);
J
jack wang 已提交
2415 2416 2417
			sata_resp = &psataPayload->sata_resp[0];
			resp = (struct ata_task_resp *)ts->buf;
			if (t->ata_task.dma_xfer == 0 &&
2418
			    t->data_dir == DMA_FROM_DEVICE) {
J
jack wang 已提交
2419
				len = sizeof(struct pio_setup_fis);
2420 2421
				pm8001_dbg(pm8001_ha, IO,
					   "PIO read len = %d\n", len);
J
jack wang 已提交
2422 2423
			} else if (t->ata_task.use_ncq) {
				len = sizeof(struct set_dev_bits_fis);
2424 2425
				pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n",
					   len);
J
jack wang 已提交
2426 2427
			} else {
				len = sizeof(struct dev_to_host_fis);
2428 2429
				pm8001_dbg(pm8001_ha, IO, "other len = %d\n",
					   len);
J
jack wang 已提交
2430 2431 2432 2433 2434 2435
			}
			if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) {
				resp->frame_len = len;
				memcpy(&resp->ending_fis[0], sata_resp, len);
				ts->buf_valid_size = sizeof(*resp);
			} else
2436 2437
				pm8001_dbg(pm8001_ha, IO,
					   "response too large\n");
J
jack wang 已提交
2438 2439
		}
		if (pm8001_dev)
V
Viswas G 已提交
2440
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2441 2442
		break;
	case IO_ABORTED:
2443
		pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n");
J
jack wang 已提交
2444 2445 2446
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_ABORTED_TASK;
		if (pm8001_dev)
V
Viswas G 已提交
2447
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2448 2449 2450 2451
		break;
		/* following cases are to do cases */
	case IO_UNDERFLOW:
		/* SATA Completion with error */
2452
		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW param = %d\n", param);
J
jack wang 已提交
2453 2454 2455 2456
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_UNDERRUN;
		ts->residual =  param;
		if (pm8001_dev)
V
Viswas G 已提交
2457
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2458 2459
		break;
	case IO_NO_DEVICE:
2460
		pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
J
jack wang 已提交
2461 2462
		ts->resp = SAS_TASK_UNDELIVERED;
		ts->stat = SAS_PHY_DOWN;
V
Viswas G 已提交
2463 2464
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2465 2466
		break;
	case IO_XFER_ERROR_BREAK:
2467
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
J
jack wang 已提交
2468 2469
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_INTERRUPTED;
V
Viswas G 已提交
2470 2471
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2472 2473
		break;
	case IO_XFER_ERROR_PHY_NOT_READY:
2474
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
J
jack wang 已提交
2475 2476 2477
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
V
Viswas G 已提交
2478 2479
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2480 2481
		break;
	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
2482
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
J
jack wang 已提交
2483 2484 2485
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_EPROTO;
V
Viswas G 已提交
2486 2487
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2488 2489
		break;
	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
2490 2491
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
J
jack wang 已提交
2492 2493 2494
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
V
Viswas G 已提交
2495 2496
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2497 2498
		break;
	case IO_OPEN_CNX_ERROR_BREAK:
2499
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
J
jack wang 已提交
2500 2501 2502
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
V
Viswas G 已提交
2503 2504
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2505 2506
		break;
	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
2507
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
J
jack wang 已提交
2508 2509 2510 2511 2512 2513 2514 2515
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
		if (!t->uldd_task) {
			pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
			ts->resp = SAS_TASK_UNDELIVERED;
			ts->stat = SAS_QUEUE_FULL;
S
Suresh Thiagarajan 已提交
2516
			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
2517
			return;
J
jack wang 已提交
2518 2519 2520
		}
		break;
	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
2521 2522
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
J
jack wang 已提交
2523 2524 2525 2526 2527 2528 2529 2530 2531
		ts->resp = SAS_TASK_UNDELIVERED;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
		if (!t->uldd_task) {
			pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
			ts->resp = SAS_TASK_UNDELIVERED;
			ts->stat = SAS_QUEUE_FULL;
S
Suresh Thiagarajan 已提交
2532
			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
2533
			return;
J
jack wang 已提交
2534 2535 2536
		}
		break;
	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
2537
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
J
jack wang 已提交
2538 2539 2540
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
V
Viswas G 已提交
2541 2542
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2543 2544
		break;
	case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
2545
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n");
J
jack wang 已提交
2546 2547 2548 2549 2550 2551 2552 2553
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
		if (!t->uldd_task) {
			pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY);
			ts->resp = SAS_TASK_UNDELIVERED;
			ts->stat = SAS_QUEUE_FULL;
S
Suresh Thiagarajan 已提交
2554
			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
2555
			return;
J
jack wang 已提交
2556 2557 2558
		}
		break;
	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
2559 2560
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
J
jack wang 已提交
2561 2562 2563
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
V
Viswas G 已提交
2564 2565
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2566 2567
		break;
	case IO_XFER_ERROR_NAK_RECEIVED:
2568
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
J
jack wang 已提交
2569 2570
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_NAK_R_ERR;
V
Viswas G 已提交
2571 2572
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2573 2574
		break;
	case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
2575
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
J
jack wang 已提交
2576 2577
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_NAK_R_ERR;
V
Viswas G 已提交
2578 2579
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2580 2581
		break;
	case IO_XFER_ERROR_DMA:
2582
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n");
J
jack wang 已提交
2583 2584
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_ABORTED_TASK;
V
Viswas G 已提交
2585 2586
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2587 2588
		break;
	case IO_XFER_ERROR_SATA_LINK_TIMEOUT:
2589
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_SATA_LINK_TIMEOUT\n");
J
jack wang 已提交
2590 2591
		ts->resp = SAS_TASK_UNDELIVERED;
		ts->stat = SAS_DEV_NO_RESPONSE;
V
Viswas G 已提交
2592 2593
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2594 2595
		break;
	case IO_XFER_ERROR_REJECTED_NCQ_MODE:
2596
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n");
J
jack wang 已提交
2597 2598
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_UNDERRUN;
V
Viswas G 已提交
2599 2600
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2601 2602
		break;
	case IO_XFER_OPEN_RETRY_TIMEOUT:
2603
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
J
jack wang 已提交
2604 2605
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
V
Viswas G 已提交
2606 2607
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2608 2609
		break;
	case IO_PORT_IN_RESET:
2610
		pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
J
jack wang 已提交
2611 2612
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
V
Viswas G 已提交
2613 2614
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2615 2616
		break;
	case IO_DS_NON_OPERATIONAL:
2617
		pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
J
jack wang 已提交
2618 2619 2620 2621 2622 2623 2624
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
		if (!t->uldd_task) {
			pm8001_handle_event(pm8001_ha, pm8001_dev,
				    IO_DS_NON_OPERATIONAL);
			ts->resp = SAS_TASK_UNDELIVERED;
			ts->stat = SAS_QUEUE_FULL;
S
Suresh Thiagarajan 已提交
2625
			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
2626
			return;
J
jack wang 已提交
2627 2628 2629
		}
		break;
	case IO_DS_IN_RECOVERY:
2630
		pm8001_dbg(pm8001_ha, IO, "  IO_DS_IN_RECOVERY\n");
J
jack wang 已提交
2631 2632
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
V
Viswas G 已提交
2633 2634
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2635 2636
		break;
	case IO_DS_IN_ERROR:
2637
		pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_ERROR\n");
J
jack wang 已提交
2638 2639 2640 2641 2642 2643 2644
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
		if (!t->uldd_task) {
			pm8001_handle_event(pm8001_ha, pm8001_dev,
				    IO_DS_IN_ERROR);
			ts->resp = SAS_TASK_UNDELIVERED;
			ts->stat = SAS_QUEUE_FULL;
S
Suresh Thiagarajan 已提交
2645
			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
2646
			return;
J
jack wang 已提交
2647 2648 2649
		}
		break;
	case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
2650 2651
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
J
jack wang 已提交
2652 2653 2654
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
V
Viswas G 已提交
2655 2656
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
2657
		break;
J
jack wang 已提交
2658
	default:
2659
		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
J
jack wang 已提交
2660 2661 2662
		/* not allowed case. Therefore, return failed status */
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
V
Viswas G 已提交
2663 2664
		if (pm8001_dev)
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2665 2666
		break;
	}
2667
	spin_lock_irqsave(&t->task_state_lock, flags);
J
jack wang 已提交
2668 2669 2670 2671
	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
	t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
	t->task_state_flags |= SAS_TASK_STATE_DONE;
	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
2672
		spin_unlock_irqrestore(&t->task_state_lock, flags);
2673 2674 2675
		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",
			   t, status, ts->resp, ts->stat);
J
jack wang 已提交
2676
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
S
Suresh Thiagarajan 已提交
2677
	} else {
2678
		spin_unlock_irqrestore(&t->task_state_lock, flags);
S
Suresh Thiagarajan 已提交
2679
		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
J
jack wang 已提交
2680 2681 2682 2683
	}
}

/*See the comments for mpi_ssp_completion */
L
Luo Jiaxing 已提交
2684
static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695
{
	struct sas_task *t;
	struct task_status_struct *ts;
	struct pm8001_ccb_info *ccb;
	struct pm8001_device *pm8001_dev;
	struct sata_event_resp *psataPayload =
		(struct sata_event_resp *)(piomb + 4);
	u32 event = le32_to_cpu(psataPayload->event);
	u32 tag = le32_to_cpu(psataPayload->tag);
	u32 port_id = le32_to_cpu(psataPayload->port_id);
	u32 dev_id = le32_to_cpu(psataPayload->device_id);
2696
	unsigned long flags;
J
jack wang 已提交
2697

2698 2699 2700 2701 2702 2703
	ccb = &pm8001_ha->ccb_info[tag];

	if (ccb) {
		t = ccb->task;
		pm8001_dev = ccb->device;
	} else {
2704
		pm8001_dbg(pm8001_ha, FAIL, "No CCB !!!. returning\n");
2705 2706
	}
	if (event)
2707
		pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718

	/* Check if this is NCQ error */
	if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) {
		/* find device using device id */
		pm8001_dev = pm8001_find_dev(pm8001_ha, dev_id);
		/* send read log extension */
		if (pm8001_dev)
			pm8001_send_read_log(pm8001_ha, pm8001_dev);
		return;
	}

J
jack wang 已提交
2719 2720 2721 2722
	ccb = &pm8001_ha->ccb_info[tag];
	t = ccb->task;
	pm8001_dev = ccb->device;
	if (event)
2723
		pm8001_dbg(pm8001_ha, FAIL, "sata IO status 0x%x\n", event);
J
jack wang 已提交
2724
	if (unlikely(!t || !t->lldd_task || !t->dev))
2725
		return;
J
jack wang 已提交
2726
	ts = &t->task_status;
2727 2728 2729
	pm8001_dbg(pm8001_ha, DEVIO,
		   "port_id:0x%x, device_id:0x%x, tag:0x%x, event:0x%x\n",
		   port_id, dev_id, tag, event);
J
jack wang 已提交
2730 2731
	switch (event) {
	case IO_OVERFLOW:
2732
		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
J
jack wang 已提交
2733 2734 2735 2736
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		ts->residual = 0;
		if (pm8001_dev)
V
Viswas G 已提交
2737
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2738 2739
		break;
	case IO_XFER_ERROR_BREAK:
2740
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
J
jack wang 已提交
2741 2742 2743 2744
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_INTERRUPTED;
		break;
	case IO_XFER_ERROR_PHY_NOT_READY:
2745
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
J
jack wang 已提交
2746 2747 2748 2749 2750
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
2751
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
J
jack wang 已提交
2752 2753 2754 2755 2756
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_EPROTO;
		break;
	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
2757 2758
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
J
jack wang 已提交
2759 2760 2761 2762 2763
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		break;
	case IO_OPEN_CNX_ERROR_BREAK:
2764
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
J
jack wang 已提交
2765 2766 2767 2768 2769
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
		break;
	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
2770
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
J
jack wang 已提交
2771 2772 2773 2774 2775 2776 2777 2778
		ts->resp = SAS_TASK_UNDELIVERED;
		ts->stat = SAS_DEV_NO_RESPONSE;
		if (!t->uldd_task) {
			pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
			ts->resp = SAS_TASK_COMPLETE;
			ts->stat = SAS_QUEUE_FULL;
S
Suresh Thiagarajan 已提交
2779
			pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
2780
			return;
J
jack wang 已提交
2781 2782 2783
		}
		break;
	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
2784 2785
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
J
jack wang 已提交
2786 2787 2788 2789 2790
		ts->resp = SAS_TASK_UNDELIVERED;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
		break;
	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
2791
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
J
jack wang 已提交
2792 2793 2794 2795 2796
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
		break;
	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
2797 2798
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
J
jack wang 已提交
2799 2800 2801 2802 2803
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
		break;
	case IO_XFER_ERROR_NAK_RECEIVED:
2804
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
J
jack wang 已提交
2805 2806 2807 2808
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_NAK_R_ERR;
		break;
	case IO_XFER_ERROR_PEER_ABORTED:
2809
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PEER_ABORTED\n");
J
jack wang 已提交
2810 2811 2812 2813
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_NAK_R_ERR;
		break;
	case IO_XFER_ERROR_REJECTED_NCQ_MODE:
2814
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n");
J
jack wang 已提交
2815 2816 2817 2818
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_UNDERRUN;
		break;
	case IO_XFER_OPEN_RETRY_TIMEOUT:
2819
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
J
jack wang 已提交
2820 2821 2822 2823
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	case IO_XFER_ERROR_UNEXPECTED_PHASE:
2824
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n");
J
jack wang 已提交
2825 2826 2827 2828
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	case IO_XFER_ERROR_XFER_RDY_OVERRUN:
2829
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n");
J
jack wang 已提交
2830 2831 2832 2833
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
2834 2835
		pm8001_dbg(pm8001_ha, IO,
			   "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n");
J
jack wang 已提交
2836 2837 2838 2839
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	case IO_XFER_ERROR_OFFSET_MISMATCH:
2840
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
J
jack wang 已提交
2841 2842 2843 2844
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
2845 2846
		pm8001_dbg(pm8001_ha, IO,
			   "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n");
J
jack wang 已提交
2847 2848 2849 2850
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	case IO_XFER_CMD_FRAME_ISSUED:
2851
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n");
J
jack wang 已提交
2852 2853
		break;
	case IO_XFER_PIO_SETUP_ERROR:
2854
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_PIO_SETUP_ERROR\n");
J
jack wang 已提交
2855 2856 2857 2858
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	default:
2859
		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event);
J
jack wang 已提交
2860 2861 2862 2863 2864
		/* not allowed case. Therefore, return failed status */
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_TO;
		break;
	}
2865
	spin_lock_irqsave(&t->task_state_lock, flags);
J
jack wang 已提交
2866 2867 2868 2869
	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
	t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
	t->task_state_flags |= SAS_TASK_STATE_DONE;
	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
2870
		spin_unlock_irqrestore(&t->task_state_lock, flags);
2871 2872 2873
		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",
			   t, event, ts->resp, ts->stat);
J
jack wang 已提交
2874
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
S
Suresh Thiagarajan 已提交
2875
	} else {
2876
		spin_unlock_irqrestore(&t->task_state_lock, flags);
S
Suresh Thiagarajan 已提交
2877
		pm8001_ccb_task_free_done(pm8001_ha, t, ccb, tag);
J
jack wang 已提交
2878 2879 2880 2881
	}
}

/*See the comments for mpi_ssp_completion */
2882
static void
J
jack wang 已提交
2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901
mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
	struct sas_task *t;
	struct pm8001_ccb_info *ccb;
	unsigned long flags;
	u32 status;
	u32 tag;
	struct smp_completion_resp *psmpPayload;
	struct task_status_struct *ts;
	struct pm8001_device *pm8001_dev;

	psmpPayload = (struct smp_completion_resp *)(piomb + 4);
	status = le32_to_cpu(psmpPayload->status);
	tag = le32_to_cpu(psmpPayload->tag);

	ccb = &pm8001_ha->ccb_info[tag];
	t = ccb->task;
	ts = &t->task_status;
	pm8001_dev = ccb->device;
2902
	if (status) {
2903 2904 2905 2906
		pm8001_dbg(pm8001_ha, FAIL, "smp IO status 0x%x\n", status);
		pm8001_dbg(pm8001_ha, IOERR,
			   "status:0x%x, tag:0x%x, task:0x%p\n",
			   status, tag, t);
2907
	}
J
jack wang 已提交
2908
	if (unlikely(!t || !t->lldd_task || !t->dev))
2909
		return;
J
jack wang 已提交
2910 2911 2912

	switch (status) {
	case IO_SUCCESS:
2913
		pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
J
jack wang 已提交
2914
		ts->resp = SAS_TASK_COMPLETE;
2915
		ts->stat = SAS_SAM_STAT_GOOD;
2916
		if (pm8001_dev)
V
Viswas G 已提交
2917
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2918 2919
		break;
	case IO_ABORTED:
2920
		pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB\n");
J
jack wang 已提交
2921 2922 2923
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_ABORTED_TASK;
		if (pm8001_dev)
V
Viswas G 已提交
2924
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2925 2926
		break;
	case IO_OVERFLOW:
2927
		pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
J
jack wang 已提交
2928 2929 2930 2931
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DATA_OVERRUN;
		ts->residual = 0;
		if (pm8001_dev)
V
Viswas G 已提交
2932
			atomic_dec(&pm8001_dev->running_req);
J
jack wang 已提交
2933 2934
		break;
	case IO_NO_DEVICE:
2935
		pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
J
jack wang 已提交
2936 2937 2938 2939
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_PHY_DOWN;
		break;
	case IO_ERROR_HW_TIMEOUT:
2940
		pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n");
J
jack wang 已提交
2941
		ts->resp = SAS_TASK_COMPLETE;
2942
		ts->stat = SAS_SAM_STAT_BUSY;
J
jack wang 已提交
2943 2944
		break;
	case IO_XFER_ERROR_BREAK:
2945
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
J
jack wang 已提交
2946
		ts->resp = SAS_TASK_COMPLETE;
2947
		ts->stat = SAS_SAM_STAT_BUSY;
J
jack wang 已提交
2948 2949
		break;
	case IO_XFER_ERROR_PHY_NOT_READY:
2950
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
J
jack wang 已提交
2951
		ts->resp = SAS_TASK_COMPLETE;
2952
		ts->stat = SAS_SAM_STAT_BUSY;
J
jack wang 已提交
2953 2954
		break;
	case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
2955 2956
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
J
jack wang 已提交
2957 2958 2959 2960 2961
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		break;
	case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
2962 2963
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
J
jack wang 已提交
2964 2965 2966 2967 2968
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		break;
	case IO_OPEN_CNX_ERROR_BREAK:
2969
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
J
jack wang 已提交
2970 2971 2972 2973 2974
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
		break;
	case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
2975
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
J
jack wang 已提交
2976 2977 2978 2979 2980 2981 2982 2983
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_UNKNOWN;
		pm8001_handle_event(pm8001_ha,
				pm8001_dev,
				IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS);
		break;
	case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
2984 2985
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
J
jack wang 已提交
2986 2987 2988 2989 2990
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_BAD_DEST;
		break;
	case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
2991
		pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
J
jack wang 已提交
2992 2993 2994 2995 2996
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_CONN_RATE;
		break;
	case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
2997 2998
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
J
jack wang 已提交
2999 3000 3001 3002 3003
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
		break;
	case IO_XFER_ERROR_RX_FRAME:
3004
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_RX_FRAME\n");
J
jack wang 已提交
3005 3006 3007 3008
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
		break;
	case IO_XFER_OPEN_RETRY_TIMEOUT:
3009
		pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
J
jack wang 已提交
3010 3011 3012 3013 3014
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	case IO_ERROR_INTERNAL_SMP_RESOURCE:
3015
		pm8001_dbg(pm8001_ha, IO, "IO_ERROR_INTERNAL_SMP_RESOURCE\n");
J
jack wang 已提交
3016 3017 3018 3019
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_QUEUE_FULL;
		break;
	case IO_PORT_IN_RESET:
3020
		pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
J
jack wang 已提交
3021 3022 3023 3024 3025
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	case IO_DS_NON_OPERATIONAL:
3026
		pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
J
jack wang 已提交
3027 3028 3029 3030
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
		break;
	case IO_DS_IN_RECOVERY:
3031
		pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n");
J
jack wang 已提交
3032 3033 3034 3035 3036
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
3037 3038
		pm8001_dbg(pm8001_ha, IO,
			   "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
J
jack wang 已提交
3039 3040 3041 3042 3043
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_OPEN_REJECT;
		ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
		break;
	default:
3044
		pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
J
jack wang 已提交
3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055
		ts->resp = SAS_TASK_COMPLETE;
		ts->stat = SAS_DEV_NO_RESPONSE;
		/* not allowed case. Therefore, return failed status */
		break;
	}
	spin_lock_irqsave(&t->task_state_lock, flags);
	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
	t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
	t->task_state_flags |= SAS_TASK_STATE_DONE;
	if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
3056 3057
		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",
			   t, status, ts->resp, ts->stat);
J
jack wang 已提交
3058 3059 3060 3061 3062 3063 3064 3065 3066
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
	} else {
		spin_unlock_irqrestore(&t->task_state_lock, flags);
		pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
		mb();/* in order to force CPU ordering */
		t->task_done(t);
	}
}

3067 3068
void pm8001_mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha,
		void *piomb)
J
jack wang 已提交
3069 3070 3071 3072 3073 3074 3075 3076
{
	struct set_dev_state_resp *pPayload =
		(struct set_dev_state_resp *)(piomb + 4);
	u32 tag = le32_to_cpu(pPayload->tag);
	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
	struct pm8001_device *pm8001_dev = ccb->device;
	u32 status = le32_to_cpu(pPayload->status);
	u32 device_id = le32_to_cpu(pPayload->device_id);
3077 3078
	u8 pds = le32_to_cpu(pPayload->pds_nds) & PDS_BITS;
	u8 nds = le32_to_cpu(pPayload->pds_nds) & NDS_BITS;
3079 3080
	pm8001_dbg(pm8001_ha, MSG, "Set device id = 0x%x state from 0x%x to 0x%x status = 0x%x!\n",
		   device_id, pds, nds, status);
J
jack wang 已提交
3081 3082 3083
	complete(pm8001_dev->setds_completion);
	ccb->task = NULL;
	ccb->ccb_tag = 0xFFFFFFFF;
3084
	pm8001_tag_free(pm8001_ha, tag);
J
jack wang 已提交
3085 3086
}

3087
void pm8001_mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3088 3089 3090 3091 3092 3093 3094
{
	struct get_nvm_data_resp *pPayload =
		(struct get_nvm_data_resp *)(piomb + 4);
	u32 tag = le32_to_cpu(pPayload->tag);
	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
	u32 dlen_status = le32_to_cpu(pPayload->dlen_status);
	complete(pm8001_ha->nvmd_completion);
3095
	pm8001_dbg(pm8001_ha, MSG, "Set nvm data complete!\n");
J
jack wang 已提交
3096
	if ((dlen_status & NVMD_STAT) != 0) {
3097 3098
		pm8001_dbg(pm8001_ha, FAIL, "Set nvm data error %x\n",
				dlen_status);
J
jack wang 已提交
3099 3100 3101
	}
	ccb->task = NULL;
	ccb->ccb_tag = 0xFFFFFFFF;
3102
	pm8001_tag_free(pm8001_ha, tag);
J
jack wang 已提交
3103 3104
}

3105 3106
void
pm8001_mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3107
{
3108
	struct fw_control_ex    *fw_control_context;
J
jack wang 已提交
3109 3110 3111 3112 3113 3114 3115 3116
	struct get_nvm_data_resp *pPayload =
		(struct get_nvm_data_resp *)(piomb + 4);
	u32 tag = le32_to_cpu(pPayload->tag);
	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
	u32 dlen_status = le32_to_cpu(pPayload->dlen_status);
	u32 ir_tds_bn_dps_das_nvm =
		le32_to_cpu(pPayload->ir_tda_bn_dps_das_nvm);
	void *virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr;
3117
	fw_control_context = ccb->fw_control_context;
J
jack wang 已提交
3118

3119
	pm8001_dbg(pm8001_ha, MSG, "Get nvm data complete!\n");
J
jack wang 已提交
3120
	if ((dlen_status & NVMD_STAT) != 0) {
3121 3122
		pm8001_dbg(pm8001_ha, FAIL, "Get nvm data error %x\n",
				dlen_status);
J
jack wang 已提交
3123
		complete(pm8001_ha->nvmd_completion);
3124 3125 3126 3127 3128 3129
		/* We should free tag during failure also, the tag is not being
		 * freed by requesting path anywhere.
		 */
		ccb->task = NULL;
		ccb->ccb_tag = 0xFFFFFFFF;
		pm8001_tag_free(pm8001_ha, tag);
J
jack wang 已提交
3130 3131 3132 3133
		return;
	}
	if (ir_tds_bn_dps_das_nvm & IPMode) {
		/* indirect mode - IR bit set */
3134
		pm8001_dbg(pm8001_ha, MSG, "Get NVMD success, IR=1\n");
J
jack wang 已提交
3135 3136 3137 3138 3139
		if ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == TWI_DEVICE) {
			if (ir_tds_bn_dps_das_nvm == 0x80a80200) {
				memcpy(pm8001_ha->sas_addr,
				      ((u8 *)virt_addr + 4),
				       SAS_ADDR_SIZE);
3140
				pm8001_dbg(pm8001_ha, MSG, "Get SAS address from VPD successfully!\n");
J
jack wang 已提交
3141 3142 3143 3144 3145 3146 3147 3148 3149 3150
			}
		} else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == C_SEEPROM)
			|| ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == VPD_FLASH) ||
			((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == EXPAN_ROM)) {
				;
		} else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == AAP1_RDUMP)
			|| ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == IOP_RDUMP)) {
			;
		} else {
			/* Should not be happened*/
3151 3152 3153
			pm8001_dbg(pm8001_ha, MSG,
				   "(IR=1)Wrong Device type 0x%x\n",
				   ir_tds_bn_dps_das_nvm);
J
jack wang 已提交
3154 3155
		}
	} else /* direct mode */{
3156 3157 3158
		pm8001_dbg(pm8001_ha, MSG,
			   "Get NVMD success, IR=0, dataLen=%d\n",
			   (dlen_status & NVMD_LEN) >> 24);
J
jack wang 已提交
3159
	}
3160 3161 3162 3163 3164 3165
	/* Though fw_control_context is freed below, usrAddr still needs
	 * to be updated as this holds the response to the request function
	 */
	memcpy(fw_control_context->usrAddr,
		pm8001_ha->memoryMap.region[NVMD].virt_ptr,
		fw_control_context->len);
3166
	kfree(ccb->fw_control_context);
3167 3168 3169 3170 3171
	/* To avoid race condition, complete should be
	 * called after the message is copied to
	 * fw_control_context->usrAddr
	 */
	complete(pm8001_ha->nvmd_completion);
3172
	pm8001_dbg(pm8001_ha, MSG, "Set nvm data complete!\n");
J
jack wang 已提交
3173 3174
	ccb->task = NULL;
	ccb->ccb_tag = 0xFFFFFFFF;
3175
	pm8001_tag_free(pm8001_ha, tag);
J
jack wang 已提交
3176 3177
}

3178
int pm8001_mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3179
{
3180
	u32 tag;
J
jack wang 已提交
3181 3182 3183 3184 3185
	struct local_phy_ctl_resp *pPayload =
		(struct local_phy_ctl_resp *)(piomb + 4);
	u32 status = le32_to_cpu(pPayload->status);
	u32 phy_id = le32_to_cpu(pPayload->phyop_phyid) & ID_BITS;
	u32 phy_op = le32_to_cpu(pPayload->phyop_phyid) & OP_BITS;
3186
	tag = le32_to_cpu(pPayload->tag);
J
jack wang 已提交
3187
	if (status != 0) {
3188 3189 3190
		pm8001_dbg(pm8001_ha, MSG,
			   "%x phy execute %x phy op failed!\n",
			   phy_id, phy_op);
3191
	} else {
3192 3193 3194
		pm8001_dbg(pm8001_ha, MSG,
			   "%x phy execute %x phy op success!\n",
			   phy_id, phy_op);
3195 3196 3197 3198 3199 3200
		pm8001_ha->phy[phy_id].reset_success = true;
	}
	if (pm8001_ha->phy[phy_id].enable_completion) {
		complete(pm8001_ha->phy[phy_id].enable_completion);
		pm8001_ha->phy[phy_id].enable_completion = NULL;
	}
3201
	pm8001_tag_free(pm8001_ha, tag);
J
jack wang 已提交
3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215
	return 0;
}

/**
 * pm8001_bytes_dmaed - one of the interface function communication with libsas
 * @pm8001_ha: our hba card information
 * @i: which phy that received the event.
 *
 * when HBA driver received the identify done event or initiate FIS received
 * event(for SATA), it will invoke this function to notify the sas layer that
 * the sas toplogy has formed, please discover the the whole sas domain,
 * while receive a broadcast(change) primitive just tell the sas
 * layer to discover the changed domain rather than the whole domain.
 */
3216
void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i)
J
jack wang 已提交
3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240
{
	struct pm8001_phy *phy = &pm8001_ha->phy[i];
	struct asd_sas_phy *sas_phy = &phy->sas_phy;
	if (!phy->phy_attached)
		return;

	if (sas_phy->phy) {
		struct sas_phy *sphy = sas_phy->phy;
		sphy->negotiated_linkrate = sas_phy->linkrate;
		sphy->minimum_linkrate = phy->minimum_linkrate;
		sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
		sphy->maximum_linkrate = phy->maximum_linkrate;
		sphy->maximum_linkrate_hw = phy->maximum_linkrate;
	}

	if (phy->phy_type & PORT_TYPE_SAS) {
		struct sas_identify_frame *id;
		id = (struct sas_identify_frame *)phy->frame_rcvd;
		id->dev_type = phy->identify.device_type;
		id->initiator_bits = SAS_PROTOCOL_ALL;
		id->target_bits = phy->identify.target_port_protocols;
	} else if (phy->phy_type & PORT_TYPE_SATA) {
		/*Nothing*/
	}
3241
	pm8001_dbg(pm8001_ha, MSG, "phy %d byte dmaded.\n", i);
J
jack wang 已提交
3242 3243

	sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
3244
	sas_notify_port_event(sas_phy, PORTE_BYTES_DMAED, GFP_ATOMIC);
J
jack wang 已提交
3245 3246 3247
}

/* Get the link rate speed  */
3248
void pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate)
J
jack wang 已提交
3249 3250 3251 3252
{
	struct sas_phy *sas_phy = phy->sas_phy.phy;

	switch (link_rate) {
V
Viswas G 已提交
3253 3254 3255 3256
	case PHY_SPEED_120:
		phy->sas_phy.linkrate = SAS_LINK_RATE_12_0_GBPS;
		phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_12_0_GBPS;
		break;
J
jack wang 已提交
3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277
	case PHY_SPEED_60:
		phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS;
		phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
		break;
	case PHY_SPEED_30:
		phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS;
		phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
		break;
	case PHY_SPEED_15:
		phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS;
		phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
		break;
	}
	sas_phy->negotiated_linkrate = phy->sas_phy.linkrate;
	sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_6_0_GBPS;
	sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
	sas_phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS;
	sas_phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
}

/**
3278
 * pm8001_get_attached_sas_addr - extract/generate attached SAS address
J
jack wang 已提交
3279 3280 3281 3282 3283 3284 3285 3286 3287 3288
 * @phy: pointer to asd_phy
 * @sas_addr: pointer to buffer where the SAS address is to be written
 *
 * This function extracts the SAS address from an IDENTIFY frame
 * received.  If OOB is SATA, then a SAS address is generated from the
 * HA tables.
 *
 * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame
 * buffer.
 */
3289
void pm8001_get_attached_sas_addr(struct pm8001_phy *phy,
J
jack wang 已提交
3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320 3321 3322 3323 3324 3325
	u8 *sas_addr)
{
	if (phy->sas_phy.frame_rcvd[0] == 0x34
		&& phy->sas_phy.oob_mode == SATA_OOB_MODE) {
		struct pm8001_hba_info *pm8001_ha = phy->sas_phy.ha->lldd_ha;
		/* FIS device-to-host */
		u64 addr = be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr);
		addr += phy->sas_phy.id;
		*(__be64 *)sas_addr = cpu_to_be64(addr);
	} else {
		struct sas_identify_frame *idframe =
			(void *) phy->sas_phy.frame_rcvd;
		memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE);
	}
}

/**
 * pm8001_hw_event_ack_req- For PM8001,some events need to acknowage to FW.
 * @pm8001_ha: our hba card information
 * @Qnum: the outbound queue message number.
 * @SEA: source of event to ack
 * @port_id: port id.
 * @phyId: phy id.
 * @param0: parameter 0.
 * @param1: parameter 1.
 */
static void pm8001_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha,
	u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, u32 param1)
{
	struct hw_event_ack_req	 payload;
	u32 opc = OPC_INB_SAS_HW_EVENT_ACK;

	struct inbound_queue_table *circularQ;

	memset((u8 *)&payload, 0, sizeof(payload));
	circularQ = &pm8001_ha->inbnd_q_tbl[Qnum];
3326
	payload.tag = cpu_to_le32(1);
J
jack wang 已提交
3327 3328 3329 3330
	payload.sea_phyid_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) |
		((phyId & 0x0F) << 4) | (port_id & 0x0F));
	payload.param0 = cpu_to_le32(param0);
	payload.param1 = cpu_to_le32(param1);
3331 3332
	pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
			sizeof(payload), 0);
J
jack wang 已提交
3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351
}

static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
	u32 phyId, u32 phy_op);

/**
 * hw_event_sas_phy_up -FW tells me a SAS phy up event.
 * @pm8001_ha: our hba card information
 * @piomb: IO message buffer
 */
static void
hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
	struct hw_event_resp *pPayload =
		(struct hw_event_resp *)(piomb + 4);
	u32 lr_evt_status_phyid_portid =
		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
	u8 link_rate =
		(u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
3352
	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
J
jack wang 已提交
3353 3354
	u8 phy_id =
		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
3355 3356 3357
	u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
	u8 portstate = (u8)(npip_portstate & 0x0000000F);
	struct pm8001_port *port = &pm8001_ha->port[port_id];
J
jack wang 已提交
3358 3359 3360
	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
	unsigned long flags;
	u8 deviceType = pPayload->sas_identify.dev_type;
3361
	port->port_state =  portstate;
3362
	phy->phy_state = PHY_STATE_LINK_UP_SPC;
3363 3364 3365
	pm8001_dbg(pm8001_ha, MSG,
		   "HW_EVENT_SAS_PHY_UP port id = %d, phy id = %d\n",
		   port_id, phy_id);
J
jack wang 已提交
3366 3367 3368

	switch (deviceType) {
	case SAS_PHY_UNUSED:
3369
		pm8001_dbg(pm8001_ha, MSG, "device type no device.\n");
J
jack wang 已提交
3370 3371
		break;
	case SAS_END_DEVICE:
3372
		pm8001_dbg(pm8001_ha, MSG, "end device.\n");
J
jack wang 已提交
3373 3374
		pm8001_chip_phy_ctl_req(pm8001_ha, phy_id,
			PHY_NOTIFY_ENABLE_SPINUP);
3375
		port->port_attached = 1;
3376
		pm8001_get_lrate_mode(phy, link_rate);
J
jack wang 已提交
3377 3378
		break;
	case SAS_EDGE_EXPANDER_DEVICE:
3379
		pm8001_dbg(pm8001_ha, MSG, "expander device.\n");
3380
		port->port_attached = 1;
3381
		pm8001_get_lrate_mode(phy, link_rate);
J
jack wang 已提交
3382 3383
		break;
	case SAS_FANOUT_EXPANDER_DEVICE:
3384
		pm8001_dbg(pm8001_ha, MSG, "fanout expander device.\n");
3385
		port->port_attached = 1;
3386
		pm8001_get_lrate_mode(phy, link_rate);
J
jack wang 已提交
3387 3388
		break;
	default:
3389 3390
		pm8001_dbg(pm8001_ha, DEVIO, "unknown device type(%x)\n",
			   deviceType);
J
jack wang 已提交
3391 3392 3393 3394 3395
		break;
	}
	phy->phy_type |= PORT_TYPE_SAS;
	phy->identify.device_type = deviceType;
	phy->phy_attached = 1;
3396
	if (phy->identify.device_type == SAS_END_DEVICE)
J
jack wang 已提交
3397
		phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
3398
	else if (phy->identify.device_type != SAS_PHY_UNUSED)
J
jack wang 已提交
3399 3400
		phy->identify.target_port_protocols = SAS_PROTOCOL_SMP;
	phy->sas_phy.oob_mode = SAS_OOB_MODE;
3401
	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
J
jack wang 已提交
3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426
	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
	memcpy(phy->frame_rcvd, &pPayload->sas_identify,
		sizeof(struct sas_identify_frame)-4);
	phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4;
	pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
	if (pm8001_ha->flags == PM8001F_RUN_TIME)
		mdelay(200);/*delay a moment to wait disk to spinup*/
	pm8001_bytes_dmaed(pm8001_ha, phy_id);
}

/**
 * hw_event_sata_phy_up -FW tells me a SATA phy up event.
 * @pm8001_ha: our hba card information
 * @piomb: IO message buffer
 */
static void
hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
	struct hw_event_resp *pPayload =
		(struct hw_event_resp *)(piomb + 4);
	u32 lr_evt_status_phyid_portid =
		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
	u8 link_rate =
		(u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28);
3427
	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
J
jack wang 已提交
3428 3429
	u8 phy_id =
		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
3430 3431 3432
	u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
	u8 portstate = (u8)(npip_portstate & 0x0000000F);
	struct pm8001_port *port = &pm8001_ha->port[port_id];
J
jack wang 已提交
3433 3434
	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
	unsigned long flags;
3435 3436
	pm8001_dbg(pm8001_ha, DEVIO, "HW_EVENT_SATA_PHY_UP port id = %d, phy id = %d\n",
		   port_id, phy_id);
3437
	port->port_state =  portstate;
3438
	phy->phy_state = PHY_STATE_LINK_UP_SPC;
3439
	port->port_attached = 1;
3440
	pm8001_get_lrate_mode(phy, link_rate);
J
jack wang 已提交
3441 3442 3443
	phy->phy_type |= PORT_TYPE_SATA;
	phy->phy_attached = 1;
	phy->sas_phy.oob_mode = SATA_OOB_MODE;
3444
	sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
J
jack wang 已提交
3445 3446 3447 3448 3449
	spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags);
	memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4),
		sizeof(struct dev_to_host_fis));
	phy->frame_rcvd_size = sizeof(struct dev_to_host_fis);
	phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
3450
	phy->identify.device_type = SAS_SATA_DEV;
J
jack wang 已提交
3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472
	pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
	spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
	pm8001_bytes_dmaed(pm8001_ha, phy_id);
}

/**
 * hw_event_phy_down -we should notify the libsas the phy is down.
 * @pm8001_ha: our hba card information
 * @piomb: IO message buffer
 */
static void
hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
	struct hw_event_resp *pPayload =
		(struct hw_event_resp *)(piomb + 4);
	u32 lr_evt_status_phyid_portid =
		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
	u8 phy_id =
		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
	u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate);
	u8 portstate = (u8)(npip_portstate & 0x0000000F);
3473 3474 3475 3476 3477 3478 3479
	struct pm8001_port *port = &pm8001_ha->port[port_id];
	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
	port->port_state =  portstate;
	phy->phy_type = 0;
	phy->identify.device_type = 0;
	phy->phy_attached = 0;
	memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE);
J
jack wang 已提交
3480 3481 3482 3483
	switch (portstate) {
	case PORT_VALID:
		break;
	case PORT_INVALID:
3484 3485 3486 3487
		pm8001_dbg(pm8001_ha, MSG, " PortInvalid portID %d\n",
			   port_id);
		pm8001_dbg(pm8001_ha, MSG,
			   " Last phy Down and port invalid\n");
3488
		port->port_attached = 0;
J
jack wang 已提交
3489 3490 3491 3492
		pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
			port_id, phy_id, 0, 0);
		break;
	case PORT_IN_RESET:
3493 3494
		pm8001_dbg(pm8001_ha, MSG, " Port In Reset portID %d\n",
			   port_id);
J
jack wang 已提交
3495 3496
		break;
	case PORT_NOT_ESTABLISHED:
3497 3498
		pm8001_dbg(pm8001_ha, MSG,
			   " phy Down and PORT_NOT_ESTABLISHED\n");
3499
		port->port_attached = 0;
J
jack wang 已提交
3500 3501
		break;
	case PORT_LOSTCOMM:
3502 3503 3504
		pm8001_dbg(pm8001_ha, MSG, " phy Down and PORT_LOSTCOMM\n");
		pm8001_dbg(pm8001_ha, MSG,
			   " Last phy Down and port invalid\n");
3505
		port->port_attached = 0;
J
jack wang 已提交
3506 3507 3508 3509
		pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
			port_id, phy_id, 0, 0);
		break;
	default:
3510
		port->port_attached = 0;
3511 3512
		pm8001_dbg(pm8001_ha, DEVIO, " phy Down and(default) = %x\n",
			   portstate);
J
jack wang 已提交
3513 3514 3515 3516 3517 3518
		break;

	}
}

/**
3519
 * pm8001_mpi_reg_resp -process register device ID response.
J
jack wang 已提交
3520 3521 3522 3523 3524 3525 3526 3527
 * @pm8001_ha: our hba card information
 * @piomb: IO message buffer
 *
 * when sas layer find a device it will notify LLDD, then the driver register
 * the domain device to FW, this event is the return device ID which the FW
 * has assigned, from now,inter-communication with FW is no longer using the
 * SAS address, use device ID which FW assigned.
 */
3528
int pm8001_mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3529 3530 3531 3532 3533 3534 3535 3536 3537 3538
{
	u32 status;
	u32 device_id;
	u32 htag;
	struct pm8001_ccb_info *ccb;
	struct pm8001_device *pm8001_dev;
	struct dev_reg_resp *registerRespPayload =
		(struct dev_reg_resp *)(piomb + 4);

	htag = le32_to_cpu(registerRespPayload->tag);
3539
	ccb = &pm8001_ha->ccb_info[htag];
J
jack wang 已提交
3540 3541 3542
	pm8001_dev = ccb->device;
	status = le32_to_cpu(registerRespPayload->status);
	device_id = le32_to_cpu(registerRespPayload->device_id);
3543 3544
	pm8001_dbg(pm8001_ha, MSG, " register device is status = %d\n",
		   status);
J
jack wang 已提交
3545 3546
	switch (status) {
	case DEVREG_SUCCESS:
3547
		pm8001_dbg(pm8001_ha, MSG, "DEVREG_SUCCESS\n");
J
jack wang 已提交
3548 3549 3550
		pm8001_dev->device_id = device_id;
		break;
	case DEVREG_FAILURE_OUT_OF_RESOURCE:
3551
		pm8001_dbg(pm8001_ha, MSG, "DEVREG_FAILURE_OUT_OF_RESOURCE\n");
J
jack wang 已提交
3552 3553
		break;
	case DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED:
3554 3555
		pm8001_dbg(pm8001_ha, MSG,
			   "DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED\n");
J
jack wang 已提交
3556 3557
		break;
	case DEVREG_FAILURE_INVALID_PHY_ID:
3558
		pm8001_dbg(pm8001_ha, MSG, "DEVREG_FAILURE_INVALID_PHY_ID\n");
J
jack wang 已提交
3559 3560
		break;
	case DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED:
3561 3562
		pm8001_dbg(pm8001_ha, MSG,
			   "DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED\n");
J
jack wang 已提交
3563 3564
		break;
	case DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE:
3565 3566
		pm8001_dbg(pm8001_ha, MSG,
			   "DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE\n");
J
jack wang 已提交
3567 3568
		break;
	case DEVREG_FAILURE_PORT_NOT_VALID_STATE:
3569 3570
		pm8001_dbg(pm8001_ha, MSG,
			   "DEVREG_FAILURE_PORT_NOT_VALID_STATE\n");
J
jack wang 已提交
3571 3572
		break;
	case DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID:
3573 3574
		pm8001_dbg(pm8001_ha, MSG,
			   "DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID\n");
J
jack wang 已提交
3575 3576
		break;
	default:
3577 3578
		pm8001_dbg(pm8001_ha, MSG,
			   "DEVREG_FAILURE_DEVICE_TYPE_NOT_SUPPORTED\n");
J
jack wang 已提交
3579 3580 3581 3582 3583
		break;
	}
	complete(pm8001_dev->dcompletion);
	ccb->task = NULL;
	ccb->ccb_tag = 0xFFFFFFFF;
3584
	pm8001_tag_free(pm8001_ha, htag);
J
jack wang 已提交
3585 3586 3587
	return 0;
}

3588
int pm8001_mpi_dereg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3589 3590 3591 3592 3593 3594 3595 3596 3597
{
	u32 status;
	u32 device_id;
	struct dev_reg_resp *registerRespPayload =
		(struct dev_reg_resp *)(piomb + 4);

	status = le32_to_cpu(registerRespPayload->status);
	device_id = le32_to_cpu(registerRespPayload->device_id);
	if (status != 0)
3598 3599 3600
		pm8001_dbg(pm8001_ha, MSG,
			   " deregister device failed ,status = %x, device_id = %x\n",
			   status, device_id);
J
jack wang 已提交
3601 3602 3603
	return 0;
}

3604
/**
3605
 * pm8001_mpi_fw_flash_update_resp - Response from FW for flash update command.
3606 3607 3608 3609 3610
 * @pm8001_ha: our hba card information
 * @piomb: IO message buffer
 */
int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
		void *piomb)
J
jack wang 已提交
3611 3612 3613 3614
{
	u32 status;
	struct fw_flash_Update_resp *ppayload =
		(struct fw_flash_Update_resp *)(piomb + 4);
3615
	u32 tag = le32_to_cpu(ppayload->tag);
J
jack wang 已提交
3616 3617 3618 3619
	struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag];
	status = le32_to_cpu(ppayload->status);
	switch (status) {
	case FLASH_UPDATE_COMPLETE_PENDING_REBOOT:
3620 3621
		pm8001_dbg(pm8001_ha, MSG,
			   ": FLASH_UPDATE_COMPLETE_PENDING_REBOOT\n");
J
jack wang 已提交
3622 3623
		break;
	case FLASH_UPDATE_IN_PROGRESS:
3624
		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_IN_PROGRESS\n");
J
jack wang 已提交
3625 3626
		break;
	case FLASH_UPDATE_HDR_ERR:
3627
		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_HDR_ERR\n");
J
jack wang 已提交
3628 3629
		break;
	case FLASH_UPDATE_OFFSET_ERR:
3630
		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_OFFSET_ERR\n");
J
jack wang 已提交
3631 3632
		break;
	case FLASH_UPDATE_CRC_ERR:
3633
		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_CRC_ERR\n");
J
jack wang 已提交
3634 3635
		break;
	case FLASH_UPDATE_LENGTH_ERR:
3636
		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_LENGTH_ERR\n");
J
jack wang 已提交
3637 3638
		break;
	case FLASH_UPDATE_HW_ERR:
3639
		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_HW_ERR\n");
J
jack wang 已提交
3640 3641
		break;
	case FLASH_UPDATE_DNLD_NOT_SUPPORTED:
3642 3643
		pm8001_dbg(pm8001_ha, MSG,
			   ": FLASH_UPDATE_DNLD_NOT_SUPPORTED\n");
J
jack wang 已提交
3644 3645
		break;
	case FLASH_UPDATE_DISABLED:
3646
		pm8001_dbg(pm8001_ha, MSG, ": FLASH_UPDATE_DISABLED\n");
J
jack wang 已提交
3647 3648
		break;
	default:
3649 3650
		pm8001_dbg(pm8001_ha, DEVIO, "No matched status = %d\n",
			   status);
J
jack wang 已提交
3651 3652
		break;
	}
3653
	kfree(ccb->fw_control_context);
J
jack wang 已提交
3654 3655
	ccb->task = NULL;
	ccb->ccb_tag = 0xFFFFFFFF;
3656
	pm8001_tag_free(pm8001_ha, tag);
3657
	complete(pm8001_ha->nvmd_completion);
J
jack wang 已提交
3658 3659 3660
	return 0;
}

L
Luo Jiaxing 已提交
3661
int pm8001_mpi_general_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3662 3663 3664 3665 3666 3667
{
	u32 status;
	int i;
	struct general_event_resp *pPayload =
		(struct general_event_resp *)(piomb + 4);
	status = le32_to_cpu(pPayload->status);
3668
	pm8001_dbg(pm8001_ha, MSG, " status = 0x%x\n", status);
J
jack wang 已提交
3669
	for (i = 0; i < GENERAL_EVENT_PAYLOAD; i++)
3670 3671 3672
		pm8001_dbg(pm8001_ha, MSG, "inb_IOMB_payload[0x%x] 0x%x,\n",
			   i,
			   pPayload->inb_IOMB_payload[i]);
J
jack wang 已提交
3673 3674 3675
	return 0;
}

3676
int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3677 3678 3679 3680 3681 3682 3683
{
	struct sas_task *t;
	struct pm8001_ccb_info *ccb;
	unsigned long flags;
	u32 status ;
	u32 tag, scp;
	struct task_status_struct *ts;
3684
	struct pm8001_device *pm8001_dev;
J
jack wang 已提交
3685 3686 3687 3688 3689 3690

	struct task_abort_resp *pPayload =
		(struct task_abort_resp *)(piomb + 4);

	status = le32_to_cpu(pPayload->status);
	tag = le32_to_cpu(pPayload->tag);
3691
	if (!tag) {
3692
		pm8001_dbg(pm8001_ha, FAIL, " TAG NULL. RETURNING !!!\n");
3693 3694 3695
		return -1;
	}

J
jack wang 已提交
3696
	scp = le32_to_cpu(pPayload->scp);
3697 3698
	ccb = &pm8001_ha->ccb_info[tag];
	t = ccb->task;
3699 3700 3701
	pm8001_dev = ccb->device; /* retrieve device */

	if (!t)	{
3702
		pm8001_dbg(pm8001_ha, FAIL, " TASK NULL. RETURNING !!!\n");
3703
		return -1;
3704
	}
3705
	ts = &t->task_status;
J
jack wang 已提交
3706
	if (status != 0)
3707 3708
		pm8001_dbg(pm8001_ha, FAIL, "task abort failed status 0x%x ,tag = 0x%x, scp= 0x%x\n",
			   status, tag, scp);
J
jack wang 已提交
3709 3710
	switch (status) {
	case IO_SUCCESS:
3711
		pm8001_dbg(pm8001_ha, EH, "IO_SUCCESS\n");
J
jack wang 已提交
3712
		ts->resp = SAS_TASK_COMPLETE;
3713
		ts->stat = SAS_SAM_STAT_GOOD;
J
jack wang 已提交
3714 3715
		break;
	case IO_NOT_VALID:
3716
		pm8001_dbg(pm8001_ha, EH, "IO_NOT_VALID\n");
J
jack wang 已提交
3717 3718 3719 3720 3721 3722 3723 3724
		ts->resp = TMF_RESP_FUNC_FAILED;
		break;
	}
	spin_lock_irqsave(&t->task_state_lock, flags);
	t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
	t->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
	t->task_state_flags |= SAS_TASK_STATE_DONE;
	spin_unlock_irqrestore(&t->task_state_lock, flags);
3725
	pm8001_ccb_task_free(pm8001_ha, t, ccb, tag);
J
jack wang 已提交
3726
	mb();
3727

3728
	if (pm8001_dev->id & NCQ_ABORT_ALL_FLAG) {
3729 3730 3731 3732 3733 3734 3735
		pm8001_tag_free(pm8001_ha, tag);
		sas_free_task(t);
		/* clear the flag */
		pm8001_dev->id &= 0xBFFFFFFF;
	} else
		t->task_done(t);

J
jack wang 已提交
3736 3737 3738 3739 3740 3741 3742 3743
	return 0;
}

/**
 * mpi_hw_event -The hw event has come.
 * @pm8001_ha: our hba card information
 * @piomb: IO message buffer
 */
L
Luo Jiaxing 已提交
3744
static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
J
jack wang 已提交
3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760
{
	unsigned long flags;
	struct hw_event_resp *pPayload =
		(struct hw_event_resp *)(piomb + 4);
	u32 lr_evt_status_phyid_portid =
		le32_to_cpu(pPayload->lr_evt_status_phyid_portid);
	u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F);
	u8 phy_id =
		(u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4);
	u16 eventType =
		(u16)((lr_evt_status_phyid_portid & 0x00FFFF00) >> 8);
	u8 status =
		(u8)((lr_evt_status_phyid_portid & 0x0F000000) >> 24);
	struct sas_ha_struct *sas_ha = pm8001_ha->sas;
	struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
	struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
3761 3762 3763
	pm8001_dbg(pm8001_ha, DEVIO,
		   "SPC HW event for portid:%d, phyid:%d, event:%x, status:%x\n",
		   port_id, phy_id, eventType, status);
J
jack wang 已提交
3764 3765
	switch (eventType) {
	case HW_EVENT_PHY_START_STATUS:
3766 3767
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS status = %x\n",
			   status);
3768
		if (status == 0)
J
jack wang 已提交
3769
			phy->phy_state = 1;
3770 3771 3772 3773 3774

		if (pm8001_ha->flags == PM8001F_RUN_TIME &&
				phy->enable_completion != NULL) {
			complete(phy->enable_completion);
			phy->enable_completion = NULL;
J
jack wang 已提交
3775 3776 3777
		}
		break;
	case HW_EVENT_SAS_PHY_UP:
3778
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_START_STATUS\n");
J
jack wang 已提交
3779 3780 3781
		hw_event_sas_phy_up(pm8001_ha, piomb);
		break;
	case HW_EVENT_SATA_PHY_UP:
3782
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_PHY_UP\n");
J
jack wang 已提交
3783 3784 3785
		hw_event_sata_phy_up(pm8001_ha, piomb);
		break;
	case HW_EVENT_PHY_STOP_STATUS:
3786 3787
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_STOP_STATUS status = %x\n",
			   status);
J
jack wang 已提交
3788 3789 3790 3791
		if (status == 0)
			phy->phy_state = 0;
		break;
	case HW_EVENT_SATA_SPINUP_HOLD:
3792
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_SATA_SPINUP_HOLD\n");
3793
		sas_notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD,
3794
			GFP_ATOMIC);
J
jack wang 已提交
3795 3796
		break;
	case HW_EVENT_PHY_DOWN:
3797
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_DOWN\n");
3798
		sas_notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL,
3799
			GFP_ATOMIC);
J
jack wang 已提交
3800 3801 3802 3803 3804
		phy->phy_attached = 0;
		phy->phy_state = 0;
		hw_event_phy_down(pm8001_ha, piomb);
		break;
	case HW_EVENT_PORT_INVALID:
3805
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_INVALID\n");
J
jack wang 已提交
3806 3807
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3808
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3809
			GFP_ATOMIC);
J
jack wang 已提交
3810 3811 3812 3813
		break;
	/* the broadcast change primitive received, tell the LIBSAS this event
	to revalidate the sas domain*/
	case HW_EVENT_BROADCAST_CHANGE:
3814
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_CHANGE\n");
J
jack wang 已提交
3815 3816 3817 3818 3819
		pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_BROADCAST_CHANGE,
			port_id, phy_id, 1, 0);
		spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
		sas_phy->sas_prim = HW_EVENT_BROADCAST_CHANGE;
		spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
3820
		sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
3821
			GFP_ATOMIC);
J
jack wang 已提交
3822 3823
		break;
	case HW_EVENT_PHY_ERROR:
3824
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PHY_ERROR\n");
J
jack wang 已提交
3825 3826
		sas_phy_disconnected(&phy->sas_phy);
		phy->phy_attached = 0;
3827
		sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR, GFP_ATOMIC);
J
jack wang 已提交
3828 3829
		break;
	case HW_EVENT_BROADCAST_EXP:
3830
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_EXP\n");
J
jack wang 已提交
3831 3832 3833
		spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
		sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP;
		spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
3834
		sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
3835
			GFP_ATOMIC);
J
jack wang 已提交
3836 3837
		break;
	case HW_EVENT_LINK_ERR_INVALID_DWORD:
3838 3839
		pm8001_dbg(pm8001_ha, MSG,
			   "HW_EVENT_LINK_ERR_INVALID_DWORD\n");
J
jack wang 已提交
3840 3841 3842 3843
		pm8001_hw_event_ack_req(pm8001_ha, 0,
			HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0);
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3844
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3845
			GFP_ATOMIC);
J
jack wang 已提交
3846 3847
		break;
	case HW_EVENT_LINK_ERR_DISPARITY_ERROR:
3848 3849
		pm8001_dbg(pm8001_ha, MSG,
			   "HW_EVENT_LINK_ERR_DISPARITY_ERROR\n");
J
jack wang 已提交
3850 3851 3852 3853 3854
		pm8001_hw_event_ack_req(pm8001_ha, 0,
			HW_EVENT_LINK_ERR_DISPARITY_ERROR,
			port_id, phy_id, 0, 0);
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3855
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3856
			GFP_ATOMIC);
J
jack wang 已提交
3857 3858
		break;
	case HW_EVENT_LINK_ERR_CODE_VIOLATION:
3859 3860
		pm8001_dbg(pm8001_ha, MSG,
			   "HW_EVENT_LINK_ERR_CODE_VIOLATION\n");
J
jack wang 已提交
3861 3862 3863 3864 3865
		pm8001_hw_event_ack_req(pm8001_ha, 0,
			HW_EVENT_LINK_ERR_CODE_VIOLATION,
			port_id, phy_id, 0, 0);
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3866
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3867
			GFP_ATOMIC);
J
jack wang 已提交
3868 3869
		break;
	case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH:
3870 3871
		pm8001_dbg(pm8001_ha, MSG,
			   "HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n");
J
jack wang 已提交
3872 3873 3874 3875 3876
		pm8001_hw_event_ack_req(pm8001_ha, 0,
			HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH,
			port_id, phy_id, 0, 0);
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3877
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3878
			GFP_ATOMIC);
J
jack wang 已提交
3879 3880
		break;
	case HW_EVENT_MALFUNCTION:
3881
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_MALFUNCTION\n");
J
jack wang 已提交
3882 3883
		break;
	case HW_EVENT_BROADCAST_SES:
3884
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n");
J
jack wang 已提交
3885 3886 3887
		spin_lock_irqsave(&sas_phy->sas_prim_lock, flags);
		sas_phy->sas_prim = HW_EVENT_BROADCAST_SES;
		spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags);
3888
		sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
3889
			GFP_ATOMIC);
J
jack wang 已提交
3890 3891
		break;
	case HW_EVENT_INBOUND_CRC_ERROR:
3892
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_INBOUND_CRC_ERROR\n");
J
jack wang 已提交
3893 3894 3895 3896 3897
		pm8001_hw_event_ack_req(pm8001_ha, 0,
			HW_EVENT_INBOUND_CRC_ERROR,
			port_id, phy_id, 0, 0);
		break;
	case HW_EVENT_HARD_RESET_RECEIVED:
3898
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_HARD_RESET_RECEIVED\n");
3899
		sas_notify_port_event(sas_phy, PORTE_HARD_RESET, GFP_ATOMIC);
J
jack wang 已提交
3900 3901
		break;
	case HW_EVENT_ID_FRAME_TIMEOUT:
3902
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_ID_FRAME_TIMEOUT\n");
J
jack wang 已提交
3903 3904
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3905
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3906
			GFP_ATOMIC);
J
jack wang 已提交
3907 3908
		break;
	case HW_EVENT_LINK_ERR_PHY_RESET_FAILED:
3909 3910
		pm8001_dbg(pm8001_ha, MSG,
			   "HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n");
J
jack wang 已提交
3911 3912 3913 3914 3915
		pm8001_hw_event_ack_req(pm8001_ha, 0,
			HW_EVENT_LINK_ERR_PHY_RESET_FAILED,
			port_id, phy_id, 0, 0);
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3916
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3917
			GFP_ATOMIC);
J
jack wang 已提交
3918 3919
		break;
	case HW_EVENT_PORT_RESET_TIMER_TMO:
3920
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_TIMER_TMO\n");
J
jack wang 已提交
3921 3922
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3923
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3924
			GFP_ATOMIC);
J
jack wang 已提交
3925 3926
		break;
	case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
3927 3928
		pm8001_dbg(pm8001_ha, MSG,
			   "HW_EVENT_PORT_RECOVERY_TIMER_TMO\n");
J
jack wang 已提交
3929 3930
		sas_phy_disconnected(sas_phy);
		phy->phy_attached = 0;
3931
		sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
3932
			GFP_ATOMIC);
J
jack wang 已提交
3933 3934
		break;
	case HW_EVENT_PORT_RECOVER:
3935
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RECOVER\n");
J
jack wang 已提交
3936 3937
		break;
	case HW_EVENT_PORT_RESET_COMPLETE:
3938
		pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_COMPLETE\n");
J
jack wang 已提交
3939 3940
		break;
	case EVENT_BROADCAST_ASYNCH_EVENT:
3941
		pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n");
J
jack wang 已提交
3942 3943
		break;
	default:
3944 3945
		pm8001_dbg(pm8001_ha, DEVIO, "Unknown event type = %x\n",
			   eventType);
J
jack wang 已提交
3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957
		break;
	}
	return 0;
}

/**
 * process_one_iomb - process one outbound Queue memory block
 * @pm8001_ha: our hba card information
 * @piomb: IO message buffer
 */
static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
3958 3959
	__le32 pHeader = *(__le32 *)piomb;
	u8 opc = (u8)((le32_to_cpu(pHeader)) & 0xFFF);
J
jack wang 已提交
3960

3961
	pm8001_dbg(pm8001_ha, MSG, "process_one_iomb:\n");
J
jack wang 已提交
3962 3963 3964

	switch (opc) {
	case OPC_OUB_ECHO:
3965
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_ECHO\n");
J
jack wang 已提交
3966 3967
		break;
	case OPC_OUB_HW_EVENT:
3968
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_HW_EVENT\n");
J
jack wang 已提交
3969 3970 3971
		mpi_hw_event(pm8001_ha, piomb);
		break;
	case OPC_OUB_SSP_COMP:
3972
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_COMP\n");
J
jack wang 已提交
3973 3974 3975
		mpi_ssp_completion(pm8001_ha, piomb);
		break;
	case OPC_OUB_SMP_COMP:
3976
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_COMP\n");
J
jack wang 已提交
3977 3978 3979
		mpi_smp_completion(pm8001_ha, piomb);
		break;
	case OPC_OUB_LOCAL_PHY_CNTRL:
3980
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_LOCAL_PHY_CNTRL\n");
3981
		pm8001_mpi_local_phy_ctl(pm8001_ha, piomb);
J
jack wang 已提交
3982 3983
		break;
	case OPC_OUB_DEV_REGIST:
3984
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_REGIST\n");
3985
		pm8001_mpi_reg_resp(pm8001_ha, piomb);
J
jack wang 已提交
3986 3987
		break;
	case OPC_OUB_DEREG_DEV:
3988
		pm8001_dbg(pm8001_ha, MSG, "unregister the device\n");
3989
		pm8001_mpi_dereg_resp(pm8001_ha, piomb);
J
jack wang 已提交
3990 3991
		break;
	case OPC_OUB_GET_DEV_HANDLE:
3992
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEV_HANDLE\n");
J
jack wang 已提交
3993 3994
		break;
	case OPC_OUB_SATA_COMP:
3995
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n");
J
jack wang 已提交
3996 3997 3998
		mpi_sata_completion(pm8001_ha, piomb);
		break;
	case OPC_OUB_SATA_EVENT:
3999
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n");
J
jack wang 已提交
4000 4001 4002
		mpi_sata_event(pm8001_ha, piomb);
		break;
	case OPC_OUB_SSP_EVENT:
4003
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n");
J
jack wang 已提交
4004 4005 4006
		mpi_ssp_event(pm8001_ha, piomb);
		break;
	case OPC_OUB_DEV_HANDLE_ARRIV:
4007
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_HANDLE_ARRIV\n");
J
jack wang 已提交
4008 4009 4010
		/*This is for target*/
		break;
	case OPC_OUB_SSP_RECV_EVENT:
4011
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_RECV_EVENT\n");
J
jack wang 已提交
4012 4013 4014
		/*This is for target*/
		break;
	case OPC_OUB_DEV_INFO:
4015
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_INFO\n");
J
jack wang 已提交
4016 4017
		break;
	case OPC_OUB_FW_FLASH_UPDATE:
4018
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_FW_FLASH_UPDATE\n");
4019
		pm8001_mpi_fw_flash_update_resp(pm8001_ha, piomb);
J
jack wang 已提交
4020 4021
		break;
	case OPC_OUB_GPIO_RESPONSE:
4022
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_RESPONSE\n");
J
jack wang 已提交
4023 4024
		break;
	case OPC_OUB_GPIO_EVENT:
4025
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_EVENT\n");
J
jack wang 已提交
4026 4027
		break;
	case OPC_OUB_GENERAL_EVENT:
4028
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GENERAL_EVENT\n");
4029
		pm8001_mpi_general_event(pm8001_ha, piomb);
J
jack wang 已提交
4030 4031
		break;
	case OPC_OUB_SSP_ABORT_RSP:
4032
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_ABORT_RSP\n");
4033
		pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
J
jack wang 已提交
4034 4035
		break;
	case OPC_OUB_SATA_ABORT_RSP:
4036
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_ABORT_RSP\n");
4037
		pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
J
jack wang 已提交
4038 4039
		break;
	case OPC_OUB_SAS_DIAG_MODE_START_END:
4040 4041
		pm8001_dbg(pm8001_ha, MSG,
			   "OPC_OUB_SAS_DIAG_MODE_START_END\n");
J
jack wang 已提交
4042 4043
		break;
	case OPC_OUB_SAS_DIAG_EXECUTE:
4044
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_DIAG_EXECUTE\n");
J
jack wang 已提交
4045 4046
		break;
	case OPC_OUB_GET_TIME_STAMP:
4047
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_TIME_STAMP\n");
J
jack wang 已提交
4048 4049
		break;
	case OPC_OUB_SAS_HW_EVENT_ACK:
4050
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_HW_EVENT_ACK\n");
J
jack wang 已提交
4051 4052
		break;
	case OPC_OUB_PORT_CONTROL:
4053
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_PORT_CONTROL\n");
J
jack wang 已提交
4054 4055
		break;
	case OPC_OUB_SMP_ABORT_RSP:
4056
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_ABORT_RSP\n");
4057
		pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
J
jack wang 已提交
4058 4059
		break;
	case OPC_OUB_GET_NVMD_DATA:
4060
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_NVMD_DATA\n");
4061
		pm8001_mpi_get_nvmd_resp(pm8001_ha, piomb);
J
jack wang 已提交
4062 4063
		break;
	case OPC_OUB_SET_NVMD_DATA:
4064
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_NVMD_DATA\n");
4065
		pm8001_mpi_set_nvmd_resp(pm8001_ha, piomb);
J
jack wang 已提交
4066 4067
		break;
	case OPC_OUB_DEVICE_HANDLE_REMOVAL:
4068
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEVICE_HANDLE_REMOVAL\n");
J
jack wang 已提交
4069 4070
		break;
	case OPC_OUB_SET_DEVICE_STATE:
4071
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEVICE_STATE\n");
4072
		pm8001_mpi_set_dev_state_resp(pm8001_ha, piomb);
J
jack wang 已提交
4073 4074
		break;
	case OPC_OUB_GET_DEVICE_STATE:
4075
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEVICE_STATE\n");
J
jack wang 已提交
4076 4077
		break;
	case OPC_OUB_SET_DEV_INFO:
4078
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n");
J
jack wang 已提交
4079 4080
		break;
	case OPC_OUB_SAS_RE_INITIALIZE:
4081
		pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_RE_INITIALIZE\n");
J
jack wang 已提交
4082 4083
		break;
	default:
4084 4085 4086
		pm8001_dbg(pm8001_ha, DEVIO,
			   "Unknown outbound Queue IOMB OPC = %x\n",
			   opc);
J
jack wang 已提交
4087 4088 4089 4090
		break;
	}
}

4091
static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
J
jack wang 已提交
4092 4093 4094
{
	struct outbound_queue_table *circularQ;
	void *pMsg1 = NULL;
4095
	u8 bc;
4096
	u32 ret = MPI_IO_STATUS_FAIL;
4097
	unsigned long flags;
J
jack wang 已提交
4098

4099
	spin_lock_irqsave(&pm8001_ha->lock, flags);
4100
	circularQ = &pm8001_ha->outbnd_q_tbl[vec];
J
jack wang 已提交
4101
	do {
4102
		ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
J
jack wang 已提交
4103 4104
		if (MPI_IO_STATUS_SUCCESS == ret) {
			/* process the outbound message */
4105
			process_one_iomb(pm8001_ha, (void *)(pMsg1 - 4));
J
jack wang 已提交
4106
			/* free the message from the outbound circular buffer */
4107 4108
			pm8001_mpi_msg_free_set(pm8001_ha, pMsg1,
							circularQ, bc);
J
jack wang 已提交
4109 4110 4111
		}
		if (MPI_IO_STATUS_BUSY == ret) {
			/* Update the producer index from SPC */
4112 4113 4114
			circularQ->producer_index =
				cpu_to_le32(pm8001_read_32(circularQ->pi_virt));
			if (le32_to_cpu(circularQ->producer_index) ==
J
jack wang 已提交
4115 4116 4117 4118
				circularQ->consumer_idx)
				/* OQ is empty */
				break;
		}
4119
	} while (1);
4120
	spin_unlock_irqrestore(&pm8001_ha->lock, flags);
J
jack wang 已提交
4121 4122 4123
	return ret;
}

4124
/* DMA_... to our direction translation. */
J
jack wang 已提交
4125
static const u8 data_dir_flags[] = {
4126 4127 4128 4129
	[DMA_BIDIRECTIONAL]	= DATA_DIR_BYRECIPIENT,	/* UNSPECIFIED */
	[DMA_TO_DEVICE]		= DATA_DIR_OUT,		/* OUTBOUND */
	[DMA_FROM_DEVICE]	= DATA_DIR_IN,		/* INBOUND */
	[DMA_NONE]		= DATA_DIR_NONE,	/* NO TRANSFER */
J
jack wang 已提交
4130
};
4131
void
J
jack wang 已提交
4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145
pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd)
{
	int i;
	struct scatterlist *sg;
	struct pm8001_prd *buf_prd = prd;

	for_each_sg(scatter, sg, nr, i) {
		buf_prd->addr = cpu_to_le64(sg_dma_address(sg));
		buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg));
		buf_prd->im_len.e = 0;
		buf_prd++;
	}
}

4146
static void build_smp_cmd(u32 deviceID, __le32 hTag, struct smp_req *psmp_cmd)
J
jack wang 已提交
4147
{
4148
	psmp_cmd->tag = hTag;
J
jack wang 已提交
4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175
	psmp_cmd->device_id = cpu_to_le32(deviceID);
	psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1));
}

/**
 * pm8001_chip_smp_req - send a SMP task to FW
 * @pm8001_ha: our hba card information.
 * @ccb: the ccb information this request used.
 */
static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha,
	struct pm8001_ccb_info *ccb)
{
	int elem, rc;
	struct sas_task *task = ccb->task;
	struct domain_device *dev = task->dev;
	struct pm8001_device *pm8001_dev = dev->lldd_dev;
	struct scatterlist *sg_req, *sg_resp;
	u32 req_len, resp_len;
	struct smp_req smp_cmd;
	u32 opc;
	struct inbound_queue_table *circularQ;

	memset(&smp_cmd, 0, sizeof(smp_cmd));
	/*
	 * DMA-map SMP request, response buffers
	 */
	sg_req = &task->smp_task.smp_req;
4176
	elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE);
J
jack wang 已提交
4177 4178 4179 4180 4181
	if (!elem)
		return -ENOMEM;
	req_len = sg_dma_len(sg_req);

	sg_resp = &task->smp_task.smp_resp;
4182
	elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE);
J
jack wang 已提交
4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205
	if (!elem) {
		rc = -ENOMEM;
		goto err_out;
	}
	resp_len = sg_dma_len(sg_resp);
	/* must be in dwords */
	if ((req_len & 0x3) || (resp_len & 0x3)) {
		rc = -EINVAL;
		goto err_out_2;
	}

	opc = OPC_INB_SMP_REQUEST;
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	smp_cmd.tag = cpu_to_le32(ccb->ccb_tag);
	smp_cmd.long_smp_req.long_req_addr =
		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req));
	smp_cmd.long_smp_req.long_req_size =
		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4);
	smp_cmd.long_smp_req.long_resp_addr =
		cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp));
	smp_cmd.long_smp_req.long_resp_size =
		cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4);
	build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd);
T
Tomas Henzl 已提交
4206
	rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc,
4207
			&smp_cmd, sizeof(smp_cmd), 0);
T
Tomas Henzl 已提交
4208 4209 4210
	if (rc)
		goto err_out_2;

J
jack wang 已提交
4211 4212 4213 4214
	return 0;

err_out_2:
	dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1,
4215
			DMA_FROM_DEVICE);
J
jack wang 已提交
4216 4217
err_out:
	dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1,
4218
			DMA_TO_DEVICE);
J
jack wang 已提交
4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234
	return rc;
}

/**
 * pm8001_chip_ssp_io_req - send a SSP task to FW
 * @pm8001_ha: our hba card information.
 * @ccb: the ccb information this request used.
 */
static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha,
	struct pm8001_ccb_info *ccb)
{
	struct sas_task *task = ccb->task;
	struct domain_device *dev = task->dev;
	struct pm8001_device *pm8001_dev = dev->lldd_dev;
	struct ssp_ini_io_start_req ssp_cmd;
	u32 tag = ccb->ccb_tag;
4235
	int ret;
4236
	u64 phys_addr;
J
jack wang 已提交
4237 4238 4239 4240
	struct inbound_queue_table *circularQ;
	u32 opc = OPC_INB_SSPINIIOSTART;
	memset(&ssp_cmd, 0, sizeof(ssp_cmd));
	memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8);
4241 4242
	ssp_cmd.dir_m_tlr =
		cpu_to_le32(data_dir_flags[task->data_dir] << 8 | 0x0);/*0 for
J
jack wang 已提交
4243 4244 4245 4246 4247 4248 4249 4250
	SAS 1.1 compatible TLR*/
	ssp_cmd.data_len = cpu_to_le32(task->total_xfer_len);
	ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id);
	ssp_cmd.tag = cpu_to_le32(tag);
	if (task->ssp_task.enable_first_burst)
		ssp_cmd.ssp_iu.efb_prio_attr |= 0x80;
	ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_prio << 3);
	ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7);
4251 4252
	memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd,
	       task->ssp_task.cmd->cmd_len);
J
jack wang 已提交
4253 4254 4255 4256 4257
	circularQ = &pm8001_ha->inbnd_q_tbl[0];

	/* fill in PRD (scatter/gather) table, if any */
	if (task->num_scatter > 1) {
		pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
4258
		phys_addr = ccb->ccb_dma_handle;
4259 4260
		ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(phys_addr));
		ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(phys_addr));
J
jack wang 已提交
4261 4262
		ssp_cmd.esgl = cpu_to_le32(1<<31);
	} else if (task->num_scatter == 1) {
4263 4264 4265
		u64 dma_addr = sg_dma_address(task->scatter);
		ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr));
		ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(dma_addr));
J
jack wang 已提交
4266 4267 4268 4269 4270 4271 4272 4273
		ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
		ssp_cmd.esgl = 0;
	} else if (task->num_scatter == 0) {
		ssp_cmd.addr_low = 0;
		ssp_cmd.addr_high = 0;
		ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
		ssp_cmd.esgl = 0;
	}
4274 4275
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd,
			sizeof(ssp_cmd), 0);
4276
	return ret;
J
jack wang 已提交
4277 4278 4279 4280 4281 4282 4283 4284 4285
}

static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha,
	struct pm8001_ccb_info *ccb)
{
	struct sas_task *task = ccb->task;
	struct domain_device *dev = task->dev;
	struct pm8001_device *pm8001_ha_dev = dev->lldd_dev;
	u32 tag = ccb->ccb_tag;
4286
	int ret;
J
jack wang 已提交
4287 4288
	struct sata_start_req sata_cmd;
	u32 hdr_tag, ncg_tag = 0;
4289
	u64 phys_addr;
J
jack wang 已提交
4290 4291 4292
	u32 ATAP = 0x0;
	u32 dir;
	struct inbound_queue_table *circularQ;
4293
	unsigned long flags;
J
jack wang 已提交
4294 4295 4296
	u32  opc = OPC_INB_SATA_HOST_OPSTART;
	memset(&sata_cmd, 0, sizeof(sata_cmd));
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
4297
	if (task->data_dir == DMA_NONE) {
J
jack wang 已提交
4298
		ATAP = 0x04;  /* no data*/
4299
		pm8001_dbg(pm8001_ha, IO, "no data\n");
J
jack wang 已提交
4300 4301 4302
	} else if (likely(!task->ata_task.device_control_reg_update)) {
		if (task->ata_task.dma_xfer) {
			ATAP = 0x06; /* DMA */
4303
			pm8001_dbg(pm8001_ha, IO, "DMA\n");
J
jack wang 已提交
4304 4305
		} else {
			ATAP = 0x05; /* PIO*/
4306
			pm8001_dbg(pm8001_ha, IO, "PIO\n");
J
jack wang 已提交
4307 4308
		}
		if (task->ata_task.use_ncq &&
H
Hannes Reinecke 已提交
4309
			dev->sata_dev.class != ATA_DEV_ATAPI) {
J
jack wang 已提交
4310
			ATAP = 0x07; /* FPDMA */
4311
			pm8001_dbg(pm8001_ha, IO, "FPDMA\n");
J
jack wang 已提交
4312 4313
		}
	}
4314 4315
	if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) {
		task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
4316
		ncg_tag = hdr_tag;
4317
	}
J
jack wang 已提交
4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330
	dir = data_dir_flags[task->data_dir] << 8;
	sata_cmd.tag = cpu_to_le32(tag);
	sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id);
	sata_cmd.data_len = cpu_to_le32(task->total_xfer_len);
	sata_cmd.ncqtag_atap_dir_m =
		cpu_to_le32(((ncg_tag & 0xff)<<16)|((ATAP & 0x3f) << 10) | dir);
	sata_cmd.sata_fis = task->ata_task.fis;
	if (likely(!task->ata_task.device_control_reg_update))
		sata_cmd.sata_fis.flags |= 0x80;/* C=1: update ATA cmd reg */
	sata_cmd.sata_fis.flags &= 0xF0;/* PM_PORT field shall be 0 */
	/* fill in PRD (scatter/gather) table, if any */
	if (task->num_scatter > 1) {
		pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd);
4331
		phys_addr = ccb->ccb_dma_handle;
J
jack wang 已提交
4332 4333 4334 4335
		sata_cmd.addr_low = lower_32_bits(phys_addr);
		sata_cmd.addr_high = upper_32_bits(phys_addr);
		sata_cmd.esgl = cpu_to_le32(1 << 31);
	} else if (task->num_scatter == 1) {
4336
		u64 dma_addr = sg_dma_address(task->scatter);
J
jack wang 已提交
4337 4338 4339 4340 4341 4342 4343 4344 4345 4346
		sata_cmd.addr_low = lower_32_bits(dma_addr);
		sata_cmd.addr_high = upper_32_bits(dma_addr);
		sata_cmd.len = cpu_to_le32(task->total_xfer_len);
		sata_cmd.esgl = 0;
	} else if (task->num_scatter == 0) {
		sata_cmd.addr_low = 0;
		sata_cmd.addr_high = 0;
		sata_cmd.len = cpu_to_le32(task->total_xfer_len);
		sata_cmd.esgl = 0;
	}
4347 4348 4349

	/* Check for read log for failed drive and return */
	if (sata_cmd.sata_fis.command == 0x2f) {
4350
		if (((pm8001_ha_dev->id & NCQ_READ_LOG_FLAG) ||
4351 4352 4353 4354 4355 4356 4357 4358 4359
			(pm8001_ha_dev->id & NCQ_ABORT_ALL_FLAG) ||
			(pm8001_ha_dev->id & NCQ_2ND_RLE_FLAG))) {
			struct task_status_struct *ts;

			pm8001_ha_dev->id &= 0xDFFFFFFF;
			ts = &task->task_status;

			spin_lock_irqsave(&task->task_state_lock, flags);
			ts->resp = SAS_TASK_COMPLETE;
4360
			ts->stat = SAS_SAM_STAT_GOOD;
4361 4362 4363 4364 4365 4366 4367
			task->task_state_flags &= ~SAS_TASK_STATE_PENDING;
			task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
			task->task_state_flags |= SAS_TASK_STATE_DONE;
			if (unlikely((task->task_state_flags &
					SAS_TASK_STATE_ABORTED))) {
				spin_unlock_irqrestore(&task->task_state_lock,
							flags);
4368 4369 4370 4371
				pm8001_dbg(pm8001_ha, FAIL,
					   "task 0x%p resp 0x%x  stat 0x%x but aborted by upper layer\n",
					   task, ts->resp,
					   ts->stat);
4372
				pm8001_ccb_task_free(pm8001_ha, task, ccb, tag);
S
Suresh Thiagarajan 已提交
4373
			} else {
4374 4375
				spin_unlock_irqrestore(&task->task_state_lock,
							flags);
S
Suresh Thiagarajan 已提交
4376 4377
				pm8001_ccb_task_free_done(pm8001_ha, task,
								ccb, tag);
4378 4379 4380 4381 4382
				return 0;
			}
		}
	}

4383 4384
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd,
			sizeof(sata_cmd), 0);
4385
	return ret;
J
jack wang 已提交
4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397
}

/**
 * pm8001_chip_phy_start_req - start phy via PHY_START COMMAND
 * @pm8001_ha: our hba card information.
 * @phy_id: the phy id which we wanted to start up.
 */
static int
pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
{
	struct phy_start_req payload;
	struct inbound_queue_table *circularQ;
4398
	int ret;
J
jack wang 已提交
4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412
	u32 tag = 0x01;
	u32 opcode = OPC_INB_PHYSTART;
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	memset(&payload, 0, sizeof(payload));
	payload.tag = cpu_to_le32(tag);
	/*
	 ** [0:7]   PHY Identifier
	 ** [8:11]  link rate 1.5G, 3G, 6G
	 ** [12:13] link mode 01b SAS mode; 10b SATA mode; 11b both
	 ** [14]    0b disable spin up hold; 1b enable spin up hold
	 */
	payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
		LINKMODE_AUTO |	LINKRATE_15 |
		LINKRATE_30 | LINKRATE_60 | phy_id);
4413
	payload.sas_identify.dev_type = SAS_END_DEVICE;
J
jack wang 已提交
4414 4415 4416 4417
	payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL;
	memcpy(payload.sas_identify.sas_addr,
		pm8001_ha->sas_addr, SAS_ADDR_SIZE);
	payload.sas_identify.phy_id = phy_id;
4418 4419
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload,
			sizeof(payload), 0);
4420
	return ret;
J
jack wang 已提交
4421 4422 4423 4424 4425 4426 4427
}

/**
 * pm8001_chip_phy_stop_req - start phy via PHY_STOP COMMAND
 * @pm8001_ha: our hba card information.
 * @phy_id: the phy id which we wanted to start up.
 */
4428 4429
static int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
				    u8 phy_id)
J
jack wang 已提交
4430 4431 4432
{
	struct phy_stop_req payload;
	struct inbound_queue_table *circularQ;
4433
	int ret;
J
jack wang 已提交
4434 4435 4436 4437 4438 4439
	u32 tag = 0x01;
	u32 opcode = OPC_INB_PHYSTOP;
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	memset(&payload, 0, sizeof(payload));
	payload.tag = cpu_to_le32(tag);
	payload.phy_id = cpu_to_le32(phy_id);
4440 4441
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload,
			sizeof(payload), 0);
4442
	return ret;
J
jack wang 已提交
4443 4444
}

4445
/*
4446
 * see comments on pm8001_mpi_reg_resp.
J
jack wang 已提交
4447 4448 4449 4450 4451 4452 4453 4454 4455
 */
static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha,
	struct pm8001_device *pm8001_dev, u32 flag)
{
	struct reg_dev_req payload;
	u32	opc;
	u32 stp_sspsmp_sata = 0x4;
	struct inbound_queue_table *circularQ;
	u32 linkrate, phy_id;
4456
	int rc, tag = 0xdeadbeef;
J
jack wang 已提交
4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475
	struct pm8001_ccb_info *ccb;
	u8 retryFlag = 0x1;
	u16 firstBurstSize = 0;
	u16 ITNT = 2000;
	struct domain_device *dev = pm8001_dev->sas_device;
	struct domain_device *parent_dev = dev->parent;
	circularQ = &pm8001_ha->inbnd_q_tbl[0];

	memset(&payload, 0, sizeof(payload));
	rc = pm8001_tag_alloc(pm8001_ha, &tag);
	if (rc)
		return rc;
	ccb = &pm8001_ha->ccb_info[tag];
	ccb->device = pm8001_dev;
	ccb->ccb_tag = tag;
	payload.tag = cpu_to_le32(tag);
	if (flag == 1)
		stp_sspsmp_sata = 0x02; /*direct attached sata */
	else {
4476
		if (pm8001_dev->dev_type == SAS_SATA_DEV)
J
jack wang 已提交
4477
			stp_sspsmp_sata = 0x00; /* stp*/
4478 4479 4480
		else if (pm8001_dev->dev_type == SAS_END_DEVICE ||
			pm8001_dev->dev_type == SAS_EDGE_EXPANDER_DEVICE ||
			pm8001_dev->dev_type == SAS_FANOUT_EXPANDER_DEVICE)
J
jack wang 已提交
4481 4482
			stp_sspsmp_sata = 0x01; /*ssp or smp*/
	}
4483
	if (parent_dev && dev_is_expander(parent_dev->dev_type))
J
jack wang 已提交
4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497
		phy_id = parent_dev->ex_dev.ex_phy->phy_id;
	else
		phy_id = pm8001_dev->attached_phy;
	opc = OPC_INB_REG_DEV;
	linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ?
			pm8001_dev->sas_device->linkrate : dev->port->linkrate;
	payload.phyid_portid =
		cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0x0F) |
		((phy_id & 0x0F) << 4));
	payload.dtype_dlr_retry = cpu_to_le32((retryFlag & 0x01) |
		((linkrate & 0x0F) * 0x1000000) |
		((stp_sspsmp_sata & 0x03) * 0x10000000));
	payload.firstburstsize_ITNexustimeout =
		cpu_to_le32(ITNT | (firstBurstSize * 0x10000));
4498
	memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
J
jack wang 已提交
4499
		SAS_ADDR_SIZE);
4500 4501
	rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
			sizeof(payload), 0);
4502
	return rc;
J
jack wang 已提交
4503 4504
}

4505
/*
4506
 * see comments on pm8001_mpi_reg_resp.
J
jack wang 已提交
4507
 */
4508
int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha,
J
jack wang 已提交
4509 4510 4511 4512
	u32 device_id)
{
	struct dereg_dev_req payload;
	u32 opc = OPC_INB_DEREG_DEV_HANDLE;
4513
	int ret;
J
jack wang 已提交
4514 4515 4516
	struct inbound_queue_table *circularQ;

	circularQ = &pm8001_ha->inbnd_q_tbl[0];
4517
	memset(&payload, 0, sizeof(payload));
4518
	payload.tag = cpu_to_le32(1);
J
jack wang 已提交
4519
	payload.device_id = cpu_to_le32(device_id);
4520 4521
	pm8001_dbg(pm8001_ha, MSG, "unregister device device_id = %d\n",
		   device_id);
4522 4523
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
			sizeof(payload), 0);
4524
	return ret;
J
jack wang 已提交
4525 4526 4527 4528 4529
}

/**
 * pm8001_chip_phy_ctl_req - support the local phy operation
 * @pm8001_ha: our hba card information.
4530 4531
 * @phyId: the phy id which we wanted to operate
 * @phy_op: the phy operation to request
J
jack wang 已提交
4532 4533 4534 4535 4536 4537
 */
static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
	u32 phyId, u32 phy_op)
{
	struct local_phy_ctl_req payload;
	struct inbound_queue_table *circularQ;
4538
	int ret;
J
jack wang 已提交
4539
	u32 opc = OPC_INB_LOCAL_PHY_CONTROL;
J
jack wang 已提交
4540
	memset(&payload, 0, sizeof(payload));
J
jack wang 已提交
4541
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
4542
	payload.tag = cpu_to_le32(1);
J
jack wang 已提交
4543 4544
	payload.phyop_phyid =
		cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F));
4545 4546
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
			sizeof(payload), 0);
4547
	return ret;
J
jack wang 已提交
4548 4549
}

4550
static u32 pm8001_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha)
J
jack wang 已提交
4551 4552 4553
{
#ifdef PM8001_USE_MSIX
	return 1;
4554 4555 4556
#else
	u32 value;

J
jack wang 已提交
4557 4558 4559 4560
	value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR);
	if (value)
		return 1;
	return 0;
4561
#endif
J
jack wang 已提交
4562 4563 4564 4565 4566
}

/**
 * pm8001_chip_isr - PM8001 isr handler.
 * @pm8001_ha: our hba card information.
4567
 * @vec: IRQ number
J
jack wang 已提交
4568
 */
4569
static irqreturn_t
4570
pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)
J
jack wang 已提交
4571
{
4572
	pm8001_chip_interrupt_disable(pm8001_ha, vec);
4573 4574 4575
	pm8001_dbg(pm8001_ha, DEVIO,
		   "irq vec %d, ODMR:0x%x\n",
		   vec, pm8001_cr32(pm8001_ha, 0, 0x30));
4576 4577
	process_oq(pm8001_ha, vec);
	pm8001_chip_interrupt_enable(pm8001_ha, vec);
4578
	return IRQ_HANDLED;
J
jack wang 已提交
4579 4580 4581 4582 4583 4584 4585
}

static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc,
	u32 dev_id, u8 flag, u32 task_tag, u32 cmd_tag)
{
	struct task_abort_req task_abort;
	struct inbound_queue_table *circularQ;
4586
	int ret;
J
jack wang 已提交
4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	memset(&task_abort, 0, sizeof(task_abort));
	if (ABORT_SINGLE == (flag & ABORT_MASK)) {
		task_abort.abort_all = 0;
		task_abort.device_id = cpu_to_le32(dev_id);
		task_abort.tag_to_abort = cpu_to_le32(task_tag);
		task_abort.tag = cpu_to_le32(cmd_tag);
	} else if (ABORT_ALL == (flag & ABORT_MASK)) {
		task_abort.abort_all = cpu_to_le32(1);
		task_abort.device_id = cpu_to_le32(dev_id);
		task_abort.tag = cpu_to_le32(cmd_tag);
	}
4599 4600
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort,
			sizeof(task_abort), 0);
4601
	return ret;
J
jack wang 已提交
4602 4603
}

4604
/*
J
jack wang 已提交
4605 4606
 * pm8001_chip_abort_task - SAS abort task when error or exception happened.
 */
4607
int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha,
J
jack wang 已提交
4608 4609 4610 4611
	struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag, u32 cmd_tag)
{
	u32 opc, device_id;
	int rc = TMF_RESP_FUNC_FAILED;
4612 4613
	pm8001_dbg(pm8001_ha, EH, "cmd_tag = %x, abort task tag = 0x%x\n",
		   cmd_tag, task_tag);
4614
	if (pm8001_dev->dev_type == SAS_END_DEVICE)
J
jack wang 已提交
4615
		opc = OPC_INB_SSP_ABORT;
4616
	else if (pm8001_dev->dev_type == SAS_SATA_DEV)
J
jack wang 已提交
4617 4618 4619 4620 4621 4622 4623
		opc = OPC_INB_SATA_ABORT;
	else
		opc = OPC_INB_SMP_ABORT;/* SMP */
	device_id = pm8001_dev->device_id;
	rc = send_task_abort(pm8001_ha, opc, device_id, flag,
		task_tag, cmd_tag);
	if (rc != TMF_RESP_FUNC_COMPLETE)
4624
		pm8001_dbg(pm8001_ha, EH, "rc= %d\n", rc);
J
jack wang 已提交
4625 4626 4627 4628
	return rc;
}

/**
4629
 * pm8001_chip_ssp_tm_req - built the task management command.
J
jack wang 已提交
4630 4631 4632 4633
 * @pm8001_ha: our hba card information.
 * @ccb: the ccb information.
 * @tmf: task management function.
 */
4634
int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha,
J
jack wang 已提交
4635 4636 4637 4638 4639 4640 4641 4642
	struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf)
{
	struct sas_task *task = ccb->task;
	struct domain_device *dev = task->dev;
	struct pm8001_device *pm8001_dev = dev->lldd_dev;
	u32 opc = OPC_INB_SSPINITMSTART;
	struct inbound_queue_table *circularQ;
	struct ssp_ini_tm_start_req sspTMCmd;
4643
	int ret;
J
jack wang 已提交
4644 4645 4646 4647 4648 4649 4650

	memset(&sspTMCmd, 0, sizeof(sspTMCmd));
	sspTMCmd.device_id = cpu_to_le32(pm8001_dev->device_id);
	sspTMCmd.relate_tag = cpu_to_le32(tmf->tag_of_task_to_be_managed);
	sspTMCmd.tmf = cpu_to_le32(tmf->tmf);
	memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8);
	sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag);
4651 4652
	if (pm8001_ha->chip_id != chip_8001)
		sspTMCmd.ds_ads_m = 0x08;
J
jack wang 已提交
4653
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
4654 4655
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd,
			sizeof(sspTMCmd), 0);
4656
	return ret;
J
jack wang 已提交
4657 4658
}

4659
int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
J
jack wang 已提交
4660 4661 4662 4663
	void *payload)
{
	u32 opc = OPC_INB_GET_NVMD_DATA;
	u32 nvmd_type;
4664
	int rc;
J
jack wang 已提交
4665 4666 4667 4668 4669 4670 4671 4672 4673
	u32 tag;
	struct pm8001_ccb_info *ccb;
	struct inbound_queue_table *circularQ;
	struct get_nvm_data_req nvmd_req;
	struct fw_control_ex *fw_control_context;
	struct pm8001_ioctl_payload *ioctl_payload = payload;

	nvmd_type = ioctl_payload->minor_function;
	fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
4674 4675
	if (!fw_control_context)
		return -ENOMEM;
4676
	fw_control_context->usrAddr = (u8 *)ioctl_payload->func_specific;
4677
	fw_control_context->len = ioctl_payload->rd_length;
J
jack wang 已提交
4678 4679 4680
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	memset(&nvmd_req, 0, sizeof(nvmd_req));
	rc = pm8001_tag_alloc(pm8001_ha, &tag);
4681 4682
	if (rc) {
		kfree(fw_control_context);
J
jack wang 已提交
4683
		return rc;
4684
	}
J
jack wang 已提交
4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697
	ccb = &pm8001_ha->ccb_info[tag];
	ccb->ccb_tag = tag;
	ccb->fw_control_context = fw_control_context;
	nvmd_req.tag = cpu_to_le32(tag);

	switch (nvmd_type) {
	case TWI_DEVICE: {
		u32 twi_addr, twi_page_size;
		twi_addr = 0xa8;
		twi_page_size = 2;

		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
			twi_page_size << 8 | TWI_DEVICE);
4698
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
J
jack wang 已提交
4699 4700 4701 4702 4703 4704 4705 4706
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	}
	case C_SEEPROM: {
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
4707
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
J
jack wang 已提交
4708 4709 4710 4711 4712 4713 4714 4715
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	}
	case VPD_FLASH: {
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
4716
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
J
jack wang 已提交
4717 4718 4719 4720 4721 4722 4723 4724
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	}
	case EXPAN_ROM: {
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
4725
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
J
jack wang 已提交
4726 4727 4728 4729 4730 4731
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	}
4732 4733
	case IOP_RDUMP: {
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | IOP_RDUMP);
4734
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
4735 4736 4737 4738 4739 4740 4741
		nvmd_req.vpd_offset = cpu_to_le32(ioctl_payload->offset);
		nvmd_req.resp_addr_hi =
		cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	}
J
jack wang 已提交
4742 4743 4744
	default:
		break;
	}
4745 4746
	rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req,
			sizeof(nvmd_req), 0);
T
Tomas Henzl 已提交
4747 4748 4749 4750
	if (rc) {
		kfree(fw_control_context);
		pm8001_tag_free(pm8001_ha, tag);
	}
4751
	return rc;
J
jack wang 已提交
4752 4753
}

4754
int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
J
jack wang 已提交
4755 4756 4757 4758
	void *payload)
{
	u32 opc = OPC_INB_SET_NVMD_DATA;
	u32 nvmd_type;
4759
	int rc;
J
jack wang 已提交
4760 4761 4762 4763 4764 4765 4766 4767 4768
	u32 tag;
	struct pm8001_ccb_info *ccb;
	struct inbound_queue_table *circularQ;
	struct set_nvm_data_req nvmd_req;
	struct fw_control_ex *fw_control_context;
	struct pm8001_ioctl_payload *ioctl_payload = payload;

	nvmd_type = ioctl_payload->minor_function;
	fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
4769 4770
	if (!fw_control_context)
		return -ENOMEM;
J
jack wang 已提交
4771 4772
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	memcpy(pm8001_ha->memoryMap.region[NVMD].virt_ptr,
4773
		&ioctl_payload->func_specific,
4774
		ioctl_payload->wr_length);
J
jack wang 已提交
4775 4776
	memset(&nvmd_req, 0, sizeof(nvmd_req));
	rc = pm8001_tag_alloc(pm8001_ha, &tag);
4777 4778
	if (rc) {
		kfree(fw_control_context);
T
Tomas Henzl 已提交
4779
		return -EBUSY;
4780
	}
J
jack wang 已提交
4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792
	ccb = &pm8001_ha->ccb_info[tag];
	ccb->fw_control_context = fw_control_context;
	ccb->ccb_tag = tag;
	nvmd_req.tag = cpu_to_le32(tag);
	switch (nvmd_type) {
	case TWI_DEVICE: {
		u32 twi_addr, twi_page_size;
		twi_addr = 0xa8;
		twi_page_size = 2;
		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
			twi_page_size << 8 | TWI_DEVICE);
4793
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
J
jack wang 已提交
4794 4795 4796 4797 4798 4799 4800 4801
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	}
	case C_SEEPROM:
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
4802
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
J
jack wang 已提交
4803 4804 4805 4806 4807 4808 4809 4810
		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	case VPD_FLASH:
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
4811
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
J
jack wang 已提交
4812 4813 4814 4815 4816 4817 4818 4819
		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	case EXPAN_ROM:
		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
4820
		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
J
jack wang 已提交
4821 4822 4823 4824 4825 4826 4827 4828 4829
		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
		nvmd_req.resp_addr_hi =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
		nvmd_req.resp_addr_lo =
		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo);
		break;
	default:
		break;
	}
4830 4831
	rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req,
			sizeof(nvmd_req), 0);
4832 4833 4834 4835
	if (rc) {
		kfree(fw_control_context);
		pm8001_tag_free(pm8001_ha, tag);
	}
4836
	return rc;
J
jack wang 已提交
4837 4838 4839 4840 4841 4842
}

/**
 * pm8001_chip_fw_flash_update_build - support the firmware update operation
 * @pm8001_ha: our hba card information.
 * @fw_flash_updata_info: firmware flash update param
4843
 * @tag: Tag to apply to the payload
J
jack wang 已提交
4844
 */
4845
int
J
jack wang 已提交
4846 4847 4848 4849 4850 4851
pm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha,
	void *fw_flash_updata_info, u32 tag)
{
	struct fw_flash_Update_req payload;
	struct fw_flash_updata_info *info;
	struct inbound_queue_table *circularQ;
4852
	int ret;
J
jack wang 已提交
4853 4854
	u32 opc = OPC_INB_FW_FLASH_UPDATE;

4855
	memset(&payload, 0, sizeof(struct fw_flash_Update_req));
J
jack wang 已提交
4856 4857 4858 4859 4860 4861 4862
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	info = fw_flash_updata_info;
	payload.tag = cpu_to_le32(tag);
	payload.cur_image_len = cpu_to_le32(info->cur_image_len);
	payload.cur_image_offset = cpu_to_le32(info->cur_image_offset);
	payload.total_image_len = cpu_to_le32(info->total_image_len);
	payload.len = info->sgl.im_len.len ;
4863 4864 4865 4866
	payload.sgl_addr_lo =
		cpu_to_le32(lower_32_bits(le64_to_cpu(info->sgl.addr)));
	payload.sgl_addr_hi =
		cpu_to_le32(upper_32_bits(le64_to_cpu(info->sgl.addr)));
4867 4868
	ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
			sizeof(payload), 0);
4869
	return ret;
J
jack wang 已提交
4870 4871
}

4872
int
J
jack wang 已提交
4873 4874 4875 4876 4877 4878
pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha,
	void *payload)
{
	struct fw_flash_updata_info flash_update_info;
	struct fw_control_info *fw_control;
	struct fw_control_ex *fw_control_context;
4879
	int rc;
J
jack wang 已提交
4880 4881
	u32 tag;
	struct pm8001_ccb_info *ccb;
4882 4883
	void *buffer = pm8001_ha->memoryMap.region[FW_FLASH].virt_ptr;
	dma_addr_t phys_addr = pm8001_ha->memoryMap.region[FW_FLASH].phys_addr;
J
jack wang 已提交
4884 4885 4886
	struct pm8001_ioctl_payload *ioctl_payload = payload;

	fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL);
4887 4888
	if (!fw_control_context)
		return -ENOMEM;
4889
	fw_control = (struct fw_control_info *)&ioctl_payload->func_specific;
4890 4891 4892
	pm8001_dbg(pm8001_ha, DEVIO,
		   "dma fw_control context input length :%x\n",
		   fw_control->len);
4893
	memcpy(buffer, fw_control->buffer, fw_control->len);
J
jack wang 已提交
4894 4895 4896 4897 4898 4899 4900 4901
	flash_update_info.sgl.addr = cpu_to_le64(phys_addr);
	flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len);
	flash_update_info.sgl.im_len.e = 0;
	flash_update_info.cur_image_offset = fw_control->offset;
	flash_update_info.cur_image_len = fw_control->len;
	flash_update_info.total_image_len = fw_control->size;
	fw_control_context->fw_control = fw_control;
	fw_control_context->virtAddr = buffer;
4902
	fw_control_context->phys_addr = phys_addr;
J
jack wang 已提交
4903 4904
	fw_control_context->len = fw_control->len;
	rc = pm8001_tag_alloc(pm8001_ha, &tag);
4905 4906
	if (rc) {
		kfree(fw_control_context);
T
Tomas Henzl 已提交
4907
		return -EBUSY;
4908
	}
J
jack wang 已提交
4909 4910 4911
	ccb = &pm8001_ha->ccb_info[tag];
	ccb->fw_control_context = fw_control_context;
	ccb->ccb_tag = tag;
4912 4913 4914
	rc = pm8001_chip_fw_flash_update_build(pm8001_ha, &flash_update_info,
		tag);
	return rc;
J
jack wang 已提交
4915 4916
}

4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933
ssize_t
pm8001_get_gsm_dump(struct device *cdev, u32 length, char *buf)
{
	u32 value, rem, offset = 0, bar = 0;
	u32 index, work_offset, dw_length;
	u32 shift_value, gsm_base, gsm_dump_offset;
	char *direct_data;
	struct Scsi_Host *shost = class_to_shost(cdev);
	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;

	direct_data = buf;
	gsm_dump_offset = pm8001_ha->fatal_forensic_shift_offset;

	/* check max is 1 Mbytes */
	if ((length > 0x100000) || (gsm_dump_offset & 3) ||
		((gsm_dump_offset + length) > 0x1000000))
4934
			return -EINVAL;
4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961

	if (pm8001_ha->chip_id == chip_8001)
		bar = 2;
	else
		bar = 1;

	work_offset = gsm_dump_offset & 0xFFFF0000;
	offset = gsm_dump_offset & 0x0000FFFF;
	gsm_dump_offset = work_offset;
	/* adjust length to dword boundary */
	rem = length & 3;
	dw_length = length >> 2;

	for (index = 0; index < dw_length; index++) {
		if ((work_offset + offset) & 0xFFFF0000) {
			if (pm8001_ha->chip_id == chip_8001)
				shift_value = ((gsm_dump_offset + offset) &
						SHIFT_REG_64K_MASK);
			else
				shift_value = (((gsm_dump_offset + offset) &
						SHIFT_REG_64K_MASK) >>
						SHIFT_REG_BIT_SHIFT);

			if (pm8001_ha->chip_id == chip_8001) {
				gsm_base = GSM_BASE;
				if (-1 == pm8001_bar4_shift(pm8001_ha,
						(gsm_base + shift_value)))
4962
					return -EIO;
4963 4964 4965 4966
			} else {
				gsm_base = 0;
				if (-1 == pm80xx_bar4_shift(pm8001_ha,
						(gsm_base + shift_value)))
4967
					return -EIO;
4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985
			}
			gsm_dump_offset = (gsm_dump_offset + offset) &
						0xFFFF0000;
			work_offset = 0;
			offset = offset & 0x0000FFFF;
		}
		value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
						0x0000FFFF);
		direct_data += sprintf(direct_data, "%08x ", value);
		offset += 4;
	}
	if (rem != 0) {
		value = pm8001_cr32(pm8001_ha, bar, (work_offset + offset) &
						0x0000FFFF);
		/* xfr for non_dw */
		direct_data += sprintf(direct_data, "%08x ", value);
	}
	/* Shift back to BAR4 original address */
4986
	if (-1 == pm8001_bar4_shift(pm8001_ha, 0))
4987
			return -EIO;
4988 4989 4990 4991 4992 4993 4994
	pm8001_ha->fatal_forensic_shift_offset += 1024;

	if (pm8001_ha->fatal_forensic_shift_offset >= 0x100000)
		pm8001_ha->fatal_forensic_shift_offset = 0;
	return direct_data - buf;
}

4995
int
J
jack wang 已提交
4996 4997 4998 4999 5000 5001
pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha,
	struct pm8001_device *pm8001_dev, u32 state)
{
	struct set_dev_state_req payload;
	struct inbound_queue_table *circularQ;
	struct pm8001_ccb_info *ccb;
5002
	int rc;
J
jack wang 已提交
5003 5004
	u32 tag;
	u32 opc = OPC_INB_SET_DEVICE_STATE;
5005
	memset(&payload, 0, sizeof(payload));
J
jack wang 已提交
5006 5007 5008 5009 5010 5011 5012 5013 5014 5015
	rc = pm8001_tag_alloc(pm8001_ha, &tag);
	if (rc)
		return -1;
	ccb = &pm8001_ha->ccb_info[tag];
	ccb->ccb_tag = tag;
	ccb->device = pm8001_dev;
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	payload.tag = cpu_to_le32(tag);
	payload.device_id = cpu_to_le32(pm8001_dev->device_id);
	payload.nds = cpu_to_le32(state);
5016 5017
	rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
			sizeof(payload), 0);
5018 5019
	return rc;

5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033
}

static int
pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha)
{
	struct sas_re_initialization_req payload;
	struct inbound_queue_table *circularQ;
	struct pm8001_ccb_info *ccb;
	int rc;
	u32 tag;
	u32 opc = OPC_INB_SAS_RE_INITIALIZE;
	memset(&payload, 0, sizeof(payload));
	rc = pm8001_tag_alloc(pm8001_ha, &tag);
	if (rc)
T
Tomas Henzl 已提交
5034
		return -ENOMEM;
5035 5036 5037 5038 5039 5040 5041
	ccb = &pm8001_ha->ccb_info[tag];
	ccb->ccb_tag = tag;
	circularQ = &pm8001_ha->inbnd_q_tbl[0];
	payload.tag = cpu_to_le32(tag);
	payload.SSAHOLT = cpu_to_le32(0xd << 25);
	payload.sata_hol_tmo = cpu_to_le32(80);
	payload.open_reject_cmdretries_data_retries = cpu_to_le32(0xff00ff);
5042 5043
	rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload,
			sizeof(payload), 0);
T
Tomas Henzl 已提交
5044 5045
	if (rc)
		pm8001_tag_free(pm8001_ha, tag);
5046
	return rc;
J
jack wang 已提交
5047 5048 5049 5050 5051 5052 5053 5054 5055 5056

}

const struct pm8001_dispatch pm8001_8001_dispatch = {
	.name			= "pmc8001",
	.chip_init		= pm8001_chip_init,
	.chip_soft_rst		= pm8001_chip_soft_rst,
	.chip_rst		= pm8001_hw_chip_rst,
	.chip_iounmap		= pm8001_chip_iounmap,
	.isr			= pm8001_chip_isr,
5057
	.is_our_interrupt	= pm8001_chip_is_our_interrupt,
J
jack wang 已提交
5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075
	.isr_process_oq		= process_oq,
	.interrupt_enable 	= pm8001_chip_interrupt_enable,
	.interrupt_disable	= pm8001_chip_interrupt_disable,
	.make_prd		= pm8001_chip_make_sg,
	.smp_req		= pm8001_chip_smp_req,
	.ssp_io_req		= pm8001_chip_ssp_io_req,
	.sata_req		= pm8001_chip_sata_req,
	.phy_start_req		= pm8001_chip_phy_start_req,
	.phy_stop_req		= pm8001_chip_phy_stop_req,
	.reg_dev_req		= pm8001_chip_reg_dev_req,
	.dereg_dev_req		= pm8001_chip_dereg_dev_req,
	.phy_ctl_req		= pm8001_chip_phy_ctl_req,
	.task_abort		= pm8001_chip_abort_task,
	.ssp_tm_req		= pm8001_chip_ssp_tm_req,
	.get_nvmd_req		= pm8001_chip_get_nvmd_req,
	.set_nvmd_req		= pm8001_chip_set_nvmd_req,
	.fw_flash_update_req	= pm8001_chip_fw_flash_update_req,
	.set_dev_state_req	= pm8001_chip_set_dev_state_req,
5076
	.sas_re_init_req	= pm8001_chip_sas_re_initialization,
A
akshatzen 已提交
5077
	.fatal_errors		= pm80xx_fatal_errors,
J
jack wang 已提交
5078
};