Skip to content

Commit 8aa580c

Browse files
Xingui Yangmartinkpetersen
authored andcommitted
scsi: hisi_sas: Enable force phy when SATA disk directly connected
when a SATA disk is directly connected the SAS controller determines the disk to which I/Os are delivered based on the port ID in the DQ entry. When many phys are disconnected and reconnect, the port ID of phys were changed and used by other link, resulting in I/O being sent to incorrect disk. Data inconsistency on the SATA disk may occur during I/O retries using the old port ID. So enable force phy, then force the command to be executed in a certain phy, and if the actual phy ID of the port does not match the phy configured in the command, the chip will stop delivering the I/O to disk. Fixes: ce60689 ("scsi: hisi_sas: add v3 code to send ATA frame") Signed-off-by: Xingui Yang <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Yihang Li <[email protected]> Signed-off-by: Martin K. Petersen <[email protected]>
1 parent 8db816c commit 8aa580c

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

drivers/scsi/hisi_sas/hisi_sas_v2_hw.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2501,17 +2501,22 @@ static void prep_ata_v2_hw(struct hisi_hba *hisi_hba,
25012501
struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
25022502
struct sas_ata_task *ata_task = &task->ata_task;
25032503
struct sas_tmf_task *tmf = slot->tmf;
2504+
int phy_id;
25042505
u8 *buf_cmd;
25052506
int has_data = 0, hdr_tag = 0;
25062507
u32 dw0, dw1 = 0, dw2 = 0;
25072508

25082509
/* create header */
25092510
/* dw0 */
25102511
dw0 = port->id << CMD_HDR_PORT_OFF;
2511-
if (parent_dev && dev_is_expander(parent_dev->dev_type))
2512+
if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
25122513
dw0 |= 3 << CMD_HDR_CMD_OFF;
2513-
else
2514+
} else {
2515+
phy_id = device->phy->identify.phy_identifier;
2516+
dw0 |= (1U << phy_id) << CMD_HDR_PHY_ID_OFF;
2517+
dw0 |= CMD_HDR_FORCE_PHY_MSK;
25142518
dw0 |= 4 << CMD_HDR_CMD_OFF;
2519+
}
25152520

25162521
if (tmf && ata_task->force_phy) {
25172522
dw0 |= CMD_HDR_FORCE_PHY_MSK;

drivers/scsi/hisi_sas/hisi_sas_v3_hw.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,10 @@
359359
#define CMD_HDR_RESP_REPORT_MSK (0x1 << CMD_HDR_RESP_REPORT_OFF)
360360
#define CMD_HDR_TLR_CTRL_OFF 6
361361
#define CMD_HDR_TLR_CTRL_MSK (0x3 << CMD_HDR_TLR_CTRL_OFF)
362+
#define CMD_HDR_PHY_ID_OFF 8
363+
#define CMD_HDR_PHY_ID_MSK (0x1ff << CMD_HDR_PHY_ID_OFF)
364+
#define CMD_HDR_FORCE_PHY_OFF 17
365+
#define CMD_HDR_FORCE_PHY_MSK (0x1U << CMD_HDR_FORCE_PHY_OFF)
362366
#define CMD_HDR_PORT_OFF 18
363367
#define CMD_HDR_PORT_MSK (0xf << CMD_HDR_PORT_OFF)
364368
#define CMD_HDR_PRIORITY_OFF 27
@@ -1429,15 +1433,21 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
14291433
struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
14301434
struct asd_sas_port *sas_port = device->port;
14311435
struct hisi_sas_port *port = to_hisi_sas_port(sas_port);
1436+
int phy_id;
14321437
u8 *buf_cmd;
14331438
int has_data = 0, hdr_tag = 0;
14341439
u32 dw1 = 0, dw2 = 0;
14351440

14361441
hdr->dw0 = cpu_to_le32(port->id << CMD_HDR_PORT_OFF);
1437-
if (parent_dev && dev_is_expander(parent_dev->dev_type))
1442+
if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
14381443
hdr->dw0 |= cpu_to_le32(3 << CMD_HDR_CMD_OFF);
1439-
else
1444+
} else {
1445+
phy_id = device->phy->identify.phy_identifier;
1446+
hdr->dw0 |= cpu_to_le32((1U << phy_id)
1447+
<< CMD_HDR_PHY_ID_OFF);
1448+
hdr->dw0 |= CMD_HDR_FORCE_PHY_MSK;
14401449
hdr->dw0 |= cpu_to_le32(4U << CMD_HDR_CMD_OFF);
1450+
}
14411451

14421452
switch (task->data_dir) {
14431453
case DMA_TO_DEVICE:

0 commit comments

Comments
 (0)