18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2015 Linaro Ltd. 48c2ecf20Sopenharmony_ci * Copyright (c) 2015 Hisilicon Limited. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "hisi_sas.h" 88c2ecf20Sopenharmony_ci#define DRV_NAME "hisi_sas" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#define DEV_IS_GONE(dev) \ 118c2ecf20Sopenharmony_ci ((!dev) || (dev->dev_type == SAS_PHY_UNUSED)) 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_cistatic int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, 148c2ecf20Sopenharmony_ci u8 *lun, struct hisi_sas_tmf_task *tmf); 158c2ecf20Sopenharmony_cistatic int 168c2ecf20Sopenharmony_cihisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, 178c2ecf20Sopenharmony_ci struct domain_device *device, 188c2ecf20Sopenharmony_ci int abort_flag, int tag); 198c2ecf20Sopenharmony_cistatic int hisi_sas_softreset_ata_disk(struct domain_device *device); 208c2ecf20Sopenharmony_cistatic int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, 218c2ecf20Sopenharmony_ci void *funcdata); 228c2ecf20Sopenharmony_cistatic void hisi_sas_release_task(struct hisi_hba *hisi_hba, 238c2ecf20Sopenharmony_ci struct domain_device *device); 248c2ecf20Sopenharmony_cistatic void hisi_sas_dev_gone(struct domain_device *device); 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciu8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci switch (fis->command) { 298c2ecf20Sopenharmony_ci case ATA_CMD_FPDMA_WRITE: 308c2ecf20Sopenharmony_ci case ATA_CMD_FPDMA_READ: 318c2ecf20Sopenharmony_ci case ATA_CMD_FPDMA_RECV: 328c2ecf20Sopenharmony_ci case ATA_CMD_FPDMA_SEND: 338c2ecf20Sopenharmony_ci case ATA_CMD_NCQ_NON_DATA: 348c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_FPDMA; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci case ATA_CMD_DOWNLOAD_MICRO: 378c2ecf20Sopenharmony_ci case ATA_CMD_ID_ATA: 388c2ecf20Sopenharmony_ci case ATA_CMD_PMP_READ: 398c2ecf20Sopenharmony_ci case ATA_CMD_READ_LOG_EXT: 408c2ecf20Sopenharmony_ci case ATA_CMD_PIO_READ: 418c2ecf20Sopenharmony_ci case ATA_CMD_PIO_READ_EXT: 428c2ecf20Sopenharmony_ci case ATA_CMD_PMP_WRITE: 438c2ecf20Sopenharmony_ci case ATA_CMD_WRITE_LOG_EXT: 448c2ecf20Sopenharmony_ci case ATA_CMD_PIO_WRITE: 458c2ecf20Sopenharmony_ci case ATA_CMD_PIO_WRITE_EXT: 468c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_PIO; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci case ATA_CMD_DSM: 498c2ecf20Sopenharmony_ci case ATA_CMD_DOWNLOAD_MICRO_DMA: 508c2ecf20Sopenharmony_ci case ATA_CMD_PMP_READ_DMA: 518c2ecf20Sopenharmony_ci case ATA_CMD_PMP_WRITE_DMA: 528c2ecf20Sopenharmony_ci case ATA_CMD_READ: 538c2ecf20Sopenharmony_ci case ATA_CMD_READ_EXT: 548c2ecf20Sopenharmony_ci case ATA_CMD_READ_LOG_DMA_EXT: 558c2ecf20Sopenharmony_ci case ATA_CMD_READ_STREAM_DMA_EXT: 568c2ecf20Sopenharmony_ci case ATA_CMD_TRUSTED_RCV_DMA: 578c2ecf20Sopenharmony_ci case ATA_CMD_TRUSTED_SND_DMA: 588c2ecf20Sopenharmony_ci case ATA_CMD_WRITE: 598c2ecf20Sopenharmony_ci case ATA_CMD_WRITE_EXT: 608c2ecf20Sopenharmony_ci case ATA_CMD_WRITE_FUA_EXT: 618c2ecf20Sopenharmony_ci case ATA_CMD_WRITE_QUEUED: 628c2ecf20Sopenharmony_ci case ATA_CMD_WRITE_LOG_DMA_EXT: 638c2ecf20Sopenharmony_ci case ATA_CMD_WRITE_STREAM_DMA_EXT: 648c2ecf20Sopenharmony_ci case ATA_CMD_ZAC_MGMT_IN: 658c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_DMA; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci case ATA_CMD_CHK_POWER: 688c2ecf20Sopenharmony_ci case ATA_CMD_DEV_RESET: 698c2ecf20Sopenharmony_ci case ATA_CMD_EDD: 708c2ecf20Sopenharmony_ci case ATA_CMD_FLUSH: 718c2ecf20Sopenharmony_ci case ATA_CMD_FLUSH_EXT: 728c2ecf20Sopenharmony_ci case ATA_CMD_VERIFY: 738c2ecf20Sopenharmony_ci case ATA_CMD_VERIFY_EXT: 748c2ecf20Sopenharmony_ci case ATA_CMD_SET_FEATURES: 758c2ecf20Sopenharmony_ci case ATA_CMD_STANDBY: 768c2ecf20Sopenharmony_ci case ATA_CMD_STANDBYNOW1: 778c2ecf20Sopenharmony_ci case ATA_CMD_ZAC_MGMT_OUT: 788c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_NONDATA; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci case ATA_CMD_SET_MAX: 818c2ecf20Sopenharmony_ci switch (fis->features) { 828c2ecf20Sopenharmony_ci case ATA_SET_MAX_PASSWD: 838c2ecf20Sopenharmony_ci case ATA_SET_MAX_LOCK: 848c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_PIO; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci case ATA_SET_MAX_PASSWD_DMA: 878c2ecf20Sopenharmony_ci case ATA_SET_MAX_UNLOCK_DMA: 888c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_DMA; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci default: 918c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_NONDATA; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci default: 958c2ecf20Sopenharmony_ci { 968c2ecf20Sopenharmony_ci if (direction == DMA_NONE) 978c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_NONDATA; 988c2ecf20Sopenharmony_ci return HISI_SAS_SATA_PROTOCOL_PIO; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci } 1018c2ecf20Sopenharmony_ci} 1028c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_civoid hisi_sas_sata_done(struct sas_task *task, 1058c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct task_status_struct *ts = &task->task_status; 1088c2ecf20Sopenharmony_ci struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf; 1098c2ecf20Sopenharmony_ci struct hisi_sas_status_buffer *status_buf = 1108c2ecf20Sopenharmony_ci hisi_sas_status_buf_addr_mem(slot); 1118c2ecf20Sopenharmony_ci u8 *iu = &status_buf->iu[0]; 1128c2ecf20Sopenharmony_ci struct dev_to_host_fis *d2h = (struct dev_to_host_fis *)iu; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci resp->frame_len = sizeof(struct dev_to_host_fis); 1158c2ecf20Sopenharmony_ci memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis)); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci ts->buf_valid_size = sizeof(*resp); 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_sata_done); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci/* 1228c2ecf20Sopenharmony_ci * This function assumes linkrate mask fits in 8 bits, which it 1238c2ecf20Sopenharmony_ci * does for all HW versions supported. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ciu8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci u8 rate = 0; 1288c2ecf20Sopenharmony_ci int i; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci max -= SAS_LINK_RATE_1_5_GBPS; 1318c2ecf20Sopenharmony_ci for (i = 0; i <= max; i++) 1328c2ecf20Sopenharmony_ci rate |= 1 << (i * 2); 1338c2ecf20Sopenharmony_ci return rate; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_get_prog_phy_linkrate_mask); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic struct hisi_hba *dev_to_hisi_hba(struct domain_device *device) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci return device->port->ha->lldd_ha; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistruct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci return container_of(sas_port, struct hisi_sas_port, sas_port); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(to_hisi_sas_port); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_civoid hisi_sas_stop_phys(struct hisi_hba *hisi_hba) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci int phy_no; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) 1538c2ecf20Sopenharmony_ci hisi_sas_phy_enable(hisi_hba, phy_no, 0); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_stop_phys); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci void *bitmap = hisi_hba->slot_index_tags; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci clear_bit(slot_idx, bitmap); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci if (hisi_hba->hw->slot_index_alloc || 1678c2ecf20Sopenharmony_ci slot_idx >= HISI_SAS_UNRESERVED_IPTT) { 1688c2ecf20Sopenharmony_ci spin_lock(&hisi_hba->lock); 1698c2ecf20Sopenharmony_ci hisi_sas_slot_index_clear(hisi_hba, slot_idx); 1708c2ecf20Sopenharmony_ci spin_unlock(&hisi_hba->lock); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci void *bitmap = hisi_hba->slot_index_tags; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci set_bit(slot_idx, bitmap); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba, 1828c2ecf20Sopenharmony_ci struct scsi_cmnd *scsi_cmnd) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci int index; 1858c2ecf20Sopenharmony_ci void *bitmap = hisi_hba->slot_index_tags; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (scsi_cmnd) 1888c2ecf20Sopenharmony_ci return scsi_cmnd->request->tag; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci spin_lock(&hisi_hba->lock); 1918c2ecf20Sopenharmony_ci index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count, 1928c2ecf20Sopenharmony_ci hisi_hba->last_slot_index + 1); 1938c2ecf20Sopenharmony_ci if (index >= hisi_hba->slot_index_count) { 1948c2ecf20Sopenharmony_ci index = find_next_zero_bit(bitmap, 1958c2ecf20Sopenharmony_ci hisi_hba->slot_index_count, 1968c2ecf20Sopenharmony_ci HISI_SAS_UNRESERVED_IPTT); 1978c2ecf20Sopenharmony_ci if (index >= hisi_hba->slot_index_count) { 1988c2ecf20Sopenharmony_ci spin_unlock(&hisi_hba->lock); 1998c2ecf20Sopenharmony_ci return -SAS_QUEUE_FULL; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci hisi_sas_slot_index_set(hisi_hba, index); 2038c2ecf20Sopenharmony_ci hisi_hba->last_slot_index = index; 2048c2ecf20Sopenharmony_ci spin_unlock(&hisi_hba->lock); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return index; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci int i; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->slot_index_count; ++i) 2148c2ecf20Sopenharmony_ci hisi_sas_slot_index_clear(hisi_hba, i); 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_civoid hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task, 2188c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci int device_id = slot->device_id; 2218c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = &hisi_hba->devices[device_id]; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (task) { 2248c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (!task->lldd_task) 2278c2ecf20Sopenharmony_ci return; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci task->lldd_task = NULL; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (!sas_protocol_ata(task->task_proto)) { 2328c2ecf20Sopenharmony_ci if (slot->n_elem) 2338c2ecf20Sopenharmony_ci dma_unmap_sg(dev, task->scatter, 2348c2ecf20Sopenharmony_ci task->num_scatter, 2358c2ecf20Sopenharmony_ci task->data_dir); 2368c2ecf20Sopenharmony_ci if (slot->n_elem_dif) { 2378c2ecf20Sopenharmony_ci struct sas_ssp_task *ssp_task = &task->ssp_task; 2388c2ecf20Sopenharmony_ci struct scsi_cmnd *scsi_cmnd = ssp_task->cmd; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd), 2418c2ecf20Sopenharmony_ci scsi_prot_sg_count(scsi_cmnd), 2428c2ecf20Sopenharmony_ci task->data_dir); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci } 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci spin_lock(&sas_dev->lock); 2488c2ecf20Sopenharmony_ci list_del_init(&slot->entry); 2498c2ecf20Sopenharmony_ci spin_unlock(&sas_dev->lock); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci memset(slot, 0, offsetof(struct hisi_sas_slot, buf)); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci hisi_sas_slot_index_free(hisi_hba, slot->idx); 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_slot_task_free); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void hisi_sas_task_prep_smp(struct hisi_hba *hisi_hba, 2588c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot) 2598c2ecf20Sopenharmony_ci{ 2608c2ecf20Sopenharmony_ci hisi_hba->hw->prep_smp(hisi_hba, slot); 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba, 2648c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci hisi_hba->hw->prep_ssp(hisi_hba, slot); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba, 2708c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci hisi_hba->hw->prep_stp(hisi_hba, slot); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba, 2768c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot, 2778c2ecf20Sopenharmony_ci int device_id, int abort_flag, int tag_to_abort) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci hisi_hba->hw->prep_abort(hisi_hba, slot, 2808c2ecf20Sopenharmony_ci device_id, abort_flag, tag_to_abort); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba, 2848c2ecf20Sopenharmony_ci struct sas_task *task, int n_elem, 2858c2ecf20Sopenharmony_ci int n_elem_req) 2868c2ecf20Sopenharmony_ci{ 2878c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (!sas_protocol_ata(task->task_proto)) { 2908c2ecf20Sopenharmony_ci if (task->num_scatter) { 2918c2ecf20Sopenharmony_ci if (n_elem) 2928c2ecf20Sopenharmony_ci dma_unmap_sg(dev, task->scatter, 2938c2ecf20Sopenharmony_ci task->num_scatter, 2948c2ecf20Sopenharmony_ci task->data_dir); 2958c2ecf20Sopenharmony_ci } else if (task->task_proto & SAS_PROTOCOL_SMP) { 2968c2ecf20Sopenharmony_ci if (n_elem_req) 2978c2ecf20Sopenharmony_ci dma_unmap_sg(dev, &task->smp_task.smp_req, 2988c2ecf20Sopenharmony_ci 1, DMA_TO_DEVICE); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci} 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_cistatic int hisi_sas_dma_map(struct hisi_hba *hisi_hba, 3048c2ecf20Sopenharmony_ci struct sas_task *task, int *n_elem, 3058c2ecf20Sopenharmony_ci int *n_elem_req) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 3088c2ecf20Sopenharmony_ci int rc; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if (sas_protocol_ata(task->task_proto)) { 3118c2ecf20Sopenharmony_ci *n_elem = task->num_scatter; 3128c2ecf20Sopenharmony_ci } else { 3138c2ecf20Sopenharmony_ci unsigned int req_len; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci if (task->num_scatter) { 3168c2ecf20Sopenharmony_ci *n_elem = dma_map_sg(dev, task->scatter, 3178c2ecf20Sopenharmony_ci task->num_scatter, task->data_dir); 3188c2ecf20Sopenharmony_ci if (!*n_elem) { 3198c2ecf20Sopenharmony_ci rc = -ENOMEM; 3208c2ecf20Sopenharmony_ci goto prep_out; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci } else if (task->task_proto & SAS_PROTOCOL_SMP) { 3238c2ecf20Sopenharmony_ci *n_elem_req = dma_map_sg(dev, &task->smp_task.smp_req, 3248c2ecf20Sopenharmony_ci 1, DMA_TO_DEVICE); 3258c2ecf20Sopenharmony_ci if (!*n_elem_req) { 3268c2ecf20Sopenharmony_ci rc = -ENOMEM; 3278c2ecf20Sopenharmony_ci goto prep_out; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci req_len = sg_dma_len(&task->smp_task.smp_req); 3308c2ecf20Sopenharmony_ci if (req_len & 0x3) { 3318c2ecf20Sopenharmony_ci rc = -EINVAL; 3328c2ecf20Sopenharmony_ci goto err_out_dma_unmap; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (*n_elem > HISI_SAS_SGE_PAGE_CNT) { 3388c2ecf20Sopenharmony_ci dev_err(dev, "task prep: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT\n", 3398c2ecf20Sopenharmony_ci *n_elem); 3408c2ecf20Sopenharmony_ci rc = -EINVAL; 3418c2ecf20Sopenharmony_ci goto err_out_dma_unmap; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci return 0; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cierr_out_dma_unmap: 3468c2ecf20Sopenharmony_ci /* It would be better to call dma_unmap_sg() here, but it's messy */ 3478c2ecf20Sopenharmony_ci hisi_sas_dma_unmap(hisi_hba, task, *n_elem, 3488c2ecf20Sopenharmony_ci *n_elem_req); 3498c2ecf20Sopenharmony_ciprep_out: 3508c2ecf20Sopenharmony_ci return rc; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_cistatic void hisi_sas_dif_dma_unmap(struct hisi_hba *hisi_hba, 3548c2ecf20Sopenharmony_ci struct sas_task *task, int n_elem_dif) 3558c2ecf20Sopenharmony_ci{ 3568c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci if (n_elem_dif) { 3598c2ecf20Sopenharmony_ci struct sas_ssp_task *ssp_task = &task->ssp_task; 3608c2ecf20Sopenharmony_ci struct scsi_cmnd *scsi_cmnd = ssp_task->cmd; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd), 3638c2ecf20Sopenharmony_ci scsi_prot_sg_count(scsi_cmnd), 3648c2ecf20Sopenharmony_ci task->data_dir); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int hisi_sas_dif_dma_map(struct hisi_hba *hisi_hba, 3698c2ecf20Sopenharmony_ci int *n_elem_dif, struct sas_task *task) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 3728c2ecf20Sopenharmony_ci struct sas_ssp_task *ssp_task; 3738c2ecf20Sopenharmony_ci struct scsi_cmnd *scsi_cmnd; 3748c2ecf20Sopenharmony_ci int rc; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci if (task->num_scatter) { 3778c2ecf20Sopenharmony_ci ssp_task = &task->ssp_task; 3788c2ecf20Sopenharmony_ci scsi_cmnd = ssp_task->cmd; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci if (scsi_prot_sg_count(scsi_cmnd)) { 3818c2ecf20Sopenharmony_ci *n_elem_dif = dma_map_sg(dev, 3828c2ecf20Sopenharmony_ci scsi_prot_sglist(scsi_cmnd), 3838c2ecf20Sopenharmony_ci scsi_prot_sg_count(scsi_cmnd), 3848c2ecf20Sopenharmony_ci task->data_dir); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci if (!*n_elem_dif) 3878c2ecf20Sopenharmony_ci return -ENOMEM; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (*n_elem_dif > HISI_SAS_SGE_DIF_PAGE_CNT) { 3908c2ecf20Sopenharmony_ci dev_err(dev, "task prep: n_elem_dif(%d) too large\n", 3918c2ecf20Sopenharmony_ci *n_elem_dif); 3928c2ecf20Sopenharmony_ci rc = -EINVAL; 3938c2ecf20Sopenharmony_ci goto err_out_dif_dma_unmap; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cierr_out_dif_dma_unmap: 4018c2ecf20Sopenharmony_ci dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd), 4028c2ecf20Sopenharmony_ci scsi_prot_sg_count(scsi_cmnd), task->data_dir); 4038c2ecf20Sopenharmony_ci return rc; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int hisi_sas_task_prep(struct sas_task *task, 4078c2ecf20Sopenharmony_ci struct hisi_sas_dq **dq_pointer, 4088c2ecf20Sopenharmony_ci bool is_tmf, struct hisi_sas_tmf_task *tmf, 4098c2ecf20Sopenharmony_ci int *pass) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct domain_device *device = task->dev; 4128c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 4138c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 4148c2ecf20Sopenharmony_ci struct hisi_sas_port *port; 4158c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot; 4168c2ecf20Sopenharmony_ci struct hisi_sas_cmd_hdr *cmd_hdr_base; 4178c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port = device->port; 4188c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 4198c2ecf20Sopenharmony_ci int dlvry_queue_slot, dlvry_queue, rc, slot_idx; 4208c2ecf20Sopenharmony_ci int n_elem = 0, n_elem_dif = 0, n_elem_req = 0; 4218c2ecf20Sopenharmony_ci struct scsi_cmnd *scmd = NULL; 4228c2ecf20Sopenharmony_ci struct hisi_sas_dq *dq; 4238c2ecf20Sopenharmony_ci unsigned long flags; 4248c2ecf20Sopenharmony_ci int wr_q_index; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (DEV_IS_GONE(sas_dev)) { 4278c2ecf20Sopenharmony_ci if (sas_dev) 4288c2ecf20Sopenharmony_ci dev_info(dev, "task prep: device %d not ready\n", 4298c2ecf20Sopenharmony_ci sas_dev->device_id); 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci dev_info(dev, "task prep: device %016llx not ready\n", 4328c2ecf20Sopenharmony_ci SAS_ADDR(device->sas_addr)); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci return -ECOMM; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (task->uldd_task) { 4388c2ecf20Sopenharmony_ci struct ata_queued_cmd *qc; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci if (dev_is_sata(device)) { 4418c2ecf20Sopenharmony_ci qc = task->uldd_task; 4428c2ecf20Sopenharmony_ci scmd = qc->scsicmd; 4438c2ecf20Sopenharmony_ci } else { 4448c2ecf20Sopenharmony_ci scmd = task->uldd_task; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci if (scmd && hisi_hba->shost->nr_hw_queues) { 4498c2ecf20Sopenharmony_ci unsigned int dq_index; 4508c2ecf20Sopenharmony_ci u32 blk_tag; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci blk_tag = blk_mq_unique_tag(scmd->request); 4538c2ecf20Sopenharmony_ci dq_index = blk_mq_unique_tag_to_hwq(blk_tag); 4548c2ecf20Sopenharmony_ci *dq_pointer = dq = &hisi_hba->dq[dq_index]; 4558c2ecf20Sopenharmony_ci } else if (hisi_hba->shost->nr_hw_queues) { 4568c2ecf20Sopenharmony_ci struct Scsi_Host *shost = hisi_hba->shost; 4578c2ecf20Sopenharmony_ci struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT]; 4588c2ecf20Sopenharmony_ci int queue = qmap->mq_map[raw_smp_processor_id()]; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci *dq_pointer = dq = &hisi_hba->dq[queue]; 4618c2ecf20Sopenharmony_ci } else { 4628c2ecf20Sopenharmony_ci *dq_pointer = dq = sas_dev->dq; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci port = to_hisi_sas_port(sas_port); 4668c2ecf20Sopenharmony_ci if (port && !port->port_attached) { 4678c2ecf20Sopenharmony_ci dev_info(dev, "task prep: %s port%d not attach device\n", 4688c2ecf20Sopenharmony_ci (dev_is_sata(device)) ? 4698c2ecf20Sopenharmony_ci "SATA/STP" : "SAS", 4708c2ecf20Sopenharmony_ci device->port->id); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci return -ECOMM; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci rc = hisi_sas_dma_map(hisi_hba, task, &n_elem, 4768c2ecf20Sopenharmony_ci &n_elem_req); 4778c2ecf20Sopenharmony_ci if (rc < 0) 4788c2ecf20Sopenharmony_ci goto prep_out; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci if (!sas_protocol_ata(task->task_proto)) { 4818c2ecf20Sopenharmony_ci rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task); 4828c2ecf20Sopenharmony_ci if (rc < 0) 4838c2ecf20Sopenharmony_ci goto err_out_dma_unmap; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (hisi_hba->hw->slot_index_alloc) 4878c2ecf20Sopenharmony_ci rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device); 4888c2ecf20Sopenharmony_ci else 4898c2ecf20Sopenharmony_ci rc = hisi_sas_slot_index_alloc(hisi_hba, scmd); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (rc < 0) 4928c2ecf20Sopenharmony_ci goto err_out_dif_dma_unmap; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci slot_idx = rc; 4958c2ecf20Sopenharmony_ci slot = &hisi_hba->slot_info[slot_idx]; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci spin_lock(&dq->lock); 4988c2ecf20Sopenharmony_ci wr_q_index = dq->wr_point; 4998c2ecf20Sopenharmony_ci dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; 5008c2ecf20Sopenharmony_ci list_add_tail(&slot->delivery, &dq->list); 5018c2ecf20Sopenharmony_ci spin_unlock(&dq->lock); 5028c2ecf20Sopenharmony_ci spin_lock(&sas_dev->lock); 5038c2ecf20Sopenharmony_ci list_add_tail(&slot->entry, &sas_dev->list); 5048c2ecf20Sopenharmony_ci spin_unlock(&sas_dev->lock); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci dlvry_queue = dq->id; 5078c2ecf20Sopenharmony_ci dlvry_queue_slot = wr_q_index; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci slot->device_id = sas_dev->device_id; 5108c2ecf20Sopenharmony_ci slot->n_elem = n_elem; 5118c2ecf20Sopenharmony_ci slot->n_elem_dif = n_elem_dif; 5128c2ecf20Sopenharmony_ci slot->dlvry_queue = dlvry_queue; 5138c2ecf20Sopenharmony_ci slot->dlvry_queue_slot = dlvry_queue_slot; 5148c2ecf20Sopenharmony_ci cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; 5158c2ecf20Sopenharmony_ci slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; 5168c2ecf20Sopenharmony_ci slot->task = task; 5178c2ecf20Sopenharmony_ci slot->port = port; 5188c2ecf20Sopenharmony_ci slot->tmf = tmf; 5198c2ecf20Sopenharmony_ci slot->is_internal = is_tmf; 5208c2ecf20Sopenharmony_ci task->lldd_task = slot; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); 5238c2ecf20Sopenharmony_ci memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ); 5248c2ecf20Sopenharmony_ci memset(hisi_sas_status_buf_addr_mem(slot), 0, 5258c2ecf20Sopenharmony_ci sizeof(struct hisi_sas_err_record)); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci switch (task->task_proto) { 5288c2ecf20Sopenharmony_ci case SAS_PROTOCOL_SMP: 5298c2ecf20Sopenharmony_ci hisi_sas_task_prep_smp(hisi_hba, slot); 5308c2ecf20Sopenharmony_ci break; 5318c2ecf20Sopenharmony_ci case SAS_PROTOCOL_SSP: 5328c2ecf20Sopenharmony_ci hisi_sas_task_prep_ssp(hisi_hba, slot); 5338c2ecf20Sopenharmony_ci break; 5348c2ecf20Sopenharmony_ci case SAS_PROTOCOL_SATA: 5358c2ecf20Sopenharmony_ci case SAS_PROTOCOL_STP: 5368c2ecf20Sopenharmony_ci case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: 5378c2ecf20Sopenharmony_ci hisi_sas_task_prep_ata(hisi_hba, slot); 5388c2ecf20Sopenharmony_ci break; 5398c2ecf20Sopenharmony_ci default: 5408c2ecf20Sopenharmony_ci dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n", 5418c2ecf20Sopenharmony_ci task->task_proto); 5428c2ecf20Sopenharmony_ci break; 5438c2ecf20Sopenharmony_ci } 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci spin_lock_irqsave(&task->task_state_lock, flags); 5468c2ecf20Sopenharmony_ci task->task_state_flags |= SAS_TASK_AT_INITIATOR; 5478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci ++(*pass); 5508c2ecf20Sopenharmony_ci WRITE_ONCE(slot->ready, 1); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return 0; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_cierr_out_dif_dma_unmap: 5558c2ecf20Sopenharmony_ci if (!sas_protocol_ata(task->task_proto)) 5568c2ecf20Sopenharmony_ci hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif); 5578c2ecf20Sopenharmony_cierr_out_dma_unmap: 5588c2ecf20Sopenharmony_ci hisi_sas_dma_unmap(hisi_hba, task, n_elem, 5598c2ecf20Sopenharmony_ci n_elem_req); 5608c2ecf20Sopenharmony_ciprep_out: 5618c2ecf20Sopenharmony_ci dev_err(dev, "task prep: failed[%d]!\n", rc); 5628c2ecf20Sopenharmony_ci return rc; 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_cistatic int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, 5668c2ecf20Sopenharmony_ci bool is_tmf, struct hisi_sas_tmf_task *tmf) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci u32 rc; 5698c2ecf20Sopenharmony_ci u32 pass = 0; 5708c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba; 5718c2ecf20Sopenharmony_ci struct device *dev; 5728c2ecf20Sopenharmony_ci struct domain_device *device = task->dev; 5738c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port = device->port; 5748c2ecf20Sopenharmony_ci struct hisi_sas_dq *dq = NULL; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci if (!sas_port) { 5778c2ecf20Sopenharmony_ci struct task_status_struct *ts = &task->task_status; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_UNDELIVERED; 5808c2ecf20Sopenharmony_ci ts->stat = SAS_PHY_DOWN; 5818c2ecf20Sopenharmony_ci /* 5828c2ecf20Sopenharmony_ci * libsas will use dev->port, should 5838c2ecf20Sopenharmony_ci * not call task_done for sata 5848c2ecf20Sopenharmony_ci */ 5858c2ecf20Sopenharmony_ci if (device->dev_type != SAS_SATA_DEV) 5868c2ecf20Sopenharmony_ci task->task_done(task); 5878c2ecf20Sopenharmony_ci return -ECOMM; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci hisi_hba = dev_to_hisi_hba(device); 5918c2ecf20Sopenharmony_ci dev = hisi_hba->dev; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { 5948c2ecf20Sopenharmony_ci /* 5958c2ecf20Sopenharmony_ci * For IOs from upper layer, it may already disable preempt 5968c2ecf20Sopenharmony_ci * in the IO path, if disable preempt again in down(), 5978c2ecf20Sopenharmony_ci * function schedule() will report schedule_bug(), so check 5988c2ecf20Sopenharmony_ci * preemptible() before goto down(). 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci if (!preemptible()) 6018c2ecf20Sopenharmony_ci return -EINVAL; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci down(&hisi_hba->sem); 6048c2ecf20Sopenharmony_ci up(&hisi_hba->sem); 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* protect task_prep and start_delivery sequence */ 6088c2ecf20Sopenharmony_ci rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf, &pass); 6098c2ecf20Sopenharmony_ci if (rc) 6108c2ecf20Sopenharmony_ci dev_err(dev, "task exec: failed[%d]!\n", rc); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci if (likely(pass)) { 6138c2ecf20Sopenharmony_ci spin_lock(&dq->lock); 6148c2ecf20Sopenharmony_ci hisi_hba->hw->start_delivery(dq); 6158c2ecf20Sopenharmony_ci spin_unlock(&dq->lock); 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return rc; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; 6248c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (!phy->phy_attached) 6278c2ecf20Sopenharmony_ci return; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci if (test_bit(HISI_SAS_PM_BIT, &hisi_hba->flags) && 6308c2ecf20Sopenharmony_ci !sas_phy->suspended) { 6318c2ecf20Sopenharmony_ci dev_warn(hisi_hba->dev, "phy%d during suspend filtered out\n", phy_no); 6328c2ecf20Sopenharmony_ci return; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci sas_notify_phy_event(sas_phy, PHYE_OOB_DONE); 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci if (sas_phy->phy) { 6388c2ecf20Sopenharmony_ci struct sas_phy *sphy = sas_phy->phy; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci sphy->negotiated_linkrate = sas_phy->linkrate; 6418c2ecf20Sopenharmony_ci sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 6428c2ecf20Sopenharmony_ci sphy->maximum_linkrate_hw = 6438c2ecf20Sopenharmony_ci hisi_hba->hw->phy_get_max_linkrate(); 6448c2ecf20Sopenharmony_ci if (sphy->minimum_linkrate == SAS_LINK_RATE_UNKNOWN) 6458c2ecf20Sopenharmony_ci sphy->minimum_linkrate = phy->minimum_linkrate; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci if (sphy->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) 6488c2ecf20Sopenharmony_ci sphy->maximum_linkrate = phy->maximum_linkrate; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 6528c2ecf20Sopenharmony_ci struct sas_identify_frame *id; 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci id = (struct sas_identify_frame *)phy->frame_rcvd; 6558c2ecf20Sopenharmony_ci id->dev_type = phy->identify.device_type; 6568c2ecf20Sopenharmony_ci id->initiator_bits = SAS_PROTOCOL_ALL; 6578c2ecf20Sopenharmony_ci id->target_bits = phy->identify.target_port_protocols; 6588c2ecf20Sopenharmony_ci } else if (phy->phy_type & PORT_TYPE_SATA) { 6598c2ecf20Sopenharmony_ci /* Nothing */ 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci sas_phy->frame_rcvd_size = phy->frame_rcvd_size; 6638c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, PORTE_BYTES_DMAED); 6648c2ecf20Sopenharmony_ci} 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_cistatic struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device) 6678c2ecf20Sopenharmony_ci{ 6688c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 6698c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = NULL; 6708c2ecf20Sopenharmony_ci int last = hisi_hba->last_dev_id; 6718c2ecf20Sopenharmony_ci int first = (hisi_hba->last_dev_id + 1) % HISI_SAS_MAX_DEVICES; 6728c2ecf20Sopenharmony_ci int i; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci spin_lock(&hisi_hba->lock); 6758c2ecf20Sopenharmony_ci for (i = first; i != last; i %= HISI_SAS_MAX_DEVICES) { 6768c2ecf20Sopenharmony_ci if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) { 6778c2ecf20Sopenharmony_ci int queue = i % hisi_hba->queue_count; 6788c2ecf20Sopenharmony_ci struct hisi_sas_dq *dq = &hisi_hba->dq[queue]; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci hisi_hba->devices[i].device_id = i; 6818c2ecf20Sopenharmony_ci sas_dev = &hisi_hba->devices[i]; 6828c2ecf20Sopenharmony_ci sas_dev->dev_status = HISI_SAS_DEV_INIT; 6838c2ecf20Sopenharmony_ci sas_dev->dev_type = device->dev_type; 6848c2ecf20Sopenharmony_ci sas_dev->hisi_hba = hisi_hba; 6858c2ecf20Sopenharmony_ci sas_dev->sas_device = device; 6868c2ecf20Sopenharmony_ci sas_dev->dq = dq; 6878c2ecf20Sopenharmony_ci spin_lock_init(&sas_dev->lock); 6888c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&hisi_hba->devices[i].list); 6898c2ecf20Sopenharmony_ci break; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci i++; 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci hisi_hba->last_dev_id = i; 6948c2ecf20Sopenharmony_ci spin_unlock(&hisi_hba->lock); 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci return sas_dev; 6978c2ecf20Sopenharmony_ci} 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci#define HISI_SAS_DISK_RECOVER_CNT 3 7008c2ecf20Sopenharmony_cistatic int hisi_sas_init_device(struct domain_device *device) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci int rc = TMF_RESP_FUNC_COMPLETE; 7038c2ecf20Sopenharmony_ci struct scsi_lun lun; 7048c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task tmf_task; 7058c2ecf20Sopenharmony_ci int retry = HISI_SAS_DISK_RECOVER_CNT; 7068c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 7078c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 7088c2ecf20Sopenharmony_ci struct sas_phy *local_phy; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci switch (device->dev_type) { 7118c2ecf20Sopenharmony_ci case SAS_END_DEVICE: 7128c2ecf20Sopenharmony_ci int_to_scsilun(0, &lun); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci tmf_task.tmf = TMF_CLEAR_TASK_SET; 7158c2ecf20Sopenharmony_ci while (retry-- > 0) { 7168c2ecf20Sopenharmony_ci rc = hisi_sas_debug_issue_ssp_tmf(device, lun.scsi_lun, 7178c2ecf20Sopenharmony_ci &tmf_task); 7188c2ecf20Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE) { 7198c2ecf20Sopenharmony_ci hisi_sas_release_task(hisi_hba, device); 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci break; 7248c2ecf20Sopenharmony_ci case SAS_SATA_DEV: 7258c2ecf20Sopenharmony_ci case SAS_SATA_PM: 7268c2ecf20Sopenharmony_ci case SAS_SATA_PM_PORT: 7278c2ecf20Sopenharmony_ci case SAS_SATA_PENDING: 7288c2ecf20Sopenharmony_ci /* 7298c2ecf20Sopenharmony_ci * send HARD RESET to clear previous affiliation of 7308c2ecf20Sopenharmony_ci * STP target port 7318c2ecf20Sopenharmony_ci */ 7328c2ecf20Sopenharmony_ci local_phy = sas_get_local_phy(device); 7338c2ecf20Sopenharmony_ci if (!scsi_is_sas_phy_local(local_phy) && 7348c2ecf20Sopenharmony_ci !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { 7358c2ecf20Sopenharmony_ci unsigned long deadline = ata_deadline(jiffies, 20000); 7368c2ecf20Sopenharmony_ci struct sata_device *sata_dev = &device->sata_dev; 7378c2ecf20Sopenharmony_ci struct ata_host *ata_host = sata_dev->ata_host; 7388c2ecf20Sopenharmony_ci struct ata_port_operations *ops = ata_host->ops; 7398c2ecf20Sopenharmony_ci struct ata_port *ap = sata_dev->ap; 7408c2ecf20Sopenharmony_ci struct ata_link *link; 7418c2ecf20Sopenharmony_ci unsigned int classes; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) 7448c2ecf20Sopenharmony_ci rc = ops->hardreset(link, &classes, 7458c2ecf20Sopenharmony_ci deadline); 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci sas_put_local_phy(local_phy); 7488c2ecf20Sopenharmony_ci if (rc) { 7498c2ecf20Sopenharmony_ci dev_warn(dev, "SATA disk hardreset fail: %d\n", rc); 7508c2ecf20Sopenharmony_ci return rc; 7518c2ecf20Sopenharmony_ci } 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci while (retry-- > 0) { 7548c2ecf20Sopenharmony_ci rc = hisi_sas_softreset_ata_disk(device); 7558c2ecf20Sopenharmony_ci if (!rc) 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci default: 7608c2ecf20Sopenharmony_ci break; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return rc; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int hisi_sas_dev_found(struct domain_device *device) 7678c2ecf20Sopenharmony_ci{ 7688c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 7698c2ecf20Sopenharmony_ci struct domain_device *parent_dev = device->parent; 7708c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev; 7718c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 7728c2ecf20Sopenharmony_ci int rc; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (hisi_hba->hw->alloc_dev) 7758c2ecf20Sopenharmony_ci sas_dev = hisi_hba->hw->alloc_dev(device); 7768c2ecf20Sopenharmony_ci else 7778c2ecf20Sopenharmony_ci sas_dev = hisi_sas_alloc_dev(device); 7788c2ecf20Sopenharmony_ci if (!sas_dev) { 7798c2ecf20Sopenharmony_ci dev_err(dev, "fail alloc dev: max support %d devices\n", 7808c2ecf20Sopenharmony_ci HISI_SAS_MAX_DEVICES); 7818c2ecf20Sopenharmony_ci return -EINVAL; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci device->lldd_dev = sas_dev; 7858c2ecf20Sopenharmony_ci hisi_hba->hw->setup_itct(hisi_hba, sas_dev); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (parent_dev && dev_is_expander(parent_dev->dev_type)) { 7888c2ecf20Sopenharmony_ci int phy_no; 7898c2ecf20Sopenharmony_ci u8 phy_num = parent_dev->ex_dev.num_phys; 7908c2ecf20Sopenharmony_ci struct ex_phy *phy; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci for (phy_no = 0; phy_no < phy_num; phy_no++) { 7938c2ecf20Sopenharmony_ci phy = &parent_dev->ex_dev.ex_phy[phy_no]; 7948c2ecf20Sopenharmony_ci if (SAS_ADDR(phy->attached_sas_addr) == 7958c2ecf20Sopenharmony_ci SAS_ADDR(device->sas_addr)) 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci if (phy_no == phy_num) { 8008c2ecf20Sopenharmony_ci dev_info(dev, "dev found: no attached " 8018c2ecf20Sopenharmony_ci "dev:%016llx at ex:%016llx\n", 8028c2ecf20Sopenharmony_ci SAS_ADDR(device->sas_addr), 8038c2ecf20Sopenharmony_ci SAS_ADDR(parent_dev->sas_addr)); 8048c2ecf20Sopenharmony_ci rc = -EINVAL; 8058c2ecf20Sopenharmony_ci goto err_out; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci dev_info(dev, "dev[%d:%x] found\n", 8108c2ecf20Sopenharmony_ci sas_dev->device_id, sas_dev->dev_type); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci rc = hisi_sas_init_device(device); 8138c2ecf20Sopenharmony_ci if (rc) 8148c2ecf20Sopenharmony_ci goto err_out; 8158c2ecf20Sopenharmony_ci sas_dev->dev_status = HISI_SAS_DEV_NORMAL; 8168c2ecf20Sopenharmony_ci return 0; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cierr_out: 8198c2ecf20Sopenharmony_ci hisi_sas_dev_gone(device); 8208c2ecf20Sopenharmony_ci return rc; 8218c2ecf20Sopenharmony_ci} 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ciint hisi_sas_slave_configure(struct scsi_device *sdev) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct domain_device *dev = sdev_to_domain_dev(sdev); 8268c2ecf20Sopenharmony_ci int ret = sas_slave_configure(sdev); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci if (ret) 8298c2ecf20Sopenharmony_ci return ret; 8308c2ecf20Sopenharmony_ci if (!dev_is_sata(dev)) 8318c2ecf20Sopenharmony_ci sas_change_queue_depth(sdev, 64); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci return 0; 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_slave_configure); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_civoid hisi_sas_scan_start(struct Scsi_Host *shost) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = shost_priv(shost); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci hisi_hba->hw->phys_init(hisi_hba); 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_scan_start); 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ciint hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = shost_priv(shost); 8488c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = &hisi_hba->sha; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci /* Wait for PHY up interrupt to occur */ 8518c2ecf20Sopenharmony_ci if (time < HZ) 8528c2ecf20Sopenharmony_ci return 0; 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci sas_drain_work(sha); 8558c2ecf20Sopenharmony_ci return 1; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_scan_finished); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_cistatic void hisi_sas_phyup_work(struct work_struct *work) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = 8628c2ecf20Sopenharmony_ci container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP]); 8638c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = phy->hisi_hba; 8648c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 8658c2ecf20Sopenharmony_ci int phy_no = sas_phy->id; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP) 8688c2ecf20Sopenharmony_ci hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no); 8698c2ecf20Sopenharmony_ci hisi_sas_bytes_dmaed(hisi_hba, phy_no); 8708c2ecf20Sopenharmony_ci} 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_cistatic void hisi_sas_linkreset_work(struct work_struct *work) 8738c2ecf20Sopenharmony_ci{ 8748c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = 8758c2ecf20Sopenharmony_ci container_of(work, typeof(*phy), works[HISI_PHYE_LINK_RESET]); 8768c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci hisi_sas_control_phy(sas_phy, PHY_FUNC_LINK_RESET, NULL); 8798c2ecf20Sopenharmony_ci} 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = { 8828c2ecf20Sopenharmony_ci [HISI_PHYE_PHY_UP] = hisi_sas_phyup_work, 8838c2ecf20Sopenharmony_ci [HISI_PHYE_LINK_RESET] = hisi_sas_linkreset_work, 8848c2ecf20Sopenharmony_ci}; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cibool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy, 8878c2ecf20Sopenharmony_ci enum hisi_sas_phy_event event) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = phy->hisi_hba; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci if (WARN_ON(event >= HISI_PHYES_NUM)) 8928c2ecf20Sopenharmony_ci return false; 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci return queue_work(hisi_hba->wq, &phy->works[event]); 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_cistatic void hisi_sas_wait_phyup_timedout(struct timer_list *t) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = from_timer(phy, t, timer); 9018c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = phy->hisi_hba; 9028c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 9038c2ecf20Sopenharmony_ci int phy_no = phy->sas_phy.id; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci dev_warn(dev, "phy%d wait phyup timeout, issuing link reset\n", phy_no); 9068c2ecf20Sopenharmony_ci hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_civoid hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; 9128c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci dev_dbg(dev, "phy%d OOB ready\n", phy_no); 9158c2ecf20Sopenharmony_ci if (phy->phy_attached) 9168c2ecf20Sopenharmony_ci return; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (!timer_pending(&phy->timer)) { 9198c2ecf20Sopenharmony_ci phy->timer.expires = jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT * HZ; 9208c2ecf20Sopenharmony_ci add_timer(&phy->timer); 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci} 9238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_phy_oob_ready); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_cistatic void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no) 9268c2ecf20Sopenharmony_ci{ 9278c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; 9288c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 9298c2ecf20Sopenharmony_ci int i; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci phy->hisi_hba = hisi_hba; 9328c2ecf20Sopenharmony_ci phy->port = NULL; 9338c2ecf20Sopenharmony_ci phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; 9348c2ecf20Sopenharmony_ci phy->maximum_linkrate = hisi_hba->hw->phy_get_max_linkrate(); 9358c2ecf20Sopenharmony_ci sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0; 9368c2ecf20Sopenharmony_ci sas_phy->class = SAS; 9378c2ecf20Sopenharmony_ci sas_phy->iproto = SAS_PROTOCOL_ALL; 9388c2ecf20Sopenharmony_ci sas_phy->tproto = 0; 9398c2ecf20Sopenharmony_ci sas_phy->type = PHY_TYPE_PHYSICAL; 9408c2ecf20Sopenharmony_ci sas_phy->role = PHY_ROLE_INITIATOR; 9418c2ecf20Sopenharmony_ci sas_phy->oob_mode = OOB_NOT_CONNECTED; 9428c2ecf20Sopenharmony_ci sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; 9438c2ecf20Sopenharmony_ci sas_phy->id = phy_no; 9448c2ecf20Sopenharmony_ci sas_phy->sas_addr = &hisi_hba->sas_addr[0]; 9458c2ecf20Sopenharmony_ci sas_phy->frame_rcvd = &phy->frame_rcvd[0]; 9468c2ecf20Sopenharmony_ci sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata; 9478c2ecf20Sopenharmony_ci sas_phy->lldd_phy = phy; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci for (i = 0; i < HISI_PHYES_NUM; i++) 9508c2ecf20Sopenharmony_ci INIT_WORK(&phy->works[i], hisi_sas_phye_fns[i]); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci spin_lock_init(&phy->lock); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci timer_setup(&phy->timer, hisi_sas_wait_phyup_timedout, 0); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/* Wrapper to ensure we track hisi_sas_phy.enable properly */ 9588c2ecf20Sopenharmony_civoid hisi_sas_phy_enable(struct hisi_hba *hisi_hba, int phy_no, int enable) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; 9618c2ecf20Sopenharmony_ci struct asd_sas_phy *aphy = &phy->sas_phy; 9628c2ecf20Sopenharmony_ci struct sas_phy *sphy = aphy->phy; 9638c2ecf20Sopenharmony_ci unsigned long flags; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci spin_lock_irqsave(&phy->lock, flags); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci if (enable) { 9688c2ecf20Sopenharmony_ci /* We may have been enabled already; if so, don't touch */ 9698c2ecf20Sopenharmony_ci if (!phy->enable) 9708c2ecf20Sopenharmony_ci sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 9718c2ecf20Sopenharmony_ci hisi_hba->hw->phy_start(hisi_hba, phy_no); 9728c2ecf20Sopenharmony_ci } else { 9738c2ecf20Sopenharmony_ci sphy->negotiated_linkrate = SAS_PHY_DISABLED; 9748c2ecf20Sopenharmony_ci hisi_hba->hw->phy_disable(hisi_hba, phy_no); 9758c2ecf20Sopenharmony_ci } 9768c2ecf20Sopenharmony_ci phy->enable = enable; 9778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&phy->lock, flags); 9788c2ecf20Sopenharmony_ci} 9798c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_phy_enable); 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) 9828c2ecf20Sopenharmony_ci{ 9838c2ecf20Sopenharmony_ci struct sas_ha_struct *sas_ha = sas_phy->ha; 9848c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = sas_ha->lldd_ha; 9858c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = sas_phy->lldd_phy; 9868c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port = sas_phy->port; 9878c2ecf20Sopenharmony_ci struct hisi_sas_port *port; 9888c2ecf20Sopenharmony_ci unsigned long flags; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci if (!sas_port) 9918c2ecf20Sopenharmony_ci return; 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci port = to_hisi_sas_port(sas_port); 9948c2ecf20Sopenharmony_ci spin_lock_irqsave(&hisi_hba->lock, flags); 9958c2ecf20Sopenharmony_ci port->port_attached = 1; 9968c2ecf20Sopenharmony_ci port->id = phy->port_id; 9978c2ecf20Sopenharmony_ci phy->port = port; 9988c2ecf20Sopenharmony_ci sas_port->lldd_port = port; 9998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hisi_hba->lock, flags); 10008c2ecf20Sopenharmony_ci} 10018c2ecf20Sopenharmony_ci 10028c2ecf20Sopenharmony_cistatic void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task *task, 10038c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot) 10048c2ecf20Sopenharmony_ci{ 10058c2ecf20Sopenharmony_ci if (task) { 10068c2ecf20Sopenharmony_ci unsigned long flags; 10078c2ecf20Sopenharmony_ci struct task_status_struct *ts; 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci ts = &task->task_status; 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci ts->resp = SAS_TASK_COMPLETE; 10128c2ecf20Sopenharmony_ci ts->stat = SAS_ABORTED_TASK; 10138c2ecf20Sopenharmony_ci spin_lock_irqsave(&task->task_state_lock, flags); 10148c2ecf20Sopenharmony_ci task->task_state_flags &= 10158c2ecf20Sopenharmony_ci ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); 10168c2ecf20Sopenharmony_ci if (!slot->is_internal && task->task_proto != SAS_PROTOCOL_SMP) 10178c2ecf20Sopenharmony_ci task->task_state_flags |= SAS_TASK_STATE_DONE; 10188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci hisi_sas_slot_task_free(hisi_hba, task, slot); 10228c2ecf20Sopenharmony_ci} 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_cistatic void hisi_sas_release_task(struct hisi_hba *hisi_hba, 10258c2ecf20Sopenharmony_ci struct domain_device *device) 10268c2ecf20Sopenharmony_ci{ 10278c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot, *slot2; 10288c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry) 10318c2ecf20Sopenharmony_ci hisi_sas_do_release_task(hisi_hba, slot->task, slot); 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_civoid hisi_sas_release_tasks(struct hisi_hba *hisi_hba) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev; 10378c2ecf20Sopenharmony_ci struct domain_device *device; 10388c2ecf20Sopenharmony_ci int i; 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { 10418c2ecf20Sopenharmony_ci sas_dev = &hisi_hba->devices[i]; 10428c2ecf20Sopenharmony_ci device = sas_dev->sas_device; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if ((sas_dev->dev_type == SAS_PHY_UNUSED) || 10458c2ecf20Sopenharmony_ci !device) 10468c2ecf20Sopenharmony_ci continue; 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci hisi_sas_release_task(hisi_hba, device); 10498c2ecf20Sopenharmony_ci } 10508c2ecf20Sopenharmony_ci} 10518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_release_tasks); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_cistatic void hisi_sas_dereg_device(struct hisi_hba *hisi_hba, 10548c2ecf20Sopenharmony_ci struct domain_device *device) 10558c2ecf20Sopenharmony_ci{ 10568c2ecf20Sopenharmony_ci if (hisi_hba->hw->dereg_device) 10578c2ecf20Sopenharmony_ci hisi_hba->hw->dereg_device(hisi_hba, device); 10588c2ecf20Sopenharmony_ci} 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_cistatic void hisi_sas_dev_gone(struct domain_device *device) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 10638c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 10648c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 10658c2ecf20Sopenharmony_ci int ret = 0; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci dev_info(dev, "dev[%d:%x] is gone\n", 10688c2ecf20Sopenharmony_ci sas_dev->device_id, sas_dev->dev_type); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci down(&hisi_hba->sem); 10718c2ecf20Sopenharmony_ci if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) { 10728c2ecf20Sopenharmony_ci hisi_sas_internal_task_abort(hisi_hba, device, 10738c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_DEV, 0); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci hisi_sas_dereg_device(hisi_hba, device); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci ret = hisi_hba->hw->clear_itct(hisi_hba, sas_dev); 10788c2ecf20Sopenharmony_ci device->lldd_dev = NULL; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci if (hisi_hba->hw->free_device) 10828c2ecf20Sopenharmony_ci hisi_hba->hw->free_device(sas_dev); 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* Don't mark it as SAS_PHY_UNUSED if failed to clear ITCT */ 10858c2ecf20Sopenharmony_ci if (!ret) 10868c2ecf20Sopenharmony_ci sas_dev->dev_type = SAS_PHY_UNUSED; 10878c2ecf20Sopenharmony_ci sas_dev->sas_device = NULL; 10888c2ecf20Sopenharmony_ci up(&hisi_hba->sem); 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci return hisi_sas_task_exec(task, gfp_flags, 0, NULL); 10948c2ecf20Sopenharmony_ci} 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_cistatic int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no, 10978c2ecf20Sopenharmony_ci struct sas_phy_linkrates *r) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci struct sas_phy_linkrates _r; 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; 11028c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 11038c2ecf20Sopenharmony_ci enum sas_linkrate min, max; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (r->minimum_linkrate > SAS_LINK_RATE_1_5_GBPS) 11068c2ecf20Sopenharmony_ci return -EINVAL; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) { 11098c2ecf20Sopenharmony_ci max = sas_phy->phy->maximum_linkrate; 11108c2ecf20Sopenharmony_ci min = r->minimum_linkrate; 11118c2ecf20Sopenharmony_ci } else if (r->minimum_linkrate == SAS_LINK_RATE_UNKNOWN) { 11128c2ecf20Sopenharmony_ci max = r->maximum_linkrate; 11138c2ecf20Sopenharmony_ci min = sas_phy->phy->minimum_linkrate; 11148c2ecf20Sopenharmony_ci } else 11158c2ecf20Sopenharmony_ci return -EINVAL; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci _r.maximum_linkrate = max; 11188c2ecf20Sopenharmony_ci _r.minimum_linkrate = min; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci sas_phy->phy->maximum_linkrate = max; 11218c2ecf20Sopenharmony_ci sas_phy->phy->minimum_linkrate = min; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci hisi_sas_phy_enable(hisi_hba, phy_no, 0); 11248c2ecf20Sopenharmony_ci msleep(100); 11258c2ecf20Sopenharmony_ci hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r); 11268c2ecf20Sopenharmony_ci hisi_sas_phy_enable(hisi_hba, phy_no, 1); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci return 0; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func, 11328c2ecf20Sopenharmony_ci void *funcdata) 11338c2ecf20Sopenharmony_ci{ 11348c2ecf20Sopenharmony_ci struct sas_ha_struct *sas_ha = sas_phy->ha; 11358c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = sas_ha->lldd_ha; 11368c2ecf20Sopenharmony_ci int phy_no = sas_phy->id; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci switch (func) { 11398c2ecf20Sopenharmony_ci case PHY_FUNC_HARD_RESET: 11408c2ecf20Sopenharmony_ci hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no); 11418c2ecf20Sopenharmony_ci break; 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci case PHY_FUNC_LINK_RESET: 11448c2ecf20Sopenharmony_ci hisi_sas_phy_enable(hisi_hba, phy_no, 0); 11458c2ecf20Sopenharmony_ci msleep(100); 11468c2ecf20Sopenharmony_ci hisi_sas_phy_enable(hisi_hba, phy_no, 1); 11478c2ecf20Sopenharmony_ci break; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci case PHY_FUNC_DISABLE: 11508c2ecf20Sopenharmony_ci hisi_sas_phy_enable(hisi_hba, phy_no, 0); 11518c2ecf20Sopenharmony_ci break; 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci case PHY_FUNC_SET_LINK_RATE: 11548c2ecf20Sopenharmony_ci return hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata); 11558c2ecf20Sopenharmony_ci case PHY_FUNC_GET_EVENTS: 11568c2ecf20Sopenharmony_ci if (hisi_hba->hw->get_events) { 11578c2ecf20Sopenharmony_ci hisi_hba->hw->get_events(hisi_hba, phy_no); 11588c2ecf20Sopenharmony_ci break; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci fallthrough; 11618c2ecf20Sopenharmony_ci case PHY_FUNC_RELEASE_SPINUP_HOLD: 11628c2ecf20Sopenharmony_ci default: 11638c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 11648c2ecf20Sopenharmony_ci } 11658c2ecf20Sopenharmony_ci return 0; 11668c2ecf20Sopenharmony_ci} 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_cistatic void hisi_sas_task_done(struct sas_task *task) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci del_timer(&task->slow_task->timer); 11718c2ecf20Sopenharmony_ci complete(&task->slow_task->completion); 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cistatic void hisi_sas_tmf_timedout(struct timer_list *t) 11758c2ecf20Sopenharmony_ci{ 11768c2ecf20Sopenharmony_ci struct sas_task_slow *slow = from_timer(slow, t, timer); 11778c2ecf20Sopenharmony_ci struct sas_task *task = slow->task; 11788c2ecf20Sopenharmony_ci unsigned long flags; 11798c2ecf20Sopenharmony_ci bool is_completed = true; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci spin_lock_irqsave(&task->task_state_lock, flags); 11828c2ecf20Sopenharmony_ci if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { 11838c2ecf20Sopenharmony_ci task->task_state_flags |= SAS_TASK_STATE_ABORTED; 11848c2ecf20Sopenharmony_ci is_completed = false; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci if (!is_completed) 11898c2ecf20Sopenharmony_ci complete(&task->slow_task->completion); 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci#define TASK_TIMEOUT 20 11938c2ecf20Sopenharmony_ci#define TASK_RETRY 3 11948c2ecf20Sopenharmony_ci#define INTERNAL_ABORT_TIMEOUT 6 11958c2ecf20Sopenharmony_cistatic int hisi_sas_exec_internal_tmf_task(struct domain_device *device, 11968c2ecf20Sopenharmony_ci void *parameter, u32 para_len, 11978c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task *tmf) 11988c2ecf20Sopenharmony_ci{ 11998c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 12008c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = sas_dev->hisi_hba; 12018c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 12028c2ecf20Sopenharmony_ci struct sas_task *task; 12038c2ecf20Sopenharmony_ci int res, retry; 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci for (retry = 0; retry < TASK_RETRY; retry++) { 12068c2ecf20Sopenharmony_ci task = sas_alloc_slow_task(GFP_KERNEL); 12078c2ecf20Sopenharmony_ci if (!task) 12088c2ecf20Sopenharmony_ci return -ENOMEM; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci task->dev = device; 12118c2ecf20Sopenharmony_ci task->task_proto = device->tproto; 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci if (dev_is_sata(device)) { 12148c2ecf20Sopenharmony_ci task->ata_task.device_control_reg_update = 1; 12158c2ecf20Sopenharmony_ci memcpy(&task->ata_task.fis, parameter, para_len); 12168c2ecf20Sopenharmony_ci } else { 12178c2ecf20Sopenharmony_ci memcpy(&task->ssp_task, parameter, para_len); 12188c2ecf20Sopenharmony_ci } 12198c2ecf20Sopenharmony_ci task->task_done = hisi_sas_task_done; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci task->slow_task->timer.function = hisi_sas_tmf_timedout; 12228c2ecf20Sopenharmony_ci task->slow_task->timer.expires = jiffies + TASK_TIMEOUT * HZ; 12238c2ecf20Sopenharmony_ci add_timer(&task->slow_task->timer); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (res) { 12288c2ecf20Sopenharmony_ci del_timer(&task->slow_task->timer); 12298c2ecf20Sopenharmony_ci dev_err(dev, "abort tmf: executing internal task failed: %d\n", 12308c2ecf20Sopenharmony_ci res); 12318c2ecf20Sopenharmony_ci goto ex_err; 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci wait_for_completion(&task->slow_task->completion); 12358c2ecf20Sopenharmony_ci res = TMF_RESP_FUNC_FAILED; 12368c2ecf20Sopenharmony_ci /* Even TMF timed out, return direct. */ 12378c2ecf20Sopenharmony_ci if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { 12388c2ecf20Sopenharmony_ci if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { 12398c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot = task->lldd_task; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci dev_err(dev, "abort tmf: TMF task timeout and not done\n"); 12428c2ecf20Sopenharmony_ci if (slot) { 12438c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = 12448c2ecf20Sopenharmony_ci &hisi_hba->cq[slot->dlvry_queue]; 12458c2ecf20Sopenharmony_ci /* 12468c2ecf20Sopenharmony_ci * sync irq to avoid free'ing task 12478c2ecf20Sopenharmony_ci * before using task in IO completion 12488c2ecf20Sopenharmony_ci */ 12498c2ecf20Sopenharmony_ci synchronize_irq(cq->irq_no); 12508c2ecf20Sopenharmony_ci slot->task = NULL; 12518c2ecf20Sopenharmony_ci } 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_ci goto ex_err; 12548c2ecf20Sopenharmony_ci } else 12558c2ecf20Sopenharmony_ci dev_err(dev, "abort tmf: TMF task timeout\n"); 12568c2ecf20Sopenharmony_ci } 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (task->task_status.resp == SAS_TASK_COMPLETE && 12598c2ecf20Sopenharmony_ci task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { 12608c2ecf20Sopenharmony_ci res = TMF_RESP_FUNC_COMPLETE; 12618c2ecf20Sopenharmony_ci break; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci if (task->task_status.resp == SAS_TASK_COMPLETE && 12658c2ecf20Sopenharmony_ci task->task_status.stat == TMF_RESP_FUNC_SUCC) { 12668c2ecf20Sopenharmony_ci res = TMF_RESP_FUNC_SUCC; 12678c2ecf20Sopenharmony_ci break; 12688c2ecf20Sopenharmony_ci } 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (task->task_status.resp == SAS_TASK_COMPLETE && 12718c2ecf20Sopenharmony_ci task->task_status.stat == SAS_DATA_UNDERRUN) { 12728c2ecf20Sopenharmony_ci /* no error, but return the number of bytes of 12738c2ecf20Sopenharmony_ci * underrun 12748c2ecf20Sopenharmony_ci */ 12758c2ecf20Sopenharmony_ci dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x sts 0x%x underrun\n", 12768c2ecf20Sopenharmony_ci SAS_ADDR(device->sas_addr), 12778c2ecf20Sopenharmony_ci task->task_status.resp, 12788c2ecf20Sopenharmony_ci task->task_status.stat); 12798c2ecf20Sopenharmony_ci res = task->task_status.residual; 12808c2ecf20Sopenharmony_ci break; 12818c2ecf20Sopenharmony_ci } 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_ci if (task->task_status.resp == SAS_TASK_COMPLETE && 12848c2ecf20Sopenharmony_ci task->task_status.stat == SAS_DATA_OVERRUN) { 12858c2ecf20Sopenharmony_ci dev_warn(dev, "abort tmf: blocked task error\n"); 12868c2ecf20Sopenharmony_ci res = -EMSGSIZE; 12878c2ecf20Sopenharmony_ci break; 12888c2ecf20Sopenharmony_ci } 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci if (task->task_status.resp == SAS_TASK_COMPLETE && 12918c2ecf20Sopenharmony_ci task->task_status.stat == SAS_OPEN_REJECT) { 12928c2ecf20Sopenharmony_ci dev_warn(dev, "abort tmf: open reject failed\n"); 12938c2ecf20Sopenharmony_ci res = -EIO; 12948c2ecf20Sopenharmony_ci } else { 12958c2ecf20Sopenharmony_ci dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x status 0x%x\n", 12968c2ecf20Sopenharmony_ci SAS_ADDR(device->sas_addr), 12978c2ecf20Sopenharmony_ci task->task_status.resp, 12988c2ecf20Sopenharmony_ci task->task_status.stat); 12998c2ecf20Sopenharmony_ci } 13008c2ecf20Sopenharmony_ci sas_free_task(task); 13018c2ecf20Sopenharmony_ci task = NULL; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ciex_err: 13048c2ecf20Sopenharmony_ci if (retry == TASK_RETRY) 13058c2ecf20Sopenharmony_ci dev_warn(dev, "abort tmf: executing internal task failed!\n"); 13068c2ecf20Sopenharmony_ci sas_free_task(task); 13078c2ecf20Sopenharmony_ci return res; 13088c2ecf20Sopenharmony_ci} 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_cistatic void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev, 13118c2ecf20Sopenharmony_ci bool reset, int pmp, u8 *fis) 13128c2ecf20Sopenharmony_ci{ 13138c2ecf20Sopenharmony_ci struct ata_taskfile tf; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci ata_tf_init(dev, &tf); 13168c2ecf20Sopenharmony_ci if (reset) 13178c2ecf20Sopenharmony_ci tf.ctl |= ATA_SRST; 13188c2ecf20Sopenharmony_ci else 13198c2ecf20Sopenharmony_ci tf.ctl &= ~ATA_SRST; 13208c2ecf20Sopenharmony_ci tf.command = ATA_CMD_DEV_RESET; 13218c2ecf20Sopenharmony_ci ata_tf_to_fis(&tf, pmp, 0, fis); 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_cistatic int hisi_sas_softreset_ata_disk(struct domain_device *device) 13258c2ecf20Sopenharmony_ci{ 13268c2ecf20Sopenharmony_ci u8 fis[20] = {0}; 13278c2ecf20Sopenharmony_ci struct ata_port *ap = device->sata_dev.ap; 13288c2ecf20Sopenharmony_ci struct ata_link *link; 13298c2ecf20Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 13308c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 13318c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 13328c2ecf20Sopenharmony_ci int s = sizeof(struct host_to_dev_fis); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 13358c2ecf20Sopenharmony_ci int pmp = sata_srst_pmp(link); 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); 13388c2ecf20Sopenharmony_ci rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL); 13398c2ecf20Sopenharmony_ci if (rc != TMF_RESP_FUNC_COMPLETE) 13408c2ecf20Sopenharmony_ci break; 13418c2ecf20Sopenharmony_ci } 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE) { 13448c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 13458c2ecf20Sopenharmony_ci int pmp = sata_srst_pmp(link); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis); 13488c2ecf20Sopenharmony_ci rc = hisi_sas_exec_internal_tmf_task(device, fis, 13498c2ecf20Sopenharmony_ci s, NULL); 13508c2ecf20Sopenharmony_ci if (rc != TMF_RESP_FUNC_COMPLETE) 13518c2ecf20Sopenharmony_ci dev_err(dev, "ata disk de-reset failed\n"); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci } else { 13548c2ecf20Sopenharmony_ci dev_err(dev, "ata disk reset failed\n"); 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE) 13588c2ecf20Sopenharmony_ci hisi_sas_release_task(hisi_hba, device); 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci return rc; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_cistatic int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device, 13648c2ecf20Sopenharmony_ci u8 *lun, struct hisi_sas_tmf_task *tmf) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci struct sas_ssp_task ssp_task; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (!(device->tproto & SAS_PROTOCOL_SSP)) 13698c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_ESUPP; 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci memcpy(ssp_task.LUN, lun, 8); 13728c2ecf20Sopenharmony_ci 13738c2ecf20Sopenharmony_ci return hisi_sas_exec_internal_tmf_task(device, &ssp_task, 13748c2ecf20Sopenharmony_ci sizeof(ssp_task), tmf); 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci u32 state = hisi_hba->hw->get_phys_state(hisi_hba); 13808c2ecf20Sopenharmony_ci int i; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { 13838c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = &hisi_hba->devices[i]; 13848c2ecf20Sopenharmony_ci struct domain_device *device = sas_dev->sas_device; 13858c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port; 13868c2ecf20Sopenharmony_ci struct hisi_sas_port *port; 13878c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = NULL; 13888c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci if ((sas_dev->dev_type == SAS_PHY_UNUSED) 13918c2ecf20Sopenharmony_ci || !device || !device->port) 13928c2ecf20Sopenharmony_ci continue; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci sas_port = device->port; 13958c2ecf20Sopenharmony_ci port = to_hisi_sas_port(sas_port); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) 13988c2ecf20Sopenharmony_ci if (state & BIT(sas_phy->id)) { 13998c2ecf20Sopenharmony_ci phy = sas_phy->lldd_phy; 14008c2ecf20Sopenharmony_ci break; 14018c2ecf20Sopenharmony_ci } 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci if (phy) { 14048c2ecf20Sopenharmony_ci port->id = phy->port_id; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci /* Update linkrate of directly attached device. */ 14078c2ecf20Sopenharmony_ci if (!device->parent) 14088c2ecf20Sopenharmony_ci device->linkrate = phy->sas_phy.linkrate; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci hisi_hba->hw->setup_itct(hisi_hba, sas_dev); 14118c2ecf20Sopenharmony_ci } else if (!port->port_attached) 14128c2ecf20Sopenharmony_ci port->id = 0xff; 14138c2ecf20Sopenharmony_ci } 14148c2ecf20Sopenharmony_ci} 14158c2ecf20Sopenharmony_ci 14168c2ecf20Sopenharmony_cistatic void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) 14178c2ecf20Sopenharmony_ci{ 14188c2ecf20Sopenharmony_ci struct asd_sas_port *_sas_port = NULL; 14198c2ecf20Sopenharmony_ci int phy_no; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { 14228c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; 14238c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 14248c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port = sas_phy->port; 14258c2ecf20Sopenharmony_ci bool do_port_check = _sas_port != sas_port; 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci if (!sas_phy->phy->enabled) 14288c2ecf20Sopenharmony_ci continue; 14298c2ecf20Sopenharmony_ci 14308c2ecf20Sopenharmony_ci /* Report PHY state change to libsas */ 14318c2ecf20Sopenharmony_ci if (state & BIT(phy_no)) { 14328c2ecf20Sopenharmony_ci if (do_port_check && sas_port && sas_port->port_dev) { 14338c2ecf20Sopenharmony_ci struct domain_device *dev = sas_port->port_dev; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci _sas_port = sas_port; 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_ci if (dev_is_expander(dev->dev_type)) 14388c2ecf20Sopenharmony_ci sas_notify_port_event(sas_phy, 14398c2ecf20Sopenharmony_ci PORTE_BROADCAST_RCVD); 14408c2ecf20Sopenharmony_ci } 14418c2ecf20Sopenharmony_ci } else { 14428c2ecf20Sopenharmony_ci hisi_sas_phy_down(hisi_hba, phy_no, 0); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci } 14458c2ecf20Sopenharmony_ci} 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_cistatic void hisi_sas_reset_init_all_devices(struct hisi_hba *hisi_hba) 14488c2ecf20Sopenharmony_ci{ 14498c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev; 14508c2ecf20Sopenharmony_ci struct domain_device *device; 14518c2ecf20Sopenharmony_ci int i; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { 14548c2ecf20Sopenharmony_ci sas_dev = &hisi_hba->devices[i]; 14558c2ecf20Sopenharmony_ci device = sas_dev->sas_device; 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device) 14588c2ecf20Sopenharmony_ci continue; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci hisi_sas_init_device(device); 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba, 14658c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port, 14668c2ecf20Sopenharmony_ci struct domain_device *device) 14678c2ecf20Sopenharmony_ci{ 14688c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task tmf_task = { .force_phy = 1 }; 14698c2ecf20Sopenharmony_ci struct ata_port *ap = device->sata_dev.ap; 14708c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 14718c2ecf20Sopenharmony_ci int s = sizeof(struct host_to_dev_fis); 14728c2ecf20Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 14738c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy; 14748c2ecf20Sopenharmony_ci struct ata_link *link; 14758c2ecf20Sopenharmony_ci u8 fis[20] = {0}; 14768c2ecf20Sopenharmony_ci u32 state; 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci state = hisi_hba->hw->get_phys_state(hisi_hba); 14798c2ecf20Sopenharmony_ci list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) { 14808c2ecf20Sopenharmony_ci if (!(state & BIT(sas_phy->id))) 14818c2ecf20Sopenharmony_ci continue; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci ata_for_each_link(link, ap, EDGE) { 14848c2ecf20Sopenharmony_ci int pmp = sata_srst_pmp(link); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci tmf_task.phy_id = sas_phy->id; 14878c2ecf20Sopenharmony_ci hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis); 14888c2ecf20Sopenharmony_ci rc = hisi_sas_exec_internal_tmf_task(device, fis, s, 14898c2ecf20Sopenharmony_ci &tmf_task); 14908c2ecf20Sopenharmony_ci if (rc != TMF_RESP_FUNC_COMPLETE) { 14918c2ecf20Sopenharmony_ci dev_err(dev, "phy%d ata reset failed rc=%d\n", 14928c2ecf20Sopenharmony_ci sas_phy->id, rc); 14938c2ecf20Sopenharmony_ci break; 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci } 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba) 15008c2ecf20Sopenharmony_ci{ 15018c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 15028c2ecf20Sopenharmony_ci int port_no, rc, i; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { 15058c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = &hisi_hba->devices[i]; 15068c2ecf20Sopenharmony_ci struct domain_device *device = sas_dev->sas_device; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device) 15098c2ecf20Sopenharmony_ci continue; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci rc = hisi_sas_internal_task_abort(hisi_hba, device, 15128c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_DEV, 0); 15138c2ecf20Sopenharmony_ci if (rc < 0) 15148c2ecf20Sopenharmony_ci dev_err(dev, "STP reject: abort dev failed %d\n", rc); 15158c2ecf20Sopenharmony_ci } 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci for (port_no = 0; port_no < hisi_hba->n_phy; port_no++) { 15188c2ecf20Sopenharmony_ci struct hisi_sas_port *port = &hisi_hba->port[port_no]; 15198c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port = &port->sas_port; 15208c2ecf20Sopenharmony_ci struct domain_device *port_dev = sas_port->port_dev; 15218c2ecf20Sopenharmony_ci struct domain_device *device; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (!port_dev || !dev_is_expander(port_dev->dev_type)) 15248c2ecf20Sopenharmony_ci continue; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci /* Try to find a SATA device */ 15278c2ecf20Sopenharmony_ci list_for_each_entry(device, &sas_port->dev_list, 15288c2ecf20Sopenharmony_ci dev_list_node) { 15298c2ecf20Sopenharmony_ci if (dev_is_sata(device)) { 15308c2ecf20Sopenharmony_ci hisi_sas_send_ata_reset_each_phy(hisi_hba, 15318c2ecf20Sopenharmony_ci sas_port, 15328c2ecf20Sopenharmony_ci device); 15338c2ecf20Sopenharmony_ci break; 15348c2ecf20Sopenharmony_ci } 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci } 15378c2ecf20Sopenharmony_ci} 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_civoid hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci struct Scsi_Host *shost = hisi_hba->shost; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci down(&hisi_hba->sem); 15448c2ecf20Sopenharmony_ci hisi_hba->phy_state = hisi_hba->hw->get_phys_state(hisi_hba); 15458c2ecf20Sopenharmony_ci 15468c2ecf20Sopenharmony_ci scsi_block_requests(shost); 15478c2ecf20Sopenharmony_ci hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000); 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci if (timer_pending(&hisi_hba->timer)) 15508c2ecf20Sopenharmony_ci del_timer_sync(&hisi_hba->timer); 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); 15538c2ecf20Sopenharmony_ci} 15548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_controller_reset_prepare); 15558c2ecf20Sopenharmony_ci 15568c2ecf20Sopenharmony_civoid hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba) 15578c2ecf20Sopenharmony_ci{ 15588c2ecf20Sopenharmony_ci struct Scsi_Host *shost = hisi_hba->shost; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci /* Init and wait for PHYs to come up and all libsas event finished. */ 15618c2ecf20Sopenharmony_ci hisi_hba->hw->phys_init(hisi_hba); 15628c2ecf20Sopenharmony_ci msleep(1000); 15638c2ecf20Sopenharmony_ci hisi_sas_refresh_port_id(hisi_hba); 15648c2ecf20Sopenharmony_ci clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); 15658c2ecf20Sopenharmony_ci 15668c2ecf20Sopenharmony_ci if (hisi_hba->reject_stp_links_msk) 15678c2ecf20Sopenharmony_ci hisi_sas_terminate_stp_reject(hisi_hba); 15688c2ecf20Sopenharmony_ci hisi_sas_reset_init_all_devices(hisi_hba); 15698c2ecf20Sopenharmony_ci up(&hisi_hba->sem); 15708c2ecf20Sopenharmony_ci scsi_unblock_requests(shost); 15718c2ecf20Sopenharmony_ci clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci hisi_sas_rescan_topology(hisi_hba, hisi_hba->phy_state); 15748c2ecf20Sopenharmony_ci} 15758c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_controller_reset_done); 15768c2ecf20Sopenharmony_ci 15778c2ecf20Sopenharmony_cistatic int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) 15788c2ecf20Sopenharmony_ci{ 15798c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 15808c2ecf20Sopenharmony_ci struct Scsi_Host *shost = hisi_hba->shost; 15818c2ecf20Sopenharmony_ci int rc; 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_ci if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) 15848c2ecf20Sopenharmony_ci queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci if (!hisi_hba->hw->soft_reset) 15878c2ecf20Sopenharmony_ci return -ENOENT; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) 15908c2ecf20Sopenharmony_ci return -EPERM; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci dev_info(dev, "controller resetting...\n"); 15938c2ecf20Sopenharmony_ci hisi_sas_controller_reset_prepare(hisi_hba); 15948c2ecf20Sopenharmony_ci 15958c2ecf20Sopenharmony_ci rc = hisi_hba->hw->soft_reset(hisi_hba); 15968c2ecf20Sopenharmony_ci if (rc) { 15978c2ecf20Sopenharmony_ci dev_warn(dev, "controller reset failed (%d)\n", rc); 15988c2ecf20Sopenharmony_ci clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); 15998c2ecf20Sopenharmony_ci up(&hisi_hba->sem); 16008c2ecf20Sopenharmony_ci scsi_unblock_requests(shost); 16018c2ecf20Sopenharmony_ci clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags); 16028c2ecf20Sopenharmony_ci return rc; 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci hisi_sas_controller_reset_done(hisi_hba); 16068c2ecf20Sopenharmony_ci dev_info(dev, "controller reset complete\n"); 16078c2ecf20Sopenharmony_ci 16088c2ecf20Sopenharmony_ci return 0; 16098c2ecf20Sopenharmony_ci} 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_cistatic int hisi_sas_abort_task(struct sas_task *task) 16128c2ecf20Sopenharmony_ci{ 16138c2ecf20Sopenharmony_ci struct scsi_lun lun; 16148c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task tmf_task; 16158c2ecf20Sopenharmony_ci struct domain_device *device = task->dev; 16168c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 16178c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba; 16188c2ecf20Sopenharmony_ci struct device *dev; 16198c2ecf20Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 16208c2ecf20Sopenharmony_ci unsigned long flags; 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci if (!sas_dev) 16238c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci hisi_hba = dev_to_hisi_hba(task->dev); 16268c2ecf20Sopenharmony_ci dev = hisi_hba->dev; 16278c2ecf20Sopenharmony_ci 16288c2ecf20Sopenharmony_ci spin_lock_irqsave(&task->task_state_lock, flags); 16298c2ecf20Sopenharmony_ci if (task->task_state_flags & SAS_TASK_STATE_DONE) { 16308c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot = task->lldd_task; 16318c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq; 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci if (slot) { 16348c2ecf20Sopenharmony_ci /* 16358c2ecf20Sopenharmony_ci * sync irq to avoid free'ing task 16368c2ecf20Sopenharmony_ci * before using task in IO completion 16378c2ecf20Sopenharmony_ci */ 16388c2ecf20Sopenharmony_ci cq = &hisi_hba->cq[slot->dlvry_queue]; 16398c2ecf20Sopenharmony_ci synchronize_irq(cq->irq_no); 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 16428c2ecf20Sopenharmony_ci rc = TMF_RESP_FUNC_COMPLETE; 16438c2ecf20Sopenharmony_ci goto out; 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci task->task_state_flags |= SAS_TASK_STATE_ABORTED; 16468c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { 16498c2ecf20Sopenharmony_ci struct scsi_cmnd *cmnd = task->uldd_task; 16508c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot = task->lldd_task; 16518c2ecf20Sopenharmony_ci u16 tag = slot->idx; 16528c2ecf20Sopenharmony_ci int rc2; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci int_to_scsilun(cmnd->device->lun, &lun); 16558c2ecf20Sopenharmony_ci tmf_task.tmf = TMF_ABORT_TASK; 16568c2ecf20Sopenharmony_ci tmf_task.tag_of_task_to_be_managed = tag; 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun, 16598c2ecf20Sopenharmony_ci &tmf_task); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci rc2 = hisi_sas_internal_task_abort(hisi_hba, device, 16628c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_CMD, tag); 16638c2ecf20Sopenharmony_ci if (rc2 < 0) { 16648c2ecf20Sopenharmony_ci dev_err(dev, "abort task: internal abort (%d)\n", rc2); 16658c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 16668c2ecf20Sopenharmony_ci } 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci /* 16698c2ecf20Sopenharmony_ci * If the TMF finds that the IO is not in the device and also 16708c2ecf20Sopenharmony_ci * the internal abort does not succeed, then it is safe to 16718c2ecf20Sopenharmony_ci * free the slot. 16728c2ecf20Sopenharmony_ci * Note: if the internal abort succeeds then the slot 16738c2ecf20Sopenharmony_ci * will have already been completed 16748c2ecf20Sopenharmony_ci */ 16758c2ecf20Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE && rc2 != TMF_RESP_FUNC_SUCC) { 16768c2ecf20Sopenharmony_ci if (task->lldd_task) 16778c2ecf20Sopenharmony_ci hisi_sas_do_release_task(hisi_hba, task, slot); 16788c2ecf20Sopenharmony_ci } 16798c2ecf20Sopenharmony_ci } else if (task->task_proto & SAS_PROTOCOL_SATA || 16808c2ecf20Sopenharmony_ci task->task_proto & SAS_PROTOCOL_STP) { 16818c2ecf20Sopenharmony_ci if (task->dev->dev_type == SAS_SATA_DEV) { 16828c2ecf20Sopenharmony_ci rc = hisi_sas_internal_task_abort(hisi_hba, device, 16838c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_DEV, 16848c2ecf20Sopenharmony_ci 0); 16858c2ecf20Sopenharmony_ci if (rc < 0) { 16868c2ecf20Sopenharmony_ci dev_err(dev, "abort task: internal abort failed\n"); 16878c2ecf20Sopenharmony_ci goto out; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci hisi_sas_dereg_device(hisi_hba, device); 16908c2ecf20Sopenharmony_ci rc = hisi_sas_softreset_ata_disk(device); 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci } else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) { 16938c2ecf20Sopenharmony_ci /* SMP */ 16948c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot = task->lldd_task; 16958c2ecf20Sopenharmony_ci u32 tag = slot->idx; 16968c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci rc = hisi_sas_internal_task_abort(hisi_hba, device, 16998c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_CMD, tag); 17008c2ecf20Sopenharmony_ci if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) && 17018c2ecf20Sopenharmony_ci task->lldd_task) { 17028c2ecf20Sopenharmony_ci /* 17038c2ecf20Sopenharmony_ci * sync irq to avoid free'ing task 17048c2ecf20Sopenharmony_ci * before using task in IO completion 17058c2ecf20Sopenharmony_ci */ 17068c2ecf20Sopenharmony_ci synchronize_irq(cq->irq_no); 17078c2ecf20Sopenharmony_ci slot->task = NULL; 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci } 17108c2ecf20Sopenharmony_ci 17118c2ecf20Sopenharmony_ciout: 17128c2ecf20Sopenharmony_ci if (rc != TMF_RESP_FUNC_COMPLETE) 17138c2ecf20Sopenharmony_ci dev_notice(dev, "abort task: rc=%d\n", rc); 17148c2ecf20Sopenharmony_ci return rc; 17158c2ecf20Sopenharmony_ci} 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_cistatic int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun) 17188c2ecf20Sopenharmony_ci{ 17198c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 17208c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 17218c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task tmf_task; 17228c2ecf20Sopenharmony_ci int rc; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci rc = hisi_sas_internal_task_abort(hisi_hba, device, 17258c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_DEV, 0); 17268c2ecf20Sopenharmony_ci if (rc < 0) { 17278c2ecf20Sopenharmony_ci dev_err(dev, "abort task set: internal abort rc=%d\n", rc); 17288c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 17298c2ecf20Sopenharmony_ci } 17308c2ecf20Sopenharmony_ci hisi_sas_dereg_device(hisi_hba, device); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_ci tmf_task.tmf = TMF_ABORT_TASK_SET; 17338c2ecf20Sopenharmony_ci rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); 17348c2ecf20Sopenharmony_ci 17358c2ecf20Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE) 17368c2ecf20Sopenharmony_ci hisi_sas_release_task(hisi_hba, device); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci return rc; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_cistatic int hisi_sas_clear_aca(struct domain_device *device, u8 *lun) 17428c2ecf20Sopenharmony_ci{ 17438c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task tmf_task; 17448c2ecf20Sopenharmony_ci int rc; 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci tmf_task.tmf = TMF_CLEAR_ACA; 17478c2ecf20Sopenharmony_ci rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); 17488c2ecf20Sopenharmony_ci 17498c2ecf20Sopenharmony_ci return rc; 17508c2ecf20Sopenharmony_ci} 17518c2ecf20Sopenharmony_ci 17528c2ecf20Sopenharmony_cistatic int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device) 17538c2ecf20Sopenharmony_ci{ 17548c2ecf20Sopenharmony_ci struct sas_phy *local_phy = sas_get_local_phy(device); 17558c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 17568c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 17578c2ecf20Sopenharmony_ci struct sas_ha_struct *sas_ha = &hisi_hba->sha; 17588c2ecf20Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(phyreset); 17598c2ecf20Sopenharmony_ci int rc, reset_type; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci if (!local_phy->enabled) { 17628c2ecf20Sopenharmony_ci sas_put_local_phy(local_phy); 17638c2ecf20Sopenharmony_ci return -ENODEV; 17648c2ecf20Sopenharmony_ci } 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci if (scsi_is_sas_phy_local(local_phy)) { 17678c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = 17688c2ecf20Sopenharmony_ci sas_ha->sas_phy[local_phy->number]; 17698c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = 17708c2ecf20Sopenharmony_ci container_of(sas_phy, struct hisi_sas_phy, sas_phy); 17718c2ecf20Sopenharmony_ci phy->in_reset = 1; 17728c2ecf20Sopenharmony_ci phy->reset_completion = &phyreset; 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci reset_type = (sas_dev->dev_status == HISI_SAS_DEV_INIT || 17768c2ecf20Sopenharmony_ci !dev_is_sata(device)) ? true : false; 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci rc = sas_phy_reset(local_phy, reset_type); 17798c2ecf20Sopenharmony_ci sas_put_local_phy(local_phy); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci if (scsi_is_sas_phy_local(local_phy)) { 17828c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = 17838c2ecf20Sopenharmony_ci sas_ha->sas_phy[local_phy->number]; 17848c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = 17858c2ecf20Sopenharmony_ci container_of(sas_phy, struct hisi_sas_phy, sas_phy); 17868c2ecf20Sopenharmony_ci int ret = wait_for_completion_timeout(&phyreset, 2 * HZ); 17878c2ecf20Sopenharmony_ci unsigned long flags; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci spin_lock_irqsave(&phy->lock, flags); 17908c2ecf20Sopenharmony_ci phy->reset_completion = NULL; 17918c2ecf20Sopenharmony_ci phy->in_reset = 0; 17928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&phy->lock, flags); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci /* report PHY down if timed out */ 17958c2ecf20Sopenharmony_ci if (!ret) 17968c2ecf20Sopenharmony_ci hisi_sas_phy_down(hisi_hba, sas_phy->id, 0); 17978c2ecf20Sopenharmony_ci } else if (sas_dev->dev_status != HISI_SAS_DEV_INIT) { 17988c2ecf20Sopenharmony_ci /* 17998c2ecf20Sopenharmony_ci * If in init state, we rely on caller to wait for link to be 18008c2ecf20Sopenharmony_ci * ready; otherwise, except phy reset is fail, delay. 18018c2ecf20Sopenharmony_ci */ 18028c2ecf20Sopenharmony_ci if (!rc) 18038c2ecf20Sopenharmony_ci msleep(2000); 18048c2ecf20Sopenharmony_ci } 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ci return rc; 18078c2ecf20Sopenharmony_ci} 18088c2ecf20Sopenharmony_ci 18098c2ecf20Sopenharmony_cistatic int hisi_sas_I_T_nexus_reset(struct domain_device *device) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 18128c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 18138c2ecf20Sopenharmony_ci int rc; 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci rc = hisi_sas_internal_task_abort(hisi_hba, device, 18168c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_DEV, 0); 18178c2ecf20Sopenharmony_ci if (rc < 0) { 18188c2ecf20Sopenharmony_ci dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc); 18198c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 18208c2ecf20Sopenharmony_ci } 18218c2ecf20Sopenharmony_ci hisi_sas_dereg_device(hisi_hba, device); 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (dev_is_sata(device)) { 18248c2ecf20Sopenharmony_ci rc = hisi_sas_softreset_ata_disk(device); 18258c2ecf20Sopenharmony_ci if (rc == TMF_RESP_FUNC_FAILED) 18268c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci rc = hisi_sas_debug_I_T_nexus_reset(device); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV)) 18328c2ecf20Sopenharmony_ci hisi_sas_release_task(hisi_hba, device); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci return rc; 18358c2ecf20Sopenharmony_ci} 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_cistatic int hisi_sas_lu_reset(struct domain_device *device, u8 *lun) 18388c2ecf20Sopenharmony_ci{ 18398c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 18408c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); 18418c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 18428c2ecf20Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 18438c2ecf20Sopenharmony_ci 18448c2ecf20Sopenharmony_ci /* Clear internal IO and then lu reset */ 18458c2ecf20Sopenharmony_ci rc = hisi_sas_internal_task_abort(hisi_hba, device, 18468c2ecf20Sopenharmony_ci HISI_SAS_INT_ABT_DEV, 0); 18478c2ecf20Sopenharmony_ci if (rc < 0) { 18488c2ecf20Sopenharmony_ci dev_err(dev, "lu_reset: internal abort failed\n"); 18498c2ecf20Sopenharmony_ci goto out; 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci hisi_sas_dereg_device(hisi_hba, device); 18528c2ecf20Sopenharmony_ci 18538c2ecf20Sopenharmony_ci if (dev_is_sata(device)) { 18548c2ecf20Sopenharmony_ci struct sas_phy *phy; 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci phy = sas_get_local_phy(device); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci rc = sas_phy_reset(phy, true); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci if (rc == 0) 18618c2ecf20Sopenharmony_ci hisi_sas_release_task(hisi_hba, device); 18628c2ecf20Sopenharmony_ci sas_put_local_phy(phy); 18638c2ecf20Sopenharmony_ci } else { 18648c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET }; 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_ci rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task); 18678c2ecf20Sopenharmony_ci if (rc == TMF_RESP_FUNC_COMPLETE) 18688c2ecf20Sopenharmony_ci hisi_sas_release_task(hisi_hba, device); 18698c2ecf20Sopenharmony_ci } 18708c2ecf20Sopenharmony_ciout: 18718c2ecf20Sopenharmony_ci if (rc != TMF_RESP_FUNC_COMPLETE) 18728c2ecf20Sopenharmony_ci dev_err(dev, "lu_reset: for device[%d]:rc= %d\n", 18738c2ecf20Sopenharmony_ci sas_dev->device_id, rc); 18748c2ecf20Sopenharmony_ci return rc; 18758c2ecf20Sopenharmony_ci} 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_cistatic int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha) 18788c2ecf20Sopenharmony_ci{ 18798c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = sas_ha->lldd_ha; 18808c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 18818c2ecf20Sopenharmony_ci HISI_SAS_DECLARE_RST_WORK_ON_STACK(r); 18828c2ecf20Sopenharmony_ci int rc, i; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci queue_work(hisi_hba->wq, &r.work); 18858c2ecf20Sopenharmony_ci wait_for_completion(r.completion); 18868c2ecf20Sopenharmony_ci if (!r.done) 18878c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 18888c2ecf20Sopenharmony_ci 18898c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { 18908c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = &hisi_hba->devices[i]; 18918c2ecf20Sopenharmony_ci struct domain_device *device = sas_dev->sas_device; 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device || 18948c2ecf20Sopenharmony_ci dev_is_expander(device->dev_type)) 18958c2ecf20Sopenharmony_ci continue; 18968c2ecf20Sopenharmony_ci 18978c2ecf20Sopenharmony_ci rc = hisi_sas_debug_I_T_nexus_reset(device); 18988c2ecf20Sopenharmony_ci if (rc != TMF_RESP_FUNC_COMPLETE) 18998c2ecf20Sopenharmony_ci dev_info(dev, "clear nexus ha: for device[%d] rc=%d\n", 19008c2ecf20Sopenharmony_ci sas_dev->device_id, rc); 19018c2ecf20Sopenharmony_ci } 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci hisi_sas_release_tasks(hisi_hba); 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_COMPLETE; 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_cistatic int hisi_sas_query_task(struct sas_task *task) 19098c2ecf20Sopenharmony_ci{ 19108c2ecf20Sopenharmony_ci struct scsi_lun lun; 19118c2ecf20Sopenharmony_ci struct hisi_sas_tmf_task tmf_task; 19128c2ecf20Sopenharmony_ci int rc = TMF_RESP_FUNC_FAILED; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { 19158c2ecf20Sopenharmony_ci struct scsi_cmnd *cmnd = task->uldd_task; 19168c2ecf20Sopenharmony_ci struct domain_device *device = task->dev; 19178c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot = task->lldd_task; 19188c2ecf20Sopenharmony_ci u32 tag = slot->idx; 19198c2ecf20Sopenharmony_ci 19208c2ecf20Sopenharmony_ci int_to_scsilun(cmnd->device->lun, &lun); 19218c2ecf20Sopenharmony_ci tmf_task.tmf = TMF_QUERY_TASK; 19228c2ecf20Sopenharmony_ci tmf_task.tag_of_task_to_be_managed = tag; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci rc = hisi_sas_debug_issue_ssp_tmf(device, 19258c2ecf20Sopenharmony_ci lun.scsi_lun, 19268c2ecf20Sopenharmony_ci &tmf_task); 19278c2ecf20Sopenharmony_ci switch (rc) { 19288c2ecf20Sopenharmony_ci /* The task is still in Lun, release it then */ 19298c2ecf20Sopenharmony_ci case TMF_RESP_FUNC_SUCC: 19308c2ecf20Sopenharmony_ci /* The task is not in Lun or failed, reset the phy */ 19318c2ecf20Sopenharmony_ci case TMF_RESP_FUNC_FAILED: 19328c2ecf20Sopenharmony_ci case TMF_RESP_FUNC_COMPLETE: 19338c2ecf20Sopenharmony_ci break; 19348c2ecf20Sopenharmony_ci default: 19358c2ecf20Sopenharmony_ci rc = TMF_RESP_FUNC_FAILED; 19368c2ecf20Sopenharmony_ci break; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci } 19398c2ecf20Sopenharmony_ci return rc; 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cistatic int 19438c2ecf20Sopenharmony_cihisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id, 19448c2ecf20Sopenharmony_ci struct sas_task *task, int abort_flag, 19458c2ecf20Sopenharmony_ci int task_tag, struct hisi_sas_dq *dq) 19468c2ecf20Sopenharmony_ci{ 19478c2ecf20Sopenharmony_ci struct domain_device *device = task->dev; 19488c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 19498c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 19508c2ecf20Sopenharmony_ci struct hisi_sas_port *port; 19518c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot; 19528c2ecf20Sopenharmony_ci struct asd_sas_port *sas_port = device->port; 19538c2ecf20Sopenharmony_ci struct hisi_sas_cmd_hdr *cmd_hdr_base; 19548c2ecf20Sopenharmony_ci int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx; 19558c2ecf20Sopenharmony_ci unsigned long flags; 19568c2ecf20Sopenharmony_ci int wr_q_index; 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) 19598c2ecf20Sopenharmony_ci return -EINVAL; 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci if (!device->port) 19628c2ecf20Sopenharmony_ci return -1; 19638c2ecf20Sopenharmony_ci 19648c2ecf20Sopenharmony_ci port = to_hisi_sas_port(sas_port); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci /* simply get a slot and send abort command */ 19678c2ecf20Sopenharmony_ci rc = hisi_sas_slot_index_alloc(hisi_hba, NULL); 19688c2ecf20Sopenharmony_ci if (rc < 0) 19698c2ecf20Sopenharmony_ci goto err_out; 19708c2ecf20Sopenharmony_ci 19718c2ecf20Sopenharmony_ci slot_idx = rc; 19728c2ecf20Sopenharmony_ci slot = &hisi_hba->slot_info[slot_idx]; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci spin_lock(&dq->lock); 19758c2ecf20Sopenharmony_ci wr_q_index = dq->wr_point; 19768c2ecf20Sopenharmony_ci dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS; 19778c2ecf20Sopenharmony_ci list_add_tail(&slot->delivery, &dq->list); 19788c2ecf20Sopenharmony_ci spin_unlock(&dq->lock); 19798c2ecf20Sopenharmony_ci spin_lock(&sas_dev->lock); 19808c2ecf20Sopenharmony_ci list_add_tail(&slot->entry, &sas_dev->list); 19818c2ecf20Sopenharmony_ci spin_unlock(&sas_dev->lock); 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci dlvry_queue = dq->id; 19848c2ecf20Sopenharmony_ci dlvry_queue_slot = wr_q_index; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci slot->device_id = sas_dev->device_id; 19878c2ecf20Sopenharmony_ci slot->n_elem = n_elem; 19888c2ecf20Sopenharmony_ci slot->dlvry_queue = dlvry_queue; 19898c2ecf20Sopenharmony_ci slot->dlvry_queue_slot = dlvry_queue_slot; 19908c2ecf20Sopenharmony_ci cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue]; 19918c2ecf20Sopenharmony_ci slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot]; 19928c2ecf20Sopenharmony_ci slot->task = task; 19938c2ecf20Sopenharmony_ci slot->port = port; 19948c2ecf20Sopenharmony_ci slot->is_internal = true; 19958c2ecf20Sopenharmony_ci task->lldd_task = slot; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr)); 19988c2ecf20Sopenharmony_ci memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ); 19998c2ecf20Sopenharmony_ci memset(hisi_sas_status_buf_addr_mem(slot), 0, 20008c2ecf20Sopenharmony_ci sizeof(struct hisi_sas_err_record)); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci hisi_sas_task_prep_abort(hisi_hba, slot, device_id, 20038c2ecf20Sopenharmony_ci abort_flag, task_tag); 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci spin_lock_irqsave(&task->task_state_lock, flags); 20068c2ecf20Sopenharmony_ci task->task_state_flags |= SAS_TASK_AT_INITIATOR; 20078c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&task->task_state_lock, flags); 20088c2ecf20Sopenharmony_ci WRITE_ONCE(slot->ready, 1); 20098c2ecf20Sopenharmony_ci /* send abort command to the chip */ 20108c2ecf20Sopenharmony_ci spin_lock(&dq->lock); 20118c2ecf20Sopenharmony_ci hisi_hba->hw->start_delivery(dq); 20128c2ecf20Sopenharmony_ci spin_unlock(&dq->lock); 20138c2ecf20Sopenharmony_ci 20148c2ecf20Sopenharmony_ci return 0; 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_cierr_out: 20178c2ecf20Sopenharmony_ci dev_err(dev, "internal abort task prep: failed[%d]!\n", rc); 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci return rc; 20208c2ecf20Sopenharmony_ci} 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci/** 20238c2ecf20Sopenharmony_ci * _hisi_sas_internal_task_abort -- execute an internal 20248c2ecf20Sopenharmony_ci * abort command for single IO command or a device 20258c2ecf20Sopenharmony_ci * @hisi_hba: host controller struct 20268c2ecf20Sopenharmony_ci * @device: domain device 20278c2ecf20Sopenharmony_ci * @abort_flag: mode of operation, device or single IO 20288c2ecf20Sopenharmony_ci * @tag: tag of IO to be aborted (only relevant to single 20298c2ecf20Sopenharmony_ci * IO mode) 20308c2ecf20Sopenharmony_ci * @dq: delivery queue for this internal abort command 20318c2ecf20Sopenharmony_ci */ 20328c2ecf20Sopenharmony_cistatic int 20338c2ecf20Sopenharmony_ci_hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, 20348c2ecf20Sopenharmony_ci struct domain_device *device, int abort_flag, 20358c2ecf20Sopenharmony_ci int tag, struct hisi_sas_dq *dq) 20368c2ecf20Sopenharmony_ci{ 20378c2ecf20Sopenharmony_ci struct sas_task *task; 20388c2ecf20Sopenharmony_ci struct hisi_sas_device *sas_dev = device->lldd_dev; 20398c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 20408c2ecf20Sopenharmony_ci int res; 20418c2ecf20Sopenharmony_ci 20428c2ecf20Sopenharmony_ci /* 20438c2ecf20Sopenharmony_ci * The interface is not realized means this HW don't support internal 20448c2ecf20Sopenharmony_ci * abort, or don't need to do internal abort. Then here, we return 20458c2ecf20Sopenharmony_ci * TMF_RESP_FUNC_FAILED and let other steps go on, which depends that 20468c2ecf20Sopenharmony_ci * the internal abort has been executed and returned CQ. 20478c2ecf20Sopenharmony_ci */ 20488c2ecf20Sopenharmony_ci if (!hisi_hba->hw->prep_abort) 20498c2ecf20Sopenharmony_ci return TMF_RESP_FUNC_FAILED; 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci task = sas_alloc_slow_task(GFP_KERNEL); 20528c2ecf20Sopenharmony_ci if (!task) 20538c2ecf20Sopenharmony_ci return -ENOMEM; 20548c2ecf20Sopenharmony_ci 20558c2ecf20Sopenharmony_ci task->dev = device; 20568c2ecf20Sopenharmony_ci task->task_proto = device->tproto; 20578c2ecf20Sopenharmony_ci task->task_done = hisi_sas_task_done; 20588c2ecf20Sopenharmony_ci task->slow_task->timer.function = hisi_sas_tmf_timedout; 20598c2ecf20Sopenharmony_ci task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT * HZ; 20608c2ecf20Sopenharmony_ci add_timer(&task->slow_task->timer); 20618c2ecf20Sopenharmony_ci 20628c2ecf20Sopenharmony_ci res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id, 20638c2ecf20Sopenharmony_ci task, abort_flag, tag, dq); 20648c2ecf20Sopenharmony_ci if (res) { 20658c2ecf20Sopenharmony_ci del_timer(&task->slow_task->timer); 20668c2ecf20Sopenharmony_ci dev_err(dev, "internal task abort: executing internal task failed: %d\n", 20678c2ecf20Sopenharmony_ci res); 20688c2ecf20Sopenharmony_ci goto exit; 20698c2ecf20Sopenharmony_ci } 20708c2ecf20Sopenharmony_ci wait_for_completion(&task->slow_task->completion); 20718c2ecf20Sopenharmony_ci res = TMF_RESP_FUNC_FAILED; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci /* Internal abort timed out */ 20748c2ecf20Sopenharmony_ci if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { 20758c2ecf20Sopenharmony_ci if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) 20768c2ecf20Sopenharmony_ci queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { 20798c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot = task->lldd_task; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_ci if (slot) { 20828c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = 20838c2ecf20Sopenharmony_ci &hisi_hba->cq[slot->dlvry_queue]; 20848c2ecf20Sopenharmony_ci /* 20858c2ecf20Sopenharmony_ci * sync irq to avoid free'ing task 20868c2ecf20Sopenharmony_ci * before using task in IO completion 20878c2ecf20Sopenharmony_ci */ 20888c2ecf20Sopenharmony_ci synchronize_irq(cq->irq_no); 20898c2ecf20Sopenharmony_ci slot->task = NULL; 20908c2ecf20Sopenharmony_ci } 20918c2ecf20Sopenharmony_ci dev_err(dev, "internal task abort: timeout and not done.\n"); 20928c2ecf20Sopenharmony_ci 20938c2ecf20Sopenharmony_ci res = -EIO; 20948c2ecf20Sopenharmony_ci goto exit; 20958c2ecf20Sopenharmony_ci } else 20968c2ecf20Sopenharmony_ci dev_err(dev, "internal task abort: timeout.\n"); 20978c2ecf20Sopenharmony_ci } 20988c2ecf20Sopenharmony_ci 20998c2ecf20Sopenharmony_ci if (task->task_status.resp == SAS_TASK_COMPLETE && 21008c2ecf20Sopenharmony_ci task->task_status.stat == TMF_RESP_FUNC_COMPLETE) { 21018c2ecf20Sopenharmony_ci res = TMF_RESP_FUNC_COMPLETE; 21028c2ecf20Sopenharmony_ci goto exit; 21038c2ecf20Sopenharmony_ci } 21048c2ecf20Sopenharmony_ci 21058c2ecf20Sopenharmony_ci if (task->task_status.resp == SAS_TASK_COMPLETE && 21068c2ecf20Sopenharmony_ci task->task_status.stat == TMF_RESP_FUNC_SUCC) { 21078c2ecf20Sopenharmony_ci res = TMF_RESP_FUNC_SUCC; 21088c2ecf20Sopenharmony_ci goto exit; 21098c2ecf20Sopenharmony_ci } 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ciexit: 21128c2ecf20Sopenharmony_ci dev_dbg(dev, "internal task abort: task to dev %016llx task=%pK resp: 0x%x sts 0x%x\n", 21138c2ecf20Sopenharmony_ci SAS_ADDR(device->sas_addr), task, 21148c2ecf20Sopenharmony_ci task->task_status.resp, /* 0 is complete, -1 is undelivered */ 21158c2ecf20Sopenharmony_ci task->task_status.stat); 21168c2ecf20Sopenharmony_ci sas_free_task(task); 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci return res; 21198c2ecf20Sopenharmony_ci} 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_cistatic int 21228c2ecf20Sopenharmony_cihisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, 21238c2ecf20Sopenharmony_ci struct domain_device *device, 21248c2ecf20Sopenharmony_ci int abort_flag, int tag) 21258c2ecf20Sopenharmony_ci{ 21268c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot; 21278c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 21288c2ecf20Sopenharmony_ci struct hisi_sas_dq *dq; 21298c2ecf20Sopenharmony_ci int i, rc; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci switch (abort_flag) { 21328c2ecf20Sopenharmony_ci case HISI_SAS_INT_ABT_CMD: 21338c2ecf20Sopenharmony_ci slot = &hisi_hba->slot_info[tag]; 21348c2ecf20Sopenharmony_ci dq = &hisi_hba->dq[slot->dlvry_queue]; 21358c2ecf20Sopenharmony_ci return _hisi_sas_internal_task_abort(hisi_hba, device, 21368c2ecf20Sopenharmony_ci abort_flag, tag, dq); 21378c2ecf20Sopenharmony_ci case HISI_SAS_INT_ABT_DEV: 21388c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->cq_nvecs; i++) { 21398c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = &hisi_hba->cq[i]; 21408c2ecf20Sopenharmony_ci const struct cpumask *mask = cq->irq_mask; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci if (mask && !cpumask_intersects(cpu_online_mask, mask)) 21438c2ecf20Sopenharmony_ci continue; 21448c2ecf20Sopenharmony_ci dq = &hisi_hba->dq[i]; 21458c2ecf20Sopenharmony_ci rc = _hisi_sas_internal_task_abort(hisi_hba, device, 21468c2ecf20Sopenharmony_ci abort_flag, tag, 21478c2ecf20Sopenharmony_ci dq); 21488c2ecf20Sopenharmony_ci if (rc) 21498c2ecf20Sopenharmony_ci return rc; 21508c2ecf20Sopenharmony_ci } 21518c2ecf20Sopenharmony_ci break; 21528c2ecf20Sopenharmony_ci default: 21538c2ecf20Sopenharmony_ci dev_err(dev, "Unrecognised internal abort flag (%d)\n", 21548c2ecf20Sopenharmony_ci abort_flag); 21558c2ecf20Sopenharmony_ci return -EINVAL; 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci return 0; 21598c2ecf20Sopenharmony_ci} 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_cistatic void hisi_sas_port_formed(struct asd_sas_phy *sas_phy) 21628c2ecf20Sopenharmony_ci{ 21638c2ecf20Sopenharmony_ci hisi_sas_port_notify_formed(sas_phy); 21648c2ecf20Sopenharmony_ci} 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_cistatic int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type, 21678c2ecf20Sopenharmony_ci u8 reg_index, u8 reg_count, u8 *write_data) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = sha->lldd_ha; 21708c2ecf20Sopenharmony_ci 21718c2ecf20Sopenharmony_ci if (!hisi_hba->hw->write_gpio) 21728c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci return hisi_hba->hw->write_gpio(hisi_hba, reg_type, 21758c2ecf20Sopenharmony_ci reg_index, reg_count, write_data); 21768c2ecf20Sopenharmony_ci} 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_cistatic void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy) 21798c2ecf20Sopenharmony_ci{ 21808c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 21818c2ecf20Sopenharmony_ci struct sas_phy *sphy = sas_phy->phy; 21828c2ecf20Sopenharmony_ci unsigned long flags; 21838c2ecf20Sopenharmony_ci 21848c2ecf20Sopenharmony_ci phy->phy_attached = 0; 21858c2ecf20Sopenharmony_ci phy->phy_type = 0; 21868c2ecf20Sopenharmony_ci phy->port = NULL; 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci spin_lock_irqsave(&phy->lock, flags); 21898c2ecf20Sopenharmony_ci if (phy->enable) 21908c2ecf20Sopenharmony_ci sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 21918c2ecf20Sopenharmony_ci else 21928c2ecf20Sopenharmony_ci sphy->negotiated_linkrate = SAS_PHY_DISABLED; 21938c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&phy->lock, flags); 21948c2ecf20Sopenharmony_ci} 21958c2ecf20Sopenharmony_ci 21968c2ecf20Sopenharmony_civoid hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy) 21978c2ecf20Sopenharmony_ci{ 21988c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; 21998c2ecf20Sopenharmony_ci struct asd_sas_phy *sas_phy = &phy->sas_phy; 22008c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci if (rdy) { 22038c2ecf20Sopenharmony_ci /* Phy down but ready */ 22048c2ecf20Sopenharmony_ci hisi_sas_bytes_dmaed(hisi_hba, phy_no); 22058c2ecf20Sopenharmony_ci hisi_sas_port_notify_formed(sas_phy); 22068c2ecf20Sopenharmony_ci } else { 22078c2ecf20Sopenharmony_ci struct hisi_sas_port *port = phy->port; 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_ci if (test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags) || 22108c2ecf20Sopenharmony_ci phy->in_reset) { 22118c2ecf20Sopenharmony_ci dev_info(dev, "ignore flutter phy%d down\n", phy_no); 22128c2ecf20Sopenharmony_ci return; 22138c2ecf20Sopenharmony_ci } 22148c2ecf20Sopenharmony_ci /* Phy down and not ready */ 22158c2ecf20Sopenharmony_ci sas_notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL); 22168c2ecf20Sopenharmony_ci sas_phy_disconnected(sas_phy); 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ci if (port) { 22198c2ecf20Sopenharmony_ci if (phy->phy_type & PORT_TYPE_SAS) { 22208c2ecf20Sopenharmony_ci int port_id = port->id; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci if (!hisi_hba->hw->get_wideport_bitmap(hisi_hba, 22238c2ecf20Sopenharmony_ci port_id)) 22248c2ecf20Sopenharmony_ci port->port_attached = 0; 22258c2ecf20Sopenharmony_ci } else if (phy->phy_type & PORT_TYPE_SATA) 22268c2ecf20Sopenharmony_ci port->port_attached = 0; 22278c2ecf20Sopenharmony_ci } 22288c2ecf20Sopenharmony_ci hisi_sas_phy_disconnected(phy); 22298c2ecf20Sopenharmony_ci } 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_phy_down); 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_civoid hisi_sas_sync_irqs(struct hisi_hba *hisi_hba) 22348c2ecf20Sopenharmony_ci{ 22358c2ecf20Sopenharmony_ci int i; 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->cq_nvecs; i++) { 22388c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = &hisi_hba->cq[i]; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci synchronize_irq(cq->irq_no); 22418c2ecf20Sopenharmony_ci } 22428c2ecf20Sopenharmony_ci} 22438c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_sync_irqs); 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ciint hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type) 22468c2ecf20Sopenharmony_ci{ 22478c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = shost_priv(shost); 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci if (reset_type != SCSI_ADAPTER_RESET) 22508c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci queue_work(hisi_hba->wq, &hisi_hba->rst_work); 22538c2ecf20Sopenharmony_ci 22548c2ecf20Sopenharmony_ci return 0; 22558c2ecf20Sopenharmony_ci} 22568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_host_reset); 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_cistruct scsi_transport_template *hisi_sas_stt; 22598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_stt); 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_cistatic struct sas_domain_function_template hisi_sas_transport_ops = { 22628c2ecf20Sopenharmony_ci .lldd_dev_found = hisi_sas_dev_found, 22638c2ecf20Sopenharmony_ci .lldd_dev_gone = hisi_sas_dev_gone, 22648c2ecf20Sopenharmony_ci .lldd_execute_task = hisi_sas_queue_command, 22658c2ecf20Sopenharmony_ci .lldd_control_phy = hisi_sas_control_phy, 22668c2ecf20Sopenharmony_ci .lldd_abort_task = hisi_sas_abort_task, 22678c2ecf20Sopenharmony_ci .lldd_abort_task_set = hisi_sas_abort_task_set, 22688c2ecf20Sopenharmony_ci .lldd_clear_aca = hisi_sas_clear_aca, 22698c2ecf20Sopenharmony_ci .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset, 22708c2ecf20Sopenharmony_ci .lldd_lu_reset = hisi_sas_lu_reset, 22718c2ecf20Sopenharmony_ci .lldd_query_task = hisi_sas_query_task, 22728c2ecf20Sopenharmony_ci .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha, 22738c2ecf20Sopenharmony_ci .lldd_port_formed = hisi_sas_port_formed, 22748c2ecf20Sopenharmony_ci .lldd_write_gpio = hisi_sas_write_gpio, 22758c2ecf20Sopenharmony_ci}; 22768c2ecf20Sopenharmony_ci 22778c2ecf20Sopenharmony_civoid hisi_sas_init_mem(struct hisi_hba *hisi_hba) 22788c2ecf20Sopenharmony_ci{ 22798c2ecf20Sopenharmony_ci int i, s, j, max_command_entries = HISI_SAS_MAX_COMMANDS; 22808c2ecf20Sopenharmony_ci struct hisi_sas_breakpoint *sata_breakpoint = hisi_hba->sata_breakpoint; 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->queue_count; i++) { 22838c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = &hisi_hba->cq[i]; 22848c2ecf20Sopenharmony_ci struct hisi_sas_dq *dq = &hisi_hba->dq[i]; 22858c2ecf20Sopenharmony_ci struct hisi_sas_cmd_hdr *cmd_hdr = hisi_hba->cmd_hdr[i]; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci s = sizeof(struct hisi_sas_cmd_hdr); 22888c2ecf20Sopenharmony_ci for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++) 22898c2ecf20Sopenharmony_ci memset(&cmd_hdr[j], 0, s); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci dq->wr_point = 0; 22928c2ecf20Sopenharmony_ci 22938c2ecf20Sopenharmony_ci s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; 22948c2ecf20Sopenharmony_ci memset(hisi_hba->complete_hdr[i], 0, s); 22958c2ecf20Sopenharmony_ci cq->rd_point = 0; 22968c2ecf20Sopenharmony_ci } 22978c2ecf20Sopenharmony_ci 22988c2ecf20Sopenharmony_ci s = sizeof(struct hisi_sas_initial_fis) * hisi_hba->n_phy; 22998c2ecf20Sopenharmony_ci memset(hisi_hba->initial_fis, 0, s); 23008c2ecf20Sopenharmony_ci 23018c2ecf20Sopenharmony_ci s = max_command_entries * sizeof(struct hisi_sas_iost); 23028c2ecf20Sopenharmony_ci memset(hisi_hba->iost, 0, s); 23038c2ecf20Sopenharmony_ci 23048c2ecf20Sopenharmony_ci s = max_command_entries * sizeof(struct hisi_sas_breakpoint); 23058c2ecf20Sopenharmony_ci memset(hisi_hba->breakpoint, 0, s); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci s = sizeof(struct hisi_sas_sata_breakpoint); 23088c2ecf20Sopenharmony_ci for (j = 0; j < HISI_SAS_MAX_ITCT_ENTRIES; j++) 23098c2ecf20Sopenharmony_ci memset(&sata_breakpoint[j], 0, s); 23108c2ecf20Sopenharmony_ci} 23118c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_init_mem); 23128c2ecf20Sopenharmony_ci 23138c2ecf20Sopenharmony_ciint hisi_sas_alloc(struct hisi_hba *hisi_hba) 23148c2ecf20Sopenharmony_ci{ 23158c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 23168c2ecf20Sopenharmony_ci int i, j, s, max_command_entries = HISI_SAS_MAX_COMMANDS; 23178c2ecf20Sopenharmony_ci int max_command_entries_ru, sz_slot_buf_ru; 23188c2ecf20Sopenharmony_ci int blk_cnt, slots_per_blk; 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci sema_init(&hisi_hba->sem, 1); 23218c2ecf20Sopenharmony_ci spin_lock_init(&hisi_hba->lock); 23228c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->n_phy; i++) { 23238c2ecf20Sopenharmony_ci hisi_sas_phy_init(hisi_hba, i); 23248c2ecf20Sopenharmony_ci hisi_hba->port[i].port_attached = 0; 23258c2ecf20Sopenharmony_ci hisi_hba->port[i].id = -1; 23268c2ecf20Sopenharmony_ci } 23278c2ecf20Sopenharmony_ci 23288c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) { 23298c2ecf20Sopenharmony_ci hisi_hba->devices[i].dev_type = SAS_PHY_UNUSED; 23308c2ecf20Sopenharmony_ci hisi_hba->devices[i].device_id = i; 23318c2ecf20Sopenharmony_ci hisi_hba->devices[i].dev_status = HISI_SAS_DEV_INIT; 23328c2ecf20Sopenharmony_ci } 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->queue_count; i++) { 23358c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = &hisi_hba->cq[i]; 23368c2ecf20Sopenharmony_ci struct hisi_sas_dq *dq = &hisi_hba->dq[i]; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci /* Completion queue structure */ 23398c2ecf20Sopenharmony_ci cq->id = i; 23408c2ecf20Sopenharmony_ci cq->hisi_hba = hisi_hba; 23418c2ecf20Sopenharmony_ci 23428c2ecf20Sopenharmony_ci /* Delivery queue structure */ 23438c2ecf20Sopenharmony_ci spin_lock_init(&dq->lock); 23448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dq->list); 23458c2ecf20Sopenharmony_ci dq->id = i; 23468c2ecf20Sopenharmony_ci dq->hisi_hba = hisi_hba; 23478c2ecf20Sopenharmony_ci 23488c2ecf20Sopenharmony_ci /* Delivery queue */ 23498c2ecf20Sopenharmony_ci s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; 23508c2ecf20Sopenharmony_ci hisi_hba->cmd_hdr[i] = dmam_alloc_coherent(dev, s, 23518c2ecf20Sopenharmony_ci &hisi_hba->cmd_hdr_dma[i], 23528c2ecf20Sopenharmony_ci GFP_KERNEL); 23538c2ecf20Sopenharmony_ci if (!hisi_hba->cmd_hdr[i]) 23548c2ecf20Sopenharmony_ci goto err_out; 23558c2ecf20Sopenharmony_ci 23568c2ecf20Sopenharmony_ci /* Completion queue */ 23578c2ecf20Sopenharmony_ci s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; 23588c2ecf20Sopenharmony_ci hisi_hba->complete_hdr[i] = dmam_alloc_coherent(dev, s, 23598c2ecf20Sopenharmony_ci &hisi_hba->complete_hdr_dma[i], 23608c2ecf20Sopenharmony_ci GFP_KERNEL); 23618c2ecf20Sopenharmony_ci if (!hisi_hba->complete_hdr[i]) 23628c2ecf20Sopenharmony_ci goto err_out; 23638c2ecf20Sopenharmony_ci } 23648c2ecf20Sopenharmony_ci 23658c2ecf20Sopenharmony_ci s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); 23668c2ecf20Sopenharmony_ci hisi_hba->itct = dmam_alloc_coherent(dev, s, &hisi_hba->itct_dma, 23678c2ecf20Sopenharmony_ci GFP_KERNEL); 23688c2ecf20Sopenharmony_ci if (!hisi_hba->itct) 23698c2ecf20Sopenharmony_ci goto err_out; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci hisi_hba->slot_info = devm_kcalloc(dev, max_command_entries, 23728c2ecf20Sopenharmony_ci sizeof(struct hisi_sas_slot), 23738c2ecf20Sopenharmony_ci GFP_KERNEL); 23748c2ecf20Sopenharmony_ci if (!hisi_hba->slot_info) 23758c2ecf20Sopenharmony_ci goto err_out; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci /* roundup to avoid overly large block size */ 23788c2ecf20Sopenharmony_ci max_command_entries_ru = roundup(max_command_entries, 64); 23798c2ecf20Sopenharmony_ci if (hisi_hba->prot_mask & HISI_SAS_DIX_PROT_MASK) 23808c2ecf20Sopenharmony_ci sz_slot_buf_ru = sizeof(struct hisi_sas_slot_dif_buf_table); 23818c2ecf20Sopenharmony_ci else 23828c2ecf20Sopenharmony_ci sz_slot_buf_ru = sizeof(struct hisi_sas_slot_buf_table); 23838c2ecf20Sopenharmony_ci sz_slot_buf_ru = roundup(sz_slot_buf_ru, 64); 23848c2ecf20Sopenharmony_ci s = max(lcm(max_command_entries_ru, sz_slot_buf_ru), PAGE_SIZE); 23858c2ecf20Sopenharmony_ci blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s; 23868c2ecf20Sopenharmony_ci slots_per_blk = s / sz_slot_buf_ru; 23878c2ecf20Sopenharmony_ci 23888c2ecf20Sopenharmony_ci for (i = 0; i < blk_cnt; i++) { 23898c2ecf20Sopenharmony_ci int slot_index = i * slots_per_blk; 23908c2ecf20Sopenharmony_ci dma_addr_t buf_dma; 23918c2ecf20Sopenharmony_ci void *buf; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci buf = dmam_alloc_coherent(dev, s, &buf_dma, 23948c2ecf20Sopenharmony_ci GFP_KERNEL); 23958c2ecf20Sopenharmony_ci if (!buf) 23968c2ecf20Sopenharmony_ci goto err_out; 23978c2ecf20Sopenharmony_ci 23988c2ecf20Sopenharmony_ci for (j = 0; j < slots_per_blk; j++, slot_index++) { 23998c2ecf20Sopenharmony_ci struct hisi_sas_slot *slot; 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci slot = &hisi_hba->slot_info[slot_index]; 24028c2ecf20Sopenharmony_ci slot->buf = buf; 24038c2ecf20Sopenharmony_ci slot->buf_dma = buf_dma; 24048c2ecf20Sopenharmony_ci slot->idx = slot_index; 24058c2ecf20Sopenharmony_ci 24068c2ecf20Sopenharmony_ci buf += sz_slot_buf_ru; 24078c2ecf20Sopenharmony_ci buf_dma += sz_slot_buf_ru; 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci } 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci s = max_command_entries * sizeof(struct hisi_sas_iost); 24128c2ecf20Sopenharmony_ci hisi_hba->iost = dmam_alloc_coherent(dev, s, &hisi_hba->iost_dma, 24138c2ecf20Sopenharmony_ci GFP_KERNEL); 24148c2ecf20Sopenharmony_ci if (!hisi_hba->iost) 24158c2ecf20Sopenharmony_ci goto err_out; 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci s = max_command_entries * sizeof(struct hisi_sas_breakpoint); 24188c2ecf20Sopenharmony_ci hisi_hba->breakpoint = dmam_alloc_coherent(dev, s, 24198c2ecf20Sopenharmony_ci &hisi_hba->breakpoint_dma, 24208c2ecf20Sopenharmony_ci GFP_KERNEL); 24218c2ecf20Sopenharmony_ci if (!hisi_hba->breakpoint) 24228c2ecf20Sopenharmony_ci goto err_out; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci hisi_hba->slot_index_count = max_command_entries; 24258c2ecf20Sopenharmony_ci s = hisi_hba->slot_index_count / BITS_PER_BYTE; 24268c2ecf20Sopenharmony_ci hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL); 24278c2ecf20Sopenharmony_ci if (!hisi_hba->slot_index_tags) 24288c2ecf20Sopenharmony_ci goto err_out; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS; 24318c2ecf20Sopenharmony_ci hisi_hba->initial_fis = dmam_alloc_coherent(dev, s, 24328c2ecf20Sopenharmony_ci &hisi_hba->initial_fis_dma, 24338c2ecf20Sopenharmony_ci GFP_KERNEL); 24348c2ecf20Sopenharmony_ci if (!hisi_hba->initial_fis) 24358c2ecf20Sopenharmony_ci goto err_out; 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_sata_breakpoint); 24388c2ecf20Sopenharmony_ci hisi_hba->sata_breakpoint = dmam_alloc_coherent(dev, s, 24398c2ecf20Sopenharmony_ci &hisi_hba->sata_breakpoint_dma, 24408c2ecf20Sopenharmony_ci GFP_KERNEL); 24418c2ecf20Sopenharmony_ci if (!hisi_hba->sata_breakpoint) 24428c2ecf20Sopenharmony_ci goto err_out; 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_ci hisi_sas_slot_index_init(hisi_hba); 24458c2ecf20Sopenharmony_ci hisi_hba->last_slot_index = HISI_SAS_UNRESERVED_IPTT; 24468c2ecf20Sopenharmony_ci 24478c2ecf20Sopenharmony_ci hisi_hba->wq = create_singlethread_workqueue(dev_name(dev)); 24488c2ecf20Sopenharmony_ci if (!hisi_hba->wq) { 24498c2ecf20Sopenharmony_ci dev_err(dev, "sas_alloc: failed to create workqueue\n"); 24508c2ecf20Sopenharmony_ci goto err_out; 24518c2ecf20Sopenharmony_ci } 24528c2ecf20Sopenharmony_ci 24538c2ecf20Sopenharmony_ci return 0; 24548c2ecf20Sopenharmony_cierr_out: 24558c2ecf20Sopenharmony_ci return -ENOMEM; 24568c2ecf20Sopenharmony_ci} 24578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_alloc); 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_civoid hisi_sas_free(struct hisi_hba *hisi_hba) 24608c2ecf20Sopenharmony_ci{ 24618c2ecf20Sopenharmony_ci int i; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->n_phy; i++) { 24648c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = &hisi_hba->phy[i]; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci del_timer_sync(&phy->timer); 24678c2ecf20Sopenharmony_ci } 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci if (hisi_hba->wq) 24708c2ecf20Sopenharmony_ci destroy_workqueue(hisi_hba->wq); 24718c2ecf20Sopenharmony_ci} 24728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_free); 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_civoid hisi_sas_rst_work_handler(struct work_struct *work) 24758c2ecf20Sopenharmony_ci{ 24768c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = 24778c2ecf20Sopenharmony_ci container_of(work, struct hisi_hba, rst_work); 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci hisi_sas_controller_reset(hisi_hba); 24808c2ecf20Sopenharmony_ci} 24818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_rst_work_handler); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_civoid hisi_sas_sync_rst_work_handler(struct work_struct *work) 24848c2ecf20Sopenharmony_ci{ 24858c2ecf20Sopenharmony_ci struct hisi_sas_rst *rst = 24868c2ecf20Sopenharmony_ci container_of(work, struct hisi_sas_rst, work); 24878c2ecf20Sopenharmony_ci 24888c2ecf20Sopenharmony_ci if (!hisi_sas_controller_reset(rst->hisi_hba)) 24898c2ecf20Sopenharmony_ci rst->done = true; 24908c2ecf20Sopenharmony_ci complete(rst->completion); 24918c2ecf20Sopenharmony_ci} 24928c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_sync_rst_work_handler); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ciint hisi_sas_get_fw_info(struct hisi_hba *hisi_hba) 24958c2ecf20Sopenharmony_ci{ 24968c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 24978c2ecf20Sopenharmony_ci struct platform_device *pdev = hisi_hba->platform_dev; 24988c2ecf20Sopenharmony_ci struct device_node *np = pdev ? pdev->dev.of_node : NULL; 24998c2ecf20Sopenharmony_ci struct clk *refclk; 25008c2ecf20Sopenharmony_ci 25018c2ecf20Sopenharmony_ci if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr, 25028c2ecf20Sopenharmony_ci SAS_ADDR_SIZE)) { 25038c2ecf20Sopenharmony_ci dev_err(dev, "could not get property sas-addr\n"); 25048c2ecf20Sopenharmony_ci return -ENOENT; 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci if (np) { 25088c2ecf20Sopenharmony_ci /* 25098c2ecf20Sopenharmony_ci * These properties are only required for platform device-based 25108c2ecf20Sopenharmony_ci * controller with DT firmware. 25118c2ecf20Sopenharmony_ci */ 25128c2ecf20Sopenharmony_ci hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np, 25138c2ecf20Sopenharmony_ci "hisilicon,sas-syscon"); 25148c2ecf20Sopenharmony_ci if (IS_ERR(hisi_hba->ctrl)) { 25158c2ecf20Sopenharmony_ci dev_err(dev, "could not get syscon\n"); 25168c2ecf20Sopenharmony_ci return -ENOENT; 25178c2ecf20Sopenharmony_ci } 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "ctrl-reset-reg", 25208c2ecf20Sopenharmony_ci &hisi_hba->ctrl_reset_reg)) { 25218c2ecf20Sopenharmony_ci dev_err(dev, "could not get property ctrl-reset-reg\n"); 25228c2ecf20Sopenharmony_ci return -ENOENT; 25238c2ecf20Sopenharmony_ci } 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "ctrl-reset-sts-reg", 25268c2ecf20Sopenharmony_ci &hisi_hba->ctrl_reset_sts_reg)) { 25278c2ecf20Sopenharmony_ci dev_err(dev, "could not get property ctrl-reset-sts-reg\n"); 25288c2ecf20Sopenharmony_ci return -ENOENT; 25298c2ecf20Sopenharmony_ci } 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "ctrl-clock-ena-reg", 25328c2ecf20Sopenharmony_ci &hisi_hba->ctrl_clock_ena_reg)) { 25338c2ecf20Sopenharmony_ci dev_err(dev, "could not get property ctrl-clock-ena-reg\n"); 25348c2ecf20Sopenharmony_ci return -ENOENT; 25358c2ecf20Sopenharmony_ci } 25368c2ecf20Sopenharmony_ci } 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci refclk = devm_clk_get(dev, NULL); 25398c2ecf20Sopenharmony_ci if (IS_ERR(refclk)) 25408c2ecf20Sopenharmony_ci dev_dbg(dev, "no ref clk property\n"); 25418c2ecf20Sopenharmony_ci else 25428c2ecf20Sopenharmony_ci hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000; 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) { 25458c2ecf20Sopenharmony_ci dev_err(dev, "could not get property phy-count\n"); 25468c2ecf20Sopenharmony_ci return -ENOENT; 25478c2ecf20Sopenharmony_ci } 25488c2ecf20Sopenharmony_ci 25498c2ecf20Sopenharmony_ci if (device_property_read_u32(dev, "queue-count", 25508c2ecf20Sopenharmony_ci &hisi_hba->queue_count)) { 25518c2ecf20Sopenharmony_ci dev_err(dev, "could not get property queue-count\n"); 25528c2ecf20Sopenharmony_ci return -ENOENT; 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci return 0; 25568c2ecf20Sopenharmony_ci} 25578c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_get_fw_info); 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_cistatic struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev, 25608c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw) 25618c2ecf20Sopenharmony_ci{ 25628c2ecf20Sopenharmony_ci struct resource *res; 25638c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 25648c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba; 25658c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 25668c2ecf20Sopenharmony_ci int error; 25678c2ecf20Sopenharmony_ci 25688c2ecf20Sopenharmony_ci shost = scsi_host_alloc(hw->sht, sizeof(*hisi_hba)); 25698c2ecf20Sopenharmony_ci if (!shost) { 25708c2ecf20Sopenharmony_ci dev_err(dev, "scsi host alloc failed\n"); 25718c2ecf20Sopenharmony_ci return NULL; 25728c2ecf20Sopenharmony_ci } 25738c2ecf20Sopenharmony_ci hisi_hba = shost_priv(shost); 25748c2ecf20Sopenharmony_ci 25758c2ecf20Sopenharmony_ci INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler); 25768c2ecf20Sopenharmony_ci hisi_hba->hw = hw; 25778c2ecf20Sopenharmony_ci hisi_hba->dev = dev; 25788c2ecf20Sopenharmony_ci hisi_hba->platform_dev = pdev; 25798c2ecf20Sopenharmony_ci hisi_hba->shost = shost; 25808c2ecf20Sopenharmony_ci SHOST_TO_SAS_HA(shost) = &hisi_hba->sha; 25818c2ecf20Sopenharmony_ci 25828c2ecf20Sopenharmony_ci timer_setup(&hisi_hba->timer, NULL, 0); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci if (hisi_sas_get_fw_info(hisi_hba) < 0) 25858c2ecf20Sopenharmony_ci goto err_out; 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64)); 25888c2ecf20Sopenharmony_ci if (error) 25898c2ecf20Sopenharmony_ci error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci if (error) { 25928c2ecf20Sopenharmony_ci dev_err(dev, "No usable DMA addressing method\n"); 25938c2ecf20Sopenharmony_ci goto err_out; 25948c2ecf20Sopenharmony_ci } 25958c2ecf20Sopenharmony_ci 25968c2ecf20Sopenharmony_ci hisi_hba->regs = devm_platform_ioremap_resource(pdev, 0); 25978c2ecf20Sopenharmony_ci if (IS_ERR(hisi_hba->regs)) 25988c2ecf20Sopenharmony_ci goto err_out; 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 26018c2ecf20Sopenharmony_ci if (res) { 26028c2ecf20Sopenharmony_ci hisi_hba->sgpio_regs = devm_ioremap_resource(dev, res); 26038c2ecf20Sopenharmony_ci if (IS_ERR(hisi_hba->sgpio_regs)) 26048c2ecf20Sopenharmony_ci goto err_out; 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci 26078c2ecf20Sopenharmony_ci if (hisi_sas_alloc(hisi_hba)) { 26088c2ecf20Sopenharmony_ci hisi_sas_free(hisi_hba); 26098c2ecf20Sopenharmony_ci goto err_out; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci return shost; 26138c2ecf20Sopenharmony_cierr_out: 26148c2ecf20Sopenharmony_ci scsi_host_put(shost); 26158c2ecf20Sopenharmony_ci dev_err(dev, "shost alloc failed\n"); 26168c2ecf20Sopenharmony_ci return NULL; 26178c2ecf20Sopenharmony_ci} 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ciint hisi_sas_probe(struct platform_device *pdev, 26208c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw) 26218c2ecf20Sopenharmony_ci{ 26228c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 26238c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba; 26248c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 26258c2ecf20Sopenharmony_ci struct asd_sas_phy **arr_phy; 26268c2ecf20Sopenharmony_ci struct asd_sas_port **arr_port; 26278c2ecf20Sopenharmony_ci struct sas_ha_struct *sha; 26288c2ecf20Sopenharmony_ci int rc, phy_nr, port_nr, i; 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci shost = hisi_sas_shost_alloc(pdev, hw); 26318c2ecf20Sopenharmony_ci if (!shost) 26328c2ecf20Sopenharmony_ci return -ENOMEM; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci sha = SHOST_TO_SAS_HA(shost); 26358c2ecf20Sopenharmony_ci hisi_hba = shost_priv(shost); 26368c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, sha); 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci phy_nr = port_nr = hisi_hba->n_phy; 26398c2ecf20Sopenharmony_ci 26408c2ecf20Sopenharmony_ci arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL); 26418c2ecf20Sopenharmony_ci arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL); 26428c2ecf20Sopenharmony_ci if (!arr_phy || !arr_port) { 26438c2ecf20Sopenharmony_ci rc = -ENOMEM; 26448c2ecf20Sopenharmony_ci goto err_out_ha; 26458c2ecf20Sopenharmony_ci } 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci sha->sas_phy = arr_phy; 26488c2ecf20Sopenharmony_ci sha->sas_port = arr_port; 26498c2ecf20Sopenharmony_ci sha->lldd_ha = hisi_hba; 26508c2ecf20Sopenharmony_ci 26518c2ecf20Sopenharmony_ci shost->transportt = hisi_sas_stt; 26528c2ecf20Sopenharmony_ci shost->max_id = HISI_SAS_MAX_DEVICES; 26538c2ecf20Sopenharmony_ci shost->max_lun = ~0; 26548c2ecf20Sopenharmony_ci shost->max_channel = 1; 26558c2ecf20Sopenharmony_ci shost->max_cmd_len = 16; 26568c2ecf20Sopenharmony_ci if (hisi_hba->hw->slot_index_alloc) { 26578c2ecf20Sopenharmony_ci shost->can_queue = HISI_SAS_MAX_COMMANDS; 26588c2ecf20Sopenharmony_ci shost->cmd_per_lun = HISI_SAS_MAX_COMMANDS; 26598c2ecf20Sopenharmony_ci } else { 26608c2ecf20Sopenharmony_ci shost->can_queue = HISI_SAS_UNRESERVED_IPTT; 26618c2ecf20Sopenharmony_ci shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT; 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci sha->sas_ha_name = DRV_NAME; 26658c2ecf20Sopenharmony_ci sha->dev = hisi_hba->dev; 26668c2ecf20Sopenharmony_ci sha->lldd_module = THIS_MODULE; 26678c2ecf20Sopenharmony_ci sha->sas_addr = &hisi_hba->sas_addr[0]; 26688c2ecf20Sopenharmony_ci sha->num_phys = hisi_hba->n_phy; 26698c2ecf20Sopenharmony_ci sha->core.shost = hisi_hba->shost; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->n_phy; i++) { 26728c2ecf20Sopenharmony_ci sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy; 26738c2ecf20Sopenharmony_ci sha->sas_port[i] = &hisi_hba->port[i].sas_port; 26748c2ecf20Sopenharmony_ci } 26758c2ecf20Sopenharmony_ci 26768c2ecf20Sopenharmony_ci rc = scsi_add_host(shost, &pdev->dev); 26778c2ecf20Sopenharmony_ci if (rc) 26788c2ecf20Sopenharmony_ci goto err_out_ha; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci rc = sas_register_ha(sha); 26818c2ecf20Sopenharmony_ci if (rc) 26828c2ecf20Sopenharmony_ci goto err_out_register_ha; 26838c2ecf20Sopenharmony_ci 26848c2ecf20Sopenharmony_ci rc = hisi_hba->hw->hw_init(hisi_hba); 26858c2ecf20Sopenharmony_ci if (rc) 26868c2ecf20Sopenharmony_ci goto err_out_register_ha; 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ci scsi_scan_host(shost); 26898c2ecf20Sopenharmony_ci 26908c2ecf20Sopenharmony_ci return 0; 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_cierr_out_register_ha: 26938c2ecf20Sopenharmony_ci scsi_remove_host(shost); 26948c2ecf20Sopenharmony_cierr_out_ha: 26958c2ecf20Sopenharmony_ci hisi_sas_debugfs_exit(hisi_hba); 26968c2ecf20Sopenharmony_ci hisi_sas_free(hisi_hba); 26978c2ecf20Sopenharmony_ci scsi_host_put(shost); 26988c2ecf20Sopenharmony_ci return rc; 26998c2ecf20Sopenharmony_ci} 27008c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_probe); 27018c2ecf20Sopenharmony_ci 27028c2ecf20Sopenharmony_cistruct dentry *hisi_sas_debugfs_dir; 27038c2ecf20Sopenharmony_ci 27048c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba) 27058c2ecf20Sopenharmony_ci{ 27068c2ecf20Sopenharmony_ci int queue_entry_size = hisi_hba->hw->complete_hdr_size; 27078c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 27088c2ecf20Sopenharmony_ci int i; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->queue_count; i++) 27118c2ecf20Sopenharmony_ci memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr, 27128c2ecf20Sopenharmony_ci hisi_hba->complete_hdr[i], 27138c2ecf20Sopenharmony_ci HISI_SAS_QUEUE_SLOTS * queue_entry_size); 27148c2ecf20Sopenharmony_ci} 27158c2ecf20Sopenharmony_ci 27168c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba) 27178c2ecf20Sopenharmony_ci{ 27188c2ecf20Sopenharmony_ci int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr); 27198c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 27208c2ecf20Sopenharmony_ci int i; 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->queue_count; i++) { 27238c2ecf20Sopenharmony_ci struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr; 27248c2ecf20Sopenharmony_ci int j; 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr; 27278c2ecf20Sopenharmony_ci cmd_hdr = hisi_hba->cmd_hdr[i]; 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++) 27308c2ecf20Sopenharmony_ci memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j], 27318c2ecf20Sopenharmony_ci queue_entry_size); 27328c2ecf20Sopenharmony_ci } 27338c2ecf20Sopenharmony_ci} 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) 27368c2ecf20Sopenharmony_ci{ 27378c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 27388c2ecf20Sopenharmony_ci const struct hisi_sas_debugfs_reg *port = 27398c2ecf20Sopenharmony_ci hisi_hba->hw->debugfs_reg_port; 27408c2ecf20Sopenharmony_ci int i, phy_cnt; 27418c2ecf20Sopenharmony_ci u32 offset; 27428c2ecf20Sopenharmony_ci u32 *databuf; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { 27458c2ecf20Sopenharmony_ci databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data; 27468c2ecf20Sopenharmony_ci for (i = 0; i < port->count; i++, databuf++) { 27478c2ecf20Sopenharmony_ci offset = port->base_off + 4 * i; 27488c2ecf20Sopenharmony_ci *databuf = port->read_port_reg(hisi_hba, phy_cnt, 27498c2ecf20Sopenharmony_ci offset); 27508c2ecf20Sopenharmony_ci } 27518c2ecf20Sopenharmony_ci } 27528c2ecf20Sopenharmony_ci} 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) 27558c2ecf20Sopenharmony_ci{ 27568c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 27578c2ecf20Sopenharmony_ci u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data; 27588c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 27598c2ecf20Sopenharmony_ci const struct hisi_sas_debugfs_reg *global = 27608c2ecf20Sopenharmony_ci hw->debugfs_reg_array[DEBUGFS_GLOBAL]; 27618c2ecf20Sopenharmony_ci int i; 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci for (i = 0; i < global->count; i++, databuf++) 27648c2ecf20Sopenharmony_ci *databuf = global->read_global_reg(hisi_hba, 4 * i); 27658c2ecf20Sopenharmony_ci} 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) 27688c2ecf20Sopenharmony_ci{ 27698c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 27708c2ecf20Sopenharmony_ci u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data; 27718c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 27728c2ecf20Sopenharmony_ci const struct hisi_sas_debugfs_reg *axi = 27738c2ecf20Sopenharmony_ci hw->debugfs_reg_array[DEBUGFS_AXI]; 27748c2ecf20Sopenharmony_ci int i; 27758c2ecf20Sopenharmony_ci 27768c2ecf20Sopenharmony_ci for (i = 0; i < axi->count; i++, databuf++) 27778c2ecf20Sopenharmony_ci *databuf = axi->read_global_reg(hisi_hba, 27788c2ecf20Sopenharmony_ci 4 * i + axi->base_off); 27798c2ecf20Sopenharmony_ci} 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) 27828c2ecf20Sopenharmony_ci{ 27838c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 27848c2ecf20Sopenharmony_ci u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data; 27858c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 27868c2ecf20Sopenharmony_ci const struct hisi_sas_debugfs_reg *ras = 27878c2ecf20Sopenharmony_ci hw->debugfs_reg_array[DEBUGFS_RAS]; 27888c2ecf20Sopenharmony_ci int i; 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci for (i = 0; i < ras->count; i++, databuf++) 27918c2ecf20Sopenharmony_ci *databuf = ras->read_global_reg(hisi_hba, 27928c2ecf20Sopenharmony_ci 4 * i + ras->base_off); 27938c2ecf20Sopenharmony_ci} 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) 27968c2ecf20Sopenharmony_ci{ 27978c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 27988c2ecf20Sopenharmony_ci void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache; 27998c2ecf20Sopenharmony_ci void *databuf = hisi_hba->debugfs_itct[dump_index].itct; 28008c2ecf20Sopenharmony_ci struct hisi_sas_itct *itct; 28018c2ecf20Sopenharmony_ci int i; 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_ITCT_CACHE, 28048c2ecf20Sopenharmony_ci cachebuf); 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci itct = hisi_hba->itct; 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { 28098c2ecf20Sopenharmony_ci memcpy(databuf, itct, sizeof(struct hisi_sas_itct)); 28108c2ecf20Sopenharmony_ci databuf += sizeof(struct hisi_sas_itct); 28118c2ecf20Sopenharmony_ci } 28128c2ecf20Sopenharmony_ci} 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) 28158c2ecf20Sopenharmony_ci{ 28168c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 28178c2ecf20Sopenharmony_ci int max_command_entries = HISI_SAS_MAX_COMMANDS; 28188c2ecf20Sopenharmony_ci void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache; 28198c2ecf20Sopenharmony_ci void *databuf = hisi_hba->debugfs_iost[dump_index].iost; 28208c2ecf20Sopenharmony_ci struct hisi_sas_iost *iost; 28218c2ecf20Sopenharmony_ci int i; 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_IOST_CACHE, 28248c2ecf20Sopenharmony_ci cachebuf); 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci iost = hisi_hba->iost; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci for (i = 0; i < max_command_entries; i++, iost++) { 28298c2ecf20Sopenharmony_ci memcpy(databuf, iost, sizeof(struct hisi_sas_iost)); 28308c2ecf20Sopenharmony_ci databuf += sizeof(struct hisi_sas_iost); 28318c2ecf20Sopenharmony_ci } 28328c2ecf20Sopenharmony_ci} 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_cistatic const char * 28358c2ecf20Sopenharmony_cihisi_sas_debugfs_to_reg_name(int off, int base_off, 28368c2ecf20Sopenharmony_ci const struct hisi_sas_debugfs_reg_lu *lu) 28378c2ecf20Sopenharmony_ci{ 28388c2ecf20Sopenharmony_ci for (; lu->name; lu++) { 28398c2ecf20Sopenharmony_ci if (off == lu->off - base_off) 28408c2ecf20Sopenharmony_ci return lu->name; 28418c2ecf20Sopenharmony_ci } 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci return NULL; 28448c2ecf20Sopenharmony_ci} 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr, 28478c2ecf20Sopenharmony_ci struct seq_file *s) 28488c2ecf20Sopenharmony_ci{ 28498c2ecf20Sopenharmony_ci const struct hisi_sas_debugfs_reg *reg = ptr; 28508c2ecf20Sopenharmony_ci int i; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci for (i = 0; i < reg->count; i++) { 28538c2ecf20Sopenharmony_ci int off = i * 4; 28548c2ecf20Sopenharmony_ci const char *name; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci name = hisi_sas_debugfs_to_reg_name(off, reg->base_off, 28578c2ecf20Sopenharmony_ci reg->lu); 28588c2ecf20Sopenharmony_ci 28598c2ecf20Sopenharmony_ci if (name) 28608c2ecf20Sopenharmony_ci seq_printf(s, "0x%08x 0x%08x %s\n", off, 28618c2ecf20Sopenharmony_ci regs_val[i], name); 28628c2ecf20Sopenharmony_ci else 28638c2ecf20Sopenharmony_ci seq_printf(s, "0x%08x 0x%08x\n", off, 28648c2ecf20Sopenharmony_ci regs_val[i]); 28658c2ecf20Sopenharmony_ci } 28668c2ecf20Sopenharmony_ci} 28678c2ecf20Sopenharmony_ci 28688c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_global_show(struct seq_file *s, void *p) 28698c2ecf20Sopenharmony_ci{ 28708c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_regs *global = s->private; 28718c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = global->hisi_hba; 28728c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 28738c2ecf20Sopenharmony_ci const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL]; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci hisi_sas_debugfs_print_reg(global->data, 28768c2ecf20Sopenharmony_ci reg_global, s); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci return 0; 28798c2ecf20Sopenharmony_ci} 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_global_open(struct inode *inode, struct file *filp) 28828c2ecf20Sopenharmony_ci{ 28838c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_global_show, 28848c2ecf20Sopenharmony_ci inode->i_private); 28858c2ecf20Sopenharmony_ci} 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_global_fops = { 28888c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_global_open, 28898c2ecf20Sopenharmony_ci .read = seq_read, 28908c2ecf20Sopenharmony_ci .llseek = seq_lseek, 28918c2ecf20Sopenharmony_ci .release = single_release, 28928c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 28938c2ecf20Sopenharmony_ci}; 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p) 28968c2ecf20Sopenharmony_ci{ 28978c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_regs *axi = s->private; 28988c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = axi->hisi_hba; 28998c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 29008c2ecf20Sopenharmony_ci const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI]; 29018c2ecf20Sopenharmony_ci 29028c2ecf20Sopenharmony_ci hisi_sas_debugfs_print_reg(axi->data, 29038c2ecf20Sopenharmony_ci reg_axi, s); 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci return 0; 29068c2ecf20Sopenharmony_ci} 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_axi_open(struct inode *inode, struct file *filp) 29098c2ecf20Sopenharmony_ci{ 29108c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_axi_show, 29118c2ecf20Sopenharmony_ci inode->i_private); 29128c2ecf20Sopenharmony_ci} 29138c2ecf20Sopenharmony_ci 29148c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_axi_fops = { 29158c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_axi_open, 29168c2ecf20Sopenharmony_ci .read = seq_read, 29178c2ecf20Sopenharmony_ci .llseek = seq_lseek, 29188c2ecf20Sopenharmony_ci .release = single_release, 29198c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 29208c2ecf20Sopenharmony_ci}; 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p) 29238c2ecf20Sopenharmony_ci{ 29248c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_regs *ras = s->private; 29258c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = ras->hisi_hba; 29268c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 29278c2ecf20Sopenharmony_ci const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS]; 29288c2ecf20Sopenharmony_ci 29298c2ecf20Sopenharmony_ci hisi_sas_debugfs_print_reg(ras->data, 29308c2ecf20Sopenharmony_ci reg_ras, s); 29318c2ecf20Sopenharmony_ci 29328c2ecf20Sopenharmony_ci return 0; 29338c2ecf20Sopenharmony_ci} 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_ras_open(struct inode *inode, struct file *filp) 29368c2ecf20Sopenharmony_ci{ 29378c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_ras_show, 29388c2ecf20Sopenharmony_ci inode->i_private); 29398c2ecf20Sopenharmony_ci} 29408c2ecf20Sopenharmony_ci 29418c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_ras_fops = { 29428c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_ras_open, 29438c2ecf20Sopenharmony_ci .read = seq_read, 29448c2ecf20Sopenharmony_ci .llseek = seq_lseek, 29458c2ecf20Sopenharmony_ci .release = single_release, 29468c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 29478c2ecf20Sopenharmony_ci}; 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_port_show(struct seq_file *s, void *p) 29508c2ecf20Sopenharmony_ci{ 29518c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_port *port = s->private; 29528c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = port->phy; 29538c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = phy->hisi_hba; 29548c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 29558c2ecf20Sopenharmony_ci const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port; 29568c2ecf20Sopenharmony_ci 29578c2ecf20Sopenharmony_ci hisi_sas_debugfs_print_reg(port->data, reg_port, s); 29588c2ecf20Sopenharmony_ci 29598c2ecf20Sopenharmony_ci return 0; 29608c2ecf20Sopenharmony_ci} 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_port_open(struct inode *inode, struct file *filp) 29638c2ecf20Sopenharmony_ci{ 29648c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_port_show, inode->i_private); 29658c2ecf20Sopenharmony_ci} 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_port_fops = { 29688c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_port_open, 29698c2ecf20Sopenharmony_ci .read = seq_read, 29708c2ecf20Sopenharmony_ci .llseek = seq_lseek, 29718c2ecf20Sopenharmony_ci .release = single_release, 29728c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 29738c2ecf20Sopenharmony_ci}; 29748c2ecf20Sopenharmony_ci 29758c2ecf20Sopenharmony_cistatic void hisi_sas_show_row_64(struct seq_file *s, int index, 29768c2ecf20Sopenharmony_ci int sz, __le64 *ptr) 29778c2ecf20Sopenharmony_ci{ 29788c2ecf20Sopenharmony_ci int i; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci /* completion header size not fixed per HW version */ 29818c2ecf20Sopenharmony_ci seq_printf(s, "index %04d:\n\t", index); 29828c2ecf20Sopenharmony_ci for (i = 1; i <= sz / 8; i++, ptr++) { 29838c2ecf20Sopenharmony_ci seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr)); 29848c2ecf20Sopenharmony_ci if (!(i % 2)) 29858c2ecf20Sopenharmony_ci seq_puts(s, "\n\t"); 29868c2ecf20Sopenharmony_ci } 29878c2ecf20Sopenharmony_ci 29888c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 29898c2ecf20Sopenharmony_ci} 29908c2ecf20Sopenharmony_ci 29918c2ecf20Sopenharmony_cistatic void hisi_sas_show_row_32(struct seq_file *s, int index, 29928c2ecf20Sopenharmony_ci int sz, __le32 *ptr) 29938c2ecf20Sopenharmony_ci{ 29948c2ecf20Sopenharmony_ci int i; 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci /* completion header size not fixed per HW version */ 29978c2ecf20Sopenharmony_ci seq_printf(s, "index %04d:\n\t", index); 29988c2ecf20Sopenharmony_ci for (i = 1; i <= sz / 4; i++, ptr++) { 29998c2ecf20Sopenharmony_ci seq_printf(s, " 0x%08x", le32_to_cpu(*ptr)); 30008c2ecf20Sopenharmony_ci if (!(i % 4)) 30018c2ecf20Sopenharmony_ci seq_puts(s, "\n\t"); 30028c2ecf20Sopenharmony_ci } 30038c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 30048c2ecf20Sopenharmony_ci} 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_cistatic void hisi_sas_cq_show_slot(struct seq_file *s, int slot, 30078c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_cq *debugfs_cq) 30088c2ecf20Sopenharmony_ci{ 30098c2ecf20Sopenharmony_ci struct hisi_sas_cq *cq = debugfs_cq->cq; 30108c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = cq->hisi_hba; 30118c2ecf20Sopenharmony_ci __le32 *complete_hdr = debugfs_cq->complete_hdr + 30128c2ecf20Sopenharmony_ci (hisi_hba->hw->complete_hdr_size * slot); 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci hisi_sas_show_row_32(s, slot, 30158c2ecf20Sopenharmony_ci hisi_hba->hw->complete_hdr_size, 30168c2ecf20Sopenharmony_ci complete_hdr); 30178c2ecf20Sopenharmony_ci} 30188c2ecf20Sopenharmony_ci 30198c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p) 30208c2ecf20Sopenharmony_ci{ 30218c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_cq *debugfs_cq = s->private; 30228c2ecf20Sopenharmony_ci int slot; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { 30258c2ecf20Sopenharmony_ci hisi_sas_cq_show_slot(s, slot, debugfs_cq); 30268c2ecf20Sopenharmony_ci } 30278c2ecf20Sopenharmony_ci return 0; 30288c2ecf20Sopenharmony_ci} 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_cq_open(struct inode *inode, struct file *filp) 30318c2ecf20Sopenharmony_ci{ 30328c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_cq_show, inode->i_private); 30338c2ecf20Sopenharmony_ci} 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_cq_fops = { 30368c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_cq_open, 30378c2ecf20Sopenharmony_ci .read = seq_read, 30388c2ecf20Sopenharmony_ci .llseek = seq_lseek, 30398c2ecf20Sopenharmony_ci .release = single_release, 30408c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 30418c2ecf20Sopenharmony_ci}; 30428c2ecf20Sopenharmony_ci 30438c2ecf20Sopenharmony_cistatic void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr) 30448c2ecf20Sopenharmony_ci{ 30458c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr; 30468c2ecf20Sopenharmony_ci void *cmd_queue = debugfs_dq->hdr; 30478c2ecf20Sopenharmony_ci __le32 *cmd_hdr = cmd_queue + 30488c2ecf20Sopenharmony_ci sizeof(struct hisi_sas_cmd_hdr) * slot; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), cmd_hdr); 30518c2ecf20Sopenharmony_ci} 30528c2ecf20Sopenharmony_ci 30538c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_dq_show(struct seq_file *s, void *p) 30548c2ecf20Sopenharmony_ci{ 30558c2ecf20Sopenharmony_ci int slot; 30568c2ecf20Sopenharmony_ci 30578c2ecf20Sopenharmony_ci for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { 30588c2ecf20Sopenharmony_ci hisi_sas_dq_show_slot(s, slot, s->private); 30598c2ecf20Sopenharmony_ci } 30608c2ecf20Sopenharmony_ci return 0; 30618c2ecf20Sopenharmony_ci} 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_dq_open(struct inode *inode, struct file *filp) 30648c2ecf20Sopenharmony_ci{ 30658c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_dq_show, inode->i_private); 30668c2ecf20Sopenharmony_ci} 30678c2ecf20Sopenharmony_ci 30688c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_dq_fops = { 30698c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_dq_open, 30708c2ecf20Sopenharmony_ci .read = seq_read, 30718c2ecf20Sopenharmony_ci .llseek = seq_lseek, 30728c2ecf20Sopenharmony_ci .release = single_release, 30738c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 30748c2ecf20Sopenharmony_ci}; 30758c2ecf20Sopenharmony_ci 30768c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p) 30778c2ecf20Sopenharmony_ci{ 30788c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_iost *debugfs_iost = s->private; 30798c2ecf20Sopenharmony_ci struct hisi_sas_iost *iost = debugfs_iost->iost; 30808c2ecf20Sopenharmony_ci int i, max_command_entries = HISI_SAS_MAX_COMMANDS; 30818c2ecf20Sopenharmony_ci 30828c2ecf20Sopenharmony_ci for (i = 0; i < max_command_entries; i++, iost++) { 30838c2ecf20Sopenharmony_ci __le64 *data = &iost->qw0; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci hisi_sas_show_row_64(s, i, sizeof(*iost), data); 30868c2ecf20Sopenharmony_ci } 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci return 0; 30898c2ecf20Sopenharmony_ci} 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_iost_open(struct inode *inode, struct file *filp) 30928c2ecf20Sopenharmony_ci{ 30938c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_iost_show, inode->i_private); 30948c2ecf20Sopenharmony_ci} 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_iost_fops = { 30978c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_iost_open, 30988c2ecf20Sopenharmony_ci .read = seq_read, 30998c2ecf20Sopenharmony_ci .llseek = seq_lseek, 31008c2ecf20Sopenharmony_ci .release = single_release, 31018c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 31028c2ecf20Sopenharmony_ci}; 31038c2ecf20Sopenharmony_ci 31048c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p) 31058c2ecf20Sopenharmony_ci{ 31068c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private; 31078c2ecf20Sopenharmony_ci struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->cache; 31088c2ecf20Sopenharmony_ci u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; 31098c2ecf20Sopenharmony_ci int i, tab_idx; 31108c2ecf20Sopenharmony_ci __le64 *iost; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) { 31138c2ecf20Sopenharmony_ci /* 31148c2ecf20Sopenharmony_ci * Data struct of IOST cache: 31158c2ecf20Sopenharmony_ci * Data[1]: BIT0~15: Table index 31168c2ecf20Sopenharmony_ci * Bit16: Valid mask 31178c2ecf20Sopenharmony_ci * Data[2]~[9]: IOST table 31188c2ecf20Sopenharmony_ci */ 31198c2ecf20Sopenharmony_ci tab_idx = (iost_cache->data[1] & 0xffff); 31208c2ecf20Sopenharmony_ci iost = (__le64 *)iost_cache; 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci hisi_sas_show_row_64(s, tab_idx, cache_size, iost); 31238c2ecf20Sopenharmony_ci } 31248c2ecf20Sopenharmony_ci 31258c2ecf20Sopenharmony_ci return 0; 31268c2ecf20Sopenharmony_ci} 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_iost_cache_open(struct inode *inode, 31298c2ecf20Sopenharmony_ci struct file *filp) 31308c2ecf20Sopenharmony_ci{ 31318c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_iost_cache_show, 31328c2ecf20Sopenharmony_ci inode->i_private); 31338c2ecf20Sopenharmony_ci} 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_iost_cache_fops = { 31368c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_iost_cache_open, 31378c2ecf20Sopenharmony_ci .read = seq_read, 31388c2ecf20Sopenharmony_ci .llseek = seq_lseek, 31398c2ecf20Sopenharmony_ci .release = single_release, 31408c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 31418c2ecf20Sopenharmony_ci}; 31428c2ecf20Sopenharmony_ci 31438c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p) 31448c2ecf20Sopenharmony_ci{ 31458c2ecf20Sopenharmony_ci int i; 31468c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_itct *debugfs_itct = s->private; 31478c2ecf20Sopenharmony_ci struct hisi_sas_itct *itct = debugfs_itct->itct; 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { 31508c2ecf20Sopenharmony_ci __le64 *data = &itct->qw0; 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci hisi_sas_show_row_64(s, i, sizeof(*itct), data); 31538c2ecf20Sopenharmony_ci } 31548c2ecf20Sopenharmony_ci 31558c2ecf20Sopenharmony_ci return 0; 31568c2ecf20Sopenharmony_ci} 31578c2ecf20Sopenharmony_ci 31588c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_itct_open(struct inode *inode, struct file *filp) 31598c2ecf20Sopenharmony_ci{ 31608c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_itct_show, inode->i_private); 31618c2ecf20Sopenharmony_ci} 31628c2ecf20Sopenharmony_ci 31638c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_itct_fops = { 31648c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_itct_open, 31658c2ecf20Sopenharmony_ci .read = seq_read, 31668c2ecf20Sopenharmony_ci .llseek = seq_lseek, 31678c2ecf20Sopenharmony_ci .release = single_release, 31688c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 31698c2ecf20Sopenharmony_ci}; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p) 31728c2ecf20Sopenharmony_ci{ 31738c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private; 31748c2ecf20Sopenharmony_ci struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->cache; 31758c2ecf20Sopenharmony_ci u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; 31768c2ecf20Sopenharmony_ci int i, tab_idx; 31778c2ecf20Sopenharmony_ci __le64 *itct; 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) { 31808c2ecf20Sopenharmony_ci /* 31818c2ecf20Sopenharmony_ci * Data struct of ITCT cache: 31828c2ecf20Sopenharmony_ci * Data[1]: BIT0~15: Table index 31838c2ecf20Sopenharmony_ci * Bit16: Valid mask 31848c2ecf20Sopenharmony_ci * Data[2]~[9]: ITCT table 31858c2ecf20Sopenharmony_ci */ 31868c2ecf20Sopenharmony_ci tab_idx = itct_cache->data[1] & 0xffff; 31878c2ecf20Sopenharmony_ci itct = (__le64 *)itct_cache; 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci hisi_sas_show_row_64(s, tab_idx, cache_size, itct); 31908c2ecf20Sopenharmony_ci } 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci return 0; 31938c2ecf20Sopenharmony_ci} 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_itct_cache_open(struct inode *inode, 31968c2ecf20Sopenharmony_ci struct file *filp) 31978c2ecf20Sopenharmony_ci{ 31988c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_itct_cache_show, 31998c2ecf20Sopenharmony_ci inode->i_private); 32008c2ecf20Sopenharmony_ci} 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_itct_cache_fops = { 32038c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_itct_cache_open, 32048c2ecf20Sopenharmony_ci .read = seq_read, 32058c2ecf20Sopenharmony_ci .llseek = seq_lseek, 32068c2ecf20Sopenharmony_ci .release = single_release, 32078c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 32088c2ecf20Sopenharmony_ci}; 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) 32118c2ecf20Sopenharmony_ci{ 32128c2ecf20Sopenharmony_ci u64 *debugfs_timestamp; 32138c2ecf20Sopenharmony_ci int dump_index = hisi_hba->debugfs_dump_index; 32148c2ecf20Sopenharmony_ci struct dentry *dump_dentry; 32158c2ecf20Sopenharmony_ci struct dentry *dentry; 32168c2ecf20Sopenharmony_ci char name[256]; 32178c2ecf20Sopenharmony_ci int p; 32188c2ecf20Sopenharmony_ci int c; 32198c2ecf20Sopenharmony_ci int d; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci snprintf(name, 256, "%d", dump_index); 32228c2ecf20Sopenharmony_ci 32238c2ecf20Sopenharmony_ci dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); 32248c2ecf20Sopenharmony_ci 32258c2ecf20Sopenharmony_ci debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index]; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci debugfs_create_u64("timestamp", 0400, dump_dentry, 32288c2ecf20Sopenharmony_ci debugfs_timestamp); 32298c2ecf20Sopenharmony_ci 32308c2ecf20Sopenharmony_ci debugfs_create_file("global", 0400, dump_dentry, 32318c2ecf20Sopenharmony_ci &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL], 32328c2ecf20Sopenharmony_ci &hisi_sas_debugfs_global_fops); 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci /* Create port dir and files */ 32358c2ecf20Sopenharmony_ci dentry = debugfs_create_dir("port", dump_dentry); 32368c2ecf20Sopenharmony_ci for (p = 0; p < hisi_hba->n_phy; p++) { 32378c2ecf20Sopenharmony_ci snprintf(name, 256, "%d", p); 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci debugfs_create_file(name, 0400, dentry, 32408c2ecf20Sopenharmony_ci &hisi_hba->debugfs_port_reg[dump_index][p], 32418c2ecf20Sopenharmony_ci &hisi_sas_debugfs_port_fops); 32428c2ecf20Sopenharmony_ci } 32438c2ecf20Sopenharmony_ci 32448c2ecf20Sopenharmony_ci /* Create CQ dir and files */ 32458c2ecf20Sopenharmony_ci dentry = debugfs_create_dir("cq", dump_dentry); 32468c2ecf20Sopenharmony_ci for (c = 0; c < hisi_hba->queue_count; c++) { 32478c2ecf20Sopenharmony_ci snprintf(name, 256, "%d", c); 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci debugfs_create_file(name, 0400, dentry, 32508c2ecf20Sopenharmony_ci &hisi_hba->debugfs_cq[dump_index][c], 32518c2ecf20Sopenharmony_ci &hisi_sas_debugfs_cq_fops); 32528c2ecf20Sopenharmony_ci } 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci /* Create DQ dir and files */ 32558c2ecf20Sopenharmony_ci dentry = debugfs_create_dir("dq", dump_dentry); 32568c2ecf20Sopenharmony_ci for (d = 0; d < hisi_hba->queue_count; d++) { 32578c2ecf20Sopenharmony_ci snprintf(name, 256, "%d", d); 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci debugfs_create_file(name, 0400, dentry, 32608c2ecf20Sopenharmony_ci &hisi_hba->debugfs_dq[dump_index][d], 32618c2ecf20Sopenharmony_ci &hisi_sas_debugfs_dq_fops); 32628c2ecf20Sopenharmony_ci } 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci debugfs_create_file("iost", 0400, dump_dentry, 32658c2ecf20Sopenharmony_ci &hisi_hba->debugfs_iost[dump_index], 32668c2ecf20Sopenharmony_ci &hisi_sas_debugfs_iost_fops); 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci debugfs_create_file("iost_cache", 0400, dump_dentry, 32698c2ecf20Sopenharmony_ci &hisi_hba->debugfs_iost_cache[dump_index], 32708c2ecf20Sopenharmony_ci &hisi_sas_debugfs_iost_cache_fops); 32718c2ecf20Sopenharmony_ci 32728c2ecf20Sopenharmony_ci debugfs_create_file("itct", 0400, dump_dentry, 32738c2ecf20Sopenharmony_ci &hisi_hba->debugfs_itct[dump_index], 32748c2ecf20Sopenharmony_ci &hisi_sas_debugfs_itct_fops); 32758c2ecf20Sopenharmony_ci 32768c2ecf20Sopenharmony_ci debugfs_create_file("itct_cache", 0400, dump_dentry, 32778c2ecf20Sopenharmony_ci &hisi_hba->debugfs_itct_cache[dump_index], 32788c2ecf20Sopenharmony_ci &hisi_sas_debugfs_itct_cache_fops); 32798c2ecf20Sopenharmony_ci 32808c2ecf20Sopenharmony_ci debugfs_create_file("axi", 0400, dump_dentry, 32818c2ecf20Sopenharmony_ci &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI], 32828c2ecf20Sopenharmony_ci &hisi_sas_debugfs_axi_fops); 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci debugfs_create_file("ras", 0400, dump_dentry, 32858c2ecf20Sopenharmony_ci &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS], 32868c2ecf20Sopenharmony_ci &hisi_sas_debugfs_ras_fops); 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci return; 32898c2ecf20Sopenharmony_ci} 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_snapshot_regs(struct hisi_hba *hisi_hba) 32928c2ecf20Sopenharmony_ci{ 32938c2ecf20Sopenharmony_ci hisi_hba->hw->snapshot_prepare(hisi_hba); 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_global_reg(hisi_hba); 32968c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_port_reg(hisi_hba); 32978c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_axi_reg(hisi_hba); 32988c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_ras_reg(hisi_hba); 32998c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_cq_reg(hisi_hba); 33008c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_dq_reg(hisi_hba); 33018c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_itct_reg(hisi_hba); 33028c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_iost_reg(hisi_hba); 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci hisi_sas_debugfs_create_files(hisi_hba); 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci hisi_hba->hw->snapshot_restore(hisi_hba); 33078c2ecf20Sopenharmony_ci} 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_trigger_dump_write(struct file *file, 33108c2ecf20Sopenharmony_ci const char __user *user_buf, 33118c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 33128c2ecf20Sopenharmony_ci{ 33138c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = file->f_inode->i_private; 33148c2ecf20Sopenharmony_ci char buf[8]; 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count) 33178c2ecf20Sopenharmony_ci return -EFAULT; 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci if (count > 8) 33208c2ecf20Sopenharmony_ci return -EFAULT; 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci if (copy_from_user(buf, user_buf, count)) 33238c2ecf20Sopenharmony_ci return -EFAULT; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci if (buf[0] != '1') 33268c2ecf20Sopenharmony_ci return -EFAULT; 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); 33298c2ecf20Sopenharmony_ci 33308c2ecf20Sopenharmony_ci return count; 33318c2ecf20Sopenharmony_ci} 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_trigger_dump_fops = { 33348c2ecf20Sopenharmony_ci .write = &hisi_sas_debugfs_trigger_dump_write, 33358c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 33368c2ecf20Sopenharmony_ci}; 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_cienum { 33398c2ecf20Sopenharmony_ci HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0, 33408c2ecf20Sopenharmony_ci HISI_SAS_BIST_LOOPBACK_MODE_SERDES, 33418c2ecf20Sopenharmony_ci HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, 33428c2ecf20Sopenharmony_ci}; 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_cistatic const struct { 33458c2ecf20Sopenharmony_ci int value; 33468c2ecf20Sopenharmony_ci char *name; 33478c2ecf20Sopenharmony_ci} hisi_sas_debugfs_loop_linkrate[] = { 33488c2ecf20Sopenharmony_ci { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, 33498c2ecf20Sopenharmony_ci { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, 33508c2ecf20Sopenharmony_ci { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, 33518c2ecf20Sopenharmony_ci { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" }, 33528c2ecf20Sopenharmony_ci}; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_linkrate_show(struct seq_file *s, void *p) 33558c2ecf20Sopenharmony_ci{ 33568c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = s->private; 33578c2ecf20Sopenharmony_ci int i; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) { 33608c2ecf20Sopenharmony_ci int match = (hisi_hba->debugfs_bist_linkrate == 33618c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_linkrate[i].value); 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci seq_printf(s, "%s%s%s ", match ? "[" : "", 33648c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_linkrate[i].name, 33658c2ecf20Sopenharmony_ci match ? "]" : ""); 33668c2ecf20Sopenharmony_ci } 33678c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci return 0; 33708c2ecf20Sopenharmony_ci} 33718c2ecf20Sopenharmony_ci 33728c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_bist_linkrate_write(struct file *filp, 33738c2ecf20Sopenharmony_ci const char __user *buf, 33748c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 33758c2ecf20Sopenharmony_ci{ 33768c2ecf20Sopenharmony_ci struct seq_file *m = filp->private_data; 33778c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = m->private; 33788c2ecf20Sopenharmony_ci char kbuf[16] = {}, *pkbuf; 33798c2ecf20Sopenharmony_ci bool found = false; 33808c2ecf20Sopenharmony_ci int i; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci if (hisi_hba->debugfs_bist_enable) 33838c2ecf20Sopenharmony_ci return -EPERM; 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_ci if (count >= sizeof(kbuf)) 33868c2ecf20Sopenharmony_ci return -EOVERFLOW; 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci if (copy_from_user(kbuf, buf, count)) 33898c2ecf20Sopenharmony_ci return -EINVAL; 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci pkbuf = strstrip(kbuf); 33928c2ecf20Sopenharmony_ci 33938c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) { 33948c2ecf20Sopenharmony_ci if (!strncmp(hisi_sas_debugfs_loop_linkrate[i].name, 33958c2ecf20Sopenharmony_ci pkbuf, 16)) { 33968c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_linkrate = 33978c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_linkrate[i].value; 33988c2ecf20Sopenharmony_ci found = true; 33998c2ecf20Sopenharmony_ci break; 34008c2ecf20Sopenharmony_ci } 34018c2ecf20Sopenharmony_ci } 34028c2ecf20Sopenharmony_ci 34038c2ecf20Sopenharmony_ci if (!found) 34048c2ecf20Sopenharmony_ci return -EINVAL; 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci return count; 34078c2ecf20Sopenharmony_ci} 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_linkrate_open(struct inode *inode, 34108c2ecf20Sopenharmony_ci struct file *filp) 34118c2ecf20Sopenharmony_ci{ 34128c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_bist_linkrate_show, 34138c2ecf20Sopenharmony_ci inode->i_private); 34148c2ecf20Sopenharmony_ci} 34158c2ecf20Sopenharmony_ci 34168c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_bist_linkrate_ops = { 34178c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_bist_linkrate_open, 34188c2ecf20Sopenharmony_ci .read = seq_read, 34198c2ecf20Sopenharmony_ci .write = hisi_sas_debugfs_bist_linkrate_write, 34208c2ecf20Sopenharmony_ci .llseek = seq_lseek, 34218c2ecf20Sopenharmony_ci .release = single_release, 34228c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 34238c2ecf20Sopenharmony_ci}; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_cistatic const struct { 34268c2ecf20Sopenharmony_ci int value; 34278c2ecf20Sopenharmony_ci char *name; 34288c2ecf20Sopenharmony_ci} hisi_sas_debugfs_loop_code_mode[] = { 34298c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" }, 34308c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" }, 34318c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" }, 34328c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" }, 34338c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" }, 34348c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" }, 34358c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" }, 34368c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" }, 34378c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" }, 34388c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" }, 34398c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" }, 34408c2ecf20Sopenharmony_ci { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" }, 34418c2ecf20Sopenharmony_ci}; 34428c2ecf20Sopenharmony_ci 34438c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_code_mode_show(struct seq_file *s, void *p) 34448c2ecf20Sopenharmony_ci{ 34458c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = s->private; 34468c2ecf20Sopenharmony_ci int i; 34478c2ecf20Sopenharmony_ci 34488c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) { 34498c2ecf20Sopenharmony_ci int match = (hisi_hba->debugfs_bist_code_mode == 34508c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_code_mode[i].value); 34518c2ecf20Sopenharmony_ci 34528c2ecf20Sopenharmony_ci seq_printf(s, "%s%s%s ", match ? "[" : "", 34538c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_code_mode[i].name, 34548c2ecf20Sopenharmony_ci match ? "]" : ""); 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 34578c2ecf20Sopenharmony_ci 34588c2ecf20Sopenharmony_ci return 0; 34598c2ecf20Sopenharmony_ci} 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_bist_code_mode_write(struct file *filp, 34628c2ecf20Sopenharmony_ci const char __user *buf, 34638c2ecf20Sopenharmony_ci size_t count, 34648c2ecf20Sopenharmony_ci loff_t *ppos) 34658c2ecf20Sopenharmony_ci{ 34668c2ecf20Sopenharmony_ci struct seq_file *m = filp->private_data; 34678c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = m->private; 34688c2ecf20Sopenharmony_ci char kbuf[16] = {}, *pkbuf; 34698c2ecf20Sopenharmony_ci bool found = false; 34708c2ecf20Sopenharmony_ci int i; 34718c2ecf20Sopenharmony_ci 34728c2ecf20Sopenharmony_ci if (hisi_hba->debugfs_bist_enable) 34738c2ecf20Sopenharmony_ci return -EPERM; 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci if (count >= sizeof(kbuf)) 34768c2ecf20Sopenharmony_ci return -EINVAL; 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_ci if (copy_from_user(kbuf, buf, count)) 34798c2ecf20Sopenharmony_ci return -EOVERFLOW; 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci pkbuf = strstrip(kbuf); 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) { 34848c2ecf20Sopenharmony_ci if (!strncmp(hisi_sas_debugfs_loop_code_mode[i].name, 34858c2ecf20Sopenharmony_ci pkbuf, 16)) { 34868c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_code_mode = 34878c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_code_mode[i].value; 34888c2ecf20Sopenharmony_ci found = true; 34898c2ecf20Sopenharmony_ci break; 34908c2ecf20Sopenharmony_ci } 34918c2ecf20Sopenharmony_ci } 34928c2ecf20Sopenharmony_ci 34938c2ecf20Sopenharmony_ci if (!found) 34948c2ecf20Sopenharmony_ci return -EINVAL; 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci return count; 34978c2ecf20Sopenharmony_ci} 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_code_mode_open(struct inode *inode, 35008c2ecf20Sopenharmony_ci struct file *filp) 35018c2ecf20Sopenharmony_ci{ 35028c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_bist_code_mode_show, 35038c2ecf20Sopenharmony_ci inode->i_private); 35048c2ecf20Sopenharmony_ci} 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_bist_code_mode_ops = { 35078c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_bist_code_mode_open, 35088c2ecf20Sopenharmony_ci .read = seq_read, 35098c2ecf20Sopenharmony_ci .write = hisi_sas_debugfs_bist_code_mode_write, 35108c2ecf20Sopenharmony_ci .llseek = seq_lseek, 35118c2ecf20Sopenharmony_ci .release = single_release, 35128c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 35138c2ecf20Sopenharmony_ci}; 35148c2ecf20Sopenharmony_ci 35158c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_bist_phy_write(struct file *filp, 35168c2ecf20Sopenharmony_ci const char __user *buf, 35178c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 35188c2ecf20Sopenharmony_ci{ 35198c2ecf20Sopenharmony_ci struct seq_file *m = filp->private_data; 35208c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = m->private; 35218c2ecf20Sopenharmony_ci unsigned int phy_no; 35228c2ecf20Sopenharmony_ci int val; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci if (hisi_hba->debugfs_bist_enable) 35258c2ecf20Sopenharmony_ci return -EPERM; 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci val = kstrtouint_from_user(buf, count, 0, &phy_no); 35288c2ecf20Sopenharmony_ci if (val) 35298c2ecf20Sopenharmony_ci return val; 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci if (phy_no >= hisi_hba->n_phy) 35328c2ecf20Sopenharmony_ci return -EINVAL; 35338c2ecf20Sopenharmony_ci 35348c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_phy_no = phy_no; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci return count; 35378c2ecf20Sopenharmony_ci} 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_phy_show(struct seq_file *s, void *p) 35408c2ecf20Sopenharmony_ci{ 35418c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = s->private; 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no); 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci return 0; 35468c2ecf20Sopenharmony_ci} 35478c2ecf20Sopenharmony_ci 35488c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_phy_open(struct inode *inode, 35498c2ecf20Sopenharmony_ci struct file *filp) 35508c2ecf20Sopenharmony_ci{ 35518c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_bist_phy_show, 35528c2ecf20Sopenharmony_ci inode->i_private); 35538c2ecf20Sopenharmony_ci} 35548c2ecf20Sopenharmony_ci 35558c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_bist_phy_ops = { 35568c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_bist_phy_open, 35578c2ecf20Sopenharmony_ci .read = seq_read, 35588c2ecf20Sopenharmony_ci .write = hisi_sas_debugfs_bist_phy_write, 35598c2ecf20Sopenharmony_ci .llseek = seq_lseek, 35608c2ecf20Sopenharmony_ci .release = single_release, 35618c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 35628c2ecf20Sopenharmony_ci}; 35638c2ecf20Sopenharmony_ci 35648c2ecf20Sopenharmony_cistatic const struct { 35658c2ecf20Sopenharmony_ci int value; 35668c2ecf20Sopenharmony_ci char *name; 35678c2ecf20Sopenharmony_ci} hisi_sas_debugfs_loop_modes[] = { 35688c2ecf20Sopenharmony_ci { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" }, 35698c2ecf20Sopenharmony_ci { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" }, 35708c2ecf20Sopenharmony_ci { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" }, 35718c2ecf20Sopenharmony_ci}; 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_mode_show(struct seq_file *s, void *p) 35748c2ecf20Sopenharmony_ci{ 35758c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = s->private; 35768c2ecf20Sopenharmony_ci int i; 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) { 35798c2ecf20Sopenharmony_ci int match = (hisi_hba->debugfs_bist_mode == 35808c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_modes[i].value); 35818c2ecf20Sopenharmony_ci 35828c2ecf20Sopenharmony_ci seq_printf(s, "%s%s%s ", match ? "[" : "", 35838c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_modes[i].name, 35848c2ecf20Sopenharmony_ci match ? "]" : ""); 35858c2ecf20Sopenharmony_ci } 35868c2ecf20Sopenharmony_ci seq_puts(s, "\n"); 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci return 0; 35898c2ecf20Sopenharmony_ci} 35908c2ecf20Sopenharmony_ci 35918c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_bist_mode_write(struct file *filp, 35928c2ecf20Sopenharmony_ci const char __user *buf, 35938c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 35948c2ecf20Sopenharmony_ci{ 35958c2ecf20Sopenharmony_ci struct seq_file *m = filp->private_data; 35968c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = m->private; 35978c2ecf20Sopenharmony_ci char kbuf[16] = {}, *pkbuf; 35988c2ecf20Sopenharmony_ci bool found = false; 35998c2ecf20Sopenharmony_ci int i; 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci if (hisi_hba->debugfs_bist_enable) 36028c2ecf20Sopenharmony_ci return -EPERM; 36038c2ecf20Sopenharmony_ci 36048c2ecf20Sopenharmony_ci if (count >= sizeof(kbuf)) 36058c2ecf20Sopenharmony_ci return -EINVAL; 36068c2ecf20Sopenharmony_ci 36078c2ecf20Sopenharmony_ci if (copy_from_user(kbuf, buf, count)) 36088c2ecf20Sopenharmony_ci return -EOVERFLOW; 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci pkbuf = strstrip(kbuf); 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) { 36138c2ecf20Sopenharmony_ci if (!strncmp(hisi_sas_debugfs_loop_modes[i].name, pkbuf, 16)) { 36148c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_mode = 36158c2ecf20Sopenharmony_ci hisi_sas_debugfs_loop_modes[i].value; 36168c2ecf20Sopenharmony_ci found = true; 36178c2ecf20Sopenharmony_ci break; 36188c2ecf20Sopenharmony_ci } 36198c2ecf20Sopenharmony_ci } 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci if (!found) 36228c2ecf20Sopenharmony_ci return -EINVAL; 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci return count; 36258c2ecf20Sopenharmony_ci} 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_mode_open(struct inode *inode, 36288c2ecf20Sopenharmony_ci struct file *filp) 36298c2ecf20Sopenharmony_ci{ 36308c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_bist_mode_show, 36318c2ecf20Sopenharmony_ci inode->i_private); 36328c2ecf20Sopenharmony_ci} 36338c2ecf20Sopenharmony_ci 36348c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_bist_mode_ops = { 36358c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_bist_mode_open, 36368c2ecf20Sopenharmony_ci .read = seq_read, 36378c2ecf20Sopenharmony_ci .write = hisi_sas_debugfs_bist_mode_write, 36388c2ecf20Sopenharmony_ci .llseek = seq_lseek, 36398c2ecf20Sopenharmony_ci .release = single_release, 36408c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 36418c2ecf20Sopenharmony_ci}; 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_bist_enable_write(struct file *filp, 36448c2ecf20Sopenharmony_ci const char __user *buf, 36458c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 36468c2ecf20Sopenharmony_ci{ 36478c2ecf20Sopenharmony_ci struct seq_file *m = filp->private_data; 36488c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = m->private; 36498c2ecf20Sopenharmony_ci unsigned int enable; 36508c2ecf20Sopenharmony_ci int val; 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci val = kstrtouint_from_user(buf, count, 0, &enable); 36538c2ecf20Sopenharmony_ci if (val) 36548c2ecf20Sopenharmony_ci return val; 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci if (enable > 1) 36578c2ecf20Sopenharmony_ci return -EINVAL; 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_ci if (enable == hisi_hba->debugfs_bist_enable) 36608c2ecf20Sopenharmony_ci return count; 36618c2ecf20Sopenharmony_ci 36628c2ecf20Sopenharmony_ci if (!hisi_hba->hw->set_bist) 36638c2ecf20Sopenharmony_ci return -EPERM; 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci val = hisi_hba->hw->set_bist(hisi_hba, enable); 36668c2ecf20Sopenharmony_ci if (val < 0) 36678c2ecf20Sopenharmony_ci return val; 36688c2ecf20Sopenharmony_ci 36698c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_enable = enable; 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci return count; 36728c2ecf20Sopenharmony_ci} 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_enable_show(struct seq_file *s, void *p) 36758c2ecf20Sopenharmony_ci{ 36768c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = s->private; 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable); 36798c2ecf20Sopenharmony_ci 36808c2ecf20Sopenharmony_ci return 0; 36818c2ecf20Sopenharmony_ci} 36828c2ecf20Sopenharmony_ci 36838c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_bist_enable_open(struct inode *inode, 36848c2ecf20Sopenharmony_ci struct file *filp) 36858c2ecf20Sopenharmony_ci{ 36868c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_bist_enable_show, 36878c2ecf20Sopenharmony_ci inode->i_private); 36888c2ecf20Sopenharmony_ci} 36898c2ecf20Sopenharmony_ci 36908c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_bist_enable_ops = { 36918c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_bist_enable_open, 36928c2ecf20Sopenharmony_ci .read = seq_read, 36938c2ecf20Sopenharmony_ci .write = hisi_sas_debugfs_bist_enable_write, 36948c2ecf20Sopenharmony_ci .llseek = seq_lseek, 36958c2ecf20Sopenharmony_ci .release = single_release, 36968c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 36978c2ecf20Sopenharmony_ci}; 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_cistatic const struct { 37008c2ecf20Sopenharmony_ci char *name; 37018c2ecf20Sopenharmony_ci} hisi_sas_debugfs_ffe_name[FFE_CFG_MAX] = { 37028c2ecf20Sopenharmony_ci { "SAS_1_5_GBPS" }, 37038c2ecf20Sopenharmony_ci { "SAS_3_0_GBPS" }, 37048c2ecf20Sopenharmony_ci { "SAS_6_0_GBPS" }, 37058c2ecf20Sopenharmony_ci { "SAS_12_0_GBPS" }, 37068c2ecf20Sopenharmony_ci { "FFE_RESV" }, 37078c2ecf20Sopenharmony_ci { "SATA_1_5_GBPS" }, 37088c2ecf20Sopenharmony_ci { "SATA_3_0_GBPS" }, 37098c2ecf20Sopenharmony_ci { "SATA_6_0_GBPS" }, 37108c2ecf20Sopenharmony_ci}; 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_write(struct file *filp, 37138c2ecf20Sopenharmony_ci const char __user *buf, 37148c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 37158c2ecf20Sopenharmony_ci{ 37168c2ecf20Sopenharmony_ci struct seq_file *m = filp->private_data; 37178c2ecf20Sopenharmony_ci u32 *val = m->private; 37188c2ecf20Sopenharmony_ci int res; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci res = kstrtouint_from_user(buf, count, 0, val); 37218c2ecf20Sopenharmony_ci if (res) 37228c2ecf20Sopenharmony_ci return res; 37238c2ecf20Sopenharmony_ci 37248c2ecf20Sopenharmony_ci return count; 37258c2ecf20Sopenharmony_ci} 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_show(struct seq_file *s, void *p) 37288c2ecf20Sopenharmony_ci{ 37298c2ecf20Sopenharmony_ci u32 *val = s->private; 37308c2ecf20Sopenharmony_ci 37318c2ecf20Sopenharmony_ci seq_printf(s, "0x%x\n", *val); 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci return 0; 37348c2ecf20Sopenharmony_ci} 37358c2ecf20Sopenharmony_ci 37368c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_open(struct inode *inode, struct file *filp) 37378c2ecf20Sopenharmony_ci{ 37388c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_show, 37398c2ecf20Sopenharmony_ci inode->i_private); 37408c2ecf20Sopenharmony_ci} 37418c2ecf20Sopenharmony_ci 37428c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_ops = { 37438c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_open, 37448c2ecf20Sopenharmony_ci .read = seq_read, 37458c2ecf20Sopenharmony_ci .write = hisi_sas_debugfs_write, 37468c2ecf20Sopenharmony_ci .llseek = seq_lseek, 37478c2ecf20Sopenharmony_ci .release = single_release, 37488c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 37498c2ecf20Sopenharmony_ci}; 37508c2ecf20Sopenharmony_ci 37518c2ecf20Sopenharmony_cistatic ssize_t hisi_sas_debugfs_phy_down_cnt_write(struct file *filp, 37528c2ecf20Sopenharmony_ci const char __user *buf, 37538c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 37548c2ecf20Sopenharmony_ci{ 37558c2ecf20Sopenharmony_ci struct seq_file *s = filp->private_data; 37568c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = s->private; 37578c2ecf20Sopenharmony_ci unsigned int set_val; 37588c2ecf20Sopenharmony_ci int res; 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_ci res = kstrtouint_from_user(buf, count, 0, &set_val); 37618c2ecf20Sopenharmony_ci if (res) 37628c2ecf20Sopenharmony_ci return res; 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci if (set_val > 0) 37658c2ecf20Sopenharmony_ci return -EINVAL; 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci atomic_set(&phy->down_cnt, 0); 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci return count; 37708c2ecf20Sopenharmony_ci} 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_phy_down_cnt_show(struct seq_file *s, void *p) 37738c2ecf20Sopenharmony_ci{ 37748c2ecf20Sopenharmony_ci struct hisi_sas_phy *phy = s->private; 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci seq_printf(s, "%d\n", atomic_read(&phy->down_cnt)); 37778c2ecf20Sopenharmony_ci 37788c2ecf20Sopenharmony_ci return 0; 37798c2ecf20Sopenharmony_ci} 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_phy_down_cnt_open(struct inode *inode, 37828c2ecf20Sopenharmony_ci struct file *filp) 37838c2ecf20Sopenharmony_ci{ 37848c2ecf20Sopenharmony_ci return single_open(filp, hisi_sas_debugfs_phy_down_cnt_show, 37858c2ecf20Sopenharmony_ci inode->i_private); 37868c2ecf20Sopenharmony_ci} 37878c2ecf20Sopenharmony_ci 37888c2ecf20Sopenharmony_cistatic const struct file_operations hisi_sas_debugfs_phy_down_cnt_ops = { 37898c2ecf20Sopenharmony_ci .open = hisi_sas_debugfs_phy_down_cnt_open, 37908c2ecf20Sopenharmony_ci .read = seq_read, 37918c2ecf20Sopenharmony_ci .write = hisi_sas_debugfs_phy_down_cnt_write, 37928c2ecf20Sopenharmony_ci .llseek = seq_lseek, 37938c2ecf20Sopenharmony_ci .release = single_release, 37948c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 37958c2ecf20Sopenharmony_ci}; 37968c2ecf20Sopenharmony_ci 37978c2ecf20Sopenharmony_civoid hisi_sas_debugfs_work_handler(struct work_struct *work) 37988c2ecf20Sopenharmony_ci{ 37998c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = 38008c2ecf20Sopenharmony_ci container_of(work, struct hisi_hba, debugfs_work); 38018c2ecf20Sopenharmony_ci int debugfs_dump_index = hisi_hba->debugfs_dump_index; 38028c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 38038c2ecf20Sopenharmony_ci u64 timestamp = local_clock(); 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) { 38068c2ecf20Sopenharmony_ci dev_warn(dev, "dump count exceeded!\n"); 38078c2ecf20Sopenharmony_ci return; 38088c2ecf20Sopenharmony_ci } 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci do_div(timestamp, NSEC_PER_MSEC); 38118c2ecf20Sopenharmony_ci hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp; 38128c2ecf20Sopenharmony_ci 38138c2ecf20Sopenharmony_ci hisi_sas_debugfs_snapshot_regs(hisi_hba); 38148c2ecf20Sopenharmony_ci hisi_hba->debugfs_dump_index++; 38158c2ecf20Sopenharmony_ci} 38168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler); 38178c2ecf20Sopenharmony_ci 38188c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba, int dump_index) 38198c2ecf20Sopenharmony_ci{ 38208c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 38218c2ecf20Sopenharmony_ci int i; 38228c2ecf20Sopenharmony_ci 38238c2ecf20Sopenharmony_ci devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache); 38248c2ecf20Sopenharmony_ci devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache); 38258c2ecf20Sopenharmony_ci devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost); 38268c2ecf20Sopenharmony_ci devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct); 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->queue_count; i++) 38298c2ecf20Sopenharmony_ci devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr); 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->queue_count; i++) 38328c2ecf20Sopenharmony_ci devm_kfree(dev, 38338c2ecf20Sopenharmony_ci hisi_hba->debugfs_cq[dump_index][i].complete_hdr); 38348c2ecf20Sopenharmony_ci 38358c2ecf20Sopenharmony_ci for (i = 0; i < DEBUGFS_REGS_NUM; i++) 38368c2ecf20Sopenharmony_ci devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data); 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci for (i = 0; i < hisi_hba->n_phy; i++) 38398c2ecf20Sopenharmony_ci devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data); 38408c2ecf20Sopenharmony_ci} 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_cistatic int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index) 38438c2ecf20Sopenharmony_ci{ 38448c2ecf20Sopenharmony_ci const struct hisi_sas_hw *hw = hisi_hba->hw; 38458c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 38468c2ecf20Sopenharmony_ci int p, c, d, r, i; 38478c2ecf20Sopenharmony_ci size_t sz; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci for (r = 0; r < DEBUGFS_REGS_NUM; r++) { 38508c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_regs *regs = 38518c2ecf20Sopenharmony_ci &hisi_hba->debugfs_regs[dump_index][r]; 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci sz = hw->debugfs_reg_array[r]->count * 4; 38548c2ecf20Sopenharmony_ci regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); 38558c2ecf20Sopenharmony_ci if (!regs->data) 38568c2ecf20Sopenharmony_ci goto fail; 38578c2ecf20Sopenharmony_ci regs->hisi_hba = hisi_hba; 38588c2ecf20Sopenharmony_ci } 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci sz = hw->debugfs_reg_port->count * 4; 38618c2ecf20Sopenharmony_ci for (p = 0; p < hisi_hba->n_phy; p++) { 38628c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_port *port = 38638c2ecf20Sopenharmony_ci &hisi_hba->debugfs_port_reg[dump_index][p]; 38648c2ecf20Sopenharmony_ci 38658c2ecf20Sopenharmony_ci port->data = devm_kmalloc(dev, sz, GFP_KERNEL); 38668c2ecf20Sopenharmony_ci if (!port->data) 38678c2ecf20Sopenharmony_ci goto fail; 38688c2ecf20Sopenharmony_ci port->phy = &hisi_hba->phy[p]; 38698c2ecf20Sopenharmony_ci } 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; 38728c2ecf20Sopenharmony_ci for (c = 0; c < hisi_hba->queue_count; c++) { 38738c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_cq *cq = 38748c2ecf20Sopenharmony_ci &hisi_hba->debugfs_cq[dump_index][c]; 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL); 38778c2ecf20Sopenharmony_ci if (!cq->complete_hdr) 38788c2ecf20Sopenharmony_ci goto fail; 38798c2ecf20Sopenharmony_ci cq->cq = &hisi_hba->cq[c]; 38808c2ecf20Sopenharmony_ci } 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; 38838c2ecf20Sopenharmony_ci for (d = 0; d < hisi_hba->queue_count; d++) { 38848c2ecf20Sopenharmony_ci struct hisi_sas_debugfs_dq *dq = 38858c2ecf20Sopenharmony_ci &hisi_hba->debugfs_dq[dump_index][d]; 38868c2ecf20Sopenharmony_ci 38878c2ecf20Sopenharmony_ci dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL); 38888c2ecf20Sopenharmony_ci if (!dq->hdr) 38898c2ecf20Sopenharmony_ci goto fail; 38908c2ecf20Sopenharmony_ci dq->dq = &hisi_hba->dq[d]; 38918c2ecf20Sopenharmony_ci } 38928c2ecf20Sopenharmony_ci 38938c2ecf20Sopenharmony_ci sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost); 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci hisi_hba->debugfs_iost[dump_index].iost = 38968c2ecf20Sopenharmony_ci devm_kmalloc(dev, sz, GFP_KERNEL); 38978c2ecf20Sopenharmony_ci if (!hisi_hba->debugfs_iost[dump_index].iost) 38988c2ecf20Sopenharmony_ci goto fail; 38998c2ecf20Sopenharmony_ci 39008c2ecf20Sopenharmony_ci sz = HISI_SAS_IOST_ITCT_CACHE_NUM * 39018c2ecf20Sopenharmony_ci sizeof(struct hisi_sas_iost_itct_cache); 39028c2ecf20Sopenharmony_ci 39038c2ecf20Sopenharmony_ci hisi_hba->debugfs_iost_cache[dump_index].cache = 39048c2ecf20Sopenharmony_ci devm_kmalloc(dev, sz, GFP_KERNEL); 39058c2ecf20Sopenharmony_ci if (!hisi_hba->debugfs_iost_cache[dump_index].cache) 39068c2ecf20Sopenharmony_ci goto fail; 39078c2ecf20Sopenharmony_ci 39088c2ecf20Sopenharmony_ci sz = HISI_SAS_IOST_ITCT_CACHE_NUM * 39098c2ecf20Sopenharmony_ci sizeof(struct hisi_sas_iost_itct_cache); 39108c2ecf20Sopenharmony_ci 39118c2ecf20Sopenharmony_ci hisi_hba->debugfs_itct_cache[dump_index].cache = 39128c2ecf20Sopenharmony_ci devm_kmalloc(dev, sz, GFP_KERNEL); 39138c2ecf20Sopenharmony_ci if (!hisi_hba->debugfs_itct_cache[dump_index].cache) 39148c2ecf20Sopenharmony_ci goto fail; 39158c2ecf20Sopenharmony_ci 39168c2ecf20Sopenharmony_ci /* New memory allocation must be locate before itct */ 39178c2ecf20Sopenharmony_ci sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); 39188c2ecf20Sopenharmony_ci 39198c2ecf20Sopenharmony_ci hisi_hba->debugfs_itct[dump_index].itct = 39208c2ecf20Sopenharmony_ci devm_kmalloc(dev, sz, GFP_KERNEL); 39218c2ecf20Sopenharmony_ci if (!hisi_hba->debugfs_itct[dump_index].itct) 39228c2ecf20Sopenharmony_ci goto fail; 39238c2ecf20Sopenharmony_ci 39248c2ecf20Sopenharmony_ci return 0; 39258c2ecf20Sopenharmony_cifail: 39268c2ecf20Sopenharmony_ci for (i = 0; i < hisi_sas_debugfs_dump_count; i++) 39278c2ecf20Sopenharmony_ci hisi_sas_debugfs_release(hisi_hba, i); 39288c2ecf20Sopenharmony_ci return -ENOMEM; 39298c2ecf20Sopenharmony_ci} 39308c2ecf20Sopenharmony_ci 39318c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba *hisi_hba) 39328c2ecf20Sopenharmony_ci{ 39338c2ecf20Sopenharmony_ci struct dentry *dir = debugfs_create_dir("phy_down_cnt", 39348c2ecf20Sopenharmony_ci hisi_hba->debugfs_dir); 39358c2ecf20Sopenharmony_ci char name[16]; 39368c2ecf20Sopenharmony_ci int phy_no; 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { 39398c2ecf20Sopenharmony_ci snprintf(name, 16, "%d", phy_no); 39408c2ecf20Sopenharmony_ci debugfs_create_file(name, 0600, dir, 39418c2ecf20Sopenharmony_ci &hisi_hba->phy[phy_no], 39428c2ecf20Sopenharmony_ci &hisi_sas_debugfs_phy_down_cnt_ops); 39438c2ecf20Sopenharmony_ci } 39448c2ecf20Sopenharmony_ci} 39458c2ecf20Sopenharmony_ci 39468c2ecf20Sopenharmony_cistatic void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba) 39478c2ecf20Sopenharmony_ci{ 39488c2ecf20Sopenharmony_ci struct dentry *ports_dentry; 39498c2ecf20Sopenharmony_ci int phy_no; 39508c2ecf20Sopenharmony_ci 39518c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_dentry = 39528c2ecf20Sopenharmony_ci debugfs_create_dir("bist", hisi_hba->debugfs_dir); 39538c2ecf20Sopenharmony_ci debugfs_create_file("link_rate", 0600, 39548c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_dentry, hisi_hba, 39558c2ecf20Sopenharmony_ci &hisi_sas_debugfs_bist_linkrate_ops); 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci debugfs_create_file("code_mode", 0600, 39588c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_dentry, hisi_hba, 39598c2ecf20Sopenharmony_ci &hisi_sas_debugfs_bist_code_mode_ops); 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci debugfs_create_file("fixed_code", 0600, 39628c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_dentry, 39638c2ecf20Sopenharmony_ci &hisi_hba->debugfs_bist_fixed_code[0], 39648c2ecf20Sopenharmony_ci &hisi_sas_debugfs_ops); 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_ci debugfs_create_file("fixed_code_1", 0600, 39678c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_dentry, 39688c2ecf20Sopenharmony_ci &hisi_hba->debugfs_bist_fixed_code[1], 39698c2ecf20Sopenharmony_ci &hisi_sas_debugfs_ops); 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry, 39728c2ecf20Sopenharmony_ci hisi_hba, &hisi_sas_debugfs_bist_phy_ops); 39738c2ecf20Sopenharmony_ci 39748c2ecf20Sopenharmony_ci debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry, 39758c2ecf20Sopenharmony_ci &hisi_hba->debugfs_bist_cnt); 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci debugfs_create_file("loopback_mode", 0600, 39788c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_dentry, 39798c2ecf20Sopenharmony_ci hisi_hba, &hisi_sas_debugfs_bist_mode_ops); 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry, 39828c2ecf20Sopenharmony_ci hisi_hba, &hisi_sas_debugfs_bist_enable_ops); 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry); 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ci for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { 39878c2ecf20Sopenharmony_ci struct dentry *port_dentry; 39888c2ecf20Sopenharmony_ci struct dentry *ffe_dentry; 39898c2ecf20Sopenharmony_ci char name[256]; 39908c2ecf20Sopenharmony_ci int i; 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci snprintf(name, 256, "%d", phy_no); 39938c2ecf20Sopenharmony_ci port_dentry = debugfs_create_dir(name, ports_dentry); 39948c2ecf20Sopenharmony_ci ffe_dentry = debugfs_create_dir("ffe", port_dentry); 39958c2ecf20Sopenharmony_ci for (i = 0; i < FFE_CFG_MAX; i++) { 39968c2ecf20Sopenharmony_ci if (i == FFE_RESV) 39978c2ecf20Sopenharmony_ci continue; 39988c2ecf20Sopenharmony_ci debugfs_create_file(hisi_sas_debugfs_ffe_name[i].name, 39998c2ecf20Sopenharmony_ci 0600, ffe_dentry, 40008c2ecf20Sopenharmony_ci &hisi_hba->debugfs_bist_ffe[phy_no][i], 40018c2ecf20Sopenharmony_ci &hisi_sas_debugfs_ops); 40028c2ecf20Sopenharmony_ci } 40038c2ecf20Sopenharmony_ci } 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_ci hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS; 40068c2ecf20Sopenharmony_ci} 40078c2ecf20Sopenharmony_ci 40088c2ecf20Sopenharmony_civoid hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) 40098c2ecf20Sopenharmony_ci{ 40108c2ecf20Sopenharmony_ci struct device *dev = hisi_hba->dev; 40118c2ecf20Sopenharmony_ci int i; 40128c2ecf20Sopenharmony_ci 40138c2ecf20Sopenharmony_ci hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), 40148c2ecf20Sopenharmony_ci hisi_sas_debugfs_dir); 40158c2ecf20Sopenharmony_ci debugfs_create_file("trigger_dump", 0200, 40168c2ecf20Sopenharmony_ci hisi_hba->debugfs_dir, 40178c2ecf20Sopenharmony_ci hisi_hba, 40188c2ecf20Sopenharmony_ci &hisi_sas_debugfs_trigger_dump_fops); 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci /* create bist structures */ 40218c2ecf20Sopenharmony_ci hisi_sas_debugfs_bist_init(hisi_hba); 40228c2ecf20Sopenharmony_ci 40238c2ecf20Sopenharmony_ci hisi_hba->debugfs_dump_dentry = 40248c2ecf20Sopenharmony_ci debugfs_create_dir("dump", hisi_hba->debugfs_dir); 40258c2ecf20Sopenharmony_ci 40268c2ecf20Sopenharmony_ci hisi_sas_debugfs_phy_down_cnt_init(hisi_hba); 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci for (i = 0; i < hisi_sas_debugfs_dump_count; i++) { 40298c2ecf20Sopenharmony_ci if (hisi_sas_debugfs_alloc(hisi_hba, i)) { 40308c2ecf20Sopenharmony_ci debugfs_remove_recursive(hisi_hba->debugfs_dir); 40318c2ecf20Sopenharmony_ci dev_dbg(dev, "failed to init debugfs!\n"); 40328c2ecf20Sopenharmony_ci break; 40338c2ecf20Sopenharmony_ci } 40348c2ecf20Sopenharmony_ci } 40358c2ecf20Sopenharmony_ci} 40368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_debugfs_init); 40378c2ecf20Sopenharmony_ci 40388c2ecf20Sopenharmony_civoid hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba) 40398c2ecf20Sopenharmony_ci{ 40408c2ecf20Sopenharmony_ci debugfs_remove_recursive(hisi_hba->debugfs_dir); 40418c2ecf20Sopenharmony_ci} 40428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_debugfs_exit); 40438c2ecf20Sopenharmony_ci 40448c2ecf20Sopenharmony_ciint hisi_sas_remove(struct platform_device *pdev) 40458c2ecf20Sopenharmony_ci{ 40468c2ecf20Sopenharmony_ci struct sas_ha_struct *sha = platform_get_drvdata(pdev); 40478c2ecf20Sopenharmony_ci struct hisi_hba *hisi_hba = sha->lldd_ha; 40488c2ecf20Sopenharmony_ci struct Scsi_Host *shost = sha->core.shost; 40498c2ecf20Sopenharmony_ci 40508c2ecf20Sopenharmony_ci if (timer_pending(&hisi_hba->timer)) 40518c2ecf20Sopenharmony_ci del_timer(&hisi_hba->timer); 40528c2ecf20Sopenharmony_ci 40538c2ecf20Sopenharmony_ci sas_unregister_ha(sha); 40548c2ecf20Sopenharmony_ci sas_remove_host(sha->core.shost); 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_ci hisi_sas_free(hisi_hba); 40578c2ecf20Sopenharmony_ci scsi_host_put(shost); 40588c2ecf20Sopenharmony_ci return 0; 40598c2ecf20Sopenharmony_ci} 40608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_remove); 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_cibool hisi_sas_debugfs_enable; 40638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_debugfs_enable); 40648c2ecf20Sopenharmony_cimodule_param_named(debugfs_enable, hisi_sas_debugfs_enable, bool, 0444); 40658c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hisi_sas_debugfs_enable, "Enable driver debugfs (default disabled)"); 40668c2ecf20Sopenharmony_ci 40678c2ecf20Sopenharmony_ciu32 hisi_sas_debugfs_dump_count = 1; 40688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count); 40698c2ecf20Sopenharmony_cimodule_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444); 40708c2ecf20Sopenharmony_ciMODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow"); 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_cistatic __init int hisi_sas_init(void) 40738c2ecf20Sopenharmony_ci{ 40748c2ecf20Sopenharmony_ci hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops); 40758c2ecf20Sopenharmony_ci if (!hisi_sas_stt) 40768c2ecf20Sopenharmony_ci return -ENOMEM; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci if (hisi_sas_debugfs_enable) { 40798c2ecf20Sopenharmony_ci hisi_sas_debugfs_dir = debugfs_create_dir("hisi_sas", NULL); 40808c2ecf20Sopenharmony_ci if (hisi_sas_debugfs_dump_count > HISI_SAS_MAX_DEBUGFS_DUMP) { 40818c2ecf20Sopenharmony_ci pr_info("hisi_sas: Limiting debugfs dump count\n"); 40828c2ecf20Sopenharmony_ci hisi_sas_debugfs_dump_count = HISI_SAS_MAX_DEBUGFS_DUMP; 40838c2ecf20Sopenharmony_ci } 40848c2ecf20Sopenharmony_ci } 40858c2ecf20Sopenharmony_ci 40868c2ecf20Sopenharmony_ci return 0; 40878c2ecf20Sopenharmony_ci} 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_cistatic __exit void hisi_sas_exit(void) 40908c2ecf20Sopenharmony_ci{ 40918c2ecf20Sopenharmony_ci sas_release_transport(hisi_sas_stt); 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci debugfs_remove(hisi_sas_debugfs_dir); 40948c2ecf20Sopenharmony_ci} 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_cimodule_init(hisi_sas_init); 40978c2ecf20Sopenharmony_cimodule_exit(hisi_sas_exit); 40988c2ecf20Sopenharmony_ci 40998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 41008c2ecf20Sopenharmony_ciMODULE_AUTHOR("John Garry <john.garry@huawei.com>"); 41018c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HISILICON SAS controller driver"); 41028c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME); 4103