Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: pm80xx: Port reset timeout error handling correction

Error handling steps were not in sequence as per the programmers
manual. Expected sequence:

- PHY_DOWN (PORT_IN_RESET)

- PORT_RESET_TIMER_TMO

- Host aborts pending I/Os

- Host deregister the device

- Host sends HW_EVENT_PHY_DOWN ACK

Previously we were sending HW_EVENT_PHY_DOWN ACK first and then deregister
the device. Fix this to use the expected sequence.

Link: https://lore.kernel.org/r/20211228111753.10802-1-Ajish.Koshy@microchip.com
Signed-off-by: Ajish Koshy <Ajish.Koshy@microchip.com>
Signed-off-by: Viswas G <Viswas.G@microchip.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Ajish Koshy and committed by
Martin K. Petersen
ee05cb71 3bb3c24e

+14 -3
+6 -1
drivers/scsi/pm8001/pm8001_sas.c
··· 1199 1199 struct pm8001_device *pm8001_dev; 1200 1200 struct pm8001_tmf_task tmf_task; 1201 1201 int rc = TMF_RESP_FUNC_FAILED, ret; 1202 - u32 phy_id; 1202 + u32 phy_id, port_id; 1203 1203 struct sas_task_slow slow_task; 1204 1204 1205 1205 if (unlikely(!task || !task->lldd_task || !task->dev)) ··· 1246 1246 DECLARE_COMPLETION_ONSTACK(completion_reset); 1247 1247 DECLARE_COMPLETION_ONSTACK(completion); 1248 1248 struct pm8001_phy *phy = pm8001_ha->phy + phy_id; 1249 + port_id = phy->port->port_id; 1249 1250 1250 1251 /* 1. Set Device state as Recovery */ 1251 1252 pm8001_dev->setds_completion = &completion; ··· 1298 1297 PORT_RESET_TMO); 1299 1298 if (phy->port_reset_status == PORT_RESET_TMO) { 1300 1299 pm8001_dev_gone_notify(dev); 1300 + PM8001_CHIP_DISP->hw_event_ack_req( 1301 + pm8001_ha, 0, 1302 + 0x07, /*HW_EVENT_PHY_DOWN ack*/ 1303 + port_id, phy_id, 0, 0); 1301 1304 goto out; 1302 1305 } 1303 1306 }
+3
drivers/scsi/pm8001/pm8001_sas.h
··· 216 216 u32 state); 217 217 int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha); 218 218 int (*fatal_errors)(struct pm8001_hba_info *pm8001_ha); 219 + void (*hw_event_ack_req)(struct pm8001_hba_info *pm8001_ha, 220 + u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, 221 + u32 param1); 219 222 }; 220 223 221 224 struct pm8001_chip_info {
+5 -2
drivers/scsi/pm8001/pm80xx_hwi.c
··· 3709 3709 break; 3710 3710 case HW_EVENT_PORT_RESET_TIMER_TMO: 3711 3711 pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_PORT_RESET_TIMER_TMO\n"); 3712 - pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, 3713 - port_id, phy_id, 0, 0); 3712 + if (!pm8001_ha->phy[phy_id].reset_completion) { 3713 + pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, 3714 + port_id, phy_id, 0, 0); 3715 + } 3714 3716 sas_phy_disconnected(sas_phy); 3715 3717 phy->phy_attached = 0; 3716 3718 sas_notify_port_event(sas_phy, PORTE_LINK_RESET_ERR, ··· 5053 5051 .fw_flash_update_req = pm8001_chip_fw_flash_update_req, 5054 5052 .set_dev_state_req = pm8001_chip_set_dev_state_req, 5055 5053 .fatal_errors = pm80xx_fatal_errors, 5054 + .hw_event_ack_req = pm80xx_hw_event_ack_req, 5056 5055 };