linux-stable/drivers/scsi/pm8001/pm80xx_hwi.c

4944 lines
160 KiB
C
Raw Normal View History

/*
* PMC-Sierra SPCv/ve 8088/8089 SAS/SATA based host adapters driver
*
* Copyright (c) 2008-2009 PMC-Sierra, Inc.,
* 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.
*
*/
#include <linux/slab.h>
#include "pm8001_sas.h"
#include "pm80xx_hwi.h"
#include "pm8001_chips.h"
#include "pm8001_ctl.h"
#include "pm80xx_tracepoints.h"
#define SMP_DIRECT 1
#define SMP_INDIRECT 2
int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value)
{
u32 reg_val;
unsigned long start;
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, shift_value);
/* confirm the setting is written */
start = jiffies + HZ; /* 1 sec */
do {
reg_val = pm8001_cr32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER);
} while ((reg_val != shift_value) && time_before(jiffies, start));
if (reg_val != shift_value) {
pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:MEMBASE_II_SHIFT_REGISTER = 0x%x\n",
reg_val);
return -1;
}
return 0;
}
static void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset,
__le32 *destination,
u32 dw_count, u32 bus_base_number)
{
u32 index, value, offset;
for (index = 0; index < dw_count; index += 4, destination++) {
offset = (soffset + index);
if (offset < (64 * 1024)) {
value = pm8001_cr32(pm8001_ha, bus_base_number, offset);
*destination = cpu_to_le32(value);
}
}
return;
}
ssize_t pm80xx_get_fatal_dump(struct device *cdev,
struct device_attribute *attr, char *buf)
{
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;
void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr;
u32 accum_len, reg_val, index, *temp;
u32 status = 1;
unsigned long start;
u8 *direct_data;
char *fatal_error_data = buf;
u32 length_to_read;
u32 offset;
pm8001_ha->forensic_info.data_buf.direct_data = buf;
if (pm8001_ha->chip_id == chip_8001) {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"Not supported for SPC controller");
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf;
}
/* initialize variables for very first call from host application */
if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
pm8001_dbg(pm8001_ha, IO,
"forensic_info TYPE_NON_FATAL..............\n");
direct_data = (u8 *)fatal_error_data;
pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL;
pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET;
pm8001_ha->forensic_info.data_buf.direct_offset = 0;
pm8001_ha->forensic_info.data_buf.read_len = 0;
pm8001_ha->forensic_preserved_accumulated_transfer = 0;
/* Write signature to fatal dump table */
pm8001_mw32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_SIGNATURE, 0x1234abcd);
pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
pm8001_dbg(pm8001_ha, IO, "ossaHwCB: status1 %d\n", status);
pm8001_dbg(pm8001_ha, IO, "ossaHwCB: read_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.read_len);
pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_len);
pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_offset 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_offset);
}
if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
/* start to get data */
/* Program the MEMBASE II Shifting Register with 0x00.*/
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
pm8001_ha->fatal_forensic_shift_offset);
pm8001_ha->forensic_last_offset = 0;
pm8001_ha->forensic_fatal_step = 0;
pm8001_ha->fatal_bar_loc = 0;
}
/* Read until accum_len is retrieved */
accum_len = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
/* Determine length of data between previously stored transfer length
* and current accumulated transfer length
*/
length_to_read =
accum_len - pm8001_ha->forensic_preserved_accumulated_transfer;
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: accum_len 0x%x\n",
accum_len);
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: length_to_read 0x%x\n",
length_to_read);
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: last_offset 0x%x\n",
pm8001_ha->forensic_last_offset);
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: read_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.read_len);
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_len 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_len);
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_offset 0x%x\n",
pm8001_ha->forensic_info.data_buf.direct_offset);
/* If accumulated length failed to read correctly fail the attempt.*/
if (accum_len == 0xFFFFFFFF) {
pm8001_dbg(pm8001_ha, IO,
"Possible PCI issue 0x%x not expected\n",
accum_len);
return status;
}
/* If accumulated length is zero fail the attempt */
if (accum_len == 0) {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 0xFFFFFFFF);
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf;
}
/* Accumulated length is good so start capturing the first data */
temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr;
if (pm8001_ha->forensic_fatal_step == 0) {
moreData:
/* If data to read is less than SYSFS_OFFSET then reduce the
* length of dataLen
*/
if (pm8001_ha->forensic_last_offset + SYSFS_OFFSET
> length_to_read) {
pm8001_ha->forensic_info.data_buf.direct_len =
length_to_read -
pm8001_ha->forensic_last_offset;
} else {
pm8001_ha->forensic_info.data_buf.direct_len =
SYSFS_OFFSET;
}
if (pm8001_ha->forensic_info.data_buf.direct_data) {
/* Data is in bar, copy to host memory */
pm80xx_pci_mem_copy(pm8001_ha,
pm8001_ha->fatal_bar_loc,
pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr,
pm8001_ha->forensic_info.data_buf.direct_len, 1);
}
pm8001_ha->fatal_bar_loc +=
pm8001_ha->forensic_info.data_buf.direct_len;
pm8001_ha->forensic_info.data_buf.direct_offset +=
pm8001_ha->forensic_info.data_buf.direct_len;
pm8001_ha->forensic_last_offset +=
pm8001_ha->forensic_info.data_buf.direct_len;
pm8001_ha->forensic_info.data_buf.read_len =
pm8001_ha->forensic_info.data_buf.direct_len;
if (pm8001_ha->forensic_last_offset >= length_to_read) {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 3);
for (index = 0; index <
(pm8001_ha->forensic_info.data_buf.direct_len
/ 4); index++) {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(
pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", *(temp + index));
}
pm8001_ha->fatal_bar_loc = 0;
pm8001_ha->forensic_fatal_step = 1;
pm8001_ha->fatal_forensic_shift_offset = 0;
pm8001_ha->forensic_last_offset = 0;
status = 0;
offset = (int)
((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
pm8001_dbg(pm8001_ha, IO,
"get_fatal_spcv:return1 0x%x\n", offset);
return (char *)pm8001_ha->
forensic_info.data_buf.direct_data -
(char *)buf;
}
if (pm8001_ha->fatal_bar_loc < (64 * 1024)) {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->
forensic_info.data_buf.direct_data,
"%08x ", 2);
for (index = 0; index <
(pm8001_ha->forensic_info.data_buf.direct_len
/ 4); index++) {
pm8001_ha->forensic_info.data_buf.direct_data
+= sprintf(pm8001_ha->
forensic_info.data_buf.direct_data,
"%08x ", *(temp + index));
}
status = 0;
offset = (int)
((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
pm8001_dbg(pm8001_ha, IO,
"get_fatal_spcv:return2 0x%x\n", offset);
return (char *)pm8001_ha->
forensic_info.data_buf.direct_data -
(char *)buf;
}
/* Increment the MEMBASE II Shifting Register value by 0x100.*/
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 2);
for (index = 0; index <
(pm8001_ha->forensic_info.data_buf.direct_len
/ 4) ; index++) {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->
forensic_info.data_buf.direct_data,
"%08x ", *(temp + index));
}
pm8001_ha->fatal_forensic_shift_offset += 0x100;
pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
pm8001_ha->fatal_forensic_shift_offset);
pm8001_ha->fatal_bar_loc = 0;
status = 0;
offset = (int)
((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return3 0x%x\n",
offset);
return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf;
}
if (pm8001_ha->forensic_fatal_step == 1) {
/* store previous accumulated length before triggering next
* accumulated length update
*/
pm8001_ha->forensic_preserved_accumulated_transfer =
pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
/* continue capturing the fatal log until Dump status is 0x3 */
if (pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_STATUS) <
MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) {
/* reset fddstat bit by writing to zero*/
pm8001_mw32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_STATUS, 0x0);
/* set dump control value to '1' so that new data will
* be transferred to shared memory
*/
pm8001_mw32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_HANDSHAKE,
MPI_FATAL_EDUMP_HANDSHAKE_RDY);
/*Poll FDDHSHK until clear */
start = jiffies + (2 * HZ); /* 2 sec */
do {
reg_val = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_HANDSHAKE);
} while ((reg_val) && time_before(jiffies, start));
if (reg_val != 0) {
pm8001_dbg(pm8001_ha, FAIL,
"TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n",
reg_val);
/* Fail the dump if a timeout occurs */
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(
pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 0xFFFFFFFF);
return((char *)
pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
}
/* Poll status register until set to 2 or
* 3 for up to 2 seconds
*/
start = jiffies + (2 * HZ); /* 2 sec */
do {
reg_val = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_STATUS);
} while (((reg_val != 2) && (reg_val != 3)) &&
time_before(jiffies, start));
if (reg_val < 2) {
pm8001_dbg(pm8001_ha, FAIL,
"TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n",
reg_val);
/* Fail the dump if a timeout occurs */
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(
pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 0xFFFFFFFF);
return((char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf);
}
/* reset fatal_forensic_shift_offset back to zero and reset MEMBASE 2 register to zero */
pm8001_ha->fatal_forensic_shift_offset = 0; /* location in 64k region */
pm8001_cw32(pm8001_ha, 0,
MEMBASE_II_SHIFT_REGISTER,
pm8001_ha->fatal_forensic_shift_offset);
}
/* Read the next block of the debug data.*/
length_to_read = pm8001_mr32(fatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN) -
pm8001_ha->forensic_preserved_accumulated_transfer;
if (length_to_read != 0x0) {
pm8001_ha->forensic_fatal_step = 0;
goto moreData;
} else {
pm8001_ha->forensic_info.data_buf.direct_data +=
sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
"%08x ", 4);
pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF;
pm8001_ha->forensic_info.data_buf.direct_len = 0;
pm8001_ha->forensic_info.data_buf.direct_offset = 0;
pm8001_ha->forensic_info.data_buf.read_len = 0;
}
}
offset = (int)((char *)pm8001_ha->forensic_info.data_buf.direct_data
- (char *)buf);
pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return4 0x%x\n", offset);
return ((char *)pm8001_ha->forensic_info.data_buf.direct_data -
(char *)buf);
}
/* pm80xx_get_non_fatal_dump - dump the nonfatal data from the dma
* location by the firmware.
*/
ssize_t pm80xx_get_non_fatal_dump(struct device *cdev,
struct device_attribute *attr, char *buf)
{
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;
void __iomem *nonfatal_table_address = pm8001_ha->fatal_tbl_addr;
u32 accum_len = 0;
u32 total_len = 0;
u32 reg_val = 0;
u32 *temp = NULL;
u32 index = 0;
u32 output_length;
unsigned long start = 0;
char *buf_copy = buf;
temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr;
if (++pm8001_ha->non_fatal_count == 1) {
if (pm8001_ha->chip_id == chip_8001) {
snprintf(pm8001_ha->forensic_info.data_buf.direct_data,
PAGE_SIZE, "Not supported for SPC controller");
return 0;
}
pm8001_dbg(pm8001_ha, IO, "forensic_info TYPE_NON_FATAL...\n");
/*
* Step 1: Write the host buffer parameters in the MPI Fatal and
* Non-Fatal Error Dump Capture Table.This is the buffer
* where debug data will be DMAed to.
*/
pm8001_mw32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_LO_OFFSET,
pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_lo);
pm8001_mw32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_HI_OFFSET,
pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_hi);
pm8001_mw32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_LENGTH, SYSFS_OFFSET);
/* Optionally, set the DUMPCTRL bit to 1 if the host
* keeps sending active I/Os while capturing the non-fatal
* debug data. Otherwise, leave this bit set to zero
*/
pm8001_mw32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_HANDSHAKE_RDY);
/*
* Step 2: Clear Accumulative Length of Debug Data Transferred
* [ACCDDLEN] field in the MPI Fatal and Non-Fatal Error Dump
* Capture Table to zero.
*/
pm8001_mw32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN, 0);
/* initiallize previous accumulated length to 0 */
pm8001_ha->forensic_preserved_accumulated_transfer = 0;
pm8001_ha->non_fatal_read_length = 0;
}
total_len = pm8001_mr32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_TOTAL_LEN);
/*
* Step 3:Clear Fatal/Non-Fatal Debug Data Transfer Status [FDDTSTAT]
* field and then request that the SPCv controller transfer the debug
* data by setting bit 7 of the Inbound Doorbell Set Register.
*/
pm8001_mw32(nonfatal_table_address, MPI_FATAL_EDUMP_TABLE_STATUS, 0);
pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET,
SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP);
/*
* Step 4.1: Read back the Inbound Doorbell Set Register (by polling for
* 2 seconds) until register bit 7 is cleared.
* This step only indicates the request is accepted by the controller.
*/
start = jiffies + (2 * HZ); /* 2 sec */
do {
reg_val = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET) &
SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP;
} while ((reg_val != 0) && time_before(jiffies, start));
/* Step 4.2: To check the completion of the transfer, poll the Fatal/Non
* Fatal Debug Data Transfer Status [FDDTSTAT] field for 2 seconds in
* the MPI Fatal and Non-Fatal Error Dump Capture Table.
*/
start = jiffies + (2 * HZ); /* 2 sec */
do {
reg_val = pm8001_mr32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_STATUS);
} while ((!reg_val) && time_before(jiffies, start));
if ((reg_val == 0x00) ||
(reg_val == MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED) ||
(reg_val > MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE)) {
pm8001_ha->non_fatal_read_length = 0;
buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 0xFFFFFFFF);
pm8001_ha->non_fatal_count = 0;
return (buf_copy - buf);
} else if (reg_val ==
MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA) {
buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 2);
} else if ((reg_val == MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) ||
(pm8001_ha->non_fatal_read_length >= total_len)) {
pm8001_ha->non_fatal_read_length = 0;
buf_copy += snprintf(buf_copy, PAGE_SIZE, "%08x ", 4);
pm8001_ha->non_fatal_count = 0;
}
accum_len = pm8001_mr32(nonfatal_table_address,
MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
output_length = accum_len -
pm8001_ha->forensic_preserved_accumulated_transfer;
for (index = 0; index < output_length/4; index++)
buf_copy += snprintf(buf_copy, PAGE_SIZE,
"%08x ", *(temp+index));
pm8001_ha->non_fatal_read_length += output_length;
/* store current accumulated length to use in next iteration as
* the previous accumulated length
*/
pm8001_ha->forensic_preserved_accumulated_transfer = accum_len;
return (buf_copy - buf);
}
/**
* read_main_config_table - read the configure table and save it.
* @pm8001_ha: our hba card information
*/
static void read_main_config_table(struct pm8001_hba_info *pm8001_ha)
{
void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature =
pm8001_mr32(address, MAIN_SIGNATURE_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev =
pm8001_mr32(address, MAIN_INTERFACE_REVISION);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev =
pm8001_mr32(address, MAIN_FW_REVISION);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io =
pm8001_mr32(address, MAIN_MAX_OUTSTANDING_IO_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl =
pm8001_mr32(address, MAIN_MAX_SGL_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag =
pm8001_mr32(address, MAIN_CNTRL_CAP_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset =
pm8001_mr32(address, MAIN_GST_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset =
pm8001_mr32(address, MAIN_IBQ_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset =
pm8001_mr32(address, MAIN_OBQ_OFFSET);
/* read Error Dump Offset and Length */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_offset0 =
pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_length0 =
pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_LENGTH);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_offset1 =
pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_length1 =
pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_LENGTH);
/* read GPIO LED settings from the configuration table */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping =
pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET);
/* read analog Setting offset from the configuration table */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.analog_setup_table_offset =
pm8001_mr32(address, MAIN_ANALOG_SETUP_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset =
pm8001_mr32(address, MAIN_INT_VECTOR_TABLE_OFFSET);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset =
pm8001_mr32(address, MAIN_SAS_PHY_ATTR_TABLE_OFFSET);
/* read port recover and reset timeout */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer =
pm8001_mr32(address, MAIN_PORT_RECOVERY_TIMER);
/* read ILA and inactive firmware version */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version =
pm8001_mr32(address, MAIN_MPI_ILA_RELEASE_TYPE);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version =
pm8001_mr32(address, MAIN_MPI_INACTIVE_FW_VERSION);
pm8001_dbg(pm8001_ha, DEV,
"Main cfg table: sign:%x interface rev:%x fw_rev:%x\n",
pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev);
pm8001_dbg(pm8001_ha, DEV,
"table offset: gst:%x iq:%x oq:%x int vec:%x phy attr:%x\n",
pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset);
pm8001_dbg(pm8001_ha, DEV,
"Main cfg table; ila rev:%x Inactive fw rev:%x\n",
pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version);
}
/**
* read_general_status_table - read the general status table and save it.
* @pm8001_ha: our hba card information
*/
static void read_general_status_table(struct pm8001_hba_info *pm8001_ha)
{
void __iomem *address = pm8001_ha->general_stat_tbl_addr;
pm8001_ha->gs_tbl.pm80xx_tbl.gst_len_mpistate =
pm8001_mr32(address, GST_GSTLEN_MPIS_OFFSET);
pm8001_ha->gs_tbl.pm80xx_tbl.iq_freeze_state0 =
pm8001_mr32(address, GST_IQ_FREEZE_STATE0_OFFSET);
pm8001_ha->gs_tbl.pm80xx_tbl.iq_freeze_state1 =
pm8001_mr32(address, GST_IQ_FREEZE_STATE1_OFFSET);
pm8001_ha->gs_tbl.pm80xx_tbl.msgu_tcnt =
pm8001_mr32(address, GST_MSGUTCNT_OFFSET);
pm8001_ha->gs_tbl.pm80xx_tbl.iop_tcnt =
pm8001_mr32(address, GST_IOPTCNT_OFFSET);
pm8001_ha->gs_tbl.pm80xx_tbl.gpio_input_val =
pm8001_mr32(address, GST_GPIO_INPUT_VAL);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[0] =
pm8001_mr32(address, GST_RERRINFO_OFFSET0);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[1] =
pm8001_mr32(address, GST_RERRINFO_OFFSET1);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[2] =
pm8001_mr32(address, GST_RERRINFO_OFFSET2);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[3] =
pm8001_mr32(address, GST_RERRINFO_OFFSET3);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[4] =
pm8001_mr32(address, GST_RERRINFO_OFFSET4);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[5] =
pm8001_mr32(address, GST_RERRINFO_OFFSET5);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[6] =
pm8001_mr32(address, GST_RERRINFO_OFFSET6);
pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[7] =
pm8001_mr32(address, GST_RERRINFO_OFFSET7);
}
/**
* read_phy_attr_table - read the phy attribute table and save it.
* @pm8001_ha: our hba card information
*/
static void read_phy_attr_table(struct pm8001_hba_info *pm8001_ha)
{
void __iomem *address = pm8001_ha->pspa_q_tbl_addr;
pm8001_ha->phy_attr_table.phystart1_16[0] =
pm8001_mr32(address, PSPA_PHYSTATE0_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[1] =
pm8001_mr32(address, PSPA_PHYSTATE1_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[2] =
pm8001_mr32(address, PSPA_PHYSTATE2_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[3] =
pm8001_mr32(address, PSPA_PHYSTATE3_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[4] =
pm8001_mr32(address, PSPA_PHYSTATE4_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[5] =
pm8001_mr32(address, PSPA_PHYSTATE5_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[6] =
pm8001_mr32(address, PSPA_PHYSTATE6_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[7] =
pm8001_mr32(address, PSPA_PHYSTATE7_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[8] =
pm8001_mr32(address, PSPA_PHYSTATE8_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[9] =
pm8001_mr32(address, PSPA_PHYSTATE9_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[10] =
pm8001_mr32(address, PSPA_PHYSTATE10_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[11] =
pm8001_mr32(address, PSPA_PHYSTATE11_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[12] =
pm8001_mr32(address, PSPA_PHYSTATE12_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[13] =
pm8001_mr32(address, PSPA_PHYSTATE13_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[14] =
pm8001_mr32(address, PSPA_PHYSTATE14_OFFSET);
pm8001_ha->phy_attr_table.phystart1_16[15] =
pm8001_mr32(address, PSPA_PHYSTATE15_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[0] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID0_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[1] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID1_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[2] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID2_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[3] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID3_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[4] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID4_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[5] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID5_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[6] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID6_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[7] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID7_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[8] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID8_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[9] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID9_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[10] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID10_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[11] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID11_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[12] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID12_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[13] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID13_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[14] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID14_OFFSET);
pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[15] =
pm8001_mr32(address, PSPA_OB_HW_EVENT_PID15_OFFSET);
}
/**
* read_inbnd_queue_table - read the inbound queue table and save it.
* @pm8001_ha: our hba card information
*/
static void read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
{
int i;
void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
for (i = 0; i < PM8001_MAX_INB_NUM; i++) {
u32 offset = i * 0x20;
pm8001_ha->inbnd_q_tbl[i].pi_pci_bar =
get_pci_bar_index(pm8001_mr32(address,
(offset + IB_PIPCI_BAR)));
pm8001_ha->inbnd_q_tbl[i].pi_offset =
pm8001_mr32(address, (offset + IB_PIPCI_BAR_OFFSET));
}
}
/**
* read_outbnd_queue_table - read the outbound queue table and save it.
* @pm8001_ha: our hba card information
*/
static void read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha)
{
int i;
void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
for (i = 0; i < PM8001_MAX_OUTB_NUM; i++) {
u32 offset = i * 0x24;
pm8001_ha->outbnd_q_tbl[i].ci_pci_bar =
get_pci_bar_index(pm8001_mr32(address,
(offset + OB_CIPCI_BAR)));
pm8001_ha->outbnd_q_tbl[i].ci_offset =
pm8001_mr32(address, (offset + OB_CIPCI_BAR_OFFSET));
}
}
/**
* init_default_table_values - init the default table.
* @pm8001_ha: our hba card information
*/
static void init_default_table_values(struct pm8001_hba_info *pm8001_ha)
{
int i;
u32 offsetib, offsetob;
void __iomem *addressib = pm8001_ha->inbnd_q_tbl_addr;
void __iomem *addressob = pm8001_ha->outbnd_q_tbl_addr;
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;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_event_log_addr =
pm8001_ha->memoryMap.region[AAP1].phys_addr_hi;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_event_log_addr =
pm8001_ha->memoryMap.region[AAP1].phys_addr_lo;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size =
PM8001_EVENT_LOG_SIZE;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_severity = 0x01;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_pcs_event_log_addr =
pm8001_ha->memoryMap.region[IOP].phys_addr_hi;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_pcs_event_log_addr =
pm8001_ha->memoryMap.region[IOP].phys_addr_lo;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size =
PM8001_EVENT_LOG_SIZE;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = 0x01;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt = 0x01;
/* Enable higher IQs and OQs, 32 to 63, bit 16 */
if (pm8001_ha->max_q_num > 32)
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |=
1 << 16;
/* Disable end to end CRC checking */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump = (0x1 << 16);
for (i = 0; i < pm8001_ha->max_q_num; i++) {
pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt =
PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30);
pm8001_ha->inbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_hi;
pm8001_ha->inbnd_q_tbl[i].lower_base_addr =
pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_lo;
pm8001_ha->inbnd_q_tbl[i].base_virt =
(u8 *)pm8001_ha->memoryMap.region[ib_offset + i].virt_ptr;
pm8001_ha->inbnd_q_tbl[i].total_length =
pm8001_ha->memoryMap.region[ib_offset + i].total_len;
pm8001_ha->inbnd_q_tbl[i].ci_upper_base_addr =
pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_hi;
pm8001_ha->inbnd_q_tbl[i].ci_lower_base_addr =
pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_lo;
pm8001_ha->inbnd_q_tbl[i].ci_virt =
pm8001_ha->memoryMap.region[ci_offset + i].virt_ptr;
pm8001_write_32(pm8001_ha->inbnd_q_tbl[i].ci_virt, 0, 0);
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;
pm8001_dbg(pm8001_ha, DEV,
"IQ %d pi_bar 0x%x pi_offset 0x%x\n", i,
pm8001_ha->inbnd_q_tbl[i].pi_pci_bar,
pm8001_ha->inbnd_q_tbl[i].pi_offset);
}
for (i = 0; i < pm8001_ha->max_q_num; i++) {
pm8001_ha->outbnd_q_tbl[i].element_size_cnt =
PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30);
pm8001_ha->outbnd_q_tbl[i].upper_base_addr =
pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_hi;
pm8001_ha->outbnd_q_tbl[i].lower_base_addr =
pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_lo;
pm8001_ha->outbnd_q_tbl[i].base_virt =
(u8 *)pm8001_ha->memoryMap.region[ob_offset + i].virt_ptr;
pm8001_ha->outbnd_q_tbl[i].total_length =
pm8001_ha->memoryMap.region[ob_offset + i].total_len;
pm8001_ha->outbnd_q_tbl[i].pi_upper_base_addr =
pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_hi;
pm8001_ha->outbnd_q_tbl[i].pi_lower_base_addr =
pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_lo;
/* interrupt vector based on oq */
pm8001_ha->outbnd_q_tbl[i].interrup_vec_cnt_delay = (i << 24);
pm8001_ha->outbnd_q_tbl[i].pi_virt =
pm8001_ha->memoryMap.region[pi_offset + i].virt_ptr;
pm8001_write_32(pm8001_ha->outbnd_q_tbl[i].pi_virt, 0, 0);
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;
pm8001_dbg(pm8001_ha, DEV,
"OQ %d ci_bar 0x%x ci_offset 0x%x\n", i,
pm8001_ha->outbnd_q_tbl[i].ci_pci_bar,
pm8001_ha->outbnd_q_tbl[i].ci_offset);
}
}
/**
* update_main_config_table - update the main default table to the HBA.
* @pm8001_ha: our hba card information
*/
static void update_main_config_table(struct pm8001_hba_info *pm8001_ha)
{
void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
pm8001_mw32(address, MAIN_IQNPPD_HPPD_OFFSET,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_q_nppd_hppd);
pm8001_mw32(address, MAIN_EVENT_LOG_ADDR_HI,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_event_log_addr);
pm8001_mw32(address, MAIN_EVENT_LOG_ADDR_LO,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_event_log_addr);
pm8001_mw32(address, MAIN_EVENT_LOG_BUFF_SIZE,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size);
pm8001_mw32(address, MAIN_EVENT_LOG_OPTION,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_severity);
pm8001_mw32(address, MAIN_PCS_EVENT_LOG_ADDR_HI,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_pcs_event_log_addr);
pm8001_mw32(address, MAIN_PCS_EVENT_LOG_ADDR_LO,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_pcs_event_log_addr);
pm8001_mw32(address, MAIN_PCS_EVENT_LOG_BUFF_SIZE,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size);
pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity);
/* Update Fatal error interrupt vector */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |=
((pm8001_ha->max_q_num - 1) << 8);
pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt);
pm8001_dbg(pm8001_ha, DEV,
"Updated Fatal error interrupt vector 0x%x\n",
pm8001_mr32(address, MAIN_FATAL_ERROR_INTERRUPT));
pm8001_mw32(address, MAIN_EVENT_CRC_CHECK,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump);
/* SPCv specific */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping &= 0xCFFFFFFF;
/* Set GPIOLED to 0x2 for LED indicator */
pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping |= 0x20000000;
pm8001_mw32(address, MAIN_GPIO_LED_FLAGS_OFFSET,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping);
pm8001_dbg(pm8001_ha, DEV,
"Programming DW 0x21 in main cfg table with 0x%x\n",
pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET));
pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer);
pm8001_mw32(address, MAIN_INT_REASSERTION_DELAY,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.interrupt_reassertion_delay);
pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= 0xffff0000;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |=
PORT_RECOVERY_TIMEOUT;
if (pm8001_ha->chip_id == chip_8006) {
pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &=
0x0000ffff;
pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |=
CHIP_8006_PORT_RECOVERY_TIMEOUT;
}
pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER,
pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer);
}
/**
* update_inbnd_queue_table - update the inbound queue table to the HBA.
* @pm8001_ha: our hba card information
scsi: pm8001: Fix some function documentation issues Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:918: warning: Function parameter or member 'number' not described in 'update_inbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:954: warning: Function parameter or member 'number' not described in 'update_outbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:1717: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_enable' drivers/scsi/pm8001/pm80xx_hwi.c:1735: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_disable' drivers/scsi/pm8001/pm80xx_hwi.c:4830: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_start_req' drivers/scsi/pm8001/pm80xx_hwi.c:4872: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_stop_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_ha' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_dev' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'flag' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phyId' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phy_op' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'phy_id' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'irq' description in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'stat' description in 'pm80xx_chip_isr' Link: https://lore.kernel.org/r/20200721164148.2617584-18-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-07-21 16:41:25 +00:00
* @number: entry in the queue
*/
static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
int number)
{
void __iomem *address = pm8001_ha->inbnd_q_tbl_addr;
u16 offset = number * 0x20;
pm8001_mw32(address, offset + IB_PROPERITY_OFFSET,
pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt);
pm8001_mw32(address, offset + IB_BASE_ADDR_HI_OFFSET,
pm8001_ha->inbnd_q_tbl[number].upper_base_addr);
pm8001_mw32(address, offset + IB_BASE_ADDR_LO_OFFSET,
pm8001_ha->inbnd_q_tbl[number].lower_base_addr);
pm8001_mw32(address, offset + IB_CI_BASE_ADDR_HI_OFFSET,
pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr);
pm8001_mw32(address, offset + IB_CI_BASE_ADDR_LO_OFFSET,
pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr);
pm8001_dbg(pm8001_ha, DEV,
"IQ %d: Element pri size 0x%x\n",
number,
pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt);
pm8001_dbg(pm8001_ha, DEV,
"IQ upr base addr 0x%x IQ lwr base addr 0x%x\n",
pm8001_ha->inbnd_q_tbl[number].upper_base_addr,
pm8001_ha->inbnd_q_tbl[number].lower_base_addr);
pm8001_dbg(pm8001_ha, DEV,
"CI upper base addr 0x%x CI lower base addr 0x%x\n",
pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr,
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
scsi: pm8001: Fix some function documentation issues Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:918: warning: Function parameter or member 'number' not described in 'update_inbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:954: warning: Function parameter or member 'number' not described in 'update_outbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:1717: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_enable' drivers/scsi/pm8001/pm80xx_hwi.c:1735: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_disable' drivers/scsi/pm8001/pm80xx_hwi.c:4830: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_start_req' drivers/scsi/pm8001/pm80xx_hwi.c:4872: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_stop_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_ha' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_dev' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'flag' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phyId' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phy_op' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'phy_id' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'irq' description in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'stat' description in 'pm80xx_chip_isr' Link: https://lore.kernel.org/r/20200721164148.2617584-18-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-07-21 16:41:25 +00:00
* @number: entry in the queue
*/
static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha,
int number)
{
void __iomem *address = pm8001_ha->outbnd_q_tbl_addr;
u16 offset = number * 0x24;
pm8001_mw32(address, offset + OB_PROPERITY_OFFSET,
pm8001_ha->outbnd_q_tbl[number].element_size_cnt);
pm8001_mw32(address, offset + OB_BASE_ADDR_HI_OFFSET,
pm8001_ha->outbnd_q_tbl[number].upper_base_addr);
pm8001_mw32(address, offset + OB_BASE_ADDR_LO_OFFSET,
pm8001_ha->outbnd_q_tbl[number].lower_base_addr);
pm8001_mw32(address, offset + OB_PI_BASE_ADDR_HI_OFFSET,
pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr);
pm8001_mw32(address, offset + OB_PI_BASE_ADDR_LO_OFFSET,
pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr);
pm8001_mw32(address, offset + OB_INTERRUPT_COALES_OFFSET,
pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay);
pm8001_dbg(pm8001_ha, DEV,
"OQ %d: Element pri size 0x%x\n",
number,
pm8001_ha->outbnd_q_tbl[number].element_size_cnt);
pm8001_dbg(pm8001_ha, DEV,
"OQ upr base addr 0x%x OQ lwr base addr 0x%x\n",
pm8001_ha->outbnd_q_tbl[number].upper_base_addr,
pm8001_ha->outbnd_q_tbl[number].lower_base_addr);
pm8001_dbg(pm8001_ha, DEV,
"PI upper base addr 0x%x PI lower base addr 0x%x\n",
pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr,
pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr);
}
/**
* 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, SPCv_MSGU_CFG_TABLE_UPDATE);
/* wait until Inbound DoorBell Clear Register toggled */
if (IS_SPCV_12G(pm8001_ha->pdev)) {
max_wait_count = SPCV_DOORBELL_CLEAR_TIMEOUT;
} else {
max_wait_count = SPC_DOORBELL_CLEAR_TIMEOUT;
}
do {
msleep(FW_READY_INTERVAL);
value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
value &= SPCv_MSGU_CFG_TABLE_UPDATE;
} while ((value != 0) && (--max_wait_count));
if (!max_wait_count) {
/* additional check */
pm8001_dbg(pm8001_ha, FAIL,
"Inb doorbell clear not toggled[value:%x]\n",
value);
return -EBUSY;
}
/* check the MPI-State for initialization up to 100ms*/
max_wait_count = 5;/* 100 msec */
do {
msleep(FW_READY_INTERVAL);
gst_len_mpistate =
pm8001_mr32(pm8001_ha->general_stat_tbl_addr,
GST_GSTLEN_MPIS_OFFSET);
} while ((GST_MPI_STATE_INIT !=
(gst_len_mpistate & GST_MPI_STATE_MASK)) && (--max_wait_count));
if (!max_wait_count)
return -EBUSY;
/* check MPI Initialization error */
gst_len_mpistate = gst_len_mpistate >> 16;
if (0x0000 != gst_len_mpistate)
return -EBUSY;
/*
* As per controller datasheet, after successful MPI
* initialization minimum 500ms delay is required before
* issuing commands.
*/
msleep(500);
return 0;
}
/**
* check_fw_ready - The LLDD check if the FW is ready, if not, return error.
* This function sleeps hence it must not be used in atomic context.
* @pm8001_ha: our hba card information
*/
static int check_fw_ready(struct pm8001_hba_info *pm8001_ha)
{
u32 value;
u32 max_wait_count;
u32 max_wait_time;
u32 expected_mask;
int ret = 0;
/* reset / PCIe ready */
max_wait_time = max_wait_count = 5; /* 100 milli sec */
do {
msleep(FW_READY_INTERVAL);
value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
} while ((value == 0xFFFFFFFF) && (--max_wait_count));
/* check ila, RAAE and iops status */
if ((pm8001_ha->chip_id != chip_8008) &&
(pm8001_ha->chip_id != chip_8009)) {
max_wait_time = max_wait_count = 180; /* 3600 milli sec */
expected_mask = SCRATCH_PAD_ILA_READY |
SCRATCH_PAD_RAAE_READY |
SCRATCH_PAD_IOP0_READY |
SCRATCH_PAD_IOP1_READY;
} else {
max_wait_time = max_wait_count = 170; /* 3400 milli sec */
expected_mask = SCRATCH_PAD_ILA_READY |
SCRATCH_PAD_RAAE_READY |
SCRATCH_PAD_IOP0_READY;
}
do {
msleep(FW_READY_INTERVAL);
value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
} while (((value & expected_mask) !=
expected_mask) && (--max_wait_count));
if (!max_wait_count) {
pm8001_dbg(pm8001_ha, INIT,
"At least one FW component failed to load within %d millisec: Scratchpad1: 0x%x\n",
max_wait_time * FW_READY_INTERVAL, value);
ret = -1;
} else {
pm8001_dbg(pm8001_ha, MSG,
"All FW components ready by %d ms\n",
(max_wait_time - max_wait_count) * FW_READY_INTERVAL);
}
return ret;
}
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
static int 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, MSGU_SCRATCH_PAD_0);
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
/*
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
* lower 26 bits of SCRATCHPAD0 register describes offset within the
* PCIe BAR where the MPI configuration table is present
*/
offset = value & 0x03FFFFFF; /* scratch pad 0 TBL address */
pm8001_dbg(pm8001_ha, DEV, "Scratchpad 0 Offset: 0x%x value 0x%x\n",
offset, value);
/*
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
* Upper 6 bits describe the offset within PCI config space where BAR
* is located.
*/
pcilogic = (value & 0xFC000000) >> 26;
pcibar = get_pci_bar_index(pcilogic);
pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n", pcibar);
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
/*
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
* Make sure the offset falls inside the ioremapped PCI BAR
*/
if (offset > pm8001_ha->io_mem[pcibar].memsize) {
pm8001_dbg(pm8001_ha, FAIL,
"Main cfg tbl offset outside %u > %u\n",
offset, pm8001_ha->io_mem[pcibar].memsize);
return -EBUSY;
}
pm8001_ha->main_cfg_tbl_addr = base_addr =
pm8001_ha->io_mem[pcibar].memvirtaddr + offset;
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
/*
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
* Validate main configuration table address: first DWord should read
* "PMCS"
*/
value = pm8001_mr32(pm8001_ha->main_cfg_tbl_addr, 0);
if (memcmp(&value, "PMCS", 4) != 0) {
pm8001_dbg(pm8001_ha, FAIL,
"BAD main config signature 0x%x\n",
value);
return -EBUSY;
}
pm8001_dbg(pm8001_ha, INIT,
"VALID main config signature 0x%x\n", value);
pm8001_ha->general_stat_tbl_addr =
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x18) &
0xFFFFFF);
pm8001_ha->inbnd_q_tbl_addr =
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C) &
0xFFFFFF);
pm8001_ha->outbnd_q_tbl_addr =
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x20) &
0xFFFFFF);
pm8001_ha->ivt_tbl_addr =
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x8C) &
0xFFFFFF);
pm8001_ha->pspa_q_tbl_addr =
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) &
0xFFFFFF);
pm8001_ha->fatal_tbl_addr =
base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0xA0) &
0xFFFFFF);
pm8001_dbg(pm8001_ha, INIT, "GST OFFSET 0x%x\n",
pm8001_cr32(pm8001_ha, pcibar, offset + 0x18));
pm8001_dbg(pm8001_ha, INIT, "INBND OFFSET 0x%x\n",
pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C));
pm8001_dbg(pm8001_ha, INIT, "OBND OFFSET 0x%x\n",
pm8001_cr32(pm8001_ha, pcibar, offset + 0x20));
pm8001_dbg(pm8001_ha, INIT, "IVT OFFSET 0x%x\n",
pm8001_cr32(pm8001_ha, pcibar, offset + 0x8C));
pm8001_dbg(pm8001_ha, INIT, "PSPA OFFSET 0x%x\n",
pm8001_cr32(pm8001_ha, pcibar, offset + 0x90));
pm8001_dbg(pm8001_ha, INIT, "addr - main cfg %p general status %p\n",
pm8001_ha->main_cfg_tbl_addr,
pm8001_ha->general_stat_tbl_addr);
pm8001_dbg(pm8001_ha, INIT, "addr - inbnd %p obnd %p\n",
pm8001_ha->inbnd_q_tbl_addr,
pm8001_ha->outbnd_q_tbl_addr);
pm8001_dbg(pm8001_ha, INIT, "addr - pspa %p ivt %p\n",
pm8001_ha->pspa_q_tbl_addr,
pm8001_ha->ivt_tbl_addr);
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
return 0;
}
/**
* pm80xx_set_thermal_config - support the thermal configuration
* @pm8001_ha: our hba card information.
*/
int
pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha)
{
struct set_ctrl_cfg_req payload;
int rc;
u32 tag;
u32 opc = OPC_INB_SET_CONTROLLER_CONFIG;
u32 page_code;
memset(&payload, 0, sizeof(struct set_ctrl_cfg_req));
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc)
return rc;
payload.tag = cpu_to_le32(tag);
if (IS_SPCV_12G(pm8001_ha->pdev))
page_code = THERMAL_PAGE_CODE_7H;
else
page_code = THERMAL_PAGE_CODE_8H;
payload.cfg_pg[0] =
cpu_to_le32((THERMAL_LOG_ENABLE << 9) |
(THERMAL_ENABLE << 8) | page_code);
payload.cfg_pg[1] =
cpu_to_le32((LTEMPHIL << 24) | (RTEMPHIL << 8));
pm8001_dbg(pm8001_ha, DEV,
"Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n",
payload.cfg_pg[0], payload.cfg_pg[1]);
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
sizeof(payload), 0);
if (rc)
pm8001_tag_free(pm8001_ha, tag);
return rc;
}
/**
* pm80xx_set_sas_protocol_timer_config - support the SAS Protocol
* Timer configuration page
* @pm8001_ha: our hba card information.
*/
static int
pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha)
{
struct set_ctrl_cfg_req payload;
SASProtocolTimerConfig_t SASConfigPage;
int rc;
u32 tag;
u32 opc = OPC_INB_SET_CONTROLLER_CONFIG;
memset(&payload, 0, sizeof(struct set_ctrl_cfg_req));
memset(&SASConfigPage, 0, sizeof(SASProtocolTimerConfig_t));
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc)
return rc;
payload.tag = cpu_to_le32(tag);
SASConfigPage.pageCode = cpu_to_le32(SAS_PROTOCOL_TIMER_CONFIG_PAGE);
SASConfigPage.MST_MSI = cpu_to_le32(3 << 15);
SASConfigPage.STP_SSP_MCT_TMO =
cpu_to_le32((STP_MCT_TMO << 16) | SSP_MCT_TMO);
SASConfigPage.STP_FRM_TMO =
cpu_to_le32((SAS_MAX_OPEN_TIME << 24) |
(SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER);
SASConfigPage.STP_IDLE_TMO = cpu_to_le32(STP_IDLE_TIME);
SASConfigPage.OPNRJT_RTRY_INTVL =
cpu_to_le32((SAS_MFD << 16) | SAS_OPNRJT_RTRY_INTVL);
SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO =
cpu_to_le32((SAS_DOPNRJT_RTRY_TMO << 16) | SAS_COPNRJT_RTRY_TMO);
SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR =
cpu_to_le32((SAS_DOPNRJT_RTRY_THR << 16) | SAS_COPNRJT_RTRY_THR);
SASConfigPage.MAX_AIP = cpu_to_le32(SAS_MAX_AIP);
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.pageCode 0x%08x\n",
le32_to_cpu(SASConfigPage.pageCode));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MST_MSI 0x%08x\n",
le32_to_cpu(SASConfigPage.MST_MSI));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_SSP_MCT_TMO 0x%08x\n",
le32_to_cpu(SASConfigPage.STP_SSP_MCT_TMO));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_FRM_TMO 0x%08x\n",
le32_to_cpu(SASConfigPage.STP_FRM_TMO));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_IDLE_TMO 0x%08x\n",
le32_to_cpu(SASConfigPage.STP_IDLE_TMO));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.OPNRJT_RTRY_INTVL 0x%08x\n",
le32_to_cpu(SASConfigPage.OPNRJT_RTRY_INTVL));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO 0x%08x\n",
le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR 0x%08x\n",
le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR));
pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MAX_AIP 0x%08x\n",
le32_to_cpu(SASConfigPage.MAX_AIP));
memcpy(&payload.cfg_pg, &SASConfigPage,
sizeof(SASProtocolTimerConfig_t));
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
sizeof(payload), 0);
if (rc)
pm8001_tag_free(pm8001_ha, tag);
return rc;
}
/**
* pm80xx_get_encrypt_info - Check for encryption
* @pm8001_ha: our hba card information.
*/
static int
pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha)
{
u32 scratch3_value;
int ret = -1;
/* Read encryption status from SCRATCH PAD 3 */
scratch3_value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) ==
SCRATCH_PAD3_ENC_READY) {
if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED)
pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMF_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMA_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMB_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB;
pm8001_ha->encrypt_info.status = 0;
pm8001_dbg(pm8001_ha, INIT,
"Encryption: SCRATCH_PAD3_ENC_READY 0x%08X.Cipher mode 0x%x Sec mode 0x%x status 0x%x\n",
scratch3_value,
pm8001_ha->encrypt_info.cipher_mode,
pm8001_ha->encrypt_info.sec_mode,
pm8001_ha->encrypt_info.status);
ret = 0;
} else if ((scratch3_value & SCRATCH_PAD3_ENC_READY) ==
SCRATCH_PAD3_ENC_DISABLED) {
pm8001_dbg(pm8001_ha, INIT,
"Encryption: SCRATCH_PAD3_ENC_DISABLED 0x%08X\n",
scratch3_value);
pm8001_ha->encrypt_info.status = 0xFFFFFFFF;
pm8001_ha->encrypt_info.cipher_mode = 0;
pm8001_ha->encrypt_info.sec_mode = 0;
ret = 0;
} else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) ==
SCRATCH_PAD3_ENC_DIS_ERR) {
pm8001_ha->encrypt_info.status =
(scratch3_value & SCRATCH_PAD3_ERR_CODE) >> 16;
if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED)
pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMF_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMA_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMB_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB;
pm8001_dbg(pm8001_ha, INIT,
"Encryption: SCRATCH_PAD3_DIS_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n",
scratch3_value,
pm8001_ha->encrypt_info.cipher_mode,
pm8001_ha->encrypt_info.sec_mode,
pm8001_ha->encrypt_info.status);
} else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) ==
SCRATCH_PAD3_ENC_ENA_ERR) {
pm8001_ha->encrypt_info.status =
(scratch3_value & SCRATCH_PAD3_ERR_CODE) >> 16;
if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED)
pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMF_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMA_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA;
if ((scratch3_value & SCRATCH_PAD3_SM_MASK) ==
SCRATCH_PAD3_SMB_ENABLED)
pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB;
pm8001_dbg(pm8001_ha, INIT,
"Encryption: SCRATCH_PAD3_ENA_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n",
scratch3_value,
pm8001_ha->encrypt_info.cipher_mode,
pm8001_ha->encrypt_info.sec_mode,
pm8001_ha->encrypt_info.status);
}
return ret;
}
/**
* pm80xx_encrypt_update - update flash with encryption information
* @pm8001_ha: our hba card information.
*/
static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha)
{
struct kek_mgmt_req payload;
int rc;
u32 tag;
u32 opc = OPC_INB_KEK_MANAGEMENT;
memset(&payload, 0, sizeof(struct kek_mgmt_req));
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc)
return rc;
payload.tag = cpu_to_le32(tag);
/* Currently only one key is used. New KEK index is 1.
* Current KEK index is 1. Store KEK to NVRAM is 1.
*/
payload.new_curidx_ksop =
cpu_to_le32(((1 << 24) | (1 << 16) | (1 << 8) |
KEK_MGMT_SUBOP_KEYCARDUPDATE));
pm8001_dbg(pm8001_ha, DEV,
"Saving Encryption info to flash. payload 0x%x\n",
le32_to_cpu(payload.new_curidx_ksop));
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
sizeof(payload), 0);
if (rc)
pm8001_tag_free(pm8001_ha, tag);
return rc;
}
/**
* pm80xx_chip_init - the main init function that initializes whole PM8001 chip.
* @pm8001_ha: our hba card information
*/
static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha)
{
int ret;
u8 i = 0;
/* check the firmware status */
if (-1 == check_fw_ready(pm8001_ha)) {
pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n");
return -EBUSY;
}
/* Initialize the controller fatal error flag */
pm8001_ha->controller_fatal_error = false;
/* Initialize pci space address eg: mpi offset */
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
ret = init_pci_device_addresses(pm8001_ha);
if (ret) {
pm8001_dbg(pm8001_ha, FAIL,
"Failed to init pci addresses");
return ret;
}
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);
read_phy_attr_table(pm8001_ha);
/* update main config table ,inbound table and outbound table */
update_main_config_table(pm8001_ha);
for (i = 0; i < pm8001_ha->max_q_num; i++) {
update_inbnd_queue_table(pm8001_ha, i);
update_outbnd_queue_table(pm8001_ha, i);
}
/* notify firmware update finished and check initialization status */
if (0 == mpi_init_check(pm8001_ha)) {
pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n");
} else
return -EBUSY;
return 0;
}
static void pm80xx_chip_post_init(struct pm8001_hba_info *pm8001_ha)
{
/* send SAS protocol timer configuration page to FW */
pm80xx_set_sas_protocol_timer_config(pm8001_ha);
/* Check for encryption */
if (pm8001_ha->chip->encrypt) {
int ret;
pm8001_dbg(pm8001_ha, INIT, "Checking for encryption\n");
ret = pm80xx_get_encrypt_info(pm8001_ha);
if (ret == -1) {
pm8001_dbg(pm8001_ha, INIT, "Encryption error !!\n");
if (pm8001_ha->encrypt_info.status == 0x81) {
pm8001_dbg(pm8001_ha, INIT,
"Encryption enabled with error.Saving encryption key to flash\n");
pm80xx_encrypt_update(pm8001_ha);
}
}
}
}
static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha)
{
u32 max_wait_count;
u32 value;
u32 gst_len_mpistate;
scsi: pm80xx: Check main config table address The driver initializes main configuration, general status, inbound queue and outbound queue table addresses based on a value read from MSGU_SCRATCH_PAD_0 register. We should validate these addresses before dereferencing them. Adds two validations: 1. Check if main configuration table offset lies within the pcibar mapped 2. Check if first dword of main configuration table reads "PMCS" There are two calls to init_pci_device_addresses() done during pm8001_pci_probe() in this sequence: 1. First inside chip_soft_rst, where if init_pci_device_addresses fails we will go ahead assuming MPI state is not ready and reset the device as long as bootloader is okay. This gives chance to second call of init_pci_device_addresses to set up the addresses after reset. 2. The second call is via pm80xx_chip_init, after soft reset is done and firmware is checked to be ready. Once that is done we are safe to go ahead and initialize default table values and use them. Tests: 1. Enabled debugging logs and observed no issues during initialization, with a controller with no issues: pm80xx0:: pm8001_setup_msix 1034: pci_alloc_irq_vectors request ret:64 no of intr 64 pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_soft_rst 1446: reset register before write : 0x0 pm80xx0:: pm80xx_chip_soft_rst 1478: reset register after write 0x40 pm80xx0:: pm80xx_chip_soft_rst 1544: SPCv soft reset Complete pm80xx0:: init_pci_device_addresses 917: Scratchpad 0 Offset: 0x2000 value 0x40002000 pm80xx0:: init_pci_device_addresses 925: Scratchpad 0 PCI BAR: 0 pm80xx0:: init_pci_device_addresses 952: VALID main config signature 0x53434d50 pm80xx0:: init_pci_device_addresses 975: GST OFFSET 0xc4 pm80xx0:: init_pci_device_addresses 978: INBND OFFSET 0x20000128 pm80xx0:: init_pci_device_addresses 981: OBND OFFSET 0x24000928 pm80xx0:: init_pci_device_addresses 984: IVT OFFSET 0x8001408 pm80xx0:: init_pci_device_addresses 987: PSPA OFFSET 0x8001608 pm80xx0:: init_pci_device_addresses 991: addr - main cfg (ptrval) general status (ptrval) pm80xx0:: init_pci_device_addresses 995: addr - inbnd (ptrval) obnd (ptrval) pm80xx0:: init_pci_device_addresses 999: addr - pspa (ptrval) ivt (ptrval) pm80xx0:: pm80xx_chip_init 1329: MPI initialize successful! 2. Tested controller with firmware known to have initialization issue and observed no crashes with this fix: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings pm80xx0:: init_pci_device_addresses 948: BAD main config signature 0x0 pm80xx0:: mpi_uninit_check 1365: Failed to init pci addresses pm80xx0:: pm80xx_chip_soft_rst 1435: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1518: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1532: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1301: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1215: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 pm80xx 0000:07:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:07:00.0: Removing from 1:1 domain pm80xx 0000:07:00.0: Requesting non-1:1 mappings scsi host6: pm80xx pm80xx1:: pm8001_setup_sgpio 5568: failed sgpio_req timeout pm80xx1:: mpi_phy_start_resp 3447: phy start resp status:0x0, phyid:0x0 pm80xx 0000:08:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:08:00.0: Removing from 1:1 domain pm80xx 0000:08:00.0: Requesting non-1:1 mappings 3. Without this fix we observe crash on the same controller: pm80xx 0000:01:00.0: pm80xx: driver version 0.1.38 pm80xx 0000:01:00.0: Removing from 1:1 domain pm80xx 0000:01:00.0: Requesting non-1:1 mappings [<ffffffffc0451b3b>] pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] RIP: 0010:pm80xx_chip_soft_rst+0x71/0x4c0 [pm80xx] [<ffffffffc0451b3b>] ? pm80xx_chip_soft_rst+0x6b/0x4c0 [pm80xx] [<ffffffffc043a933>] pm8001_pci_probe+0xa43/0x1630 [pm80xx] pm80xx0:: mpi_uninit_check 1339: TIMEOUT:IBDB value/=2 pm80xx0:: pm80xx_chip_soft_rst 1387: MPI state is not ready scratch:0:8:62a01000:0 pm80xx0:: pm80xx_chip_soft_rst 1470: Firmware is not ready! pm80xx0:: pm80xx_chip_soft_rst 1484: iButton Feature is not Available!!! pm80xx0:: pm80xx_chip_init 1266: Firmware is not ready! pm80xx0:: pm8001_pci_probe 1207: chip_init failed [ret: -16] pm80xx: probe of 0000:01:00.0 failed with error -16 Link: https://lore.kernel.org/r/20210109123849.17098-4-Viswas.G@microchip.com Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: akshatzen <akshatzen@google.com> Signed-off-by: Viswas G <Viswas.G@microchip.com> Signed-off-by: Ruksar Devadi <Ruksar.devadi@microchip.com> Signed-off-by: Radha Ramachandran <radha@google.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-01-09 12:38:44 +00:00
int ret;
ret = init_pci_device_addresses(pm8001_ha);
if (ret) {
pm8001_dbg(pm8001_ha, FAIL,
"Failed to init pci addresses");
return ret;
}
/* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the
table is stop */
pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_RESET);
/* wait until Inbound DoorBell Clear Register toggled */
if (IS_SPCV_12G(pm8001_ha->pdev)) {
max_wait_count = SPCV_DOORBELL_CLEAR_TIMEOUT;
} else {
max_wait_count = SPC_DOORBELL_CLEAR_TIMEOUT;
}
do {
msleep(FW_READY_INTERVAL);
value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET);
value &= SPCv_MSGU_CFG_TABLE_RESET;
} while ((value != 0) && (--max_wait_count));
if (!max_wait_count) {
pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=%x\n", value);
return -1;
}
/* check the MPI-State for termination in progress */
/* wait until Inbound DoorBell Clear Register toggled */
max_wait_count = 100; /* 2 sec for spcv/ve */
do {
msleep(FW_READY_INTERVAL);
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) {
pm8001_dbg(pm8001_ha, FAIL, " TIME OUT MPI State = 0x%x\n",
gst_len_mpistate & GST_MPI_STATE_MASK);
return -1;
}
return 0;
}
/**
* pm80xx_fatal_errors - returns non-zero *ONLY* when fatal errors
* @pm8001_ha: our hba card information
*
* Fatal errors are recoverable only after a host reboot.
*/
int
pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha)
{
int ret = 0;
u32 scratch_pad_rsvd0 = pm8001_cr32(pm8001_ha, 0,
MSGU_SCRATCH_PAD_RSVD_0);
u32 scratch_pad_rsvd1 = pm8001_cr32(pm8001_ha, 0,
MSGU_SCRATCH_PAD_RSVD_1);
u32 scratch_pad1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
u32 scratch_pad2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
u32 scratch_pad3 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
if (pm8001_ha->chip_id != chip_8006 &&
pm8001_ha->chip_id != chip_8074 &&
pm8001_ha->chip_id != chip_8076) {
return 0;
}
if (MSGU_SCRATCHPAD1_STATE_FATAL_ERROR(scratch_pad1)) {
pm8001_dbg(pm8001_ha, FAIL,
"Fatal error SCRATCHPAD1 = 0x%x SCRATCHPAD2 = 0x%x SCRATCHPAD3 = 0x%x SCRATCHPAD_RSVD0 = 0x%x SCRATCHPAD_RSVD1 = 0x%x\n",
scratch_pad1, scratch_pad2, scratch_pad3,
scratch_pad_rsvd0, scratch_pad_rsvd1);
ret = 1;
}
return ret;
}
/**
* pm80xx_chip_soft_rst - soft reset the PM8001 chip, so that all
* FW register status are reset to the originated status.
* @pm8001_ha: our hba card information
*/
static int
pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
{
u32 regval;
u32 bootloader_state;
u32 ibutton0, ibutton1;
/* Process MPI table uninitialization only if FW is ready */
if (!pm8001_ha->controller_fatal_error) {
/* Check if MPI is in ready state to reset */
if (mpi_uninit_check(pm8001_ha) != 0) {
u32 r0 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
u32 r1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
u32 r2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
u32 r3 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
pm8001_dbg(pm8001_ha, FAIL,
"MPI state is not ready scratch: %x:%x:%x:%x\n",
r0, r1, r2, r3);
/* if things aren't ready but the bootloader is ok then
* try the reset anyway.
*/
if (r1 & SCRATCH_PAD1_BOOTSTATE_MASK)
return -1;
}
}
/* checked for reset register normal state; 0x0 */
regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET);
pm8001_dbg(pm8001_ha, INIT, "reset register before write : 0x%x\n",
regval);
pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, SPCv_NORMAL_RESET_VALUE);
msleep(500);
regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET);
pm8001_dbg(pm8001_ha, INIT, "reset register after write 0x%x\n",
regval);
if ((regval & SPCv_SOFT_RESET_READ_MASK) ==
SPCv_SOFT_RESET_NORMAL_RESET_OCCURED) {
pm8001_dbg(pm8001_ha, MSG,
" soft reset successful [regval: 0x%x]\n",
regval);
} else {
pm8001_dbg(pm8001_ha, MSG,
" soft reset failed [regval: 0x%x]\n",
regval);
/* check bootloader is successfully executed or in HDA mode */
bootloader_state =
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) &
SCRATCH_PAD1_BOOTSTATE_MASK;
if (bootloader_state == SCRATCH_PAD1_BOOTSTATE_HDA_SEEPROM) {
pm8001_dbg(pm8001_ha, MSG,
"Bootloader state - HDA mode SEEPROM\n");
} else if (bootloader_state ==
SCRATCH_PAD1_BOOTSTATE_HDA_BOOTSTRAP) {
pm8001_dbg(pm8001_ha, MSG,
"Bootloader state - HDA mode Bootstrap Pin\n");
} else if (bootloader_state ==
SCRATCH_PAD1_BOOTSTATE_HDA_SOFTRESET) {
pm8001_dbg(pm8001_ha, MSG,
"Bootloader state - HDA mode soft reset\n");
} else if (bootloader_state ==
SCRATCH_PAD1_BOOTSTATE_CRIT_ERROR) {
pm8001_dbg(pm8001_ha, MSG,
"Bootloader state-HDA mode critical error\n");
}
return -EBUSY;
}
/* check the firmware status after reset */
if (-1 == check_fw_ready(pm8001_ha)) {
pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n");
/* check iButton feature support for motherboard controller */
if (pm8001_ha->pdev->subsystem_vendor !=
PCI_VENDOR_ID_ADAPTEC2 &&
pm8001_ha->pdev->subsystem_vendor !=
PCI_VENDOR_ID_ATTO &&
pm8001_ha->pdev->subsystem_vendor != 0) {
ibutton0 = pm8001_cr32(pm8001_ha, 0,
MSGU_SCRATCH_PAD_RSVD_0);
ibutton1 = pm8001_cr32(pm8001_ha, 0,
MSGU_SCRATCH_PAD_RSVD_1);
if (!ibutton0 && !ibutton1) {
pm8001_dbg(pm8001_ha, FAIL,
"iButton Feature is not Available!!!\n");
return -EBUSY;
}
if (ibutton0 == 0xdeadbeef && ibutton1 == 0xdeadbeef) {
pm8001_dbg(pm8001_ha, FAIL,
"CRC Check for iButton Feature Failed!!!\n");
return -EBUSY;
}
}
}
pm8001_dbg(pm8001_ha, INIT, "SPCv soft reset Complete\n");
return 0;
}
static void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha)
{
u32 i;
pm8001_dbg(pm8001_ha, INIT, "chip reset start\n");
/* do SPCv chip reset. */
pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, 0x11);
pm8001_dbg(pm8001_ha, INIT, "SPC soft reset Complete\n");
/* Check this ..whether delay is required or no */
/* delay 10 usec */
udelay(10);
/* wait for 20 msec until the firmware gets reloaded */
i = 20;
do {
mdelay(1);
} while ((--i) != 0);
pm8001_dbg(pm8001_ha, INIT, "chip reset finished\n");
}
/**
scsi: pm8001: Fix a bunch of doc-rotted function headers Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:1427: warning: expecting prototype for pm8001_chip_init(). Prototype was for pm80xx_chip_init() instead drivers/scsi/pm8001/pm80xx_hwi.c:1584: warning: expecting prototype for pm8001_chip_soft_rst(). Prototype was for pm80xx_chip_soft_rst() instead drivers/scsi/pm8001/pm80xx_hwi.c:1711: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_intx_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1722: warning: expecting prototype for pm8001_chip_intx_interrupt_disable(). Prototype was for pm80xx_chip_intx_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1733: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1752: warning: expecting prototype for pm8001_chip_interrupt_disable(). Prototype was for pm80xx_chip_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:4192: warning: expecting prototype for pm8001_chip_smp_req(). Prototype was for pm80xx_chip_smp_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4775: warning: expecting prototype for pm8001_chip_phy_stop_req(). Prototype was for pm80xx_chip_phy_stop_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4907: warning: expecting prototype for pm8001_chip_isr(). Prototype was for pm80xx_chip_isr() instead Link: https://lore.kernel.org/r/20210303144631.3175331-23-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Cc: "James E.J. Bottomley" <jejb@linux.ibm.com> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Cc: linux-scsi@vger.kernel.org Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-03 14:46:23 +00:00
* pm80xx_chip_intx_interrupt_enable - enable PM8001 chip interrupt
* @pm8001_ha: our hba card information
*/
static void
pm80xx_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);
}
/**
scsi: pm8001: Fix a bunch of doc-rotted function headers Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:1427: warning: expecting prototype for pm8001_chip_init(). Prototype was for pm80xx_chip_init() instead drivers/scsi/pm8001/pm80xx_hwi.c:1584: warning: expecting prototype for pm8001_chip_soft_rst(). Prototype was for pm80xx_chip_soft_rst() instead drivers/scsi/pm8001/pm80xx_hwi.c:1711: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_intx_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1722: warning: expecting prototype for pm8001_chip_intx_interrupt_disable(). Prototype was for pm80xx_chip_intx_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1733: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1752: warning: expecting prototype for pm8001_chip_interrupt_disable(). Prototype was for pm80xx_chip_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:4192: warning: expecting prototype for pm8001_chip_smp_req(). Prototype was for pm80xx_chip_smp_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4775: warning: expecting prototype for pm8001_chip_phy_stop_req(). Prototype was for pm80xx_chip_phy_stop_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4907: warning: expecting prototype for pm8001_chip_isr(). Prototype was for pm80xx_chip_isr() instead Link: https://lore.kernel.org/r/20210303144631.3175331-23-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Cc: "James E.J. Bottomley" <jejb@linux.ibm.com> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Cc: linux-scsi@vger.kernel.org Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-03 14:46:23 +00:00
* pm80xx_chip_intx_interrupt_disable - disable PM8001 chip interrupt
* @pm8001_ha: our hba card information
*/
static void
pm80xx_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha)
{
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR, ODMR_MASK_ALL);
}
/**
scsi: pm8001: Fix a bunch of doc-rotted function headers Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:1427: warning: expecting prototype for pm8001_chip_init(). Prototype was for pm80xx_chip_init() instead drivers/scsi/pm8001/pm80xx_hwi.c:1584: warning: expecting prototype for pm8001_chip_soft_rst(). Prototype was for pm80xx_chip_soft_rst() instead drivers/scsi/pm8001/pm80xx_hwi.c:1711: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_intx_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1722: warning: expecting prototype for pm8001_chip_intx_interrupt_disable(). Prototype was for pm80xx_chip_intx_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1733: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1752: warning: expecting prototype for pm8001_chip_interrupt_disable(). Prototype was for pm80xx_chip_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:4192: warning: expecting prototype for pm8001_chip_smp_req(). Prototype was for pm80xx_chip_smp_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4775: warning: expecting prototype for pm8001_chip_phy_stop_req(). Prototype was for pm80xx_chip_phy_stop_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4907: warning: expecting prototype for pm8001_chip_isr(). Prototype was for pm80xx_chip_isr() instead Link: https://lore.kernel.org/r/20210303144631.3175331-23-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Cc: "James E.J. Bottomley" <jejb@linux.ibm.com> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Cc: linux-scsi@vger.kernel.org Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-03 14:46:23 +00:00
* pm80xx_chip_interrupt_enable - enable PM8001 chip interrupt
* @pm8001_ha: our hba card information
scsi: pm8001: Fix some function documentation issues Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:918: warning: Function parameter or member 'number' not described in 'update_inbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:954: warning: Function parameter or member 'number' not described in 'update_outbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:1717: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_enable' drivers/scsi/pm8001/pm80xx_hwi.c:1735: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_disable' drivers/scsi/pm8001/pm80xx_hwi.c:4830: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_start_req' drivers/scsi/pm8001/pm80xx_hwi.c:4872: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_stop_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_ha' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_dev' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'flag' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phyId' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phy_op' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'phy_id' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'irq' description in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'stat' description in 'pm80xx_chip_isr' Link: https://lore.kernel.org/r/20200721164148.2617584-18-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-07-21 16:41:25 +00:00
* @vec: interrupt number to enable
*/
static void
pm80xx_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
#ifdef PM8001_USE_MSIX
if (vec < 32)
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR, 1U << vec);
else
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_CLR_U,
1U << (vec - 32));
return;
#endif
pm80xx_chip_intx_interrupt_enable(pm8001_ha);
}
/**
scsi: pm8001: Fix a bunch of doc-rotted function headers Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:1427: warning: expecting prototype for pm8001_chip_init(). Prototype was for pm80xx_chip_init() instead drivers/scsi/pm8001/pm80xx_hwi.c:1584: warning: expecting prototype for pm8001_chip_soft_rst(). Prototype was for pm80xx_chip_soft_rst() instead drivers/scsi/pm8001/pm80xx_hwi.c:1711: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_intx_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1722: warning: expecting prototype for pm8001_chip_intx_interrupt_disable(). Prototype was for pm80xx_chip_intx_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1733: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1752: warning: expecting prototype for pm8001_chip_interrupt_disable(). Prototype was for pm80xx_chip_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:4192: warning: expecting prototype for pm8001_chip_smp_req(). Prototype was for pm80xx_chip_smp_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4775: warning: expecting prototype for pm8001_chip_phy_stop_req(). Prototype was for pm80xx_chip_phy_stop_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4907: warning: expecting prototype for pm8001_chip_isr(). Prototype was for pm80xx_chip_isr() instead Link: https://lore.kernel.org/r/20210303144631.3175331-23-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Cc: "James E.J. Bottomley" <jejb@linux.ibm.com> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Cc: linux-scsi@vger.kernel.org Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-03 14:46:23 +00:00
* pm80xx_chip_interrupt_disable - disable PM8001 chip interrupt
* @pm8001_ha: our hba card information
scsi: pm8001: Fix some function documentation issues Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:918: warning: Function parameter or member 'number' not described in 'update_inbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:954: warning: Function parameter or member 'number' not described in 'update_outbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:1717: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_enable' drivers/scsi/pm8001/pm80xx_hwi.c:1735: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_disable' drivers/scsi/pm8001/pm80xx_hwi.c:4830: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_start_req' drivers/scsi/pm8001/pm80xx_hwi.c:4872: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_stop_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_ha' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_dev' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'flag' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phyId' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phy_op' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'phy_id' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'irq' description in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'stat' description in 'pm80xx_chip_isr' Link: https://lore.kernel.org/r/20200721164148.2617584-18-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-07-21 16:41:25 +00:00
* @vec: interrupt number to disable
*/
static void
pm80xx_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
#ifdef PM8001_USE_MSIX
if (vec == 0xFF) {
/* disable all vectors 0-31, 32-63 */
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, 0xFFFFFFFF);
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_U, 0xFFFFFFFF);
} else if (vec < 32)
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, 1U << vec);
else
pm8001_cw32(pm8001_ha, 0, MSGU_ODMR_U,
1U << (vec - 32));
return;
#endif
pm80xx_chip_intx_interrupt_disable(pm8001_ha);
}
/**
* 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 representing
* that he has finished the job; please check the corresponding buffer.
* So we will tell the caller who maybe waiting the result to tell upper layer
* that the task has been finished.
*/
static void
mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
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];
if ((status == IO_ABORTED) && ccb->open_retry) {
/* Being completed by another */
ccb->open_retry = 0;
return;
}
pm8001_dev = ccb->device;
param = le32_to_cpu(psspPayload->param);
t = ccb->task;
if (status && status != IO_UNDERFLOW)
pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", status);
if (unlikely(!t || !t->lldd_task || !t->dev))
return;
ts = &t->task_status;
pm8001_dbg(pm8001_ha, DEV,
"tag::0x%x, status::0x%x task::0x%p\n", tag, status, t);
/* Print sas address of IO failed device */
if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
(status != IO_UNDERFLOW))
pm8001_dbg(pm8001_ha, FAIL, "SAS Address of IO Failure Drive:%016llx\n",
SAS_ADDR(t->dev->sas_addr));
switch (status) {
case IO_SUCCESS:
pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS ,param = 0x%x\n",
param);
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_SAM_STAT_GOOD;
} 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)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_ABORTED:
pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_ABORTED_TASK;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_UNDERFLOW:
/* SSP Completion with error */
pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW ,param = 0x%x\n",
param);
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_UNDERRUN;
ts->residual = param;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_NO_DEVICE:
pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_PHY_DOWN;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
/* Force the midlayer to retry */
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_PHY_NOT_READY:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_INVALID_SSP_RSP_FRAME:
pm8001_dbg(pm8001_ha, IO,
"IO_XFER_ERROR_INVALID_SSP_RSP_FRAME\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_EPROTO;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_UNKNOWN;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_BAD_DEST;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_CONN_RATE;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_NAK_RECEIVED:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_NAK_R_ERR;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_DMA:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_OPEN_RETRY_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_OFFSET_MISMATCH:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_PORT_IN_RESET:
pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_DS_NON_OPERATIONAL:
pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
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:
pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_TM_TAG_NOT_FOUND:
pm8001_dbg(pm8001_ha, IO, "IO_TM_TAG_NOT_FOUND\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_SSP_EXT_IU_ZERO_LEN_ERROR:
pm8001_dbg(pm8001_ha, IO, "IO_SSP_EXT_IU_ZERO_LEN_ERROR\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
default:
pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
/* not allowed case. Therefore, return failed status */
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
}
pm8001_dbg(pm8001_ha, IO, "scsi_status = 0x%x\n ",
psspPayload->ssp_resp_iu.status);
spin_lock_irqsave(&t->task_state_lock, flags);
t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
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);
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);
pm8001_ccb_task_free(pm8001_ha, ccb);
if (t->slow_task)
complete(&t->slow_task->completion);
} else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
}
}
/*See the comments for mpi_ssp_completion */
static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
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);
ccb = &pm8001_ha->ccb_info[tag];
t = ccb->task;
pm8001_dev = ccb->device;
if (event)
pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n", event);
if (unlikely(!t || !t->lldd_task || !t->dev))
return;
ts = &t->task_status;
pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n",
port_id, tag, event);
switch (event) {
case IO_OVERFLOW:
pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
ts->residual = 0;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK);
return;
case IO_XFER_ERROR_PHY_NOT_READY:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_UNKNOWN;
break;
case IO_OPEN_CNX_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
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:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
break;
case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_NAK_R_ERR;
break;
case IO_XFER_OPEN_RETRY_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT);
return;
case IO_XFER_ERROR_UNEXPECTED_PHASE:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
case IO_XFER_ERROR_XFER_RDY_OVERRUN:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
pm8001_dbg(pm8001_ha, IO,
"IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT:
pm8001_dbg(pm8001_ha, IO,
"IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
case IO_XFER_ERROR_OFFSET_MISMATCH:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
pm8001_dbg(pm8001_ha, IO,
"IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
case IO_XFER_ERROR_INTERNAL_CRC_ERROR:
pm8001_dbg(pm8001_ha, IOERR,
"IO_XFR_ERROR_INTERNAL_CRC_ERROR\n");
/* TBC: used default set values */
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
break;
case IO_XFER_CMD_FRAME_ISSUED:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n");
return;
default:
pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", event);
/* 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_STATE_DONE;
if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
spin_unlock_irqrestore(&t->task_state_lock, flags);
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);
pm8001_ccb_task_free(pm8001_ha, ccb);
} else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
}
}
/*See the comments for mpi_ssp_completion */
static void
mpi_sata_completion(struct pm8001_hba_info *pm8001_ha,
struct outbound_queue_table *circularQ, void *piomb)
{
struct sas_task *t;
struct pm8001_ccb_info *ccb;
u32 param;
u32 status;
u32 tag;
int i, j;
u8 sata_addr_low[4];
u32 temp_sata_addr_low, temp_sata_addr_hi;
u8 sata_addr_hi[4];
struct sata_completion_resp *psataPayload;
struct task_status_struct *ts;
struct ata_task_resp *resp ;
u32 *sata_resp;
struct pm8001_device *pm8001_dev;
unsigned long flags;
psataPayload = (struct sata_completion_resp *)(piomb + 4);
status = le32_to_cpu(psataPayload->status);
param = le32_to_cpu(psataPayload->param);
tag = le32_to_cpu(psataPayload->tag);
ccb = &pm8001_ha->ccb_info[tag];
t = ccb->task;
pm8001_dev = ccb->device;
if (t) {
if (t->dev && (t->dev->lldd_dev))
pm8001_dev = t->dev->lldd_dev;
} else {
pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n",
ccb->ccb_tag);
pm8001_ccb_free(pm8001_ha, ccb);
return;
}
scsi: pm8001: Use sas_ata_device_link_abort() to handle NCQ errors In commit c6b9ef5779c3 ("[SCSI] pm80xx: NCQ error handling changes") the driver had support added to handle NCQ errors but much of what is done in this handling is duplicated from the libata EH. In that named commit we handle in 2x main steps: a. Issue read log ext10 to examine and clear the errors b. Issue SATA_ABORT all command Indeed, in libata EH, we do similar to above: a. ata_do_eh() -> ata_eh_autopsy() -> ata_eh_link_autopsy() -> ata_eh_analyze_ncq_error() -> ata_eh_read_log_10h() b. ata_do_eh() -> ata_eh_recover() which will issue a device soft reset or hard reset Since there is so much duplication, use sas_ata_device_link_abort() which will abort all pending IOs and kick of ATA EH which will do the steps, above. However we will not follow the advisory to send the SATA_ABORT all command after the autopsy in read log ext10. Indeed, in libsas EH, we already send a per-task SATA_ABORT command, and this is prior to the ATA EH kicking in and issuing the read log ext10 in the recovery process. I judge that this is ok as the SATA_ABORT command does not actually send any protocol on the link to abort I/O on the other side, so would not change any state on the disk (for the read log ext10 command). Signed-off-by: John Garry <john.garry@huawei.com> Link: https://lore.kernel.org/r/1665998435-199946-7-git-send-email-john.garry@huawei.com Tested-by: Damien Le Moal <damien.lemoal@opensource.wdc.com> Tested-by: Niklas Cassel <niklas.cassel@wdc.com> # pm80xx Acked-by: Jack Wang <jinpu.wang@ionos.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-10-17 09:20:33 +00:00
if (pm8001_dev && unlikely(!t->lldd_task || !t->dev))
return;
ts = &t->task_status;
if (status != IO_SUCCESS) {
pm8001_dbg(pm8001_ha, FAIL,
"IO failed device_id %u status 0x%x tag %d\n",
pm8001_dev->device_id, status, tag);
}
/* Print sas address of IO failed device */
if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) &&
(status != IO_UNDERFLOW)) {
if (!((t->dev->parent) &&
(dev_is_expander(t->dev->parent->dev_type)))) {
for (i = 0, j = 4; i <= 3 && j <= 7; i++, j++)
sata_addr_low[i] = pm8001_ha->sas_addr[j];
for (i = 0, j = 0; i <= 3 && j <= 3; i++, j++)
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);
pm8001_dbg(pm8001_ha, FAIL,
"SAS Address of IO Failure Drive:%08x%08x\n",
temp_sata_addr_hi,
temp_sata_addr_low);
} else {
pm8001_dbg(pm8001_ha, FAIL,
"SAS Address of IO Failure Drive:%016llx\n",
SAS_ADDR(t->dev->sas_addr));
}
}
switch (status) {
case IO_SUCCESS:
pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
if (param == 0) {
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_SAM_STAT_GOOD;
} else {
u8 len;
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_PROTO_RESPONSE;
ts->residual = param;
pm8001_dbg(pm8001_ha, IO,
"SAS_PROTO_RESPONSE len = %d\n",
param);
sata_resp = &psataPayload->sata_resp[0];
resp = (struct ata_task_resp *)ts->buf;
if (t->ata_task.dma_xfer == 0 &&
t->data_dir == DMA_FROM_DEVICE) {
len = sizeof(struct pio_setup_fis);
pm8001_dbg(pm8001_ha, IO,
"PIO read len = %d\n", len);
} else if (t->ata_task.use_ncq &&
t->data_dir != DMA_NONE) {
len = sizeof(struct set_dev_bits_fis);
pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n",
len);
} else {
len = sizeof(struct dev_to_host_fis);
pm8001_dbg(pm8001_ha, IO, "other len = %d\n",
len);
}
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
pm8001_dbg(pm8001_ha, IO,
"response too large\n");
}
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_ABORTED:
pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_ABORTED_TASK;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
/* following cases are to do cases */
case IO_UNDERFLOW:
/* SATA Completion with error */
pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW param = %d\n", param);
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_UNDERRUN;
ts->residual = param;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_NO_DEVICE:
pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_PHY_DOWN;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_INTERRUPTED;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_PHY_NOT_READY:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_EPROTO;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_ZONE_VIOLATION:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_UNKNOWN;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_CONT0;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS:
case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
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;
spin_unlock_irqrestore(&circularQ->oq_lock,
circularQ->lock_flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
spin_lock_irqsave(&circularQ->oq_lock,
circularQ->lock_flags);
return;
}
break;
case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
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;
spin_unlock_irqrestore(&circularQ->oq_lock,
circularQ->lock_flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
spin_lock_irqsave(&circularQ->oq_lock,
circularQ->lock_flags);
return;
}
break;
case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_CONN_RATE;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n");
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;
spin_unlock_irqrestore(&circularQ->oq_lock,
circularQ->lock_flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
spin_lock_irqsave(&circularQ->oq_lock,
circularQ->lock_flags);
return;
}
break;
case IO_OPEN_CNX_ERROR_WRONG_DESTINATION:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_WRONG_DEST;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_NAK_RECEIVED:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_NAK_R_ERR;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_ACK_NAK_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_NAK_R_ERR;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_DMA:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_ABORTED_TASK;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_SATA_LINK_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_SATA_LINK_TIMEOUT\n");
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_DEV_NO_RESPONSE;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_ERROR_REJECTED_NCQ_MODE:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_UNDERRUN;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_XFER_OPEN_RETRY_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_PORT_IN_RESET:
pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DEV_NO_RESPONSE;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_DS_NON_OPERATIONAL:
pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
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;
spin_unlock_irqrestore(&circularQ->oq_lock,
circularQ->lock_flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
spin_lock_irqsave(&circularQ->oq_lock,
circularQ->lock_flags);
return;
}
break;
case IO_DS_IN_RECOVERY:
pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DEV_NO_RESPONSE;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_DS_IN_ERROR:
pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_ERROR\n");
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;
spin_unlock_irqrestore(&circularQ->oq_lock,
circularQ->lock_flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
spin_lock_irqsave(&circularQ->oq_lock,
circularQ->lock_flags);
return;
}
break;
case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
default:
pm8001_dbg(pm8001_ha, DEVIO,
"Unknown status device_id %u status 0x%x tag %d\n",
pm8001_dev->device_id, status, tag);
/* not allowed case. Therefore, return failed status */
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DEV_NO_RESPONSE;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
}
spin_lock_irqsave(&t->task_state_lock, flags);
t->task_state_flags &= ~SAS_TASK_STATE_PENDING;
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);
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);
pm8001_ccb_task_free(pm8001_ha, ccb);
if (t->slow_task)
complete(&t->slow_task->completion);
} else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
spin_unlock_irqrestore(&circularQ->oq_lock,
circularQ->lock_flags);
pm8001_ccb_task_free_done(pm8001_ha, ccb);
spin_lock_irqsave(&circularQ->oq_lock,
circularQ->lock_flags);
}
}
/*See the comments for mpi_ssp_completion */
static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha,
struct outbound_queue_table *circularQ, void *piomb)
{
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);
if (event)
pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n", event);
/* 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);
scsi: pm8001: Use sas_ata_device_link_abort() to handle NCQ errors In commit c6b9ef5779c3 ("[SCSI] pm80xx: NCQ error handling changes") the driver had support added to handle NCQ errors but much of what is done in this handling is duplicated from the libata EH. In that named commit we handle in 2x main steps: a. Issue read log ext10 to examine and clear the errors b. Issue SATA_ABORT all command Indeed, in libata EH, we do similar to above: a. ata_do_eh() -> ata_eh_autopsy() -> ata_eh_link_autopsy() -> ata_eh_analyze_ncq_error() -> ata_eh_read_log_10h() b. ata_do_eh() -> ata_eh_recover() which will issue a device soft reset or hard reset Since there is so much duplication, use sas_ata_device_link_abort() which will abort all pending IOs and kick of ATA EH which will do the steps, above. However we will not follow the advisory to send the SATA_ABORT all command after the autopsy in read log ext10. Indeed, in libsas EH, we already send a per-task SATA_ABORT command, and this is prior to the ATA EH kicking in and issuing the read log ext10 in the recovery process. I judge that this is ok as the SATA_ABORT command does not actually send any protocol on the link to abort I/O on the other side, so would not change any state on the disk (for the read log ext10 command). Signed-off-by: John Garry <john.garry@huawei.com> Link: https://lore.kernel.org/r/1665998435-199946-7-git-send-email-john.garry@huawei.com Tested-by: Damien Le Moal <damien.lemoal@opensource.wdc.com> Tested-by: Niklas Cassel <niklas.cassel@wdc.com> # pm80xx Acked-by: Jack Wang <jinpu.wang@ionos.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-10-17 09:20:33 +00:00
/* send read log extension by aborting the link - libata does what we want */
if (pm8001_dev)
scsi: pm8001: Use sas_ata_device_link_abort() to handle NCQ errors In commit c6b9ef5779c3 ("[SCSI] pm80xx: NCQ error handling changes") the driver had support added to handle NCQ errors but much of what is done in this handling is duplicated from the libata EH. In that named commit we handle in 2x main steps: a. Issue read log ext10 to examine and clear the errors b. Issue SATA_ABORT all command Indeed, in libata EH, we do similar to above: a. ata_do_eh() -> ata_eh_autopsy() -> ata_eh_link_autopsy() -> ata_eh_analyze_ncq_error() -> ata_eh_read_log_10h() b. ata_do_eh() -> ata_eh_recover() which will issue a device soft reset or hard reset Since there is so much duplication, use sas_ata_device_link_abort() which will abort all pending IOs and kick of ATA EH which will do the steps, above. However we will not follow the advisory to send the SATA_ABORT all command after the autopsy in read log ext10. Indeed, in libsas EH, we already send a per-task SATA_ABORT command, and this is prior to the ATA EH kicking in and issuing the read log ext10 in the recovery process. I judge that this is ok as the SATA_ABORT command does not actually send any protocol on the link to abort I/O on the other side, so would not change any state on the disk (for the read log ext10 command). Signed-off-by: John Garry <john.garry@huawei.com> Link: https://lore.kernel.org/r/1665998435-199946-7-git-send-email-john.garry@huawei.com Tested-by: Damien Le Moal <damien.lemoal@opensource.wdc.com> Tested-by: Niklas Cassel <niklas.cassel@wdc.com> # pm80xx Acked-by: Jack Wang <jinpu.wang@ionos.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2022-10-17 09:20:33 +00:00
pm8001_handle_event(pm8001_ha,
pm8001_dev,
IO_XFER_ERROR_ABORTED_NCQ_MODE);
return;
}
ccb = &pm8001_ha->ccb_info[tag];
t = ccb->task;
pm8001_dev = ccb->device;
if (unlikely(!t)) {
pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n",
ccb->ccb_tag);
pm8001_ccb_free(pm8001_ha, ccb);
return;
}
if (unlikely(!t->lldd_task || !t->dev))
return;
ts = &t->task_status;
pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n",
port_id, tag, event);
switch (event) {
case IO_OVERFLOW:
pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
ts->residual = 0;
break;
case IO_XFER_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_INTERRUPTED;
break;
case IO_XFER_ERROR_PHY_NOT_READY:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_UNKNOWN;
break;
case IO_OPEN_CNX_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
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:
case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
pm8001_dbg(pm8001_ha, FAIL,
"IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
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;
return;
}
break;
case IO_OPEN_CNX_ERROR_BAD_DESTINATION:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
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:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_NAK_R_ERR;
break;
case IO_XFER_ERROR_PEER_ABORTED:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PEER_ABORTED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_NAK_R_ERR;
break;
case IO_XFER_ERROR_REJECTED_NCQ_MODE:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_UNDERRUN;
break;
case IO_XFER_OPEN_RETRY_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_ERROR_UNEXPECTED_PHASE:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_ERROR_XFER_RDY_OVERRUN:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED:
pm8001_dbg(pm8001_ha, IO,
"IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_ERROR_OFFSET_MISMATCH:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_ERROR_XFER_ZERO_DATA_LEN:
pm8001_dbg(pm8001_ha, IO,
"IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_CMD_FRAME_ISSUED:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n");
break;
case IO_XFER_PIO_SETUP_ERROR:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_PIO_SETUP_ERROR\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_ERROR_INTERNAL_CRC_ERROR:
pm8001_dbg(pm8001_ha, FAIL,
"IO_XFR_ERROR_INTERNAL_CRC_ERROR\n");
/* TBC: used default set values */
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
case IO_XFER_DMA_ACTIVATE_TIMEOUT:
pm8001_dbg(pm8001_ha, FAIL, "IO_XFR_DMA_ACTIVATE_TIMEOUT\n");
/* TBC: used default set values */
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
default:
pm8001_dbg(pm8001_ha, IO, "Unknown status 0x%x\n", event);
/* not allowed case. Therefore, return failed status */
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_TO;
break;
}
}
/*See the comments for mpi_ssp_completion */
static void
mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
u32 param, i;
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];
param = le32_to_cpu(psmpPayload->param);
t = ccb->task;
ts = &t->task_status;
pm8001_dev = ccb->device;
if (status)
pm8001_dbg(pm8001_ha, FAIL, "smp IO status 0x%x\n", status);
if (unlikely(!t || !t->lldd_task || !t->dev))
return;
pm8001_dbg(pm8001_ha, DEV, "tag::0x%x status::0x%x\n", tag, status);
switch (status) {
case IO_SUCCESS:
pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_SAM_STAT_GOOD;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
if (pm8001_ha->smp_exp_mode == SMP_DIRECT) {
struct scatterlist *sg_resp = &t->smp_task.smp_resp;
u8 *payload;
void *to;
pm8001_dbg(pm8001_ha, IO,
"DIRECT RESPONSE Length:%d\n",
param);
to = kmap_atomic(sg_page(sg_resp));
payload = to + sg_resp->offset;
for (i = 0; i < param; i++) {
*(payload + i) = psmpPayload->_r_a[i];
pm8001_dbg(pm8001_ha, IO,
"SMP Byte%d DMA data 0x%x psmp 0x%x\n",
i, *(payload + i),
psmpPayload->_r_a[i]);
}
kunmap_atomic(to);
}
break;
case IO_ABORTED:
pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_ABORTED_TASK;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_OVERFLOW:
pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DATA_OVERRUN;
ts->residual = 0;
if (pm8001_dev)
atomic_dec(&pm8001_dev->running_req);
break;
case IO_NO_DEVICE:
pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_PHY_DOWN;
break;
case IO_ERROR_HW_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_XFER_ERROR_PHY_NOT_READY:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_SAM_STAT_BUSY;
break;
case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_UNKNOWN;
break;
case IO_OPEN_CNX_ERROR_BREAK:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n");
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:
case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE:
case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED:
pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_BAD_DESTINATION\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n");
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:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_RX_FRAME\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DEV_NO_RESPONSE;
break;
case IO_XFER_OPEN_RETRY_TIMEOUT:
pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n");
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:
pm8001_dbg(pm8001_ha, IO, "IO_ERROR_INTERNAL_SMP_RESOURCE\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_QUEUE_FULL;
break;
case IO_PORT_IN_RESET:
pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
break;
case IO_DS_NON_OPERATIONAL:
pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_DEV_NO_RESPONSE;
break;
case IO_DS_IN_RECOVERY:
pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n");
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:
pm8001_dbg(pm8001_ha, IO,
"IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n");
ts->resp = SAS_TASK_COMPLETE;
ts->stat = SAS_OPEN_REJECT;
ts->open_rej_reason = SAS_OREJ_RSVD_RETRY;
break;
default:
pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n", status);
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_STATE_DONE;
if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_dbg(pm8001_ha, FAIL,
"task 0x%p done with io_status 0x%x resp 0x%xstat 0x%x but aborted by upper layer!\n",
t, status, ts->resp, ts->stat);
pm8001_ccb_task_free(pm8001_ha, ccb);
} else {
spin_unlock_irqrestore(&t->task_state_lock, flags);
pm8001_ccb_task_free(pm8001_ha, ccb);
mb();/* in order to force CPU ordering */
t->task_done(t);
}
}
/**
* pm80xx_hw_event_ack_req- For PM8001, some events need to acknowledge 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 pm80xx_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;
memset((u8 *)&payload, 0, sizeof(payload));
payload.tag = cpu_to_le32(1);
payload.phyid_sea_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) |
((phyId & 0xFF) << 24) | (port_id & 0xFF));
payload.param0 = cpu_to_le32(param0);
payload.param1 = cpu_to_le32(param1);
pm8001_mpi_build_cmd(pm8001_ha, Qnum, opc, &payload,
sizeof(payload), 0);
}
static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
u32 phyId, u32 phy_op);
static void hw_event_port_recover(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
struct hw_event_resp *pPayload = (struct hw_event_resp *)(piomb + 4);
u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate);
u8 phy_id = (u8)((phyid_npip_portstate & 0xFF0000) >> 16);
u32 lr_status_evt_portid =
le32_to_cpu(pPayload->lr_status_evt_portid);
u8 deviceType = pPayload->sas_identify.dev_type;
u8 link_rate = (u8)((lr_status_evt_portid & 0xF0000000) >> 28);
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF);
struct pm8001_port *port = &pm8001_ha->port[port_id];
if (deviceType == SAS_END_DEVICE) {
pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id,
PHY_NOTIFY_ENABLE_SPINUP);
}
port->wide_port_phymap |= (1U << phy_id);
pm8001_get_lrate_mode(phy, link_rate);
phy->sas_phy.oob_mode = SAS_OOB_MODE;
phy->phy_state = PHY_STATE_LINK_UP_SPCV;
phy->phy_attached = 1;
}
/**
* 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_status_evt_portid =
le32_to_cpu(pPayload->lr_status_evt_portid);
u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate);
u8 link_rate =
(u8)((lr_status_evt_portid & 0xF0000000) >> 28);
u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF);
u8 phy_id =
(u8)((phyid_npip_portstate & 0xFF0000) >> 16);
u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F);
struct pm8001_port *port = &pm8001_ha->port[port_id];
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
unsigned long flags;
u8 deviceType = pPayload->sas_identify.dev_type;
phy->port = port;
port->port_id = port_id;
port->port_state = portstate;
port->wide_port_phymap |= (1U << phy_id);
phy->phy_state = PHY_STATE_LINK_UP_SPCV;
pm8001_dbg(pm8001_ha, MSG,
"portid:%d; phyid:%d; linkrate:%d; portstate:%x; devicetype:%x\n",
port_id, phy_id, link_rate, portstate, deviceType);
switch (deviceType) {
case SAS_PHY_UNUSED:
pm8001_dbg(pm8001_ha, MSG, "device type no device.\n");
break;
case SAS_END_DEVICE:
pm8001_dbg(pm8001_ha, MSG, "end device.\n");
pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id,
PHY_NOTIFY_ENABLE_SPINUP);
port->port_attached = 1;
pm8001_get_lrate_mode(phy, link_rate);
break;
case SAS_EDGE_EXPANDER_DEVICE:
pm8001_dbg(pm8001_ha, MSG, "expander device.\n");
port->port_attached = 1;
pm8001_get_lrate_mode(phy, link_rate);
break;
case SAS_FANOUT_EXPANDER_DEVICE:
pm8001_dbg(pm8001_ha, MSG, "fanout expander device.\n");
port->port_attached = 1;
pm8001_get_lrate_mode(phy, link_rate);
break;
default:
pm8001_dbg(pm8001_ha, DEVIO, "unknown device type(%x)\n",
deviceType);
break;
}
phy->phy_type |= PORT_TYPE_SAS;
phy->identify.device_type = deviceType;
phy->phy_attached = 1;
if (phy->identify.device_type == SAS_END_DEVICE)
phy->identify.target_port_protocols = SAS_PROTOCOL_SSP;
else if (phy->identify.device_type != SAS_PHY_UNUSED)
phy->identify.target_port_protocols = SAS_PROTOCOL_SMP;
phy->sas_phy.oob_mode = SAS_OOB_MODE;
sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
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 for disk to spin up */
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 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate);
u32 lr_status_evt_portid =
le32_to_cpu(pPayload->lr_status_evt_portid);
u8 link_rate =
(u8)((lr_status_evt_portid & 0xF0000000) >> 28);
u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF);
u8 phy_id =
(u8)((phyid_npip_portstate & 0xFF0000) >> 16);
u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F);
struct pm8001_port *port = &pm8001_ha->port[port_id];
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
unsigned long flags;
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_SATA_PHY_UP phyid:%#x port_id:%#x link_rate:%d portstate:%#x\n",
phy_id, port_id, link_rate, portstate);
phy->port = port;
port->port_id = port_id;
port->port_state = portstate;
phy->phy_state = PHY_STATE_LINK_UP_SPCV;
port->port_attached = 1;
pm8001_get_lrate_mode(phy, link_rate);
phy->phy_type |= PORT_TYPE_SATA;
phy->phy_attached = 1;
phy->sas_phy.oob_mode = SATA_OOB_MODE;
sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE, GFP_ATOMIC);
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;
phy->identify.device_type = SAS_SATA_DEV;
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_status_evt_portid =
le32_to_cpu(pPayload->lr_status_evt_portid);
u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF);
u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate);
u8 phy_id =
(u8)((phyid_npip_portstate & 0xFF0000) >> 16);
u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F);
struct pm8001_port *port = &pm8001_ha->port[port_id];
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
u32 port_sata = (phy->phy_type & PORT_TYPE_SATA);
port->port_state = portstate;
phy->identify.device_type = 0;
phy->phy_attached = 0;
switch (portstate) {
case PORT_VALID:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_VALID\n",
phy_id, port_id);
break;
case PORT_INVALID:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_INVALID\n",
phy_id, port_id);
pm8001_dbg(pm8001_ha, MSG,
" Last phy Down and port invalid\n");
if (port_sata) {
phy->phy_type = 0;
port->port_attached = 0;
pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
port_id, phy_id, 0, 0);
}
sas_phy_disconnected(&phy->sas_phy);
break;
case PORT_IN_RESET:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_IN_RESET\n",
phy_id, port_id);
break;
case PORT_NOT_ESTABLISHED:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_NOT_ESTABLISHED\n",
phy_id, port_id);
port->port_attached = 0;
break;
case PORT_LOSTCOMM:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_LOSTCOMM\n",
phy_id, port_id);
pm8001_dbg(pm8001_ha, MSG, " Last phy Down and port invalid\n");
if (port_sata) {
port->port_attached = 0;
phy->phy_type = 0;
pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
port_id, phy_id, 0, 0);
}
sas_phy_disconnected(&phy->sas_phy);
break;
default:
port->port_attached = 0;
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate:%#x\n",
phy_id, port_id, portstate);
break;
}
if (port_sata && (portstate != PORT_IN_RESET))
sas_notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL,
GFP_ATOMIC);
}
static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
struct phy_start_resp *pPayload =
(struct phy_start_resp *)(piomb + 4);
u32 status =
le32_to_cpu(pPayload->status);
u32 phy_id =
le32_to_cpu(pPayload->phyid) & 0xFF;
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
pm8001_dbg(pm8001_ha, INIT,
"phy start resp status:0x%x, phyid:0x%x\n",
status, phy_id);
if (status == 0)
phy->phy_state = PHY_LINK_DOWN;
if (pm8001_ha->flags == PM8001F_RUN_TIME &&
phy->enable_completion != NULL) {
complete(phy->enable_completion);
phy->enable_completion = NULL;
}
return 0;
}
/**
* mpi_thermal_hw_event - a thermal hw event has come.
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
struct thermal_hw_event *pPayload =
(struct thermal_hw_event *)(piomb + 4);
u32 thermal_event = le32_to_cpu(pPayload->thermal_event);
u32 rht_lht = le32_to_cpu(pPayload->rht_lht);
if (thermal_event & 0x40) {
pm8001_dbg(pm8001_ha, IO,
"Thermal Event: Local high temperature violated!\n");
pm8001_dbg(pm8001_ha, IO,
"Thermal Event: Measured local high temperature %d\n",
((rht_lht & 0xFF00) >> 8));
}
if (thermal_event & 0x10) {
pm8001_dbg(pm8001_ha, IO,
"Thermal Event: Remote high temperature violated!\n");
pm8001_dbg(pm8001_ha, IO,
"Thermal Event: Measured remote high temperature %d\n",
((rht_lht & 0xFF000000) >> 24));
}
return 0;
}
/**
* mpi_hw_event - The hw event has come.
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
unsigned long flags, i;
struct hw_event_resp *pPayload =
(struct hw_event_resp *)(piomb + 4);
u32 lr_status_evt_portid =
le32_to_cpu(pPayload->lr_status_evt_portid);
u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate);
u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF);
u8 phy_id =
(u8)((phyid_npip_portstate & 0xFF0000) >> 16);
u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F);
u16 eventType =
(u16)((lr_status_evt_portid & 0x00FFFF00) >> 8);
u8 status =
(u8)((lr_status_evt_portid & 0x0F000000) >> 24);
struct sas_ha_struct *sas_ha = pm8001_ha->sas;
struct pm8001_phy *phy = &pm8001_ha->phy[phy_id];
struct pm8001_port *port = &pm8001_ha->port[port_id];
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
pm8001_dbg(pm8001_ha, DEV,
"portid:%d phyid:%d event:0x%x status:0x%x\n",
port_id, phy_id, eventType, status);
switch (eventType) {
case HW_EVENT_SAS_PHY_UP:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_SAS_PHY_UP phyid:%#x port_id:%#x\n",
phy_id, port_id);
hw_event_sas_phy_up(pm8001_ha, piomb);
break;
case HW_EVENT_SATA_PHY_UP:
hw_event_sata_phy_up(pm8001_ha, piomb);
break;
case HW_EVENT_SATA_SPINUP_HOLD:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_SATA_SPINUP_HOLD phyid:%#x port_id:%#x\n",
phy_id, port_id);
sas_notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD,
GFP_ATOMIC);
break;
case HW_EVENT_PHY_DOWN:
hw_event_phy_down(pm8001_ha, piomb);
phy->phy_state = PHY_LINK_DISABLE;
break;
case HW_EVENT_PORT_INVALID:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PORT_INVALID phyid:%#x port_id:%#x\n",
phy_id, port_id);
sas_phy_disconnected(sas_phy);
phy->phy_attached = 0;
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
GFP_ATOMIC);
break;
/* the broadcast change primitive received, tell the LIBSAS this event
to revalidate the sas domain*/
case HW_EVENT_BROADCAST_CHANGE:
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_CHANGE\n");
pm80xx_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);
sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
GFP_ATOMIC);
break;
case HW_EVENT_PHY_ERROR:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PHY_ERROR phyid:%#x port_id:%#x\n",
phy_id, port_id);
sas_phy_disconnected(&phy->sas_phy);
phy->phy_attached = 0;
sas_notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR, GFP_ATOMIC);
break;
case HW_EVENT_BROADCAST_EXP:
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_EXP\n");
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);
sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
GFP_ATOMIC);
break;
case HW_EVENT_LINK_ERR_INVALID_DWORD:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_LINK_ERR_INVALID_DWORD phyid:%#x port_id:%#x\n",
phy_id, port_id);
pm80xx_hw_event_ack_req(pm8001_ha, 0,
HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0);
break;
case HW_EVENT_LINK_ERR_DISPARITY_ERROR:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_LINK_ERR_DISPARITY_ERROR phyid:%#x port_id:%#x\n",
phy_id, port_id);
pm80xx_hw_event_ack_req(pm8001_ha, 0,
HW_EVENT_LINK_ERR_DISPARITY_ERROR,
port_id, phy_id, 0, 0);
break;
case HW_EVENT_LINK_ERR_CODE_VIOLATION:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_LINK_ERR_CODE_VIOLATION phyid:%#x port_id:%#x\n",
phy_id, port_id);
pm80xx_hw_event_ack_req(pm8001_ha, 0,
HW_EVENT_LINK_ERR_CODE_VIOLATION,
port_id, phy_id, 0, 0);
break;
case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH phyid:%#x port_id:%#x\n",
phy_id, port_id);
pm80xx_hw_event_ack_req(pm8001_ha, 0,
HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH,
port_id, phy_id, 0, 0);
break;
case HW_EVENT_MALFUNCTION:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_MALFUNCTION phyid:%#x\n", phy_id);
break;
case HW_EVENT_BROADCAST_SES:
pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n");
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);
sas_notify_port_event(sas_phy, PORTE_BROADCAST_RCVD,
GFP_ATOMIC);
break;
case HW_EVENT_INBOUND_CRC_ERROR:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_INBOUND_CRC_ERROR phyid:%#x port_id:%#x\n",
phy_id, port_id);
pm80xx_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:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_HARD_RESET_RECEIVED phyid:%#x\n", phy_id);
sas_notify_port_event(sas_phy, PORTE_HARD_RESET, GFP_ATOMIC);
break;
case HW_EVENT_ID_FRAME_TIMEOUT:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_ID_FRAME_TIMEOUT phyid:%#x\n", phy_id);
sas_phy_disconnected(sas_phy);
phy->phy_attached = 0;
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
GFP_ATOMIC);
break;
case HW_EVENT_LINK_ERR_PHY_RESET_FAILED:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_LINK_ERR_PHY_RESET_FAILED phyid:%#x port_id:%#x\n",
phy_id, port_id);
pm80xx_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;
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
GFP_ATOMIC);
break;
case HW_EVENT_PORT_RESET_TIMER_TMO:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PORT_RESET_TIMER_TMO phyid:%#x port_id:%#x portstate:%#x\n",
phy_id, port_id, portstate);
if (!pm8001_ha->phy[phy_id].reset_completion) {
pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN,
port_id, phy_id, 0, 0);
}
sas_phy_disconnected(sas_phy);
phy->phy_attached = 0;
port->port_state = portstate;
sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR,
GFP_ATOMIC);
if (pm8001_ha->phy[phy_id].reset_completion) {
pm8001_ha->phy[phy_id].port_reset_status =
PORT_RESET_TMO;
complete(pm8001_ha->phy[phy_id].reset_completion);
pm8001_ha->phy[phy_id].reset_completion = NULL;
}
break;
case HW_EVENT_PORT_RECOVERY_TIMER_TMO:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PORT_RECOVERY_TIMER_TMO phyid:%#x port_id:%#x\n",
phy_id, port_id);
pm80xx_hw_event_ack_req(pm8001_ha, 0,
HW_EVENT_PORT_RECOVERY_TIMER_TMO,
port_id, phy_id, 0, 0);
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
if (port->wide_port_phymap & (1 << i)) {
phy = &pm8001_ha->phy[i];
sas_notify_phy_event(&phy->sas_phy,
PHYE_LOSS_OF_SIGNAL, GFP_ATOMIC);
port->wide_port_phymap &= ~(1 << i);
}
}
break;
case HW_EVENT_PORT_RECOVER:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PORT_RECOVER phyid:%#x port_id:%#x\n",
phy_id, port_id);
hw_event_port_recover(pm8001_ha, piomb);
break;
case HW_EVENT_PORT_RESET_COMPLETE:
pm8001_dbg(pm8001_ha, EVENT,
"HW_EVENT_PORT_RESET_COMPLETE phyid:%#x port_id:%#x portstate:%#x\n",
phy_id, port_id, portstate);
if (pm8001_ha->phy[phy_id].reset_completion) {
pm8001_ha->phy[phy_id].port_reset_status =
PORT_RESET_SUCCESS;
complete(pm8001_ha->phy[phy_id].reset_completion);
pm8001_ha->phy[phy_id].reset_completion = NULL;
}
phy->phy_attached = 1;
phy->phy_state = PHY_STATE_LINK_UP_SPCV;
port->port_state = portstate;
break;
case EVENT_BROADCAST_ASYNCH_EVENT:
pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n");
break;
default:
pm8001_dbg(pm8001_ha, DEVIO,
"Unknown event portid:%d phyid:%d event:0x%x status:0x%x\n",
port_id, phy_id, eventType, status);
break;
}
return 0;
}
/**
* mpi_phy_stop_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
struct phy_stop_resp *pPayload =
(struct phy_stop_resp *)(piomb + 4);
u32 status =
le32_to_cpu(pPayload->status);
u32 phyid =
le32_to_cpu(pPayload->phyid) & 0xFF;
struct pm8001_phy *phy = &pm8001_ha->phy[phyid];
pm8001_dbg(pm8001_ha, MSG, "phy:0x%x status:0x%x\n",
phyid, status);
if (status == PHY_STOP_SUCCESS ||
status == PHY_STOP_ERR_DEVICE_ATTACHED) {
phy->phy_state = PHY_LINK_DISABLE;
phy->sas_phy.phy->negotiated_linkrate = SAS_PHY_DISABLED;
phy->sas_phy.linkrate = SAS_PHY_DISABLED;
}
return 0;
}
/**
* mpi_set_controller_config_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
struct set_ctrl_cfg_resp *pPayload =
(struct set_ctrl_cfg_resp *)(piomb + 4);
u32 status = le32_to_cpu(pPayload->status);
u32 err_qlfr_pgcd = le32_to_cpu(pPayload->err_qlfr_pgcd);
pm8001_dbg(pm8001_ha, MSG,
"SET CONTROLLER RESP: status 0x%x qlfr_pgcd 0x%x\n",
status, err_qlfr_pgcd);
return 0;
}
/**
* mpi_get_controller_config_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n");
return 0;
}
/**
* mpi_get_phy_profile_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n");
return 0;
}
/**
* mpi_flash_op_ext_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
{
pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n");
return 0;
}
/**
* mpi_set_phy_profile_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
u32 tag;
u8 page_code;
int rc = 0;
struct set_phy_profile_resp *pPayload =
(struct set_phy_profile_resp *)(piomb + 4);
u32 ppc_phyid = le32_to_cpu(pPayload->ppc_phyid);
u32 status = le32_to_cpu(pPayload->status);
tag = le32_to_cpu(pPayload->tag);
page_code = (u8)((ppc_phyid & 0xFF00) >> 8);
if (status) {
/* status is FAILED */
pm8001_dbg(pm8001_ha, FAIL,
"PhyProfile command failed with status 0x%08X\n",
status);
rc = -1;
} else {
if (page_code != SAS_PHY_ANALOG_SETTINGS_PAGE) {
pm8001_dbg(pm8001_ha, FAIL, "Invalid page code 0x%X\n",
page_code);
rc = -1;
}
}
pm8001_tag_free(pm8001_ha, tag);
return rc;
}
/**
* mpi_kek_management_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_kek_management_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
struct kek_mgmt_resp *pPayload = (struct kek_mgmt_resp *)(piomb + 4);
u32 status = le32_to_cpu(pPayload->status);
u32 kidx_new_curr_ksop = le32_to_cpu(pPayload->kidx_new_curr_ksop);
u32 err_qlfr = le32_to_cpu(pPayload->err_qlfr);
pm8001_dbg(pm8001_ha, MSG,
"KEK MGMT RESP. Status 0x%x idx_ksop 0x%x err_qlfr 0x%x\n",
status, kidx_new_curr_ksop, err_qlfr);
return 0;
}
/**
* mpi_dek_management_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int mpi_dek_management_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n");
return 0;
}
/**
* ssp_coalesced_comp_resp - SPCv specific
* @pm8001_ha: our hba card information
* @piomb: IO message buffer
*/
static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha,
void *piomb)
{
pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n");
return 0;
}
/**
* process_one_iomb - process one outbound Queue memory block
* @pm8001_ha: our hba card information
* @circularQ: outbound circular queue
* @piomb: IO message buffer
*/
static void process_one_iomb(struct pm8001_hba_info *pm8001_ha,
struct outbound_queue_table *circularQ, void *piomb)
{
__le32 pHeader = *(__le32 *)piomb;
u32 opc = (u32)((le32_to_cpu(pHeader)) & 0xFFF);
switch (opc) {
case OPC_OUB_ECHO:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_ECHO\n");
break;
case OPC_OUB_HW_EVENT:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_HW_EVENT\n");
mpi_hw_event(pm8001_ha, piomb);
break;
case OPC_OUB_THERM_HW_EVENT:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_THERMAL_EVENT\n");
mpi_thermal_hw_event(pm8001_ha, piomb);
break;
case OPC_OUB_SSP_COMP:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_COMP\n");
mpi_ssp_completion(pm8001_ha, piomb);
break;
case OPC_OUB_SMP_COMP:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_COMP\n");
mpi_smp_completion(pm8001_ha, piomb);
break;
case OPC_OUB_LOCAL_PHY_CNTRL:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_LOCAL_PHY_CNTRL\n");
pm8001_mpi_local_phy_ctl(pm8001_ha, piomb);
break;
case OPC_OUB_DEV_REGIST:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_REGIST\n");
pm8001_mpi_reg_resp(pm8001_ha, piomb);
break;
case OPC_OUB_DEREG_DEV:
pm8001_dbg(pm8001_ha, MSG, "unregister the device\n");
pm8001_mpi_dereg_resp(pm8001_ha, piomb);
break;
case OPC_OUB_GET_DEV_HANDLE:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEV_HANDLE\n");
break;
case OPC_OUB_SATA_COMP:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n");
mpi_sata_completion(pm8001_ha, circularQ, piomb);
break;
case OPC_OUB_SATA_EVENT:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n");
mpi_sata_event(pm8001_ha, circularQ, piomb);
break;
case OPC_OUB_SSP_EVENT:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n");
mpi_ssp_event(pm8001_ha, piomb);
break;
case OPC_OUB_DEV_HANDLE_ARRIV:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_HANDLE_ARRIV\n");
/*This is for target*/
break;
case OPC_OUB_SSP_RECV_EVENT:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_RECV_EVENT\n");
/*This is for target*/
break;
case OPC_OUB_FW_FLASH_UPDATE:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_FW_FLASH_UPDATE\n");
pm8001_mpi_fw_flash_update_resp(pm8001_ha, piomb);
break;
case OPC_OUB_GPIO_RESPONSE:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_RESPONSE\n");
break;
case OPC_OUB_GPIO_EVENT:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_EVENT\n");
break;
case OPC_OUB_GENERAL_EVENT:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GENERAL_EVENT\n");
pm8001_mpi_general_event(pm8001_ha, piomb);
break;
case OPC_OUB_SSP_ABORT_RSP:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_ABORT_RSP\n");
pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
break;
case OPC_OUB_SATA_ABORT_RSP:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_ABORT_RSP\n");
pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
break;
case OPC_OUB_SAS_DIAG_MODE_START_END:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_SAS_DIAG_MODE_START_END\n");
break;
case OPC_OUB_SAS_DIAG_EXECUTE:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_DIAG_EXECUTE\n");
break;
case OPC_OUB_GET_TIME_STAMP:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_TIME_STAMP\n");
break;
case OPC_OUB_SAS_HW_EVENT_ACK:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_HW_EVENT_ACK\n");
break;
case OPC_OUB_PORT_CONTROL:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_PORT_CONTROL\n");
break;
case OPC_OUB_SMP_ABORT_RSP:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_ABORT_RSP\n");
pm8001_mpi_task_abort_resp(pm8001_ha, piomb);
break;
case OPC_OUB_GET_NVMD_DATA:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_NVMD_DATA\n");
pm8001_mpi_get_nvmd_resp(pm8001_ha, piomb);
break;
case OPC_OUB_SET_NVMD_DATA:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_NVMD_DATA\n");
pm8001_mpi_set_nvmd_resp(pm8001_ha, piomb);
break;
case OPC_OUB_DEVICE_HANDLE_REMOVAL:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEVICE_HANDLE_REMOVAL\n");
break;
case OPC_OUB_SET_DEVICE_STATE:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEVICE_STATE\n");
pm8001_mpi_set_dev_state_resp(pm8001_ha, piomb);
break;
case OPC_OUB_GET_DEVICE_STATE:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEVICE_STATE\n");
break;
case OPC_OUB_SET_DEV_INFO:
pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n");
break;
/* spcv specific commands */
case OPC_OUB_PHY_START_RESP:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_PHY_START_RESP opcode:%x\n", opc);
mpi_phy_start_resp(pm8001_ha, piomb);
break;
case OPC_OUB_PHY_STOP_RESP:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_PHY_STOP_RESP opcode:%x\n", opc);
mpi_phy_stop_resp(pm8001_ha, piomb);
break;
case OPC_OUB_SET_CONTROLLER_CONFIG:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_SET_CONTROLLER_CONFIG opcode:%x\n", opc);
mpi_set_controller_config_resp(pm8001_ha, piomb);
break;
case OPC_OUB_GET_CONTROLLER_CONFIG:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_GET_CONTROLLER_CONFIG opcode:%x\n", opc);
mpi_get_controller_config_resp(pm8001_ha, piomb);
break;
case OPC_OUB_GET_PHY_PROFILE:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_GET_PHY_PROFILE opcode:%x\n", opc);
mpi_get_phy_profile_resp(pm8001_ha, piomb);
break;
case OPC_OUB_FLASH_OP_EXT:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_FLASH_OP_EXT opcode:%x\n", opc);
mpi_flash_op_ext_resp(pm8001_ha, piomb);
break;
case OPC_OUB_SET_PHY_PROFILE:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_SET_PHY_PROFILE opcode:%x\n", opc);
mpi_set_phy_profile_resp(pm8001_ha, piomb);
break;
case OPC_OUB_KEK_MANAGEMENT_RESP:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_KEK_MANAGEMENT_RESP opcode:%x\n", opc);
mpi_kek_management_resp(pm8001_ha, piomb);
break;
case OPC_OUB_DEK_MANAGEMENT_RESP:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_DEK_MANAGEMENT_RESP opcode:%x\n", opc);
mpi_dek_management_resp(pm8001_ha, piomb);
break;
case OPC_OUB_SSP_COALESCED_COMP_RESP:
pm8001_dbg(pm8001_ha, MSG,
"OPC_OUB_SSP_COALESCED_COMP_RESP opcode:%x\n", opc);
ssp_coalesced_comp_resp(pm8001_ha, piomb);
break;
default:
pm8001_dbg(pm8001_ha, DEVIO,
"Unknown outbound Queue IOMB OPC = 0x%x\n", opc);
break;
}
}
static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha)
{
pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_0: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_1:0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_2: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_3: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_0: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_1: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_2: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_3: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_4: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_5: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_RSVD_0));
pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n",
pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_RSVD_1));
}
static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
struct outbound_queue_table *circularQ;
void *pMsg1 = NULL;
treewide: Remove uninitialized_var() usage Using uninitialized_var() is dangerous as it papers over real bugs[1] (or can in the future), and suppresses unrelated compiler warnings (e.g. "unused variable"). If the compiler thinks it is uninitialized, either simply initialize the variable or make compiler changes. In preparation for removing[2] the[3] macro[4], remove all remaining needless uses with the following script: git grep '\buninitialized_var\b' | cut -d: -f1 | sort -u | \ xargs perl -pi -e \ 's/\buninitialized_var\(([^\)]+)\)/\1/g; s:\s*/\* (GCC be quiet|to make compiler happy) \*/$::g;' drivers/video/fbdev/riva/riva_hw.c was manually tweaked to avoid pathological white-space. No outstanding warnings were found building allmodconfig with GCC 9.3.0 for x86_64, i386, arm64, arm, powerpc, powerpc64le, s390x, mips, sparc64, alpha, and m68k. [1] https://lore.kernel.org/lkml/20200603174714.192027-1-glider@google.com/ [2] https://lore.kernel.org/lkml/CA+55aFw+Vbj0i=1TGqCR5vQkCzWJ0QxK6CernOU6eedsudAixw@mail.gmail.com/ [3] https://lore.kernel.org/lkml/CA+55aFwgbgqhbp1fkxvRKEpzyR5J8n1vKT1VZdz9knmPuXhOeg@mail.gmail.com/ [4] https://lore.kernel.org/lkml/CA+55aFz2500WfbKXAx8s67wrm9=yVJu65TpLgN_ybYNv0VEOKA@mail.gmail.com/ Reviewed-by: Leon Romanovsky <leonro@mellanox.com> # drivers/infiniband and mlx4/mlx5 Acked-by: Jason Gunthorpe <jgg@mellanox.com> # IB Acked-by: Kalle Valo <kvalo@codeaurora.org> # wireless drivers Reviewed-by: Chao Yu <yuchao0@huawei.com> # erofs Signed-off-by: Kees Cook <keescook@chromium.org>
2020-06-03 20:09:38 +00:00
u8 bc;
u32 ret = MPI_IO_STATUS_FAIL;
u32 regval;
/*
* Fatal errors are programmed to be signalled in irq vector
* pm8001_ha->max_q_num - 1 through pm8001_ha->main_cfg_tbl.pm80xx_tbl.
* fatal_err_interrupt
*/
if (vec == (pm8001_ha->max_q_num - 1)) {
u32 mipsall_ready;
if (pm8001_ha->chip_id == chip_8008 ||
pm8001_ha->chip_id == chip_8009)
mipsall_ready = SCRATCH_PAD_MIPSALL_READY_8PORT;
else
mipsall_ready = SCRATCH_PAD_MIPSALL_READY_16PORT;
regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
if ((regval & mipsall_ready) != mipsall_ready) {
pm8001_ha->controller_fatal_error = true;
pm8001_dbg(pm8001_ha, FAIL,
"Firmware Fatal error! Regval:0x%x\n",
regval);
pm8001_handle_event(pm8001_ha, NULL, IO_FATAL_ERROR);
print_scratchpad_registers(pm8001_ha);
return ret;
} else {
/*read scratchpad rsvd 0 register*/
regval = pm8001_cr32(pm8001_ha, 0,
MSGU_SCRATCH_PAD_RSVD_0);
switch (regval) {
case NON_FATAL_SPBC_LBUS_ECC_ERR:
case NON_FATAL_BDMA_ERR:
case NON_FATAL_THERM_OVERTEMP_ERR:
/*Clear the register*/
pm8001_cw32(pm8001_ha, 0,
MSGU_SCRATCH_PAD_RSVD_0,
0x00000000);
break;
default:
break;
}
}
}
circularQ = &pm8001_ha->outbnd_q_tbl[vec];
spin_lock_irqsave(&circularQ->oq_lock, circularQ->lock_flags);
do {
/* spurious interrupt during setup if kexec-ing and
* driver doing a doorbell access w/ the pre-kexec oq
* interrupt setup.
*/
if (!circularQ->pi_virt)
break;
ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc);
if (MPI_IO_STATUS_SUCCESS == ret) {
/* process the outbound message */
process_one_iomb(pm8001_ha, circularQ,
(void *)(pMsg1 - 4));
/* free the message from the outbound circular buffer */
pm8001_mpi_msg_free_set(pm8001_ha, pMsg1,
circularQ, bc);
}
if (MPI_IO_STATUS_BUSY == ret) {
/* Update the producer index from SPC */
circularQ->producer_index =
cpu_to_le32(pm8001_read_32(circularQ->pi_virt));
if (le32_to_cpu(circularQ->producer_index) ==
circularQ->consumer_idx)
/* OQ is empty */
break;
}
} while (1);
spin_unlock_irqrestore(&circularQ->oq_lock, circularQ->lock_flags);
return ret;
}
/* DMA_... to our direction translation. */
static const u8 data_dir_flags[] = {
[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 */
};
static void build_smp_cmd(u32 deviceID, __le32 hTag,
struct smp_req *psmp_cmd, int mode, int length)
{
psmp_cmd->tag = hTag;
psmp_cmd->device_id = cpu_to_le32(deviceID);
if (mode == SMP_DIRECT) {
length = length - 4; /* subtract crc */
psmp_cmd->len_ip_ir = cpu_to_le32(length << 16);
} else {
psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1));
}
}
/**
* pm80xx_chip_smp_req - send an SMP task to FW
* @pm8001_ha: our hba card information.
* @ccb: the ccb information this request used.
*/
static int pm80xx_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, *smp_req;
u32 req_len, resp_len;
struct smp_req smp_cmd;
u32 opc;
u32 i, length;
u8 *payload;
u8 *to;
memset(&smp_cmd, 0, sizeof(smp_cmd));
/*
* DMA-map SMP request, response buffers
*/
sg_req = &task->smp_task.smp_req;
elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE);
if (!elem)
return -ENOMEM;
req_len = sg_dma_len(sg_req);
sg_resp = &task->smp_task.smp_resp;
elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE);
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;
smp_cmd.tag = cpu_to_le32(ccb->ccb_tag);
length = sg_req->length;
pm8001_dbg(pm8001_ha, IO, "SMP Frame Length %d\n", sg_req->length);
if (!(length - 8))
pm8001_ha->smp_exp_mode = SMP_DIRECT;
else
pm8001_ha->smp_exp_mode = SMP_INDIRECT;
smp_req = &task->smp_task.smp_req;
to = kmap_atomic(sg_page(smp_req));
payload = to + smp_req->offset;
/* INDIRECT MODE command settings. Use DMA */
if (pm8001_ha->smp_exp_mode == SMP_INDIRECT) {
pm8001_dbg(pm8001_ha, IO, "SMP REQUEST INDIRECT MODE\n");
/* for SPCv indirect mode. Place the top 4 bytes of
* SMP Request header here. */
for (i = 0; i < 4; i++)
smp_cmd.smp_req16[i] = *(payload + i);
/* exclude top 4 bytes for SMP req header */
smp_cmd.long_smp_req.long_req_addr =
cpu_to_le64((u64)sg_dma_address
(&task->smp_task.smp_req) + 4);
/* exclude 4 bytes for SMP req header and CRC */
smp_cmd.long_smp_req.long_req_size =
cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-8);
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);
} else { /* DIRECT MODE */
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);
}
if (pm8001_ha->smp_exp_mode == SMP_DIRECT) {
pm8001_dbg(pm8001_ha, IO, "SMP REQUEST DIRECT MODE\n");
for (i = 0; i < length; i++)
if (i < 16) {
smp_cmd.smp_req16[i] = *(payload + i);
pm8001_dbg(pm8001_ha, IO,
"Byte[%d]:%x (DMA data:%x)\n",
i, smp_cmd.smp_req16[i],
*(payload));
} else {
smp_cmd.smp_req[i] = *(payload + i);
pm8001_dbg(pm8001_ha, IO,
"Byte[%d]:%x (DMA data:%x)\n",
i, smp_cmd.smp_req[i],
*(payload));
}
}
kunmap_atomic(to);
build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag,
&smp_cmd, pm8001_ha->smp_exp_mode, length);
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &smp_cmd,
sizeof(smp_cmd), 0);
if (rc)
goto err_out_2;
return 0;
err_out_2:
dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1,
DMA_FROM_DEVICE);
err_out:
dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1,
DMA_TO_DEVICE);
return rc;
}
static int check_enc_sas_cmd(struct sas_task *task)
{
u8 cmd = task->ssp_task.cmd->cmnd[0];
if (cmd == READ_10 || cmd == WRITE_10 || cmd == WRITE_VERIFY)
return 1;
else
return 0;
}
static int check_enc_sat_cmd(struct sas_task *task)
{
int ret = 0;
switch (task->ata_task.fis.command) {
case ATA_CMD_FPDMA_READ:
case ATA_CMD_READ_EXT:
case ATA_CMD_READ:
case ATA_CMD_FPDMA_WRITE:
case ATA_CMD_WRITE_EXT:
case ATA_CMD_WRITE:
case ATA_CMD_PIO_READ:
case ATA_CMD_PIO_READ_EXT:
case ATA_CMD_PIO_WRITE:
case ATA_CMD_PIO_WRITE_EXT:
ret = 1;
break;
default:
ret = 0;
break;
}
return ret;
}
static u32 pm80xx_chip_get_q_index(struct sas_task *task)
{
struct request *rq = sas_task_find_rq(task);
if (!rq)
return 0;
return blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(rq));
}
/**
* pm80xx_chip_ssp_io_req - send an SSP task to FW
* @pm8001_ha: our hba card information.
* @ccb: the ccb information this request used.
*/
static int pm80xx_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;
u64 phys_addr, end_addr;
u32 end_addr_high, end_addr_low;
u32 q_index;
u32 opc = OPC_INB_SSPINIIOSTART;
memset(&ssp_cmd, 0, sizeof(ssp_cmd));
memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8);
/* data address domain added for spcv; set to 0 by host,
* used internally by controller
* 0 for SAS 1.1 and SAS 2.0 compatible TLR
*/
ssp_cmd.dad_dir_m_tlr =
cpu_to_le32(data_dir_flags[task->data_dir] << 8 | 0x0);
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);
memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd,
task->ssp_task.cmd->cmd_len);
q_index = pm80xx_chip_get_q_index(task);
/* Check if encryption is set */
if (pm8001_ha->chip->encrypt &&
!(pm8001_ha->encrypt_info.status) && check_enc_sas_cmd(task)) {
pm8001_dbg(pm8001_ha, IO,
"Encryption enabled.Sending Encrypt SAS command 0x%x\n",
task->ssp_task.cmd->cmnd[0]);
opc = OPC_INB_SSP_INI_DIF_ENC_IO;
/* enable encryption. 0 for SAS 1.1 and SAS 2.0 compatible TLR*/
ssp_cmd.dad_dir_m_tlr = cpu_to_le32
((data_dir_flags[task->data_dir] << 8) | 0x20 | 0x0);
/* 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);
phys_addr = ccb->ccb_dma_handle;
ssp_cmd.enc_addr_low =
cpu_to_le32(lower_32_bits(phys_addr));
ssp_cmd.enc_addr_high =
cpu_to_le32(upper_32_bits(phys_addr));
ssp_cmd.enc_esgl = cpu_to_le32(1<<31);
} else if (task->num_scatter == 1) {
u64 dma_addr = sg_dma_address(task->scatter);
ssp_cmd.enc_addr_low =
cpu_to_le32(lower_32_bits(dma_addr));
ssp_cmd.enc_addr_high =
cpu_to_le32(upper_32_bits(dma_addr));
ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
ssp_cmd.enc_esgl = 0;
/* Check 4G Boundary */
end_addr = dma_addr + le32_to_cpu(ssp_cmd.enc_len) - 1;
end_addr_low = lower_32_bits(end_addr);
end_addr_high = upper_32_bits(end_addr);
if (end_addr_high != le32_to_cpu(ssp_cmd.enc_addr_high)) {
pm8001_dbg(pm8001_ha, FAIL,
"The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n",
dma_addr,
le32_to_cpu(ssp_cmd.enc_len),
end_addr_high, end_addr_low);
pm8001_chip_make_sg(task->scatter, 1,
ccb->buf_prd);
phys_addr = ccb->ccb_dma_handle;
ssp_cmd.enc_addr_low =
cpu_to_le32(lower_32_bits(phys_addr));
ssp_cmd.enc_addr_high =
cpu_to_le32(upper_32_bits(phys_addr));
ssp_cmd.enc_esgl = cpu_to_le32(1U<<31);
}
} else if (task->num_scatter == 0) {
ssp_cmd.enc_addr_low = 0;
ssp_cmd.enc_addr_high = 0;
ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
ssp_cmd.enc_esgl = 0;
}
/* XTS mode. All other fields are 0 */
ssp_cmd.key_cmode = cpu_to_le32(0x6 << 4);
/* set tweak values. Should be the start lba */
ssp_cmd.twk_val0 = cpu_to_le32((task->ssp_task.cmd->cmnd[2] << 24) |
(task->ssp_task.cmd->cmnd[3] << 16) |
(task->ssp_task.cmd->cmnd[4] << 8) |
(task->ssp_task.cmd->cmnd[5]));
} else {
pm8001_dbg(pm8001_ha, IO,
"Sending Normal SAS command 0x%x inb q %x\n",
task->ssp_task.cmd->cmnd[0], q_index);
/* 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);
phys_addr = ccb->ccb_dma_handle;
ssp_cmd.addr_low =
cpu_to_le32(lower_32_bits(phys_addr));
ssp_cmd.addr_high =
cpu_to_le32(upper_32_bits(phys_addr));
ssp_cmd.esgl = cpu_to_le32(1<<31);
} else if (task->num_scatter == 1) {
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));
ssp_cmd.len = cpu_to_le32(task->total_xfer_len);
ssp_cmd.esgl = 0;
/* Check 4G Boundary */
end_addr = dma_addr + le32_to_cpu(ssp_cmd.len) - 1;
end_addr_low = lower_32_bits(end_addr);
end_addr_high = upper_32_bits(end_addr);
if (end_addr_high != le32_to_cpu(ssp_cmd.addr_high)) {
pm8001_dbg(pm8001_ha, FAIL,
"The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n",
dma_addr,
le32_to_cpu(ssp_cmd.len),
end_addr_high, end_addr_low);
pm8001_chip_make_sg(task->scatter, 1,
ccb->buf_prd);
phys_addr = ccb->ccb_dma_handle;
ssp_cmd.addr_low =
cpu_to_le32(lower_32_bits(phys_addr));
ssp_cmd.addr_high =
cpu_to_le32(upper_32_bits(phys_addr));
ssp_cmd.esgl = cpu_to_le32(1<<31);
}
} 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;
}
}
return pm8001_mpi_build_cmd(pm8001_ha, q_index, opc, &ssp_cmd,
sizeof(ssp_cmd), q_index);
}
static int pm80xx_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;
struct ata_queued_cmd *qc = task->uldd_task;
u32 tag = ccb->ccb_tag, q_index;
struct sata_start_req sata_cmd;
u32 hdr_tag, ncg_tag = 0;
u64 phys_addr, end_addr;
u32 end_addr_high, end_addr_low;
u32 ATAP = 0x0;
u32 dir;
u32 opc = OPC_INB_SATA_HOST_OPSTART;
memset(&sata_cmd, 0, sizeof(sata_cmd));
q_index = pm80xx_chip_get_q_index(task);
if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) {
ATAP = 0x04; /* no data*/
pm8001_dbg(pm8001_ha, IO, "no data\n");
} else if (likely(!task->ata_task.device_control_reg_update)) {
if (task->ata_task.use_ncq &&
dev->sata_dev.class != ATA_DEV_ATAPI) {
ATAP = 0x07; /* FPDMA */
pm8001_dbg(pm8001_ha, IO, "FPDMA\n");
} else if (task->ata_task.dma_xfer) {
ATAP = 0x06; /* DMA */
pm8001_dbg(pm8001_ha, IO, "DMA\n");
} else {
ATAP = 0x05; /* PIO*/
pm8001_dbg(pm8001_ha, IO, "PIO\n");
}
}
if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) {
task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3);
ncg_tag = hdr_tag;
}
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.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 */
/* Check if encryption is set */
if (pm8001_ha->chip->encrypt &&
!(pm8001_ha->encrypt_info.status) && check_enc_sat_cmd(task)) {
pm8001_dbg(pm8001_ha, IO,
"Encryption enabled.Sending Encrypt SATA cmd 0x%x\n",
sata_cmd.sata_fis.command);
opc = OPC_INB_SATA_DIF_ENC_IO;
/* set encryption bit */
sata_cmd.ncqtag_atap_dir_m_dad =
cpu_to_le32(((ncg_tag & 0xff)<<16)|
((ATAP & 0x3f) << 10) | 0x20 | dir);
/* dad (bit 0-1) is 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);
phys_addr = ccb->ccb_dma_handle;
sata_cmd.enc_addr_low =
cpu_to_le32(lower_32_bits(phys_addr));
sata_cmd.enc_addr_high =
cpu_to_le32(upper_32_bits(phys_addr));
sata_cmd.enc_esgl = cpu_to_le32(1 << 31);
} else if (task->num_scatter == 1) {
u64 dma_addr = sg_dma_address(task->scatter);
sata_cmd.enc_addr_low =
cpu_to_le32(lower_32_bits(dma_addr));
sata_cmd.enc_addr_high =
cpu_to_le32(upper_32_bits(dma_addr));
sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
sata_cmd.enc_esgl = 0;
/* Check 4G Boundary */
end_addr = dma_addr + le32_to_cpu(sata_cmd.enc_len) - 1;
end_addr_low = lower_32_bits(end_addr);
end_addr_high = upper_32_bits(end_addr);
if (end_addr_high != le32_to_cpu(sata_cmd.enc_addr_high)) {
pm8001_dbg(pm8001_ha, FAIL,
"The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n",
dma_addr,
le32_to_cpu(sata_cmd.enc_len),
end_addr_high, end_addr_low);
pm8001_chip_make_sg(task->scatter, 1,
ccb->buf_prd);
phys_addr = ccb->ccb_dma_handle;
sata_cmd.enc_addr_low =
cpu_to_le32(lower_32_bits(phys_addr));
sata_cmd.enc_addr_high =
cpu_to_le32(upper_32_bits(phys_addr));
sata_cmd.enc_esgl =
cpu_to_le32(1 << 31);
}
} else if (task->num_scatter == 0) {
sata_cmd.enc_addr_low = 0;
sata_cmd.enc_addr_high = 0;
sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len);
sata_cmd.enc_esgl = 0;
}
/* XTS mode. All other fields are 0 */
sata_cmd.key_index_mode = cpu_to_le32(0x6 << 4);
/* set tweak values. Should be the start lba */
sata_cmd.twk_val0 =
cpu_to_le32((sata_cmd.sata_fis.lbal_exp << 24) |
(sata_cmd.sata_fis.lbah << 16) |
(sata_cmd.sata_fis.lbam << 8) |
(sata_cmd.sata_fis.lbal));
sata_cmd.twk_val1 =
cpu_to_le32((sata_cmd.sata_fis.lbah_exp << 8) |
(sata_cmd.sata_fis.lbam_exp));
} else {
pm8001_dbg(pm8001_ha, IO,
"Sending Normal SATA command 0x%x inb %x\n",
sata_cmd.sata_fis.command, q_index);
/* dad (bit 0-1) is 0 */
sata_cmd.ncqtag_atap_dir_m_dad =
cpu_to_le32(((ncg_tag & 0xff)<<16) |
((ATAP & 0x3f) << 10) | dir);
/* 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);
phys_addr = ccb->ccb_dma_handle;
sata_cmd.addr_low = lower_32_bits(phys_addr);
sata_cmd.addr_high = upper_32_bits(phys_addr);
sata_cmd.esgl = cpu_to_le32(1U << 31);
} else if (task->num_scatter == 1) {
u64 dma_addr = sg_dma_address(task->scatter);
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;
/* Check 4G Boundary */
end_addr = dma_addr + le32_to_cpu(sata_cmd.len) - 1;
end_addr_low = lower_32_bits(end_addr);
end_addr_high = upper_32_bits(end_addr);
if (end_addr_high != sata_cmd.addr_high) {
pm8001_dbg(pm8001_ha, FAIL,
"The sg list address start_addr=0x%016llx data_len=0x%xend_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n",
dma_addr,
le32_to_cpu(sata_cmd.len),
end_addr_high, end_addr_low);
pm8001_chip_make_sg(task->scatter, 1,
ccb->buf_prd);
phys_addr = ccb->ccb_dma_handle;
sata_cmd.addr_low = lower_32_bits(phys_addr);
sata_cmd.addr_high = upper_32_bits(phys_addr);
sata_cmd.esgl = cpu_to_le32(1U << 31);
}
} 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;
}
/* scsi cdb */
sata_cmd.atapi_scsi_cdb[0] =
cpu_to_le32(((task->ata_task.atapi_packet[0]) |
(task->ata_task.atapi_packet[1] << 8) |
(task->ata_task.atapi_packet[2] << 16) |
(task->ata_task.atapi_packet[3] << 24)));
sata_cmd.atapi_scsi_cdb[1] =
cpu_to_le32(((task->ata_task.atapi_packet[4]) |
(task->ata_task.atapi_packet[5] << 8) |
(task->ata_task.atapi_packet[6] << 16) |
(task->ata_task.atapi_packet[7] << 24)));
sata_cmd.atapi_scsi_cdb[2] =
cpu_to_le32(((task->ata_task.atapi_packet[8]) |
(task->ata_task.atapi_packet[9] << 8) |
(task->ata_task.atapi_packet[10] << 16) |
(task->ata_task.atapi_packet[11] << 24)));
sata_cmd.atapi_scsi_cdb[3] =
cpu_to_le32(((task->ata_task.atapi_packet[12]) |
(task->ata_task.atapi_packet[13] << 8) |
(task->ata_task.atapi_packet[14] << 16) |
(task->ata_task.atapi_packet[15] << 24)));
}
trace_pm80xx_request_issue(pm8001_ha->id,
ccb->device ? ccb->device->attached_phy : PM8001_MAX_PHYS,
ccb->ccb_tag, opc,
qc ? qc->tf.command : 0, // ata opcode
ccb->device ? atomic_read(&ccb->device->running_req) : 0);
return pm8001_mpi_build_cmd(pm8001_ha, q_index, opc, &sata_cmd,
sizeof(sata_cmd), q_index);
}
/**
* pm80xx_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
pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id)
{
struct phy_start_req payload;
u32 tag = 0x01;
u32 opcode = OPC_INB_PHYSTART;
memset(&payload, 0, sizeof(payload));
payload.tag = cpu_to_le32(tag);
pm8001_dbg(pm8001_ha, INIT, "PHY START REQ for phy_id %d\n", phy_id);
payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE |
LINKMODE_AUTO | pm8001_ha->link_rate | phy_id);
/* SSC Disable and SAS Analog ST configuration */
/*
payload.ase_sh_lm_slr_phyid =
cpu_to_le32(SSC_DISABLE_30 | SAS_ASE | SPINHOLD_DISABLE |
LINKMODE_AUTO | LINKRATE_15 | LINKRATE_30 | LINKRATE_60 |
phy_id);
Have to add "SAS PHY Analog Setup SPASTI 1 Byte" Based on need
*/
payload.sas_identify.dev_type = SAS_END_DEVICE;
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;
return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload,
sizeof(payload), 0);
}
/**
scsi: pm8001: Fix a bunch of doc-rotted function headers Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:1427: warning: expecting prototype for pm8001_chip_init(). Prototype was for pm80xx_chip_init() instead drivers/scsi/pm8001/pm80xx_hwi.c:1584: warning: expecting prototype for pm8001_chip_soft_rst(). Prototype was for pm80xx_chip_soft_rst() instead drivers/scsi/pm8001/pm80xx_hwi.c:1711: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_intx_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1722: warning: expecting prototype for pm8001_chip_intx_interrupt_disable(). Prototype was for pm80xx_chip_intx_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1733: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1752: warning: expecting prototype for pm8001_chip_interrupt_disable(). Prototype was for pm80xx_chip_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:4192: warning: expecting prototype for pm8001_chip_smp_req(). Prototype was for pm80xx_chip_smp_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4775: warning: expecting prototype for pm8001_chip_phy_stop_req(). Prototype was for pm80xx_chip_phy_stop_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4907: warning: expecting prototype for pm8001_chip_isr(). Prototype was for pm80xx_chip_isr() instead Link: https://lore.kernel.org/r/20210303144631.3175331-23-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Cc: "James E.J. Bottomley" <jejb@linux.ibm.com> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Cc: linux-scsi@vger.kernel.org Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-03 14:46:23 +00:00
* pm80xx_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.
*/
static int pm80xx_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha,
u8 phy_id)
{
struct phy_stop_req payload;
u32 tag = 0x01;
u32 opcode = OPC_INB_PHYSTOP;
memset(&payload, 0, sizeof(payload));
payload.tag = cpu_to_le32(tag);
payload.phy_id = cpu_to_le32(phy_id);
return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload,
sizeof(payload), 0);
}
scsi: pm8001: Fix some function documentation issues Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:918: warning: Function parameter or member 'number' not described in 'update_inbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:954: warning: Function parameter or member 'number' not described in 'update_outbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:1717: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_enable' drivers/scsi/pm8001/pm80xx_hwi.c:1735: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_disable' drivers/scsi/pm8001/pm80xx_hwi.c:4830: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_start_req' drivers/scsi/pm8001/pm80xx_hwi.c:4872: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_stop_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_ha' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_dev' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'flag' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phyId' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phy_op' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'phy_id' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'irq' description in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'stat' description in 'pm80xx_chip_isr' Link: https://lore.kernel.org/r/20200721164148.2617584-18-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-07-21 16:41:25 +00:00
/*
* see comments on pm8001_mpi_reg_resp.
*/
static int pm80xx_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;
u32 linkrate, phy_id;
int rc;
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;
struct pm8001_port *port = dev->port->lldd_port;
memset(&payload, 0, sizeof(payload));
ccb = pm8001_ccb_alloc(pm8001_ha, pm8001_dev, NULL);
if (!ccb)
return -SAS_QUEUE_FULL;
payload.tag = cpu_to_le32(ccb->ccb_tag);
if (flag == 1) {
stp_sspsmp_sata = 0x02; /*direct attached sata */
} else {
if (pm8001_dev->dev_type == SAS_SATA_DEV)
stp_sspsmp_sata = 0x00; /* stp*/
else if (pm8001_dev->dev_type == SAS_END_DEVICE ||
dev_is_expander(pm8001_dev->dev_type))
stp_sspsmp_sata = 0x01; /*ssp or smp*/
}
if (parent_dev && dev_is_expander(parent_dev->dev_type))
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(((port->port_id) & 0xFF) |
((phy_id & 0xFF) << 8));
payload.dtype_dlr_mcn_ir_retry = cpu_to_le32((retryFlag & 0x01) |
((linkrate & 0x0F) << 24) |
((stp_sspsmp_sata & 0x03) << 28));
payload.firstburstsize_ITNexustimeout =
cpu_to_le32(ITNT | (firstBurstSize * 0x10000));
memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr,
SAS_ADDR_SIZE);
pm8001_dbg(pm8001_ha, INIT,
"register device req phy_id 0x%x port_id 0x%x\n", phy_id,
(port->port_id & 0xFF));
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
sizeof(payload), 0);
if (rc)
pm8001_ccb_free(pm8001_ha, ccb);
return rc;
}
/**
* pm80xx_chip_phy_ctl_req - support the local phy operation
* @pm8001_ha: our hba card information.
scsi: pm8001: Fix some function documentation issues Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:918: warning: Function parameter or member 'number' not described in 'update_inbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:954: warning: Function parameter or member 'number' not described in 'update_outbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:1717: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_enable' drivers/scsi/pm8001/pm80xx_hwi.c:1735: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_disable' drivers/scsi/pm8001/pm80xx_hwi.c:4830: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_start_req' drivers/scsi/pm8001/pm80xx_hwi.c:4872: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_stop_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_ha' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_dev' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'flag' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phyId' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phy_op' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'phy_id' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'irq' description in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'stat' description in 'pm80xx_chip_isr' Link: https://lore.kernel.org/r/20200721164148.2617584-18-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-07-21 16:41:25 +00:00
* @phyId: the phy id which we wanted to operate
* @phy_op: phy operation to request
*/
static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha,
u32 phyId, u32 phy_op)
{
u32 tag;
int rc;
struct local_phy_ctl_req payload;
u32 opc = OPC_INB_LOCAL_PHY_CONTROL;
memset(&payload, 0, sizeof(payload));
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc)
return rc;
payload.tag = cpu_to_le32(tag);
payload.phyop_phyid =
cpu_to_le32(((phy_op & 0xFF) << 8) | (phyId & 0xFF));
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
sizeof(payload), 0);
if (rc)
pm8001_tag_free(pm8001_ha, tag);
return rc;
}
static u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha)
{
#ifdef PM8001_USE_MSIX
return 1;
#else
u32 value;
value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR);
if (value)
return 1;
return 0;
#endif
}
/**
scsi: pm8001: Fix a bunch of doc-rotted function headers Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:1427: warning: expecting prototype for pm8001_chip_init(). Prototype was for pm80xx_chip_init() instead drivers/scsi/pm8001/pm80xx_hwi.c:1584: warning: expecting prototype for pm8001_chip_soft_rst(). Prototype was for pm80xx_chip_soft_rst() instead drivers/scsi/pm8001/pm80xx_hwi.c:1711: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_intx_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1722: warning: expecting prototype for pm8001_chip_intx_interrupt_disable(). Prototype was for pm80xx_chip_intx_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1733: warning: expecting prototype for pm8001_chip_interrupt_enable(). Prototype was for pm80xx_chip_interrupt_enable() instead drivers/scsi/pm8001/pm80xx_hwi.c:1752: warning: expecting prototype for pm8001_chip_interrupt_disable(). Prototype was for pm80xx_chip_interrupt_disable() instead drivers/scsi/pm8001/pm80xx_hwi.c:4192: warning: expecting prototype for pm8001_chip_smp_req(). Prototype was for pm80xx_chip_smp_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4775: warning: expecting prototype for pm8001_chip_phy_stop_req(). Prototype was for pm80xx_chip_phy_stop_req() instead drivers/scsi/pm8001/pm80xx_hwi.c:4907: warning: expecting prototype for pm8001_chip_isr(). Prototype was for pm80xx_chip_isr() instead Link: https://lore.kernel.org/r/20210303144631.3175331-23-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Cc: "James E.J. Bottomley" <jejb@linux.ibm.com> Cc: "Martin K. Petersen" <martin.petersen@oracle.com> Cc: linux-scsi@vger.kernel.org Acked-by: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2021-03-03 14:46:23 +00:00
* pm80xx_chip_isr - PM8001 isr handler.
* @pm8001_ha: our hba card information.
scsi: pm8001: Fix some function documentation issues Fixes the following W=1 kernel build warning(s): drivers/scsi/pm8001/pm80xx_hwi.c:918: warning: Function parameter or member 'number' not described in 'update_inbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:954: warning: Function parameter or member 'number' not described in 'update_outbnd_queue_table' drivers/scsi/pm8001/pm80xx_hwi.c:1717: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_enable' drivers/scsi/pm8001/pm80xx_hwi.c:1735: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_interrupt_disable' drivers/scsi/pm8001/pm80xx_hwi.c:4830: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_start_req' drivers/scsi/pm8001/pm80xx_hwi.c:4872: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_stop_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_ha' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'pm8001_dev' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4892: warning: Function parameter or member 'flag' not described in 'pm80xx_chip_reg_dev_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phyId' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Function parameter or member 'phy_op' not described in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'num' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:4966: warning: Excess function parameter 'phy_id' description in 'pm80xx_chip_phy_ctl_req' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Function parameter or member 'vec' not described in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'irq' description in 'pm80xx_chip_isr' drivers/scsi/pm8001/pm80xx_hwi.c:5006: warning: Excess function parameter 'stat' description in 'pm80xx_chip_isr' Link: https://lore.kernel.org/r/20200721164148.2617584-18-lee.jones@linaro.org Cc: Jack Wang <jinpu.wang@cloud.ionos.com> Signed-off-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
2020-07-21 16:41:25 +00:00
* @vec: irq number.
*/
static irqreturn_t
pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec)
{
pm80xx_chip_interrupt_disable(pm8001_ha, vec);
pm8001_dbg(pm8001_ha, DEVIO,
"irq vec %d, ODMR:0x%x\n",
vec, pm8001_cr32(pm8001_ha, 0, 0x30));
process_oq(pm8001_ha, vec);
pm80xx_chip_interrupt_enable(pm8001_ha, vec);
return IRQ_HANDLED;
}
static void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha,
u32 operation, u32 phyid,
u32 length, u32 *buf)
{
u32 tag, i, j = 0;
int rc;
struct set_phy_profile_req payload;
u32 opc = OPC_INB_SET_PHY_PROFILE;
memset(&payload, 0, sizeof(payload));
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc) {
pm8001_dbg(pm8001_ha, FAIL, "Invalid tag\n");
return;
}
payload.tag = cpu_to_le32(tag);
payload.ppc_phyid =
cpu_to_le32(((operation & 0xF) << 8) | (phyid & 0xFF));
pm8001_dbg(pm8001_ha, DISC,
" phy profile command for phy %x ,length is %d\n",
le32_to_cpu(payload.ppc_phyid), length);
for (i = length; i < (length + PHY_DWORD_LENGTH - 1); i++) {
payload.reserved[j] = cpu_to_le32(*((u32 *)buf + i));
j++;
}
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
sizeof(payload), 0);
if (rc)
pm8001_tag_free(pm8001_ha, tag);
}
void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
u32 length, u8 *buf)
{
u32 i;
for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
mpi_set_phy_profile_req(pm8001_ha,
SAS_PHY_ANALOG_SETTINGS_PAGE, i, length, (u32 *)buf);
length = length + PHY_DWORD_LENGTH;
}
pm8001_dbg(pm8001_ha, INIT, "phy settings completed\n");
}
void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
u32 phy, u32 length, u32 *buf)
{
u32 tag, opc;
int rc, i;
struct set_phy_profile_req payload;
memset(&payload, 0, sizeof(payload));
rc = pm8001_tag_alloc(pm8001_ha, &tag);
if (rc) {
pm8001_dbg(pm8001_ha, INIT, "Invalid tag\n");
return;
}
opc = OPC_INB_SET_PHY_PROFILE;
payload.tag = cpu_to_le32(tag);
payload.ppc_phyid =
cpu_to_le32(((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8)
| (phy & 0xFF));
for (i = 0; i < length; i++)
payload.reserved[i] = cpu_to_le32(*(buf + i));
rc = pm8001_mpi_build_cmd(pm8001_ha, 0, opc, &payload,
sizeof(payload), 0);
if (rc)
pm8001_tag_free(pm8001_ha, tag);
pm8001_dbg(pm8001_ha, INIT, "PHY %d settings applied\n", phy);
}
const struct pm8001_dispatch pm8001_80xx_dispatch = {
.name = "pmc80xx",
.chip_init = pm80xx_chip_init,
.chip_post_init = pm80xx_chip_post_init,
.chip_soft_rst = pm80xx_chip_soft_rst,
.chip_rst = pm80xx_hw_chip_rst,
.chip_iounmap = pm8001_chip_iounmap,
.isr = pm80xx_chip_isr,
.is_our_interrupt = pm80xx_chip_is_our_interrupt,
.isr_process_oq = process_oq,
.interrupt_enable = pm80xx_chip_interrupt_enable,
.interrupt_disable = pm80xx_chip_interrupt_disable,
.make_prd = pm8001_chip_make_sg,
.smp_req = pm80xx_chip_smp_req,
.ssp_io_req = pm80xx_chip_ssp_io_req,
.sata_req = pm80xx_chip_sata_req,
.phy_start_req = pm80xx_chip_phy_start_req,
.phy_stop_req = pm80xx_chip_phy_stop_req,
.reg_dev_req = pm80xx_chip_reg_dev_req,
.dereg_dev_req = pm8001_chip_dereg_dev_req,
.phy_ctl_req = pm80xx_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,
.fatal_errors = pm80xx_fatal_errors,
.hw_event_ack_req = pm80xx_hw_event_ack_req,
};