diff options
| author | Xiaofei Tan <tanxiaofei@huawei.com> | 2018-05-21 06:09:23 -0400 |
|---|---|---|
| committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-05-28 22:40:32 -0400 |
| commit | 31709548d2aca9861a72e2890d62fc87c52199de (patch) | |
| tree | 80ec90612effbd594966ae1b279b39537e51e9cb | |
| parent | b09fcd09e9767f81187aa4036fb16d14e2f2fc79 (diff) | |
scsi: hisi_sas: Terminate STP reject quickly for v2 hw
For v2 hw, STP link from target is rejected after host reset because of a
SoC bug. The STP reject will be terminated after we have sent IO from each
PHY of a port.
This is not an problem before, as we don't need to setup STP link from
target immediately after host reset. But now, it is. Because we want to
send soft-reset immediately after host reset.
In order to terminate STP reject quickly, this patch send ATA reset command
through each PHY of a port. Notes: ATA reset command don't need target's
response.
Besides, we do abort dev for each device before terminating STP reject.
This is a quirk of v2 hw.
Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com>
Signed-off-by: John Garry <john.garry@huawei.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
| -rw-r--r-- | drivers/scsi/hisi_sas/hisi_sas_main.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 4e8046ecf477..cd55849bcd07 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c | |||
| @@ -1275,6 +1275,81 @@ static void hisi_sas_reset_init_all_devices(struct hisi_hba *hisi_hba) | |||
| 1275 | } | 1275 | } |
| 1276 | } | 1276 | } |
| 1277 | 1277 | ||
| 1278 | static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, | ||
| 1279 | struct asd_sas_port *sas_port, | ||
| 1280 | struct domain_device *device) | ||
| 1281 | { | ||
| 1282 | struct hisi_sas_tmf_task tmf_task = { .force_phy = 1 }; | ||
| 1283 | struct ata_port *ap = device->sata_dev.ap; | ||
| 1284 | struct device *dev = hisi_hba->dev; | ||
| 1285 | int s = sizeof(struct host_to_dev_fis); | ||
| 1286 | int rc = TMF_RESP_FUNC_FAILED; | ||
| 1287 | struct asd_sas_phy *sas_phy; | ||
| 1288 | struct ata_link *link; | ||
| 1289 | u8 fis[20] = {0}; | ||
| 1290 | u32 state; | ||
| 1291 | |||
| 1292 | state = hisi_hba->hw->get_phys_state(hisi_hba); | ||
| 1293 | list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) { | ||
| 1294 | if (!(state & BIT(sas_phy->id))) | ||
| 1295 | continue; | ||
| 1296 | |||
| 1297 | ata_for_each_link(link, ap, EDGE) { | ||
| 1298 | int pmp = sata_srst_pmp(link); | ||
| 1299 | |||
| 1300 | tmf_task.phy_id = sas_phy->id; | ||
| 1301 | hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); | ||
| 1302 | rc = hisi_sas_exec_internal_tmf_task(device, fis, s, | ||
| 1303 | &tmf_task); | ||
| 1304 | if (rc != TMF_RESP_FUNC_COMPLETE) { | ||
| 1305 | dev_err(dev, "phy%d ata reset failed rc=%d\n", | ||
| 1306 | sas_phy->id, rc); | ||
| 1307 | break; | ||
| 1308 | } | ||
| 1309 | } | ||
| 1310 | } | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) | ||
| 1314 | { | ||
| 1315 | struct device *dev = hisi_hba->dev; | ||
| 1316 | int port_no, rc, i; | ||
| 1317 | |||
| 1318 | for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { | ||
| 1319 | struct hisi_sas_device *sas_dev = &hisi_hba->devices[i]; | ||
| 1320 | struct domain_device *device = sas_dev->sas_device; | ||
| 1321 | |||
| 1322 | if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device) | ||
| 1323 | continue; | ||
| 1324 | |||
| 1325 | rc = hisi_sas_internal_task_abort(hisi_hba, device, | ||
| 1326 | HISI_SAS_INT_ABT_DEV, 0); | ||
| 1327 | if (rc < 0) | ||
| 1328 | dev_err(dev, "STP reject: abort dev failed %d\n", rc); | ||
| 1329 | } | ||
| 1330 | |||
| 1331 | for (port_no = 0; port_no < hisi_hba->n_phy; port_no++) { | ||
| 1332 | struct hisi_sas_port *port = &hisi_hba->port[port_no]; | ||
| 1333 | struct asd_sas_port *sas_port = &port->sas_port; | ||
| 1334 | struct domain_device *port_dev = sas_port->port_dev; | ||
| 1335 | struct domain_device *device; | ||
| 1336 | |||
| 1337 | if (!port_dev || !DEV_IS_EXPANDER(port_dev->dev_type)) | ||
| 1338 | continue; | ||
| 1339 | |||
| 1340 | /* Try to find a SATA device */ | ||
| 1341 | list_for_each_entry(device, &sas_port->dev_list, | ||
| 1342 | dev_list_node) { | ||
| 1343 | if (dev_is_sata(device)) { | ||
| 1344 | hisi_sas_send_ata_reset_each_phy(hisi_hba, | ||
| 1345 | sas_port, | ||
| 1346 | device); | ||
| 1347 | break; | ||
| 1348 | } | ||
| 1349 | } | ||
| 1350 | } | ||
| 1351 | } | ||
| 1352 | |||
| 1278 | static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) | 1353 | static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) |
| 1279 | { | 1354 | { |
| 1280 | struct device *dev = hisi_hba->dev; | 1355 | struct device *dev = hisi_hba->dev; |
| @@ -1312,6 +1387,9 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) | |||
| 1312 | hisi_hba->hw->phys_init(hisi_hba); | 1387 | hisi_hba->hw->phys_init(hisi_hba); |
| 1313 | msleep(1000); | 1388 | msleep(1000); |
| 1314 | hisi_sas_refresh_port_id(hisi_hba); | 1389 | hisi_sas_refresh_port_id(hisi_hba); |
| 1390 | |||
| 1391 | if (hisi_hba->reject_stp_links_msk) | ||
| 1392 | hisi_sas_terminate_stp_reject(hisi_hba); | ||
| 1315 | hisi_sas_reset_init_all_devices(hisi_hba); | 1393 | hisi_sas_reset_init_all_devices(hisi_hba); |
| 1316 | scsi_unblock_requests(shost); | 1394 | scsi_unblock_requests(shost); |
| 1317 | 1395 | ||
