Commit 32ccba52 authored by Xiaofei Tan's avatar Xiaofei Tan Committed by Martin K. Petersen

scsi: hisi_sas: workaround a SoC SATA IO processing bug

This patch provides a workaround a SoC bug where SATA IPTTs for
different devices may conflict.

The workaround solution requests the following:
1. SATA device id must be even and not equal to SAS IPTT.
2. SATA device can not share the same IPTT with other SAS or
   SATA device.

Besides we shall consider IPTT value 0 is reserved for another SoC bug
(STP device open link at firstly after SAS controller reset).

To sum up, the solution is: Each SATA device uses independent and
continuous 32 even IPTT from 64 to 4094, then v2 hw can only support 63
SATA devices.  All SAS device(SSP/SMP devices) share odd IPTT value from
1 to 4095.
Signed-off-by: default avatarXiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Reviewed-by: default avatarJohannes Thumshirn <jthumshirn@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent c7b9d369
...@@ -115,6 +115,7 @@ struct hisi_sas_device { ...@@ -115,6 +115,7 @@ struct hisi_sas_device {
atomic64_t running_req; atomic64_t running_req;
struct list_head list; struct list_head list;
u8 dev_status; u8 dev_status;
int sata_idx;
}; };
struct hisi_sas_slot { struct hisi_sas_slot {
...@@ -238,6 +239,7 @@ struct hisi_hba { ...@@ -238,6 +239,7 @@ struct hisi_hba {
struct hisi_sas_slot *slot_info; struct hisi_sas_slot *slot_info;
unsigned long flags; unsigned long flags;
const struct hisi_sas_hw *hw; /* Low level hw interface */ const struct hisi_sas_hw *hw; /* Low level hw interface */
unsigned long sata_dev_bitmap[BITS_TO_LONGS(HISI_SAS_MAX_DEVICES)];
struct work_struct rst_work; struct work_struct rst_work;
}; };
......
...@@ -537,6 +537,7 @@ enum { ...@@ -537,6 +537,7 @@ enum {
}; };
#define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096 #define HISI_SAS_COMMAND_ENTRIES_V2_HW 4096
#define HISI_MAX_SATA_SUPPORT_V2_HW (HISI_SAS_COMMAND_ENTRIES_V2_HW/64 - 1)
#define DIR_NO_DATA 0 #define DIR_NO_DATA 0
#define DIR_TO_INI 1 #define DIR_TO_INI 1
...@@ -597,39 +598,86 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba, ...@@ -597,39 +598,86 @@ static u32 hisi_sas_phy_read32(struct hisi_hba *hisi_hba,
/* This function needs to be protected from pre-emption. */ /* This function needs to be protected from pre-emption. */
static int static int
slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx, slot_index_alloc_quirk_v2_hw(struct hisi_hba *hisi_hba, int *slot_idx,
struct domain_device *device) struct domain_device *device)
{ {
/* STP link chip bug workaround:index start from 1 */
unsigned int index = 1;
void *bitmap = hisi_hba->slot_index_tags;
int sata_dev = dev_is_sata(device); int sata_dev = dev_is_sata(device);
void *bitmap = hisi_hba->slot_index_tags;
struct hisi_sas_device *sas_dev = device->lldd_dev;
int sata_idx = sas_dev->sata_idx;
int start, end;
if (!sata_dev) {
/*
* STP link SoC bug workaround: index starts from 1.
* additionally, we can only allocate odd IPTT(1~4095)
* for SAS/SMP device.
*/
start = 1;
end = hisi_hba->slot_index_count;
} else {
if (sata_idx >= HISI_MAX_SATA_SUPPORT_V2_HW)
return -EINVAL;
/*
* For SATA device: allocate even IPTT in this interval
* [64*(sata_idx+1), 64*(sata_idx+2)], then each SATA device
* own 32 IPTTs. IPTT 0 shall not be used duing to STP link
* SoC bug workaround. So we ignore the first 32 even IPTTs.
*/
start = 64 * (sata_idx + 1);
end = 64 * (sata_idx + 2);
}
while (1) { while (1) {
index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, start = find_next_zero_bit(bitmap,
index); hisi_hba->slot_index_count, start);
if (index >= hisi_hba->slot_index_count) if (start >= end)
return -SAS_QUEUE_FULL; return -SAS_QUEUE_FULL;
/* /*
* SAS IPTT bit0 should be 1 * SAS IPTT bit0 should be 1, and SATA IPTT bit0 should be 0.
*/ */
if (sata_dev || (index & 1)) if (sata_dev ^ (start & 1))
break; break;
index++; start++;
} }
set_bit(index, bitmap); set_bit(start, bitmap);
*slot_idx = index; *slot_idx = start;
return 0; return 0;
} }
static bool sata_index_alloc_v2_hw(struct hisi_hba *hisi_hba, int *idx)
{
unsigned int index;
struct device *dev = &hisi_hba->pdev->dev;
void *bitmap = hisi_hba->sata_dev_bitmap;
index = find_first_zero_bit(bitmap, HISI_MAX_SATA_SUPPORT_V2_HW);
if (index >= HISI_MAX_SATA_SUPPORT_V2_HW) {
dev_warn(dev, "alloc sata index failed, index=%d\n", index);
return false;
}
set_bit(index, bitmap);
*idx = index;
return true;
}
static struct static struct
hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
{ {
struct hisi_hba *hisi_hba = device->port->ha->lldd_ha; struct hisi_hba *hisi_hba = device->port->ha->lldd_ha;
struct hisi_sas_device *sas_dev = NULL; struct hisi_sas_device *sas_dev = NULL;
int i, sata_dev = dev_is_sata(device); int i, sata_dev = dev_is_sata(device);
int sata_idx = -1;
spin_lock(&hisi_hba->lock); spin_lock(&hisi_hba->lock);
if (sata_dev)
if (!sata_index_alloc_v2_hw(hisi_hba, &sata_idx))
goto out;
for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
/* /*
* SATA device id bit0 should be 0 * SATA device id bit0 should be 0
...@@ -643,10 +691,13 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device) ...@@ -643,10 +691,13 @@ hisi_sas_device *alloc_dev_quirk_v2_hw(struct domain_device *device)
sas_dev->dev_type = device->dev_type; sas_dev->dev_type = device->dev_type;
sas_dev->hisi_hba = hisi_hba; sas_dev->hisi_hba = hisi_hba;
sas_dev->sas_device = device; sas_dev->sas_device = device;
sas_dev->sata_idx = sata_idx;
INIT_LIST_HEAD(&hisi_hba->devices[i].list); INIT_LIST_HEAD(&hisi_hba->devices[i].list);
break; break;
} }
} }
out:
spin_unlock(&hisi_hba->lock); spin_unlock(&hisi_hba->lock);
return sas_dev; return sas_dev;
...@@ -753,6 +804,10 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba, ...@@ -753,6 +804,10 @@ static void free_device_v2_hw(struct hisi_hba *hisi_hba,
u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3);
int i; int i;
/* SoC bug workaround */
if (dev_is_sata(sas_dev->sas_device))
clear_bit(sas_dev->sata_idx, hisi_hba->sata_dev_bitmap);
/* clear the itct interrupt state */ /* clear the itct interrupt state */
if (ENT_INT_SRC3_ITC_INT_MSK & reg_val) if (ENT_INT_SRC3_ITC_INT_MSK & reg_val)
hisi_sas_write32(hisi_hba, ENT_INT_SRC3, hisi_sas_write32(hisi_hba, ENT_INT_SRC3,
...@@ -3197,6 +3252,8 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba) ...@@ -3197,6 +3252,8 @@ static int hisi_sas_v2_init(struct hisi_hba *hisi_hba)
{ {
int rc; int rc;
memset(hisi_hba->sata_dev_bitmap, 0, sizeof(hisi_hba->sata_dev_bitmap));
rc = hw_init_v2_hw(hisi_hba); rc = hw_init_v2_hw(hisi_hba);
if (rc) if (rc)
return rc; return rc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment