1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2015 Linaro Ltd.
4*4882a593Smuzhiyun * Copyright (c) 2015 Hisilicon Limited.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include "hisi_sas.h"
8*4882a593Smuzhiyun #define DRV_NAME "hisi_sas"
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define DEV_IS_GONE(dev) \
11*4882a593Smuzhiyun ((!dev) || (dev->dev_type == SAS_PHY_UNUSED))
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
14*4882a593Smuzhiyun u8 *lun, struct hisi_sas_tmf_task *tmf);
15*4882a593Smuzhiyun static int
16*4882a593Smuzhiyun hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
17*4882a593Smuzhiyun struct domain_device *device,
18*4882a593Smuzhiyun int abort_flag, int tag);
19*4882a593Smuzhiyun static int hisi_sas_softreset_ata_disk(struct domain_device *device);
20*4882a593Smuzhiyun static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
21*4882a593Smuzhiyun void *funcdata);
22*4882a593Smuzhiyun static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
23*4882a593Smuzhiyun struct domain_device *device);
24*4882a593Smuzhiyun static void hisi_sas_dev_gone(struct domain_device *device);
25*4882a593Smuzhiyun
hisi_sas_get_ata_protocol(struct host_to_dev_fis * fis,int direction)26*4882a593Smuzhiyun u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun switch (fis->command) {
29*4882a593Smuzhiyun case ATA_CMD_FPDMA_WRITE:
30*4882a593Smuzhiyun case ATA_CMD_FPDMA_READ:
31*4882a593Smuzhiyun case ATA_CMD_FPDMA_RECV:
32*4882a593Smuzhiyun case ATA_CMD_FPDMA_SEND:
33*4882a593Smuzhiyun case ATA_CMD_NCQ_NON_DATA:
34*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_FPDMA;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun case ATA_CMD_DOWNLOAD_MICRO:
37*4882a593Smuzhiyun case ATA_CMD_ID_ATA:
38*4882a593Smuzhiyun case ATA_CMD_PMP_READ:
39*4882a593Smuzhiyun case ATA_CMD_READ_LOG_EXT:
40*4882a593Smuzhiyun case ATA_CMD_PIO_READ:
41*4882a593Smuzhiyun case ATA_CMD_PIO_READ_EXT:
42*4882a593Smuzhiyun case ATA_CMD_PMP_WRITE:
43*4882a593Smuzhiyun case ATA_CMD_WRITE_LOG_EXT:
44*4882a593Smuzhiyun case ATA_CMD_PIO_WRITE:
45*4882a593Smuzhiyun case ATA_CMD_PIO_WRITE_EXT:
46*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_PIO;
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun case ATA_CMD_DSM:
49*4882a593Smuzhiyun case ATA_CMD_DOWNLOAD_MICRO_DMA:
50*4882a593Smuzhiyun case ATA_CMD_PMP_READ_DMA:
51*4882a593Smuzhiyun case ATA_CMD_PMP_WRITE_DMA:
52*4882a593Smuzhiyun case ATA_CMD_READ:
53*4882a593Smuzhiyun case ATA_CMD_READ_EXT:
54*4882a593Smuzhiyun case ATA_CMD_READ_LOG_DMA_EXT:
55*4882a593Smuzhiyun case ATA_CMD_READ_STREAM_DMA_EXT:
56*4882a593Smuzhiyun case ATA_CMD_TRUSTED_RCV_DMA:
57*4882a593Smuzhiyun case ATA_CMD_TRUSTED_SND_DMA:
58*4882a593Smuzhiyun case ATA_CMD_WRITE:
59*4882a593Smuzhiyun case ATA_CMD_WRITE_EXT:
60*4882a593Smuzhiyun case ATA_CMD_WRITE_FUA_EXT:
61*4882a593Smuzhiyun case ATA_CMD_WRITE_QUEUED:
62*4882a593Smuzhiyun case ATA_CMD_WRITE_LOG_DMA_EXT:
63*4882a593Smuzhiyun case ATA_CMD_WRITE_STREAM_DMA_EXT:
64*4882a593Smuzhiyun case ATA_CMD_ZAC_MGMT_IN:
65*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_DMA;
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun case ATA_CMD_CHK_POWER:
68*4882a593Smuzhiyun case ATA_CMD_DEV_RESET:
69*4882a593Smuzhiyun case ATA_CMD_EDD:
70*4882a593Smuzhiyun case ATA_CMD_FLUSH:
71*4882a593Smuzhiyun case ATA_CMD_FLUSH_EXT:
72*4882a593Smuzhiyun case ATA_CMD_VERIFY:
73*4882a593Smuzhiyun case ATA_CMD_VERIFY_EXT:
74*4882a593Smuzhiyun case ATA_CMD_SET_FEATURES:
75*4882a593Smuzhiyun case ATA_CMD_STANDBY:
76*4882a593Smuzhiyun case ATA_CMD_STANDBYNOW1:
77*4882a593Smuzhiyun case ATA_CMD_ZAC_MGMT_OUT:
78*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_NONDATA;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun case ATA_CMD_SET_MAX:
81*4882a593Smuzhiyun switch (fis->features) {
82*4882a593Smuzhiyun case ATA_SET_MAX_PASSWD:
83*4882a593Smuzhiyun case ATA_SET_MAX_LOCK:
84*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_PIO;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun case ATA_SET_MAX_PASSWD_DMA:
87*4882a593Smuzhiyun case ATA_SET_MAX_UNLOCK_DMA:
88*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_DMA;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun default:
91*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_NONDATA;
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun default:
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun if (direction == DMA_NONE)
97*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_NONDATA;
98*4882a593Smuzhiyun return HISI_SAS_SATA_PROTOCOL_PIO;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_get_ata_protocol);
103*4882a593Smuzhiyun
hisi_sas_sata_done(struct sas_task * task,struct hisi_sas_slot * slot)104*4882a593Smuzhiyun void hisi_sas_sata_done(struct sas_task *task,
105*4882a593Smuzhiyun struct hisi_sas_slot *slot)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun struct task_status_struct *ts = &task->task_status;
108*4882a593Smuzhiyun struct ata_task_resp *resp = (struct ata_task_resp *)ts->buf;
109*4882a593Smuzhiyun struct hisi_sas_status_buffer *status_buf =
110*4882a593Smuzhiyun hisi_sas_status_buf_addr_mem(slot);
111*4882a593Smuzhiyun u8 *iu = &status_buf->iu[0];
112*4882a593Smuzhiyun struct dev_to_host_fis *d2h = (struct dev_to_host_fis *)iu;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun resp->frame_len = sizeof(struct dev_to_host_fis);
115*4882a593Smuzhiyun memcpy(&resp->ending_fis[0], d2h, sizeof(struct dev_to_host_fis));
116*4882a593Smuzhiyun
117*4882a593Smuzhiyun ts->buf_valid_size = sizeof(*resp);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_sata_done);
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun /*
122*4882a593Smuzhiyun * This function assumes linkrate mask fits in 8 bits, which it
123*4882a593Smuzhiyun * does for all HW versions supported.
124*4882a593Smuzhiyun */
hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max)125*4882a593Smuzhiyun u8 hisi_sas_get_prog_phy_linkrate_mask(enum sas_linkrate max)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun u8 rate = 0;
128*4882a593Smuzhiyun int i;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun max -= SAS_LINK_RATE_1_5_GBPS;
131*4882a593Smuzhiyun for (i = 0; i <= max; i++)
132*4882a593Smuzhiyun rate |= 1 << (i * 2);
133*4882a593Smuzhiyun return rate;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_get_prog_phy_linkrate_mask);
136*4882a593Smuzhiyun
dev_to_hisi_hba(struct domain_device * device)137*4882a593Smuzhiyun static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun return device->port->ha->lldd_ha;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
to_hisi_sas_port(struct asd_sas_port * sas_port)142*4882a593Smuzhiyun struct hisi_sas_port *to_hisi_sas_port(struct asd_sas_port *sas_port)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun return container_of(sas_port, struct hisi_sas_port, sas_port);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(to_hisi_sas_port);
147*4882a593Smuzhiyun
hisi_sas_stop_phys(struct hisi_hba * hisi_hba)148*4882a593Smuzhiyun void hisi_sas_stop_phys(struct hisi_hba *hisi_hba)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun int phy_no;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++)
153*4882a593Smuzhiyun hisi_sas_phy_enable(hisi_hba, phy_no, 0);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_stop_phys);
156*4882a593Smuzhiyun
hisi_sas_slot_index_clear(struct hisi_hba * hisi_hba,int slot_idx)157*4882a593Smuzhiyun static void hisi_sas_slot_index_clear(struct hisi_hba *hisi_hba, int slot_idx)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun void *bitmap = hisi_hba->slot_index_tags;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun clear_bit(slot_idx, bitmap);
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
hisi_sas_slot_index_free(struct hisi_hba * hisi_hba,int slot_idx)164*4882a593Smuzhiyun static void hisi_sas_slot_index_free(struct hisi_hba *hisi_hba, int slot_idx)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun if (hisi_hba->hw->slot_index_alloc ||
167*4882a593Smuzhiyun slot_idx >= HISI_SAS_UNRESERVED_IPTT) {
168*4882a593Smuzhiyun spin_lock(&hisi_hba->lock);
169*4882a593Smuzhiyun hisi_sas_slot_index_clear(hisi_hba, slot_idx);
170*4882a593Smuzhiyun spin_unlock(&hisi_hba->lock);
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun
hisi_sas_slot_index_set(struct hisi_hba * hisi_hba,int slot_idx)174*4882a593Smuzhiyun static void hisi_sas_slot_index_set(struct hisi_hba *hisi_hba, int slot_idx)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun void *bitmap = hisi_hba->slot_index_tags;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun set_bit(slot_idx, bitmap);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun
hisi_sas_slot_index_alloc(struct hisi_hba * hisi_hba,struct scsi_cmnd * scsi_cmnd)181*4882a593Smuzhiyun static int hisi_sas_slot_index_alloc(struct hisi_hba *hisi_hba,
182*4882a593Smuzhiyun struct scsi_cmnd *scsi_cmnd)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun int index;
185*4882a593Smuzhiyun void *bitmap = hisi_hba->slot_index_tags;
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun if (scsi_cmnd)
188*4882a593Smuzhiyun return scsi_cmnd->request->tag;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun spin_lock(&hisi_hba->lock);
191*4882a593Smuzhiyun index = find_next_zero_bit(bitmap, hisi_hba->slot_index_count,
192*4882a593Smuzhiyun hisi_hba->last_slot_index + 1);
193*4882a593Smuzhiyun if (index >= hisi_hba->slot_index_count) {
194*4882a593Smuzhiyun index = find_next_zero_bit(bitmap,
195*4882a593Smuzhiyun hisi_hba->slot_index_count,
196*4882a593Smuzhiyun HISI_SAS_UNRESERVED_IPTT);
197*4882a593Smuzhiyun if (index >= hisi_hba->slot_index_count) {
198*4882a593Smuzhiyun spin_unlock(&hisi_hba->lock);
199*4882a593Smuzhiyun return -SAS_QUEUE_FULL;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun hisi_sas_slot_index_set(hisi_hba, index);
203*4882a593Smuzhiyun hisi_hba->last_slot_index = index;
204*4882a593Smuzhiyun spin_unlock(&hisi_hba->lock);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun return index;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun
hisi_sas_slot_index_init(struct hisi_hba * hisi_hba)209*4882a593Smuzhiyun static void hisi_sas_slot_index_init(struct hisi_hba *hisi_hba)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun int i;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun for (i = 0; i < hisi_hba->slot_index_count; ++i)
214*4882a593Smuzhiyun hisi_sas_slot_index_clear(hisi_hba, i);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
hisi_sas_slot_task_free(struct hisi_hba * hisi_hba,struct sas_task * task,struct hisi_sas_slot * slot)217*4882a593Smuzhiyun void hisi_sas_slot_task_free(struct hisi_hba *hisi_hba, struct sas_task *task,
218*4882a593Smuzhiyun struct hisi_sas_slot *slot)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun int device_id = slot->device_id;
221*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = &hisi_hba->devices[device_id];
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (task) {
224*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun if (!task->lldd_task)
227*4882a593Smuzhiyun return;
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun task->lldd_task = NULL;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun if (!sas_protocol_ata(task->task_proto)) {
232*4882a593Smuzhiyun if (slot->n_elem)
233*4882a593Smuzhiyun dma_unmap_sg(dev, task->scatter,
234*4882a593Smuzhiyun task->num_scatter,
235*4882a593Smuzhiyun task->data_dir);
236*4882a593Smuzhiyun if (slot->n_elem_dif) {
237*4882a593Smuzhiyun struct sas_ssp_task *ssp_task = &task->ssp_task;
238*4882a593Smuzhiyun struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd),
241*4882a593Smuzhiyun scsi_prot_sg_count(scsi_cmnd),
242*4882a593Smuzhiyun task->data_dir);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
247*4882a593Smuzhiyun spin_lock(&sas_dev->lock);
248*4882a593Smuzhiyun list_del_init(&slot->entry);
249*4882a593Smuzhiyun spin_unlock(&sas_dev->lock);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun memset(slot, 0, offsetof(struct hisi_sas_slot, buf));
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun hisi_sas_slot_index_free(hisi_hba, slot->idx);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_slot_task_free);
256*4882a593Smuzhiyun
hisi_sas_task_prep_smp(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)257*4882a593Smuzhiyun static void hisi_sas_task_prep_smp(struct hisi_hba *hisi_hba,
258*4882a593Smuzhiyun struct hisi_sas_slot *slot)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun hisi_hba->hw->prep_smp(hisi_hba, slot);
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
hisi_sas_task_prep_ssp(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)263*4882a593Smuzhiyun static void hisi_sas_task_prep_ssp(struct hisi_hba *hisi_hba,
264*4882a593Smuzhiyun struct hisi_sas_slot *slot)
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun hisi_hba->hw->prep_ssp(hisi_hba, slot);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
hisi_sas_task_prep_ata(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot)269*4882a593Smuzhiyun static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
270*4882a593Smuzhiyun struct hisi_sas_slot *slot)
271*4882a593Smuzhiyun {
272*4882a593Smuzhiyun hisi_hba->hw->prep_stp(hisi_hba, slot);
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun
hisi_sas_task_prep_abort(struct hisi_hba * hisi_hba,struct hisi_sas_slot * slot,int device_id,int abort_flag,int tag_to_abort)275*4882a593Smuzhiyun static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
276*4882a593Smuzhiyun struct hisi_sas_slot *slot,
277*4882a593Smuzhiyun int device_id, int abort_flag, int tag_to_abort)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun hisi_hba->hw->prep_abort(hisi_hba, slot,
280*4882a593Smuzhiyun device_id, abort_flag, tag_to_abort);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun
hisi_sas_dma_unmap(struct hisi_hba * hisi_hba,struct sas_task * task,int n_elem,int n_elem_req)283*4882a593Smuzhiyun static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba,
284*4882a593Smuzhiyun struct sas_task *task, int n_elem,
285*4882a593Smuzhiyun int n_elem_req)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun if (!sas_protocol_ata(task->task_proto)) {
290*4882a593Smuzhiyun if (task->num_scatter) {
291*4882a593Smuzhiyun if (n_elem)
292*4882a593Smuzhiyun dma_unmap_sg(dev, task->scatter,
293*4882a593Smuzhiyun task->num_scatter,
294*4882a593Smuzhiyun task->data_dir);
295*4882a593Smuzhiyun } else if (task->task_proto & SAS_PROTOCOL_SMP) {
296*4882a593Smuzhiyun if (n_elem_req)
297*4882a593Smuzhiyun dma_unmap_sg(dev, &task->smp_task.smp_req,
298*4882a593Smuzhiyun 1, DMA_TO_DEVICE);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun }
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
hisi_sas_dma_map(struct hisi_hba * hisi_hba,struct sas_task * task,int * n_elem,int * n_elem_req)303*4882a593Smuzhiyun static int hisi_sas_dma_map(struct hisi_hba *hisi_hba,
304*4882a593Smuzhiyun struct sas_task *task, int *n_elem,
305*4882a593Smuzhiyun int *n_elem_req)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
308*4882a593Smuzhiyun int rc;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun if (sas_protocol_ata(task->task_proto)) {
311*4882a593Smuzhiyun *n_elem = task->num_scatter;
312*4882a593Smuzhiyun } else {
313*4882a593Smuzhiyun unsigned int req_len;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun if (task->num_scatter) {
316*4882a593Smuzhiyun *n_elem = dma_map_sg(dev, task->scatter,
317*4882a593Smuzhiyun task->num_scatter, task->data_dir);
318*4882a593Smuzhiyun if (!*n_elem) {
319*4882a593Smuzhiyun rc = -ENOMEM;
320*4882a593Smuzhiyun goto prep_out;
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun } else if (task->task_proto & SAS_PROTOCOL_SMP) {
323*4882a593Smuzhiyun *n_elem_req = dma_map_sg(dev, &task->smp_task.smp_req,
324*4882a593Smuzhiyun 1, DMA_TO_DEVICE);
325*4882a593Smuzhiyun if (!*n_elem_req) {
326*4882a593Smuzhiyun rc = -ENOMEM;
327*4882a593Smuzhiyun goto prep_out;
328*4882a593Smuzhiyun }
329*4882a593Smuzhiyun req_len = sg_dma_len(&task->smp_task.smp_req);
330*4882a593Smuzhiyun if (req_len & 0x3) {
331*4882a593Smuzhiyun rc = -EINVAL;
332*4882a593Smuzhiyun goto err_out_dma_unmap;
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun }
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun if (*n_elem > HISI_SAS_SGE_PAGE_CNT) {
338*4882a593Smuzhiyun dev_err(dev, "task prep: n_elem(%d) > HISI_SAS_SGE_PAGE_CNT\n",
339*4882a593Smuzhiyun *n_elem);
340*4882a593Smuzhiyun rc = -EINVAL;
341*4882a593Smuzhiyun goto err_out_dma_unmap;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun return 0;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun err_out_dma_unmap:
346*4882a593Smuzhiyun /* It would be better to call dma_unmap_sg() here, but it's messy */
347*4882a593Smuzhiyun hisi_sas_dma_unmap(hisi_hba, task, *n_elem,
348*4882a593Smuzhiyun *n_elem_req);
349*4882a593Smuzhiyun prep_out:
350*4882a593Smuzhiyun return rc;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
hisi_sas_dif_dma_unmap(struct hisi_hba * hisi_hba,struct sas_task * task,int n_elem_dif)353*4882a593Smuzhiyun static void hisi_sas_dif_dma_unmap(struct hisi_hba *hisi_hba,
354*4882a593Smuzhiyun struct sas_task *task, int n_elem_dif)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if (n_elem_dif) {
359*4882a593Smuzhiyun struct sas_ssp_task *ssp_task = &task->ssp_task;
360*4882a593Smuzhiyun struct scsi_cmnd *scsi_cmnd = ssp_task->cmd;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd),
363*4882a593Smuzhiyun scsi_prot_sg_count(scsi_cmnd),
364*4882a593Smuzhiyun task->data_dir);
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun }
367*4882a593Smuzhiyun
hisi_sas_dif_dma_map(struct hisi_hba * hisi_hba,int * n_elem_dif,struct sas_task * task)368*4882a593Smuzhiyun static int hisi_sas_dif_dma_map(struct hisi_hba *hisi_hba,
369*4882a593Smuzhiyun int *n_elem_dif, struct sas_task *task)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
372*4882a593Smuzhiyun struct sas_ssp_task *ssp_task;
373*4882a593Smuzhiyun struct scsi_cmnd *scsi_cmnd;
374*4882a593Smuzhiyun int rc;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun if (task->num_scatter) {
377*4882a593Smuzhiyun ssp_task = &task->ssp_task;
378*4882a593Smuzhiyun scsi_cmnd = ssp_task->cmd;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun if (scsi_prot_sg_count(scsi_cmnd)) {
381*4882a593Smuzhiyun *n_elem_dif = dma_map_sg(dev,
382*4882a593Smuzhiyun scsi_prot_sglist(scsi_cmnd),
383*4882a593Smuzhiyun scsi_prot_sg_count(scsi_cmnd),
384*4882a593Smuzhiyun task->data_dir);
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun if (!*n_elem_dif)
387*4882a593Smuzhiyun return -ENOMEM;
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun if (*n_elem_dif > HISI_SAS_SGE_DIF_PAGE_CNT) {
390*4882a593Smuzhiyun dev_err(dev, "task prep: n_elem_dif(%d) too large\n",
391*4882a593Smuzhiyun *n_elem_dif);
392*4882a593Smuzhiyun rc = -EINVAL;
393*4882a593Smuzhiyun goto err_out_dif_dma_unmap;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun }
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun return 0;
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun err_out_dif_dma_unmap:
401*4882a593Smuzhiyun dma_unmap_sg(dev, scsi_prot_sglist(scsi_cmnd),
402*4882a593Smuzhiyun scsi_prot_sg_count(scsi_cmnd), task->data_dir);
403*4882a593Smuzhiyun return rc;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun
hisi_sas_task_prep(struct sas_task * task,struct hisi_sas_dq ** dq_pointer,bool is_tmf,struct hisi_sas_tmf_task * tmf,int * pass)406*4882a593Smuzhiyun static int hisi_sas_task_prep(struct sas_task *task,
407*4882a593Smuzhiyun struct hisi_sas_dq **dq_pointer,
408*4882a593Smuzhiyun bool is_tmf, struct hisi_sas_tmf_task *tmf,
409*4882a593Smuzhiyun int *pass)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun struct domain_device *device = task->dev;
412*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
413*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
414*4882a593Smuzhiyun struct hisi_sas_port *port;
415*4882a593Smuzhiyun struct hisi_sas_slot *slot;
416*4882a593Smuzhiyun struct hisi_sas_cmd_hdr *cmd_hdr_base;
417*4882a593Smuzhiyun struct asd_sas_port *sas_port = device->port;
418*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
419*4882a593Smuzhiyun int dlvry_queue_slot, dlvry_queue, rc, slot_idx;
420*4882a593Smuzhiyun int n_elem = 0, n_elem_dif = 0, n_elem_req = 0;
421*4882a593Smuzhiyun struct scsi_cmnd *scmd = NULL;
422*4882a593Smuzhiyun struct hisi_sas_dq *dq;
423*4882a593Smuzhiyun unsigned long flags;
424*4882a593Smuzhiyun int wr_q_index;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if (DEV_IS_GONE(sas_dev)) {
427*4882a593Smuzhiyun if (sas_dev)
428*4882a593Smuzhiyun dev_info(dev, "task prep: device %d not ready\n",
429*4882a593Smuzhiyun sas_dev->device_id);
430*4882a593Smuzhiyun else
431*4882a593Smuzhiyun dev_info(dev, "task prep: device %016llx not ready\n",
432*4882a593Smuzhiyun SAS_ADDR(device->sas_addr));
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun return -ECOMM;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (task->uldd_task) {
438*4882a593Smuzhiyun struct ata_queued_cmd *qc;
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun if (dev_is_sata(device)) {
441*4882a593Smuzhiyun qc = task->uldd_task;
442*4882a593Smuzhiyun scmd = qc->scsicmd;
443*4882a593Smuzhiyun } else {
444*4882a593Smuzhiyun scmd = task->uldd_task;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun }
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun if (scmd && hisi_hba->shost->nr_hw_queues) {
449*4882a593Smuzhiyun unsigned int dq_index;
450*4882a593Smuzhiyun u32 blk_tag;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun blk_tag = blk_mq_unique_tag(scmd->request);
453*4882a593Smuzhiyun dq_index = blk_mq_unique_tag_to_hwq(blk_tag);
454*4882a593Smuzhiyun *dq_pointer = dq = &hisi_hba->dq[dq_index];
455*4882a593Smuzhiyun } else if (hisi_hba->shost->nr_hw_queues) {
456*4882a593Smuzhiyun struct Scsi_Host *shost = hisi_hba->shost;
457*4882a593Smuzhiyun struct blk_mq_queue_map *qmap = &shost->tag_set.map[HCTX_TYPE_DEFAULT];
458*4882a593Smuzhiyun int queue = qmap->mq_map[raw_smp_processor_id()];
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun *dq_pointer = dq = &hisi_hba->dq[queue];
461*4882a593Smuzhiyun } else {
462*4882a593Smuzhiyun *dq_pointer = dq = sas_dev->dq;
463*4882a593Smuzhiyun }
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun port = to_hisi_sas_port(sas_port);
466*4882a593Smuzhiyun if (port && !port->port_attached) {
467*4882a593Smuzhiyun dev_info(dev, "task prep: %s port%d not attach device\n",
468*4882a593Smuzhiyun (dev_is_sata(device)) ?
469*4882a593Smuzhiyun "SATA/STP" : "SAS",
470*4882a593Smuzhiyun device->port->id);
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun return -ECOMM;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun rc = hisi_sas_dma_map(hisi_hba, task, &n_elem,
476*4882a593Smuzhiyun &n_elem_req);
477*4882a593Smuzhiyun if (rc < 0)
478*4882a593Smuzhiyun goto prep_out;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun if (!sas_protocol_ata(task->task_proto)) {
481*4882a593Smuzhiyun rc = hisi_sas_dif_dma_map(hisi_hba, &n_elem_dif, task);
482*4882a593Smuzhiyun if (rc < 0)
483*4882a593Smuzhiyun goto err_out_dma_unmap;
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun if (hisi_hba->hw->slot_index_alloc)
487*4882a593Smuzhiyun rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
488*4882a593Smuzhiyun else
489*4882a593Smuzhiyun rc = hisi_sas_slot_index_alloc(hisi_hba, scmd);
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (rc < 0)
492*4882a593Smuzhiyun goto err_out_dif_dma_unmap;
493*4882a593Smuzhiyun
494*4882a593Smuzhiyun slot_idx = rc;
495*4882a593Smuzhiyun slot = &hisi_hba->slot_info[slot_idx];
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun spin_lock(&dq->lock);
498*4882a593Smuzhiyun wr_q_index = dq->wr_point;
499*4882a593Smuzhiyun dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
500*4882a593Smuzhiyun list_add_tail(&slot->delivery, &dq->list);
501*4882a593Smuzhiyun spin_unlock(&dq->lock);
502*4882a593Smuzhiyun spin_lock(&sas_dev->lock);
503*4882a593Smuzhiyun list_add_tail(&slot->entry, &sas_dev->list);
504*4882a593Smuzhiyun spin_unlock(&sas_dev->lock);
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun dlvry_queue = dq->id;
507*4882a593Smuzhiyun dlvry_queue_slot = wr_q_index;
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun slot->device_id = sas_dev->device_id;
510*4882a593Smuzhiyun slot->n_elem = n_elem;
511*4882a593Smuzhiyun slot->n_elem_dif = n_elem_dif;
512*4882a593Smuzhiyun slot->dlvry_queue = dlvry_queue;
513*4882a593Smuzhiyun slot->dlvry_queue_slot = dlvry_queue_slot;
514*4882a593Smuzhiyun cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
515*4882a593Smuzhiyun slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
516*4882a593Smuzhiyun slot->task = task;
517*4882a593Smuzhiyun slot->port = port;
518*4882a593Smuzhiyun slot->tmf = tmf;
519*4882a593Smuzhiyun slot->is_internal = is_tmf;
520*4882a593Smuzhiyun task->lldd_task = slot;
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
523*4882a593Smuzhiyun memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ);
524*4882a593Smuzhiyun memset(hisi_sas_status_buf_addr_mem(slot), 0,
525*4882a593Smuzhiyun sizeof(struct hisi_sas_err_record));
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun switch (task->task_proto) {
528*4882a593Smuzhiyun case SAS_PROTOCOL_SMP:
529*4882a593Smuzhiyun hisi_sas_task_prep_smp(hisi_hba, slot);
530*4882a593Smuzhiyun break;
531*4882a593Smuzhiyun case SAS_PROTOCOL_SSP:
532*4882a593Smuzhiyun hisi_sas_task_prep_ssp(hisi_hba, slot);
533*4882a593Smuzhiyun break;
534*4882a593Smuzhiyun case SAS_PROTOCOL_SATA:
535*4882a593Smuzhiyun case SAS_PROTOCOL_STP:
536*4882a593Smuzhiyun case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
537*4882a593Smuzhiyun hisi_sas_task_prep_ata(hisi_hba, slot);
538*4882a593Smuzhiyun break;
539*4882a593Smuzhiyun default:
540*4882a593Smuzhiyun dev_err(dev, "task prep: unknown/unsupported proto (0x%x)\n",
541*4882a593Smuzhiyun task->task_proto);
542*4882a593Smuzhiyun break;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun
545*4882a593Smuzhiyun spin_lock_irqsave(&task->task_state_lock, flags);
546*4882a593Smuzhiyun task->task_state_flags |= SAS_TASK_AT_INITIATOR;
547*4882a593Smuzhiyun spin_unlock_irqrestore(&task->task_state_lock, flags);
548*4882a593Smuzhiyun
549*4882a593Smuzhiyun ++(*pass);
550*4882a593Smuzhiyun WRITE_ONCE(slot->ready, 1);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun return 0;
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun err_out_dif_dma_unmap:
555*4882a593Smuzhiyun if (!sas_protocol_ata(task->task_proto))
556*4882a593Smuzhiyun hisi_sas_dif_dma_unmap(hisi_hba, task, n_elem_dif);
557*4882a593Smuzhiyun err_out_dma_unmap:
558*4882a593Smuzhiyun hisi_sas_dma_unmap(hisi_hba, task, n_elem,
559*4882a593Smuzhiyun n_elem_req);
560*4882a593Smuzhiyun prep_out:
561*4882a593Smuzhiyun dev_err(dev, "task prep: failed[%d]!\n", rc);
562*4882a593Smuzhiyun return rc;
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
hisi_sas_task_exec(struct sas_task * task,gfp_t gfp_flags,bool is_tmf,struct hisi_sas_tmf_task * tmf)565*4882a593Smuzhiyun static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags,
566*4882a593Smuzhiyun bool is_tmf, struct hisi_sas_tmf_task *tmf)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun u32 rc;
569*4882a593Smuzhiyun u32 pass = 0;
570*4882a593Smuzhiyun struct hisi_hba *hisi_hba;
571*4882a593Smuzhiyun struct device *dev;
572*4882a593Smuzhiyun struct domain_device *device = task->dev;
573*4882a593Smuzhiyun struct asd_sas_port *sas_port = device->port;
574*4882a593Smuzhiyun struct hisi_sas_dq *dq = NULL;
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun if (!sas_port) {
577*4882a593Smuzhiyun struct task_status_struct *ts = &task->task_status;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun ts->resp = SAS_TASK_UNDELIVERED;
580*4882a593Smuzhiyun ts->stat = SAS_PHY_DOWN;
581*4882a593Smuzhiyun /*
582*4882a593Smuzhiyun * libsas will use dev->port, should
583*4882a593Smuzhiyun * not call task_done for sata
584*4882a593Smuzhiyun */
585*4882a593Smuzhiyun if (device->dev_type != SAS_SATA_DEV)
586*4882a593Smuzhiyun task->task_done(task);
587*4882a593Smuzhiyun return -ECOMM;
588*4882a593Smuzhiyun }
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun hisi_hba = dev_to_hisi_hba(device);
591*4882a593Smuzhiyun dev = hisi_hba->dev;
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
594*4882a593Smuzhiyun /*
595*4882a593Smuzhiyun * For IOs from upper layer, it may already disable preempt
596*4882a593Smuzhiyun * in the IO path, if disable preempt again in down(),
597*4882a593Smuzhiyun * function schedule() will report schedule_bug(), so check
598*4882a593Smuzhiyun * preemptible() before goto down().
599*4882a593Smuzhiyun */
600*4882a593Smuzhiyun if (!preemptible())
601*4882a593Smuzhiyun return -EINVAL;
602*4882a593Smuzhiyun
603*4882a593Smuzhiyun down(&hisi_hba->sem);
604*4882a593Smuzhiyun up(&hisi_hba->sem);
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun /* protect task_prep and start_delivery sequence */
608*4882a593Smuzhiyun rc = hisi_sas_task_prep(task, &dq, is_tmf, tmf, &pass);
609*4882a593Smuzhiyun if (rc)
610*4882a593Smuzhiyun dev_err(dev, "task exec: failed[%d]!\n", rc);
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun if (likely(pass)) {
613*4882a593Smuzhiyun spin_lock(&dq->lock);
614*4882a593Smuzhiyun hisi_hba->hw->start_delivery(dq);
615*4882a593Smuzhiyun spin_unlock(&dq->lock);
616*4882a593Smuzhiyun }
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun return rc;
619*4882a593Smuzhiyun }
620*4882a593Smuzhiyun
hisi_sas_bytes_dmaed(struct hisi_hba * hisi_hba,int phy_no)621*4882a593Smuzhiyun static void hisi_sas_bytes_dmaed(struct hisi_hba *hisi_hba, int phy_no)
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
624*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun if (!phy->phy_attached)
627*4882a593Smuzhiyun return;
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun if (test_bit(HISI_SAS_PM_BIT, &hisi_hba->flags) &&
630*4882a593Smuzhiyun !sas_phy->suspended) {
631*4882a593Smuzhiyun dev_warn(hisi_hba->dev, "phy%d during suspend filtered out\n", phy_no);
632*4882a593Smuzhiyun return;
633*4882a593Smuzhiyun }
634*4882a593Smuzhiyun
635*4882a593Smuzhiyun sas_notify_phy_event(sas_phy, PHYE_OOB_DONE);
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun if (sas_phy->phy) {
638*4882a593Smuzhiyun struct sas_phy *sphy = sas_phy->phy;
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun sphy->negotiated_linkrate = sas_phy->linkrate;
641*4882a593Smuzhiyun sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
642*4882a593Smuzhiyun sphy->maximum_linkrate_hw =
643*4882a593Smuzhiyun hisi_hba->hw->phy_get_max_linkrate();
644*4882a593Smuzhiyun if (sphy->minimum_linkrate == SAS_LINK_RATE_UNKNOWN)
645*4882a593Smuzhiyun sphy->minimum_linkrate = phy->minimum_linkrate;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun if (sphy->maximum_linkrate == SAS_LINK_RATE_UNKNOWN)
648*4882a593Smuzhiyun sphy->maximum_linkrate = phy->maximum_linkrate;
649*4882a593Smuzhiyun }
650*4882a593Smuzhiyun
651*4882a593Smuzhiyun if (phy->phy_type & PORT_TYPE_SAS) {
652*4882a593Smuzhiyun struct sas_identify_frame *id;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun id = (struct sas_identify_frame *)phy->frame_rcvd;
655*4882a593Smuzhiyun id->dev_type = phy->identify.device_type;
656*4882a593Smuzhiyun id->initiator_bits = SAS_PROTOCOL_ALL;
657*4882a593Smuzhiyun id->target_bits = phy->identify.target_port_protocols;
658*4882a593Smuzhiyun } else if (phy->phy_type & PORT_TYPE_SATA) {
659*4882a593Smuzhiyun /* Nothing */
660*4882a593Smuzhiyun }
661*4882a593Smuzhiyun
662*4882a593Smuzhiyun sas_phy->frame_rcvd_size = phy->frame_rcvd_size;
663*4882a593Smuzhiyun sas_notify_port_event(sas_phy, PORTE_BYTES_DMAED);
664*4882a593Smuzhiyun }
665*4882a593Smuzhiyun
hisi_sas_alloc_dev(struct domain_device * device)666*4882a593Smuzhiyun static struct hisi_sas_device *hisi_sas_alloc_dev(struct domain_device *device)
667*4882a593Smuzhiyun {
668*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
669*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = NULL;
670*4882a593Smuzhiyun int last = hisi_hba->last_dev_id;
671*4882a593Smuzhiyun int first = (hisi_hba->last_dev_id + 1) % HISI_SAS_MAX_DEVICES;
672*4882a593Smuzhiyun int i;
673*4882a593Smuzhiyun
674*4882a593Smuzhiyun spin_lock(&hisi_hba->lock);
675*4882a593Smuzhiyun for (i = first; i != last; i %= HISI_SAS_MAX_DEVICES) {
676*4882a593Smuzhiyun if (hisi_hba->devices[i].dev_type == SAS_PHY_UNUSED) {
677*4882a593Smuzhiyun int queue = i % hisi_hba->queue_count;
678*4882a593Smuzhiyun struct hisi_sas_dq *dq = &hisi_hba->dq[queue];
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun hisi_hba->devices[i].device_id = i;
681*4882a593Smuzhiyun sas_dev = &hisi_hba->devices[i];
682*4882a593Smuzhiyun sas_dev->dev_status = HISI_SAS_DEV_INIT;
683*4882a593Smuzhiyun sas_dev->dev_type = device->dev_type;
684*4882a593Smuzhiyun sas_dev->hisi_hba = hisi_hba;
685*4882a593Smuzhiyun sas_dev->sas_device = device;
686*4882a593Smuzhiyun sas_dev->dq = dq;
687*4882a593Smuzhiyun spin_lock_init(&sas_dev->lock);
688*4882a593Smuzhiyun INIT_LIST_HEAD(&hisi_hba->devices[i].list);
689*4882a593Smuzhiyun break;
690*4882a593Smuzhiyun }
691*4882a593Smuzhiyun i++;
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun hisi_hba->last_dev_id = i;
694*4882a593Smuzhiyun spin_unlock(&hisi_hba->lock);
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun return sas_dev;
697*4882a593Smuzhiyun }
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun #define HISI_SAS_DISK_RECOVER_CNT 3
hisi_sas_init_device(struct domain_device * device)700*4882a593Smuzhiyun static int hisi_sas_init_device(struct domain_device *device)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun int rc = TMF_RESP_FUNC_COMPLETE;
703*4882a593Smuzhiyun struct scsi_lun lun;
704*4882a593Smuzhiyun struct hisi_sas_tmf_task tmf_task;
705*4882a593Smuzhiyun int retry = HISI_SAS_DISK_RECOVER_CNT;
706*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
707*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
708*4882a593Smuzhiyun struct sas_phy *local_phy;
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun switch (device->dev_type) {
711*4882a593Smuzhiyun case SAS_END_DEVICE:
712*4882a593Smuzhiyun int_to_scsilun(0, &lun);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun tmf_task.tmf = TMF_CLEAR_TASK_SET;
715*4882a593Smuzhiyun while (retry-- > 0) {
716*4882a593Smuzhiyun rc = hisi_sas_debug_issue_ssp_tmf(device, lun.scsi_lun,
717*4882a593Smuzhiyun &tmf_task);
718*4882a593Smuzhiyun if (rc == TMF_RESP_FUNC_COMPLETE) {
719*4882a593Smuzhiyun hisi_sas_release_task(hisi_hba, device);
720*4882a593Smuzhiyun break;
721*4882a593Smuzhiyun }
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun break;
724*4882a593Smuzhiyun case SAS_SATA_DEV:
725*4882a593Smuzhiyun case SAS_SATA_PM:
726*4882a593Smuzhiyun case SAS_SATA_PM_PORT:
727*4882a593Smuzhiyun case SAS_SATA_PENDING:
728*4882a593Smuzhiyun /*
729*4882a593Smuzhiyun * send HARD RESET to clear previous affiliation of
730*4882a593Smuzhiyun * STP target port
731*4882a593Smuzhiyun */
732*4882a593Smuzhiyun local_phy = sas_get_local_phy(device);
733*4882a593Smuzhiyun if (!scsi_is_sas_phy_local(local_phy) &&
734*4882a593Smuzhiyun !test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
735*4882a593Smuzhiyun unsigned long deadline = ata_deadline(jiffies, 20000);
736*4882a593Smuzhiyun struct sata_device *sata_dev = &device->sata_dev;
737*4882a593Smuzhiyun struct ata_host *ata_host = sata_dev->ata_host;
738*4882a593Smuzhiyun struct ata_port_operations *ops = ata_host->ops;
739*4882a593Smuzhiyun struct ata_port *ap = sata_dev->ap;
740*4882a593Smuzhiyun struct ata_link *link;
741*4882a593Smuzhiyun unsigned int classes;
742*4882a593Smuzhiyun
743*4882a593Smuzhiyun ata_for_each_link(link, ap, EDGE)
744*4882a593Smuzhiyun rc = ops->hardreset(link, &classes,
745*4882a593Smuzhiyun deadline);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun sas_put_local_phy(local_phy);
748*4882a593Smuzhiyun if (rc) {
749*4882a593Smuzhiyun dev_warn(dev, "SATA disk hardreset fail: %d\n", rc);
750*4882a593Smuzhiyun return rc;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun while (retry-- > 0) {
754*4882a593Smuzhiyun rc = hisi_sas_softreset_ata_disk(device);
755*4882a593Smuzhiyun if (!rc)
756*4882a593Smuzhiyun break;
757*4882a593Smuzhiyun }
758*4882a593Smuzhiyun break;
759*4882a593Smuzhiyun default:
760*4882a593Smuzhiyun break;
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun return rc;
764*4882a593Smuzhiyun }
765*4882a593Smuzhiyun
hisi_sas_dev_found(struct domain_device * device)766*4882a593Smuzhiyun static int hisi_sas_dev_found(struct domain_device *device)
767*4882a593Smuzhiyun {
768*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
769*4882a593Smuzhiyun struct domain_device *parent_dev = device->parent;
770*4882a593Smuzhiyun struct hisi_sas_device *sas_dev;
771*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
772*4882a593Smuzhiyun int rc;
773*4882a593Smuzhiyun
774*4882a593Smuzhiyun if (hisi_hba->hw->alloc_dev)
775*4882a593Smuzhiyun sas_dev = hisi_hba->hw->alloc_dev(device);
776*4882a593Smuzhiyun else
777*4882a593Smuzhiyun sas_dev = hisi_sas_alloc_dev(device);
778*4882a593Smuzhiyun if (!sas_dev) {
779*4882a593Smuzhiyun dev_err(dev, "fail alloc dev: max support %d devices\n",
780*4882a593Smuzhiyun HISI_SAS_MAX_DEVICES);
781*4882a593Smuzhiyun return -EINVAL;
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun
784*4882a593Smuzhiyun device->lldd_dev = sas_dev;
785*4882a593Smuzhiyun hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
786*4882a593Smuzhiyun
787*4882a593Smuzhiyun if (parent_dev && dev_is_expander(parent_dev->dev_type)) {
788*4882a593Smuzhiyun int phy_no;
789*4882a593Smuzhiyun u8 phy_num = parent_dev->ex_dev.num_phys;
790*4882a593Smuzhiyun struct ex_phy *phy;
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun for (phy_no = 0; phy_no < phy_num; phy_no++) {
793*4882a593Smuzhiyun phy = &parent_dev->ex_dev.ex_phy[phy_no];
794*4882a593Smuzhiyun if (SAS_ADDR(phy->attached_sas_addr) ==
795*4882a593Smuzhiyun SAS_ADDR(device->sas_addr))
796*4882a593Smuzhiyun break;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun if (phy_no == phy_num) {
800*4882a593Smuzhiyun dev_info(dev, "dev found: no attached "
801*4882a593Smuzhiyun "dev:%016llx at ex:%016llx\n",
802*4882a593Smuzhiyun SAS_ADDR(device->sas_addr),
803*4882a593Smuzhiyun SAS_ADDR(parent_dev->sas_addr));
804*4882a593Smuzhiyun rc = -EINVAL;
805*4882a593Smuzhiyun goto err_out;
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun
809*4882a593Smuzhiyun dev_info(dev, "dev[%d:%x] found\n",
810*4882a593Smuzhiyun sas_dev->device_id, sas_dev->dev_type);
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun rc = hisi_sas_init_device(device);
813*4882a593Smuzhiyun if (rc)
814*4882a593Smuzhiyun goto err_out;
815*4882a593Smuzhiyun sas_dev->dev_status = HISI_SAS_DEV_NORMAL;
816*4882a593Smuzhiyun return 0;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun err_out:
819*4882a593Smuzhiyun hisi_sas_dev_gone(device);
820*4882a593Smuzhiyun return rc;
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
hisi_sas_slave_configure(struct scsi_device * sdev)823*4882a593Smuzhiyun int hisi_sas_slave_configure(struct scsi_device *sdev)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun struct domain_device *dev = sdev_to_domain_dev(sdev);
826*4882a593Smuzhiyun int ret = sas_slave_configure(sdev);
827*4882a593Smuzhiyun
828*4882a593Smuzhiyun if (ret)
829*4882a593Smuzhiyun return ret;
830*4882a593Smuzhiyun if (!dev_is_sata(dev))
831*4882a593Smuzhiyun sas_change_queue_depth(sdev, 64);
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun return 0;
834*4882a593Smuzhiyun }
835*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_slave_configure);
836*4882a593Smuzhiyun
hisi_sas_scan_start(struct Scsi_Host * shost)837*4882a593Smuzhiyun void hisi_sas_scan_start(struct Scsi_Host *shost)
838*4882a593Smuzhiyun {
839*4882a593Smuzhiyun struct hisi_hba *hisi_hba = shost_priv(shost);
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun hisi_hba->hw->phys_init(hisi_hba);
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_scan_start);
844*4882a593Smuzhiyun
hisi_sas_scan_finished(struct Scsi_Host * shost,unsigned long time)845*4882a593Smuzhiyun int hisi_sas_scan_finished(struct Scsi_Host *shost, unsigned long time)
846*4882a593Smuzhiyun {
847*4882a593Smuzhiyun struct hisi_hba *hisi_hba = shost_priv(shost);
848*4882a593Smuzhiyun struct sas_ha_struct *sha = &hisi_hba->sha;
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun /* Wait for PHY up interrupt to occur */
851*4882a593Smuzhiyun if (time < HZ)
852*4882a593Smuzhiyun return 0;
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun sas_drain_work(sha);
855*4882a593Smuzhiyun return 1;
856*4882a593Smuzhiyun }
857*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_scan_finished);
858*4882a593Smuzhiyun
hisi_sas_phyup_work(struct work_struct * work)859*4882a593Smuzhiyun static void hisi_sas_phyup_work(struct work_struct *work)
860*4882a593Smuzhiyun {
861*4882a593Smuzhiyun struct hisi_sas_phy *phy =
862*4882a593Smuzhiyun container_of(work, typeof(*phy), works[HISI_PHYE_PHY_UP]);
863*4882a593Smuzhiyun struct hisi_hba *hisi_hba = phy->hisi_hba;
864*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
865*4882a593Smuzhiyun int phy_no = sas_phy->id;
866*4882a593Smuzhiyun
867*4882a593Smuzhiyun if (phy->identify.target_port_protocols == SAS_PROTOCOL_SSP)
868*4882a593Smuzhiyun hisi_hba->hw->sl_notify_ssp(hisi_hba, phy_no);
869*4882a593Smuzhiyun hisi_sas_bytes_dmaed(hisi_hba, phy_no);
870*4882a593Smuzhiyun }
871*4882a593Smuzhiyun
hisi_sas_linkreset_work(struct work_struct * work)872*4882a593Smuzhiyun static void hisi_sas_linkreset_work(struct work_struct *work)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun struct hisi_sas_phy *phy =
875*4882a593Smuzhiyun container_of(work, typeof(*phy), works[HISI_PHYE_LINK_RESET]);
876*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun hisi_sas_control_phy(sas_phy, PHY_FUNC_LINK_RESET, NULL);
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun static const work_func_t hisi_sas_phye_fns[HISI_PHYES_NUM] = {
882*4882a593Smuzhiyun [HISI_PHYE_PHY_UP] = hisi_sas_phyup_work,
883*4882a593Smuzhiyun [HISI_PHYE_LINK_RESET] = hisi_sas_linkreset_work,
884*4882a593Smuzhiyun };
885*4882a593Smuzhiyun
hisi_sas_notify_phy_event(struct hisi_sas_phy * phy,enum hisi_sas_phy_event event)886*4882a593Smuzhiyun bool hisi_sas_notify_phy_event(struct hisi_sas_phy *phy,
887*4882a593Smuzhiyun enum hisi_sas_phy_event event)
888*4882a593Smuzhiyun {
889*4882a593Smuzhiyun struct hisi_hba *hisi_hba = phy->hisi_hba;
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun if (WARN_ON(event >= HISI_PHYES_NUM))
892*4882a593Smuzhiyun return false;
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun return queue_work(hisi_hba->wq, &phy->works[event]);
895*4882a593Smuzhiyun }
896*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_notify_phy_event);
897*4882a593Smuzhiyun
hisi_sas_wait_phyup_timedout(struct timer_list * t)898*4882a593Smuzhiyun static void hisi_sas_wait_phyup_timedout(struct timer_list *t)
899*4882a593Smuzhiyun {
900*4882a593Smuzhiyun struct hisi_sas_phy *phy = from_timer(phy, t, timer);
901*4882a593Smuzhiyun struct hisi_hba *hisi_hba = phy->hisi_hba;
902*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
903*4882a593Smuzhiyun int phy_no = phy->sas_phy.id;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun dev_warn(dev, "phy%d wait phyup timeout, issuing link reset\n", phy_no);
906*4882a593Smuzhiyun hisi_sas_notify_phy_event(phy, HISI_PHYE_LINK_RESET);
907*4882a593Smuzhiyun }
908*4882a593Smuzhiyun
hisi_sas_phy_oob_ready(struct hisi_hba * hisi_hba,int phy_no)909*4882a593Smuzhiyun void hisi_sas_phy_oob_ready(struct hisi_hba *hisi_hba, int phy_no)
910*4882a593Smuzhiyun {
911*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
912*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun dev_dbg(dev, "phy%d OOB ready\n", phy_no);
915*4882a593Smuzhiyun if (phy->phy_attached)
916*4882a593Smuzhiyun return;
917*4882a593Smuzhiyun
918*4882a593Smuzhiyun if (!timer_pending(&phy->timer)) {
919*4882a593Smuzhiyun phy->timer.expires = jiffies + HISI_SAS_WAIT_PHYUP_TIMEOUT * HZ;
920*4882a593Smuzhiyun add_timer(&phy->timer);
921*4882a593Smuzhiyun }
922*4882a593Smuzhiyun }
923*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_phy_oob_ready);
924*4882a593Smuzhiyun
hisi_sas_phy_init(struct hisi_hba * hisi_hba,int phy_no)925*4882a593Smuzhiyun static void hisi_sas_phy_init(struct hisi_hba *hisi_hba, int phy_no)
926*4882a593Smuzhiyun {
927*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
928*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
929*4882a593Smuzhiyun int i;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun phy->hisi_hba = hisi_hba;
932*4882a593Smuzhiyun phy->port = NULL;
933*4882a593Smuzhiyun phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
934*4882a593Smuzhiyun phy->maximum_linkrate = hisi_hba->hw->phy_get_max_linkrate();
935*4882a593Smuzhiyun sas_phy->enabled = (phy_no < hisi_hba->n_phy) ? 1 : 0;
936*4882a593Smuzhiyun sas_phy->class = SAS;
937*4882a593Smuzhiyun sas_phy->iproto = SAS_PROTOCOL_ALL;
938*4882a593Smuzhiyun sas_phy->tproto = 0;
939*4882a593Smuzhiyun sas_phy->type = PHY_TYPE_PHYSICAL;
940*4882a593Smuzhiyun sas_phy->role = PHY_ROLE_INITIATOR;
941*4882a593Smuzhiyun sas_phy->oob_mode = OOB_NOT_CONNECTED;
942*4882a593Smuzhiyun sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN;
943*4882a593Smuzhiyun sas_phy->id = phy_no;
944*4882a593Smuzhiyun sas_phy->sas_addr = &hisi_hba->sas_addr[0];
945*4882a593Smuzhiyun sas_phy->frame_rcvd = &phy->frame_rcvd[0];
946*4882a593Smuzhiyun sas_phy->ha = (struct sas_ha_struct *)hisi_hba->shost->hostdata;
947*4882a593Smuzhiyun sas_phy->lldd_phy = phy;
948*4882a593Smuzhiyun
949*4882a593Smuzhiyun for (i = 0; i < HISI_PHYES_NUM; i++)
950*4882a593Smuzhiyun INIT_WORK(&phy->works[i], hisi_sas_phye_fns[i]);
951*4882a593Smuzhiyun
952*4882a593Smuzhiyun spin_lock_init(&phy->lock);
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun timer_setup(&phy->timer, hisi_sas_wait_phyup_timedout, 0);
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
957*4882a593Smuzhiyun /* Wrapper to ensure we track hisi_sas_phy.enable properly */
hisi_sas_phy_enable(struct hisi_hba * hisi_hba,int phy_no,int enable)958*4882a593Smuzhiyun void hisi_sas_phy_enable(struct hisi_hba *hisi_hba, int phy_no, int enable)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
961*4882a593Smuzhiyun struct asd_sas_phy *aphy = &phy->sas_phy;
962*4882a593Smuzhiyun struct sas_phy *sphy = aphy->phy;
963*4882a593Smuzhiyun unsigned long flags;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun spin_lock_irqsave(&phy->lock, flags);
966*4882a593Smuzhiyun
967*4882a593Smuzhiyun if (enable) {
968*4882a593Smuzhiyun /* We may have been enabled already; if so, don't touch */
969*4882a593Smuzhiyun if (!phy->enable)
970*4882a593Smuzhiyun sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
971*4882a593Smuzhiyun hisi_hba->hw->phy_start(hisi_hba, phy_no);
972*4882a593Smuzhiyun } else {
973*4882a593Smuzhiyun sphy->negotiated_linkrate = SAS_PHY_DISABLED;
974*4882a593Smuzhiyun hisi_hba->hw->phy_disable(hisi_hba, phy_no);
975*4882a593Smuzhiyun }
976*4882a593Smuzhiyun phy->enable = enable;
977*4882a593Smuzhiyun spin_unlock_irqrestore(&phy->lock, flags);
978*4882a593Smuzhiyun }
979*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_phy_enable);
980*4882a593Smuzhiyun
hisi_sas_port_notify_formed(struct asd_sas_phy * sas_phy)981*4882a593Smuzhiyun static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy)
982*4882a593Smuzhiyun {
983*4882a593Smuzhiyun struct sas_ha_struct *sas_ha = sas_phy->ha;
984*4882a593Smuzhiyun struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
985*4882a593Smuzhiyun struct hisi_sas_phy *phy = sas_phy->lldd_phy;
986*4882a593Smuzhiyun struct asd_sas_port *sas_port = sas_phy->port;
987*4882a593Smuzhiyun struct hisi_sas_port *port;
988*4882a593Smuzhiyun unsigned long flags;
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun if (!sas_port)
991*4882a593Smuzhiyun return;
992*4882a593Smuzhiyun
993*4882a593Smuzhiyun port = to_hisi_sas_port(sas_port);
994*4882a593Smuzhiyun spin_lock_irqsave(&hisi_hba->lock, flags);
995*4882a593Smuzhiyun port->port_attached = 1;
996*4882a593Smuzhiyun port->id = phy->port_id;
997*4882a593Smuzhiyun phy->port = port;
998*4882a593Smuzhiyun sas_port->lldd_port = port;
999*4882a593Smuzhiyun spin_unlock_irqrestore(&hisi_hba->lock, flags);
1000*4882a593Smuzhiyun }
1001*4882a593Smuzhiyun
hisi_sas_do_release_task(struct hisi_hba * hisi_hba,struct sas_task * task,struct hisi_sas_slot * slot)1002*4882a593Smuzhiyun static void hisi_sas_do_release_task(struct hisi_hba *hisi_hba, struct sas_task *task,
1003*4882a593Smuzhiyun struct hisi_sas_slot *slot)
1004*4882a593Smuzhiyun {
1005*4882a593Smuzhiyun if (task) {
1006*4882a593Smuzhiyun unsigned long flags;
1007*4882a593Smuzhiyun struct task_status_struct *ts;
1008*4882a593Smuzhiyun
1009*4882a593Smuzhiyun ts = &task->task_status;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun ts->resp = SAS_TASK_COMPLETE;
1012*4882a593Smuzhiyun ts->stat = SAS_ABORTED_TASK;
1013*4882a593Smuzhiyun spin_lock_irqsave(&task->task_state_lock, flags);
1014*4882a593Smuzhiyun task->task_state_flags &=
1015*4882a593Smuzhiyun ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR);
1016*4882a593Smuzhiyun if (!slot->is_internal && task->task_proto != SAS_PROTOCOL_SMP)
1017*4882a593Smuzhiyun task->task_state_flags |= SAS_TASK_STATE_DONE;
1018*4882a593Smuzhiyun spin_unlock_irqrestore(&task->task_state_lock, flags);
1019*4882a593Smuzhiyun }
1020*4882a593Smuzhiyun
1021*4882a593Smuzhiyun hisi_sas_slot_task_free(hisi_hba, task, slot);
1022*4882a593Smuzhiyun }
1023*4882a593Smuzhiyun
hisi_sas_release_task(struct hisi_hba * hisi_hba,struct domain_device * device)1024*4882a593Smuzhiyun static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
1025*4882a593Smuzhiyun struct domain_device *device)
1026*4882a593Smuzhiyun {
1027*4882a593Smuzhiyun struct hisi_sas_slot *slot, *slot2;
1028*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
1029*4882a593Smuzhiyun
1030*4882a593Smuzhiyun list_for_each_entry_safe(slot, slot2, &sas_dev->list, entry)
1031*4882a593Smuzhiyun hisi_sas_do_release_task(hisi_hba, slot->task, slot);
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
hisi_sas_release_tasks(struct hisi_hba * hisi_hba)1034*4882a593Smuzhiyun void hisi_sas_release_tasks(struct hisi_hba *hisi_hba)
1035*4882a593Smuzhiyun {
1036*4882a593Smuzhiyun struct hisi_sas_device *sas_dev;
1037*4882a593Smuzhiyun struct domain_device *device;
1038*4882a593Smuzhiyun int i;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
1041*4882a593Smuzhiyun sas_dev = &hisi_hba->devices[i];
1042*4882a593Smuzhiyun device = sas_dev->sas_device;
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun if ((sas_dev->dev_type == SAS_PHY_UNUSED) ||
1045*4882a593Smuzhiyun !device)
1046*4882a593Smuzhiyun continue;
1047*4882a593Smuzhiyun
1048*4882a593Smuzhiyun hisi_sas_release_task(hisi_hba, device);
1049*4882a593Smuzhiyun }
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_release_tasks);
1052*4882a593Smuzhiyun
hisi_sas_dereg_device(struct hisi_hba * hisi_hba,struct domain_device * device)1053*4882a593Smuzhiyun static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
1054*4882a593Smuzhiyun struct domain_device *device)
1055*4882a593Smuzhiyun {
1056*4882a593Smuzhiyun if (hisi_hba->hw->dereg_device)
1057*4882a593Smuzhiyun hisi_hba->hw->dereg_device(hisi_hba, device);
1058*4882a593Smuzhiyun }
1059*4882a593Smuzhiyun
hisi_sas_dev_gone(struct domain_device * device)1060*4882a593Smuzhiyun static void hisi_sas_dev_gone(struct domain_device *device)
1061*4882a593Smuzhiyun {
1062*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
1063*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
1064*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1065*4882a593Smuzhiyun int ret = 0;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun dev_info(dev, "dev[%d:%x] is gone\n",
1068*4882a593Smuzhiyun sas_dev->device_id, sas_dev->dev_type);
1069*4882a593Smuzhiyun
1070*4882a593Smuzhiyun down(&hisi_hba->sem);
1071*4882a593Smuzhiyun if (!test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags)) {
1072*4882a593Smuzhiyun hisi_sas_internal_task_abort(hisi_hba, device,
1073*4882a593Smuzhiyun HISI_SAS_INT_ABT_DEV, 0);
1074*4882a593Smuzhiyun
1075*4882a593Smuzhiyun hisi_sas_dereg_device(hisi_hba, device);
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun ret = hisi_hba->hw->clear_itct(hisi_hba, sas_dev);
1078*4882a593Smuzhiyun device->lldd_dev = NULL;
1079*4882a593Smuzhiyun }
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun if (hisi_hba->hw->free_device)
1082*4882a593Smuzhiyun hisi_hba->hw->free_device(sas_dev);
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun /* Don't mark it as SAS_PHY_UNUSED if failed to clear ITCT */
1085*4882a593Smuzhiyun if (!ret)
1086*4882a593Smuzhiyun sas_dev->dev_type = SAS_PHY_UNUSED;
1087*4882a593Smuzhiyun sas_dev->sas_device = NULL;
1088*4882a593Smuzhiyun up(&hisi_hba->sem);
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun
hisi_sas_queue_command(struct sas_task * task,gfp_t gfp_flags)1091*4882a593Smuzhiyun static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
1092*4882a593Smuzhiyun {
1093*4882a593Smuzhiyun return hisi_sas_task_exec(task, gfp_flags, 0, NULL);
1094*4882a593Smuzhiyun }
1095*4882a593Smuzhiyun
hisi_sas_phy_set_linkrate(struct hisi_hba * hisi_hba,int phy_no,struct sas_phy_linkrates * r)1096*4882a593Smuzhiyun static int hisi_sas_phy_set_linkrate(struct hisi_hba *hisi_hba, int phy_no,
1097*4882a593Smuzhiyun struct sas_phy_linkrates *r)
1098*4882a593Smuzhiyun {
1099*4882a593Smuzhiyun struct sas_phy_linkrates _r;
1100*4882a593Smuzhiyun
1101*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
1102*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
1103*4882a593Smuzhiyun enum sas_linkrate min, max;
1104*4882a593Smuzhiyun
1105*4882a593Smuzhiyun if (r->minimum_linkrate > SAS_LINK_RATE_1_5_GBPS)
1106*4882a593Smuzhiyun return -EINVAL;
1107*4882a593Smuzhiyun
1108*4882a593Smuzhiyun if (r->maximum_linkrate == SAS_LINK_RATE_UNKNOWN) {
1109*4882a593Smuzhiyun max = sas_phy->phy->maximum_linkrate;
1110*4882a593Smuzhiyun min = r->minimum_linkrate;
1111*4882a593Smuzhiyun } else if (r->minimum_linkrate == SAS_LINK_RATE_UNKNOWN) {
1112*4882a593Smuzhiyun max = r->maximum_linkrate;
1113*4882a593Smuzhiyun min = sas_phy->phy->minimum_linkrate;
1114*4882a593Smuzhiyun } else
1115*4882a593Smuzhiyun return -EINVAL;
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun _r.maximum_linkrate = max;
1118*4882a593Smuzhiyun _r.minimum_linkrate = min;
1119*4882a593Smuzhiyun
1120*4882a593Smuzhiyun sas_phy->phy->maximum_linkrate = max;
1121*4882a593Smuzhiyun sas_phy->phy->minimum_linkrate = min;
1122*4882a593Smuzhiyun
1123*4882a593Smuzhiyun hisi_sas_phy_enable(hisi_hba, phy_no, 0);
1124*4882a593Smuzhiyun msleep(100);
1125*4882a593Smuzhiyun hisi_hba->hw->phy_set_linkrate(hisi_hba, phy_no, &_r);
1126*4882a593Smuzhiyun hisi_sas_phy_enable(hisi_hba, phy_no, 1);
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun return 0;
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun
hisi_sas_control_phy(struct asd_sas_phy * sas_phy,enum phy_func func,void * funcdata)1131*4882a593Smuzhiyun static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
1132*4882a593Smuzhiyun void *funcdata)
1133*4882a593Smuzhiyun {
1134*4882a593Smuzhiyun struct sas_ha_struct *sas_ha = sas_phy->ha;
1135*4882a593Smuzhiyun struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
1136*4882a593Smuzhiyun int phy_no = sas_phy->id;
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun switch (func) {
1139*4882a593Smuzhiyun case PHY_FUNC_HARD_RESET:
1140*4882a593Smuzhiyun hisi_hba->hw->phy_hard_reset(hisi_hba, phy_no);
1141*4882a593Smuzhiyun break;
1142*4882a593Smuzhiyun
1143*4882a593Smuzhiyun case PHY_FUNC_LINK_RESET:
1144*4882a593Smuzhiyun hisi_sas_phy_enable(hisi_hba, phy_no, 0);
1145*4882a593Smuzhiyun msleep(100);
1146*4882a593Smuzhiyun hisi_sas_phy_enable(hisi_hba, phy_no, 1);
1147*4882a593Smuzhiyun break;
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun case PHY_FUNC_DISABLE:
1150*4882a593Smuzhiyun hisi_sas_phy_enable(hisi_hba, phy_no, 0);
1151*4882a593Smuzhiyun break;
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun case PHY_FUNC_SET_LINK_RATE:
1154*4882a593Smuzhiyun return hisi_sas_phy_set_linkrate(hisi_hba, phy_no, funcdata);
1155*4882a593Smuzhiyun case PHY_FUNC_GET_EVENTS:
1156*4882a593Smuzhiyun if (hisi_hba->hw->get_events) {
1157*4882a593Smuzhiyun hisi_hba->hw->get_events(hisi_hba, phy_no);
1158*4882a593Smuzhiyun break;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun fallthrough;
1161*4882a593Smuzhiyun case PHY_FUNC_RELEASE_SPINUP_HOLD:
1162*4882a593Smuzhiyun default:
1163*4882a593Smuzhiyun return -EOPNOTSUPP;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun return 0;
1166*4882a593Smuzhiyun }
1167*4882a593Smuzhiyun
hisi_sas_task_done(struct sas_task * task)1168*4882a593Smuzhiyun static void hisi_sas_task_done(struct sas_task *task)
1169*4882a593Smuzhiyun {
1170*4882a593Smuzhiyun del_timer(&task->slow_task->timer);
1171*4882a593Smuzhiyun complete(&task->slow_task->completion);
1172*4882a593Smuzhiyun }
1173*4882a593Smuzhiyun
hisi_sas_tmf_timedout(struct timer_list * t)1174*4882a593Smuzhiyun static void hisi_sas_tmf_timedout(struct timer_list *t)
1175*4882a593Smuzhiyun {
1176*4882a593Smuzhiyun struct sas_task_slow *slow = from_timer(slow, t, timer);
1177*4882a593Smuzhiyun struct sas_task *task = slow->task;
1178*4882a593Smuzhiyun unsigned long flags;
1179*4882a593Smuzhiyun bool is_completed = true;
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun spin_lock_irqsave(&task->task_state_lock, flags);
1182*4882a593Smuzhiyun if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
1183*4882a593Smuzhiyun task->task_state_flags |= SAS_TASK_STATE_ABORTED;
1184*4882a593Smuzhiyun is_completed = false;
1185*4882a593Smuzhiyun }
1186*4882a593Smuzhiyun spin_unlock_irqrestore(&task->task_state_lock, flags);
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun if (!is_completed)
1189*4882a593Smuzhiyun complete(&task->slow_task->completion);
1190*4882a593Smuzhiyun }
1191*4882a593Smuzhiyun
1192*4882a593Smuzhiyun #define TASK_TIMEOUT 20
1193*4882a593Smuzhiyun #define TASK_RETRY 3
1194*4882a593Smuzhiyun #define INTERNAL_ABORT_TIMEOUT 6
hisi_sas_exec_internal_tmf_task(struct domain_device * device,void * parameter,u32 para_len,struct hisi_sas_tmf_task * tmf)1195*4882a593Smuzhiyun static int hisi_sas_exec_internal_tmf_task(struct domain_device *device,
1196*4882a593Smuzhiyun void *parameter, u32 para_len,
1197*4882a593Smuzhiyun struct hisi_sas_tmf_task *tmf)
1198*4882a593Smuzhiyun {
1199*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
1200*4882a593Smuzhiyun struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
1201*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1202*4882a593Smuzhiyun struct sas_task *task;
1203*4882a593Smuzhiyun int res, retry;
1204*4882a593Smuzhiyun
1205*4882a593Smuzhiyun for (retry = 0; retry < TASK_RETRY; retry++) {
1206*4882a593Smuzhiyun task = sas_alloc_slow_task(GFP_KERNEL);
1207*4882a593Smuzhiyun if (!task)
1208*4882a593Smuzhiyun return -ENOMEM;
1209*4882a593Smuzhiyun
1210*4882a593Smuzhiyun task->dev = device;
1211*4882a593Smuzhiyun task->task_proto = device->tproto;
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun if (dev_is_sata(device)) {
1214*4882a593Smuzhiyun task->ata_task.device_control_reg_update = 1;
1215*4882a593Smuzhiyun memcpy(&task->ata_task.fis, parameter, para_len);
1216*4882a593Smuzhiyun } else {
1217*4882a593Smuzhiyun memcpy(&task->ssp_task, parameter, para_len);
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun task->task_done = hisi_sas_task_done;
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun task->slow_task->timer.function = hisi_sas_tmf_timedout;
1222*4882a593Smuzhiyun task->slow_task->timer.expires = jiffies + TASK_TIMEOUT * HZ;
1223*4882a593Smuzhiyun add_timer(&task->slow_task->timer);
1224*4882a593Smuzhiyun
1225*4882a593Smuzhiyun res = hisi_sas_task_exec(task, GFP_KERNEL, 1, tmf);
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun if (res) {
1228*4882a593Smuzhiyun del_timer(&task->slow_task->timer);
1229*4882a593Smuzhiyun dev_err(dev, "abort tmf: executing internal task failed: %d\n",
1230*4882a593Smuzhiyun res);
1231*4882a593Smuzhiyun goto ex_err;
1232*4882a593Smuzhiyun }
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun wait_for_completion(&task->slow_task->completion);
1235*4882a593Smuzhiyun res = TMF_RESP_FUNC_FAILED;
1236*4882a593Smuzhiyun /* Even TMF timed out, return direct. */
1237*4882a593Smuzhiyun if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
1238*4882a593Smuzhiyun if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
1239*4882a593Smuzhiyun struct hisi_sas_slot *slot = task->lldd_task;
1240*4882a593Smuzhiyun
1241*4882a593Smuzhiyun dev_err(dev, "abort tmf: TMF task timeout and not done\n");
1242*4882a593Smuzhiyun if (slot) {
1243*4882a593Smuzhiyun struct hisi_sas_cq *cq =
1244*4882a593Smuzhiyun &hisi_hba->cq[slot->dlvry_queue];
1245*4882a593Smuzhiyun /*
1246*4882a593Smuzhiyun * sync irq to avoid free'ing task
1247*4882a593Smuzhiyun * before using task in IO completion
1248*4882a593Smuzhiyun */
1249*4882a593Smuzhiyun synchronize_irq(cq->irq_no);
1250*4882a593Smuzhiyun slot->task = NULL;
1251*4882a593Smuzhiyun }
1252*4882a593Smuzhiyun
1253*4882a593Smuzhiyun goto ex_err;
1254*4882a593Smuzhiyun } else
1255*4882a593Smuzhiyun dev_err(dev, "abort tmf: TMF task timeout\n");
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun
1258*4882a593Smuzhiyun if (task->task_status.resp == SAS_TASK_COMPLETE &&
1259*4882a593Smuzhiyun task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
1260*4882a593Smuzhiyun res = TMF_RESP_FUNC_COMPLETE;
1261*4882a593Smuzhiyun break;
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun if (task->task_status.resp == SAS_TASK_COMPLETE &&
1265*4882a593Smuzhiyun task->task_status.stat == TMF_RESP_FUNC_SUCC) {
1266*4882a593Smuzhiyun res = TMF_RESP_FUNC_SUCC;
1267*4882a593Smuzhiyun break;
1268*4882a593Smuzhiyun }
1269*4882a593Smuzhiyun
1270*4882a593Smuzhiyun if (task->task_status.resp == SAS_TASK_COMPLETE &&
1271*4882a593Smuzhiyun task->task_status.stat == SAS_DATA_UNDERRUN) {
1272*4882a593Smuzhiyun /* no error, but return the number of bytes of
1273*4882a593Smuzhiyun * underrun
1274*4882a593Smuzhiyun */
1275*4882a593Smuzhiyun dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x sts 0x%x underrun\n",
1276*4882a593Smuzhiyun SAS_ADDR(device->sas_addr),
1277*4882a593Smuzhiyun task->task_status.resp,
1278*4882a593Smuzhiyun task->task_status.stat);
1279*4882a593Smuzhiyun res = task->task_status.residual;
1280*4882a593Smuzhiyun break;
1281*4882a593Smuzhiyun }
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun if (task->task_status.resp == SAS_TASK_COMPLETE &&
1284*4882a593Smuzhiyun task->task_status.stat == SAS_DATA_OVERRUN) {
1285*4882a593Smuzhiyun dev_warn(dev, "abort tmf: blocked task error\n");
1286*4882a593Smuzhiyun res = -EMSGSIZE;
1287*4882a593Smuzhiyun break;
1288*4882a593Smuzhiyun }
1289*4882a593Smuzhiyun
1290*4882a593Smuzhiyun if (task->task_status.resp == SAS_TASK_COMPLETE &&
1291*4882a593Smuzhiyun task->task_status.stat == SAS_OPEN_REJECT) {
1292*4882a593Smuzhiyun dev_warn(dev, "abort tmf: open reject failed\n");
1293*4882a593Smuzhiyun res = -EIO;
1294*4882a593Smuzhiyun } else {
1295*4882a593Smuzhiyun dev_warn(dev, "abort tmf: task to dev %016llx resp: 0x%x status 0x%x\n",
1296*4882a593Smuzhiyun SAS_ADDR(device->sas_addr),
1297*4882a593Smuzhiyun task->task_status.resp,
1298*4882a593Smuzhiyun task->task_status.stat);
1299*4882a593Smuzhiyun }
1300*4882a593Smuzhiyun sas_free_task(task);
1301*4882a593Smuzhiyun task = NULL;
1302*4882a593Smuzhiyun }
1303*4882a593Smuzhiyun ex_err:
1304*4882a593Smuzhiyun if (retry == TASK_RETRY)
1305*4882a593Smuzhiyun dev_warn(dev, "abort tmf: executing internal task failed!\n");
1306*4882a593Smuzhiyun sas_free_task(task);
1307*4882a593Smuzhiyun return res;
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun
hisi_sas_fill_ata_reset_cmd(struct ata_device * dev,bool reset,int pmp,u8 * fis)1310*4882a593Smuzhiyun static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev,
1311*4882a593Smuzhiyun bool reset, int pmp, u8 *fis)
1312*4882a593Smuzhiyun {
1313*4882a593Smuzhiyun struct ata_taskfile tf;
1314*4882a593Smuzhiyun
1315*4882a593Smuzhiyun ata_tf_init(dev, &tf);
1316*4882a593Smuzhiyun if (reset)
1317*4882a593Smuzhiyun tf.ctl |= ATA_SRST;
1318*4882a593Smuzhiyun else
1319*4882a593Smuzhiyun tf.ctl &= ~ATA_SRST;
1320*4882a593Smuzhiyun tf.command = ATA_CMD_DEV_RESET;
1321*4882a593Smuzhiyun ata_tf_to_fis(&tf, pmp, 0, fis);
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun
hisi_sas_softreset_ata_disk(struct domain_device * device)1324*4882a593Smuzhiyun static int hisi_sas_softreset_ata_disk(struct domain_device *device)
1325*4882a593Smuzhiyun {
1326*4882a593Smuzhiyun u8 fis[20] = {0};
1327*4882a593Smuzhiyun struct ata_port *ap = device->sata_dev.ap;
1328*4882a593Smuzhiyun struct ata_link *link;
1329*4882a593Smuzhiyun int rc = TMF_RESP_FUNC_FAILED;
1330*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
1331*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1332*4882a593Smuzhiyun int s = sizeof(struct host_to_dev_fis);
1333*4882a593Smuzhiyun
1334*4882a593Smuzhiyun ata_for_each_link(link, ap, EDGE) {
1335*4882a593Smuzhiyun int pmp = sata_srst_pmp(link);
1336*4882a593Smuzhiyun
1337*4882a593Smuzhiyun hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
1338*4882a593Smuzhiyun rc = hisi_sas_exec_internal_tmf_task(device, fis, s, NULL);
1339*4882a593Smuzhiyun if (rc != TMF_RESP_FUNC_COMPLETE)
1340*4882a593Smuzhiyun break;
1341*4882a593Smuzhiyun }
1342*4882a593Smuzhiyun
1343*4882a593Smuzhiyun if (rc == TMF_RESP_FUNC_COMPLETE) {
1344*4882a593Smuzhiyun ata_for_each_link(link, ap, EDGE) {
1345*4882a593Smuzhiyun int pmp = sata_srst_pmp(link);
1346*4882a593Smuzhiyun
1347*4882a593Smuzhiyun hisi_sas_fill_ata_reset_cmd(link->device, 0, pmp, fis);
1348*4882a593Smuzhiyun rc = hisi_sas_exec_internal_tmf_task(device, fis,
1349*4882a593Smuzhiyun s, NULL);
1350*4882a593Smuzhiyun if (rc != TMF_RESP_FUNC_COMPLETE)
1351*4882a593Smuzhiyun dev_err(dev, "ata disk de-reset failed\n");
1352*4882a593Smuzhiyun }
1353*4882a593Smuzhiyun } else {
1354*4882a593Smuzhiyun dev_err(dev, "ata disk reset failed\n");
1355*4882a593Smuzhiyun }
1356*4882a593Smuzhiyun
1357*4882a593Smuzhiyun if (rc == TMF_RESP_FUNC_COMPLETE)
1358*4882a593Smuzhiyun hisi_sas_release_task(hisi_hba, device);
1359*4882a593Smuzhiyun
1360*4882a593Smuzhiyun return rc;
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun
hisi_sas_debug_issue_ssp_tmf(struct domain_device * device,u8 * lun,struct hisi_sas_tmf_task * tmf)1363*4882a593Smuzhiyun static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
1364*4882a593Smuzhiyun u8 *lun, struct hisi_sas_tmf_task *tmf)
1365*4882a593Smuzhiyun {
1366*4882a593Smuzhiyun struct sas_ssp_task ssp_task;
1367*4882a593Smuzhiyun
1368*4882a593Smuzhiyun if (!(device->tproto & SAS_PROTOCOL_SSP))
1369*4882a593Smuzhiyun return TMF_RESP_FUNC_ESUPP;
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun memcpy(ssp_task.LUN, lun, 8);
1372*4882a593Smuzhiyun
1373*4882a593Smuzhiyun return hisi_sas_exec_internal_tmf_task(device, &ssp_task,
1374*4882a593Smuzhiyun sizeof(ssp_task), tmf);
1375*4882a593Smuzhiyun }
1376*4882a593Smuzhiyun
hisi_sas_refresh_port_id(struct hisi_hba * hisi_hba)1377*4882a593Smuzhiyun static void hisi_sas_refresh_port_id(struct hisi_hba *hisi_hba)
1378*4882a593Smuzhiyun {
1379*4882a593Smuzhiyun u32 state = hisi_hba->hw->get_phys_state(hisi_hba);
1380*4882a593Smuzhiyun int i;
1381*4882a593Smuzhiyun
1382*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
1383*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = &hisi_hba->devices[i];
1384*4882a593Smuzhiyun struct domain_device *device = sas_dev->sas_device;
1385*4882a593Smuzhiyun struct asd_sas_port *sas_port;
1386*4882a593Smuzhiyun struct hisi_sas_port *port;
1387*4882a593Smuzhiyun struct hisi_sas_phy *phy = NULL;
1388*4882a593Smuzhiyun struct asd_sas_phy *sas_phy;
1389*4882a593Smuzhiyun
1390*4882a593Smuzhiyun if ((sas_dev->dev_type == SAS_PHY_UNUSED)
1391*4882a593Smuzhiyun || !device || !device->port)
1392*4882a593Smuzhiyun continue;
1393*4882a593Smuzhiyun
1394*4882a593Smuzhiyun sas_port = device->port;
1395*4882a593Smuzhiyun port = to_hisi_sas_port(sas_port);
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el)
1398*4882a593Smuzhiyun if (state & BIT(sas_phy->id)) {
1399*4882a593Smuzhiyun phy = sas_phy->lldd_phy;
1400*4882a593Smuzhiyun break;
1401*4882a593Smuzhiyun }
1402*4882a593Smuzhiyun
1403*4882a593Smuzhiyun if (phy) {
1404*4882a593Smuzhiyun port->id = phy->port_id;
1405*4882a593Smuzhiyun
1406*4882a593Smuzhiyun /* Update linkrate of directly attached device. */
1407*4882a593Smuzhiyun if (!device->parent)
1408*4882a593Smuzhiyun device->linkrate = phy->sas_phy.linkrate;
1409*4882a593Smuzhiyun
1410*4882a593Smuzhiyun hisi_hba->hw->setup_itct(hisi_hba, sas_dev);
1411*4882a593Smuzhiyun } else
1412*4882a593Smuzhiyun port->id = 0xff;
1413*4882a593Smuzhiyun }
1414*4882a593Smuzhiyun }
1415*4882a593Smuzhiyun
hisi_sas_rescan_topology(struct hisi_hba * hisi_hba,u32 state)1416*4882a593Smuzhiyun static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state)
1417*4882a593Smuzhiyun {
1418*4882a593Smuzhiyun struct asd_sas_port *_sas_port = NULL;
1419*4882a593Smuzhiyun int phy_no;
1420*4882a593Smuzhiyun
1421*4882a593Smuzhiyun for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
1422*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
1423*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
1424*4882a593Smuzhiyun struct asd_sas_port *sas_port = sas_phy->port;
1425*4882a593Smuzhiyun bool do_port_check = _sas_port != sas_port;
1426*4882a593Smuzhiyun
1427*4882a593Smuzhiyun if (!sas_phy->phy->enabled)
1428*4882a593Smuzhiyun continue;
1429*4882a593Smuzhiyun
1430*4882a593Smuzhiyun /* Report PHY state change to libsas */
1431*4882a593Smuzhiyun if (state & BIT(phy_no)) {
1432*4882a593Smuzhiyun if (do_port_check && sas_port && sas_port->port_dev) {
1433*4882a593Smuzhiyun struct domain_device *dev = sas_port->port_dev;
1434*4882a593Smuzhiyun
1435*4882a593Smuzhiyun _sas_port = sas_port;
1436*4882a593Smuzhiyun
1437*4882a593Smuzhiyun if (dev_is_expander(dev->dev_type))
1438*4882a593Smuzhiyun sas_notify_port_event(sas_phy,
1439*4882a593Smuzhiyun PORTE_BROADCAST_RCVD);
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun } else {
1442*4882a593Smuzhiyun hisi_sas_phy_down(hisi_hba, phy_no, 0);
1443*4882a593Smuzhiyun }
1444*4882a593Smuzhiyun }
1445*4882a593Smuzhiyun }
1446*4882a593Smuzhiyun
hisi_sas_reset_init_all_devices(struct hisi_hba * hisi_hba)1447*4882a593Smuzhiyun static void hisi_sas_reset_init_all_devices(struct hisi_hba *hisi_hba)
1448*4882a593Smuzhiyun {
1449*4882a593Smuzhiyun struct hisi_sas_device *sas_dev;
1450*4882a593Smuzhiyun struct domain_device *device;
1451*4882a593Smuzhiyun int i;
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
1454*4882a593Smuzhiyun sas_dev = &hisi_hba->devices[i];
1455*4882a593Smuzhiyun device = sas_dev->sas_device;
1456*4882a593Smuzhiyun
1457*4882a593Smuzhiyun if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device)
1458*4882a593Smuzhiyun continue;
1459*4882a593Smuzhiyun
1460*4882a593Smuzhiyun hisi_sas_init_device(device);
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun }
1463*4882a593Smuzhiyun
hisi_sas_send_ata_reset_each_phy(struct hisi_hba * hisi_hba,struct asd_sas_port * sas_port,struct domain_device * device)1464*4882a593Smuzhiyun static void hisi_sas_send_ata_reset_each_phy(struct hisi_hba *hisi_hba,
1465*4882a593Smuzhiyun struct asd_sas_port *sas_port,
1466*4882a593Smuzhiyun struct domain_device *device)
1467*4882a593Smuzhiyun {
1468*4882a593Smuzhiyun struct hisi_sas_tmf_task tmf_task = { .force_phy = 1 };
1469*4882a593Smuzhiyun struct ata_port *ap = device->sata_dev.ap;
1470*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1471*4882a593Smuzhiyun int s = sizeof(struct host_to_dev_fis);
1472*4882a593Smuzhiyun int rc = TMF_RESP_FUNC_FAILED;
1473*4882a593Smuzhiyun struct asd_sas_phy *sas_phy;
1474*4882a593Smuzhiyun struct ata_link *link;
1475*4882a593Smuzhiyun u8 fis[20] = {0};
1476*4882a593Smuzhiyun u32 state;
1477*4882a593Smuzhiyun
1478*4882a593Smuzhiyun state = hisi_hba->hw->get_phys_state(hisi_hba);
1479*4882a593Smuzhiyun list_for_each_entry(sas_phy, &sas_port->phy_list, port_phy_el) {
1480*4882a593Smuzhiyun if (!(state & BIT(sas_phy->id)))
1481*4882a593Smuzhiyun continue;
1482*4882a593Smuzhiyun
1483*4882a593Smuzhiyun ata_for_each_link(link, ap, EDGE) {
1484*4882a593Smuzhiyun int pmp = sata_srst_pmp(link);
1485*4882a593Smuzhiyun
1486*4882a593Smuzhiyun tmf_task.phy_id = sas_phy->id;
1487*4882a593Smuzhiyun hisi_sas_fill_ata_reset_cmd(link->device, 1, pmp, fis);
1488*4882a593Smuzhiyun rc = hisi_sas_exec_internal_tmf_task(device, fis, s,
1489*4882a593Smuzhiyun &tmf_task);
1490*4882a593Smuzhiyun if (rc != TMF_RESP_FUNC_COMPLETE) {
1491*4882a593Smuzhiyun dev_err(dev, "phy%d ata reset failed rc=%d\n",
1492*4882a593Smuzhiyun sas_phy->id, rc);
1493*4882a593Smuzhiyun break;
1494*4882a593Smuzhiyun }
1495*4882a593Smuzhiyun }
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun }
1498*4882a593Smuzhiyun
hisi_sas_terminate_stp_reject(struct hisi_hba * hisi_hba)1499*4882a593Smuzhiyun static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1502*4882a593Smuzhiyun int port_no, rc, i;
1503*4882a593Smuzhiyun
1504*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
1505*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = &hisi_hba->devices[i];
1506*4882a593Smuzhiyun struct domain_device *device = sas_dev->sas_device;
1507*4882a593Smuzhiyun
1508*4882a593Smuzhiyun if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device)
1509*4882a593Smuzhiyun continue;
1510*4882a593Smuzhiyun
1511*4882a593Smuzhiyun rc = hisi_sas_internal_task_abort(hisi_hba, device,
1512*4882a593Smuzhiyun HISI_SAS_INT_ABT_DEV, 0);
1513*4882a593Smuzhiyun if (rc < 0)
1514*4882a593Smuzhiyun dev_err(dev, "STP reject: abort dev failed %d\n", rc);
1515*4882a593Smuzhiyun }
1516*4882a593Smuzhiyun
1517*4882a593Smuzhiyun for (port_no = 0; port_no < hisi_hba->n_phy; port_no++) {
1518*4882a593Smuzhiyun struct hisi_sas_port *port = &hisi_hba->port[port_no];
1519*4882a593Smuzhiyun struct asd_sas_port *sas_port = &port->sas_port;
1520*4882a593Smuzhiyun struct domain_device *port_dev = sas_port->port_dev;
1521*4882a593Smuzhiyun struct domain_device *device;
1522*4882a593Smuzhiyun
1523*4882a593Smuzhiyun if (!port_dev || !dev_is_expander(port_dev->dev_type))
1524*4882a593Smuzhiyun continue;
1525*4882a593Smuzhiyun
1526*4882a593Smuzhiyun /* Try to find a SATA device */
1527*4882a593Smuzhiyun list_for_each_entry(device, &sas_port->dev_list,
1528*4882a593Smuzhiyun dev_list_node) {
1529*4882a593Smuzhiyun if (dev_is_sata(device)) {
1530*4882a593Smuzhiyun hisi_sas_send_ata_reset_each_phy(hisi_hba,
1531*4882a593Smuzhiyun sas_port,
1532*4882a593Smuzhiyun device);
1533*4882a593Smuzhiyun break;
1534*4882a593Smuzhiyun }
1535*4882a593Smuzhiyun }
1536*4882a593Smuzhiyun }
1537*4882a593Smuzhiyun }
1538*4882a593Smuzhiyun
hisi_sas_controller_reset_prepare(struct hisi_hba * hisi_hba)1539*4882a593Smuzhiyun void hisi_sas_controller_reset_prepare(struct hisi_hba *hisi_hba)
1540*4882a593Smuzhiyun {
1541*4882a593Smuzhiyun struct Scsi_Host *shost = hisi_hba->shost;
1542*4882a593Smuzhiyun
1543*4882a593Smuzhiyun down(&hisi_hba->sem);
1544*4882a593Smuzhiyun hisi_hba->phy_state = hisi_hba->hw->get_phys_state(hisi_hba);
1545*4882a593Smuzhiyun
1546*4882a593Smuzhiyun scsi_block_requests(shost);
1547*4882a593Smuzhiyun hisi_hba->hw->wait_cmds_complete_timeout(hisi_hba, 100, 5000);
1548*4882a593Smuzhiyun
1549*4882a593Smuzhiyun if (timer_pending(&hisi_hba->timer))
1550*4882a593Smuzhiyun del_timer_sync(&hisi_hba->timer);
1551*4882a593Smuzhiyun
1552*4882a593Smuzhiyun set_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
1553*4882a593Smuzhiyun }
1554*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_controller_reset_prepare);
1555*4882a593Smuzhiyun
hisi_sas_controller_reset_done(struct hisi_hba * hisi_hba)1556*4882a593Smuzhiyun void hisi_sas_controller_reset_done(struct hisi_hba *hisi_hba)
1557*4882a593Smuzhiyun {
1558*4882a593Smuzhiyun struct Scsi_Host *shost = hisi_hba->shost;
1559*4882a593Smuzhiyun
1560*4882a593Smuzhiyun /* Init and wait for PHYs to come up and all libsas event finished. */
1561*4882a593Smuzhiyun hisi_hba->hw->phys_init(hisi_hba);
1562*4882a593Smuzhiyun msleep(1000);
1563*4882a593Smuzhiyun hisi_sas_refresh_port_id(hisi_hba);
1564*4882a593Smuzhiyun clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
1565*4882a593Smuzhiyun
1566*4882a593Smuzhiyun if (hisi_hba->reject_stp_links_msk)
1567*4882a593Smuzhiyun hisi_sas_terminate_stp_reject(hisi_hba);
1568*4882a593Smuzhiyun hisi_sas_reset_init_all_devices(hisi_hba);
1569*4882a593Smuzhiyun up(&hisi_hba->sem);
1570*4882a593Smuzhiyun scsi_unblock_requests(shost);
1571*4882a593Smuzhiyun clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
1572*4882a593Smuzhiyun
1573*4882a593Smuzhiyun hisi_sas_rescan_topology(hisi_hba, hisi_hba->phy_state);
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_controller_reset_done);
1576*4882a593Smuzhiyun
hisi_sas_controller_reset(struct hisi_hba * hisi_hba)1577*4882a593Smuzhiyun static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1580*4882a593Smuzhiyun struct Scsi_Host *shost = hisi_hba->shost;
1581*4882a593Smuzhiyun int rc;
1582*4882a593Smuzhiyun
1583*4882a593Smuzhiyun if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
1584*4882a593Smuzhiyun queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
1585*4882a593Smuzhiyun
1586*4882a593Smuzhiyun if (!hisi_hba->hw->soft_reset)
1587*4882a593Smuzhiyun return -1;
1588*4882a593Smuzhiyun
1589*4882a593Smuzhiyun if (test_and_set_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags))
1590*4882a593Smuzhiyun return -1;
1591*4882a593Smuzhiyun
1592*4882a593Smuzhiyun dev_info(dev, "controller resetting...\n");
1593*4882a593Smuzhiyun hisi_sas_controller_reset_prepare(hisi_hba);
1594*4882a593Smuzhiyun
1595*4882a593Smuzhiyun rc = hisi_hba->hw->soft_reset(hisi_hba);
1596*4882a593Smuzhiyun if (rc) {
1597*4882a593Smuzhiyun dev_warn(dev, "controller reset failed (%d)\n", rc);
1598*4882a593Smuzhiyun clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags);
1599*4882a593Smuzhiyun up(&hisi_hba->sem);
1600*4882a593Smuzhiyun scsi_unblock_requests(shost);
1601*4882a593Smuzhiyun clear_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags);
1602*4882a593Smuzhiyun return rc;
1603*4882a593Smuzhiyun }
1604*4882a593Smuzhiyun
1605*4882a593Smuzhiyun hisi_sas_controller_reset_done(hisi_hba);
1606*4882a593Smuzhiyun dev_info(dev, "controller reset complete\n");
1607*4882a593Smuzhiyun
1608*4882a593Smuzhiyun return 0;
1609*4882a593Smuzhiyun }
1610*4882a593Smuzhiyun
hisi_sas_abort_task(struct sas_task * task)1611*4882a593Smuzhiyun static int hisi_sas_abort_task(struct sas_task *task)
1612*4882a593Smuzhiyun {
1613*4882a593Smuzhiyun struct scsi_lun lun;
1614*4882a593Smuzhiyun struct hisi_sas_tmf_task tmf_task;
1615*4882a593Smuzhiyun struct domain_device *device = task->dev;
1616*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
1617*4882a593Smuzhiyun struct hisi_hba *hisi_hba;
1618*4882a593Smuzhiyun struct device *dev;
1619*4882a593Smuzhiyun int rc = TMF_RESP_FUNC_FAILED;
1620*4882a593Smuzhiyun unsigned long flags;
1621*4882a593Smuzhiyun
1622*4882a593Smuzhiyun if (!sas_dev)
1623*4882a593Smuzhiyun return TMF_RESP_FUNC_FAILED;
1624*4882a593Smuzhiyun
1625*4882a593Smuzhiyun hisi_hba = dev_to_hisi_hba(task->dev);
1626*4882a593Smuzhiyun dev = hisi_hba->dev;
1627*4882a593Smuzhiyun
1628*4882a593Smuzhiyun spin_lock_irqsave(&task->task_state_lock, flags);
1629*4882a593Smuzhiyun if (task->task_state_flags & SAS_TASK_STATE_DONE) {
1630*4882a593Smuzhiyun struct hisi_sas_slot *slot = task->lldd_task;
1631*4882a593Smuzhiyun struct hisi_sas_cq *cq;
1632*4882a593Smuzhiyun
1633*4882a593Smuzhiyun if (slot) {
1634*4882a593Smuzhiyun /*
1635*4882a593Smuzhiyun * sync irq to avoid free'ing task
1636*4882a593Smuzhiyun * before using task in IO completion
1637*4882a593Smuzhiyun */
1638*4882a593Smuzhiyun cq = &hisi_hba->cq[slot->dlvry_queue];
1639*4882a593Smuzhiyun synchronize_irq(cq->irq_no);
1640*4882a593Smuzhiyun }
1641*4882a593Smuzhiyun spin_unlock_irqrestore(&task->task_state_lock, flags);
1642*4882a593Smuzhiyun rc = TMF_RESP_FUNC_COMPLETE;
1643*4882a593Smuzhiyun goto out;
1644*4882a593Smuzhiyun }
1645*4882a593Smuzhiyun task->task_state_flags |= SAS_TASK_STATE_ABORTED;
1646*4882a593Smuzhiyun spin_unlock_irqrestore(&task->task_state_lock, flags);
1647*4882a593Smuzhiyun
1648*4882a593Smuzhiyun if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
1649*4882a593Smuzhiyun struct scsi_cmnd *cmnd = task->uldd_task;
1650*4882a593Smuzhiyun struct hisi_sas_slot *slot = task->lldd_task;
1651*4882a593Smuzhiyun u16 tag = slot->idx;
1652*4882a593Smuzhiyun int rc2;
1653*4882a593Smuzhiyun
1654*4882a593Smuzhiyun int_to_scsilun(cmnd->device->lun, &lun);
1655*4882a593Smuzhiyun tmf_task.tmf = TMF_ABORT_TASK;
1656*4882a593Smuzhiyun tmf_task.tag_of_task_to_be_managed = tag;
1657*4882a593Smuzhiyun
1658*4882a593Smuzhiyun rc = hisi_sas_debug_issue_ssp_tmf(task->dev, lun.scsi_lun,
1659*4882a593Smuzhiyun &tmf_task);
1660*4882a593Smuzhiyun
1661*4882a593Smuzhiyun rc2 = hisi_sas_internal_task_abort(hisi_hba, device,
1662*4882a593Smuzhiyun HISI_SAS_INT_ABT_CMD, tag);
1663*4882a593Smuzhiyun if (rc2 < 0) {
1664*4882a593Smuzhiyun dev_err(dev, "abort task: internal abort (%d)\n", rc2);
1665*4882a593Smuzhiyun return TMF_RESP_FUNC_FAILED;
1666*4882a593Smuzhiyun }
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun /*
1669*4882a593Smuzhiyun * If the TMF finds that the IO is not in the device and also
1670*4882a593Smuzhiyun * the internal abort does not succeed, then it is safe to
1671*4882a593Smuzhiyun * free the slot.
1672*4882a593Smuzhiyun * Note: if the internal abort succeeds then the slot
1673*4882a593Smuzhiyun * will have already been completed
1674*4882a593Smuzhiyun */
1675*4882a593Smuzhiyun if (rc == TMF_RESP_FUNC_COMPLETE && rc2 != TMF_RESP_FUNC_SUCC) {
1676*4882a593Smuzhiyun if (task->lldd_task)
1677*4882a593Smuzhiyun hisi_sas_do_release_task(hisi_hba, task, slot);
1678*4882a593Smuzhiyun }
1679*4882a593Smuzhiyun } else if (task->task_proto & SAS_PROTOCOL_SATA ||
1680*4882a593Smuzhiyun task->task_proto & SAS_PROTOCOL_STP) {
1681*4882a593Smuzhiyun if (task->dev->dev_type == SAS_SATA_DEV) {
1682*4882a593Smuzhiyun rc = hisi_sas_internal_task_abort(hisi_hba, device,
1683*4882a593Smuzhiyun HISI_SAS_INT_ABT_DEV,
1684*4882a593Smuzhiyun 0);
1685*4882a593Smuzhiyun if (rc < 0) {
1686*4882a593Smuzhiyun dev_err(dev, "abort task: internal abort failed\n");
1687*4882a593Smuzhiyun goto out;
1688*4882a593Smuzhiyun }
1689*4882a593Smuzhiyun hisi_sas_dereg_device(hisi_hba, device);
1690*4882a593Smuzhiyun rc = hisi_sas_softreset_ata_disk(device);
1691*4882a593Smuzhiyun }
1692*4882a593Smuzhiyun } else if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SMP) {
1693*4882a593Smuzhiyun /* SMP */
1694*4882a593Smuzhiyun struct hisi_sas_slot *slot = task->lldd_task;
1695*4882a593Smuzhiyun u32 tag = slot->idx;
1696*4882a593Smuzhiyun struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];
1697*4882a593Smuzhiyun
1698*4882a593Smuzhiyun rc = hisi_sas_internal_task_abort(hisi_hba, device,
1699*4882a593Smuzhiyun HISI_SAS_INT_ABT_CMD, tag);
1700*4882a593Smuzhiyun if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
1701*4882a593Smuzhiyun task->lldd_task) {
1702*4882a593Smuzhiyun /*
1703*4882a593Smuzhiyun * sync irq to avoid free'ing task
1704*4882a593Smuzhiyun * before using task in IO completion
1705*4882a593Smuzhiyun */
1706*4882a593Smuzhiyun synchronize_irq(cq->irq_no);
1707*4882a593Smuzhiyun slot->task = NULL;
1708*4882a593Smuzhiyun }
1709*4882a593Smuzhiyun }
1710*4882a593Smuzhiyun
1711*4882a593Smuzhiyun out:
1712*4882a593Smuzhiyun if (rc != TMF_RESP_FUNC_COMPLETE)
1713*4882a593Smuzhiyun dev_notice(dev, "abort task: rc=%d\n", rc);
1714*4882a593Smuzhiyun return rc;
1715*4882a593Smuzhiyun }
1716*4882a593Smuzhiyun
hisi_sas_abort_task_set(struct domain_device * device,u8 * lun)1717*4882a593Smuzhiyun static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
1718*4882a593Smuzhiyun {
1719*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
1720*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1721*4882a593Smuzhiyun struct hisi_sas_tmf_task tmf_task;
1722*4882a593Smuzhiyun int rc;
1723*4882a593Smuzhiyun
1724*4882a593Smuzhiyun rc = hisi_sas_internal_task_abort(hisi_hba, device,
1725*4882a593Smuzhiyun HISI_SAS_INT_ABT_DEV, 0);
1726*4882a593Smuzhiyun if (rc < 0) {
1727*4882a593Smuzhiyun dev_err(dev, "abort task set: internal abort rc=%d\n", rc);
1728*4882a593Smuzhiyun return TMF_RESP_FUNC_FAILED;
1729*4882a593Smuzhiyun }
1730*4882a593Smuzhiyun hisi_sas_dereg_device(hisi_hba, device);
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun tmf_task.tmf = TMF_ABORT_TASK_SET;
1733*4882a593Smuzhiyun rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
1734*4882a593Smuzhiyun
1735*4882a593Smuzhiyun if (rc == TMF_RESP_FUNC_COMPLETE)
1736*4882a593Smuzhiyun hisi_sas_release_task(hisi_hba, device);
1737*4882a593Smuzhiyun
1738*4882a593Smuzhiyun return rc;
1739*4882a593Smuzhiyun }
1740*4882a593Smuzhiyun
hisi_sas_clear_aca(struct domain_device * device,u8 * lun)1741*4882a593Smuzhiyun static int hisi_sas_clear_aca(struct domain_device *device, u8 *lun)
1742*4882a593Smuzhiyun {
1743*4882a593Smuzhiyun struct hisi_sas_tmf_task tmf_task;
1744*4882a593Smuzhiyun int rc;
1745*4882a593Smuzhiyun
1746*4882a593Smuzhiyun tmf_task.tmf = TMF_CLEAR_ACA;
1747*4882a593Smuzhiyun rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
1748*4882a593Smuzhiyun
1749*4882a593Smuzhiyun return rc;
1750*4882a593Smuzhiyun }
1751*4882a593Smuzhiyun
hisi_sas_debug_I_T_nexus_reset(struct domain_device * device)1752*4882a593Smuzhiyun static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)
1753*4882a593Smuzhiyun {
1754*4882a593Smuzhiyun struct sas_phy *local_phy = sas_get_local_phy(device);
1755*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
1756*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
1757*4882a593Smuzhiyun struct sas_ha_struct *sas_ha = &hisi_hba->sha;
1758*4882a593Smuzhiyun DECLARE_COMPLETION_ONSTACK(phyreset);
1759*4882a593Smuzhiyun int rc, reset_type;
1760*4882a593Smuzhiyun
1761*4882a593Smuzhiyun if (!local_phy->enabled) {
1762*4882a593Smuzhiyun sas_put_local_phy(local_phy);
1763*4882a593Smuzhiyun return -ENODEV;
1764*4882a593Smuzhiyun }
1765*4882a593Smuzhiyun
1766*4882a593Smuzhiyun if (scsi_is_sas_phy_local(local_phy)) {
1767*4882a593Smuzhiyun struct asd_sas_phy *sas_phy =
1768*4882a593Smuzhiyun sas_ha->sas_phy[local_phy->number];
1769*4882a593Smuzhiyun struct hisi_sas_phy *phy =
1770*4882a593Smuzhiyun container_of(sas_phy, struct hisi_sas_phy, sas_phy);
1771*4882a593Smuzhiyun phy->in_reset = 1;
1772*4882a593Smuzhiyun phy->reset_completion = &phyreset;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun
1775*4882a593Smuzhiyun reset_type = (sas_dev->dev_status == HISI_SAS_DEV_INIT ||
1776*4882a593Smuzhiyun !dev_is_sata(device)) ? true : false;
1777*4882a593Smuzhiyun
1778*4882a593Smuzhiyun rc = sas_phy_reset(local_phy, reset_type);
1779*4882a593Smuzhiyun sas_put_local_phy(local_phy);
1780*4882a593Smuzhiyun
1781*4882a593Smuzhiyun if (scsi_is_sas_phy_local(local_phy)) {
1782*4882a593Smuzhiyun struct asd_sas_phy *sas_phy =
1783*4882a593Smuzhiyun sas_ha->sas_phy[local_phy->number];
1784*4882a593Smuzhiyun struct hisi_sas_phy *phy =
1785*4882a593Smuzhiyun container_of(sas_phy, struct hisi_sas_phy, sas_phy);
1786*4882a593Smuzhiyun int ret = wait_for_completion_timeout(&phyreset, 2 * HZ);
1787*4882a593Smuzhiyun unsigned long flags;
1788*4882a593Smuzhiyun
1789*4882a593Smuzhiyun spin_lock_irqsave(&phy->lock, flags);
1790*4882a593Smuzhiyun phy->reset_completion = NULL;
1791*4882a593Smuzhiyun phy->in_reset = 0;
1792*4882a593Smuzhiyun spin_unlock_irqrestore(&phy->lock, flags);
1793*4882a593Smuzhiyun
1794*4882a593Smuzhiyun /* report PHY down if timed out */
1795*4882a593Smuzhiyun if (!ret)
1796*4882a593Smuzhiyun hisi_sas_phy_down(hisi_hba, sas_phy->id, 0);
1797*4882a593Smuzhiyun } else if (sas_dev->dev_status != HISI_SAS_DEV_INIT) {
1798*4882a593Smuzhiyun /*
1799*4882a593Smuzhiyun * If in init state, we rely on caller to wait for link to be
1800*4882a593Smuzhiyun * ready; otherwise, except phy reset is fail, delay.
1801*4882a593Smuzhiyun */
1802*4882a593Smuzhiyun if (!rc)
1803*4882a593Smuzhiyun msleep(2000);
1804*4882a593Smuzhiyun }
1805*4882a593Smuzhiyun
1806*4882a593Smuzhiyun return rc;
1807*4882a593Smuzhiyun }
1808*4882a593Smuzhiyun
hisi_sas_I_T_nexus_reset(struct domain_device * device)1809*4882a593Smuzhiyun static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
1810*4882a593Smuzhiyun {
1811*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
1812*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1813*4882a593Smuzhiyun int rc;
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun rc = hisi_sas_internal_task_abort(hisi_hba, device,
1816*4882a593Smuzhiyun HISI_SAS_INT_ABT_DEV, 0);
1817*4882a593Smuzhiyun if (rc < 0) {
1818*4882a593Smuzhiyun dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc);
1819*4882a593Smuzhiyun return TMF_RESP_FUNC_FAILED;
1820*4882a593Smuzhiyun }
1821*4882a593Smuzhiyun hisi_sas_dereg_device(hisi_hba, device);
1822*4882a593Smuzhiyun
1823*4882a593Smuzhiyun if (dev_is_sata(device)) {
1824*4882a593Smuzhiyun rc = hisi_sas_softreset_ata_disk(device);
1825*4882a593Smuzhiyun if (rc == TMF_RESP_FUNC_FAILED)
1826*4882a593Smuzhiyun return TMF_RESP_FUNC_FAILED;
1827*4882a593Smuzhiyun }
1828*4882a593Smuzhiyun
1829*4882a593Smuzhiyun rc = hisi_sas_debug_I_T_nexus_reset(device);
1830*4882a593Smuzhiyun
1831*4882a593Smuzhiyun if ((rc == TMF_RESP_FUNC_COMPLETE) || (rc == -ENODEV))
1832*4882a593Smuzhiyun hisi_sas_release_task(hisi_hba, device);
1833*4882a593Smuzhiyun
1834*4882a593Smuzhiyun return rc;
1835*4882a593Smuzhiyun }
1836*4882a593Smuzhiyun
hisi_sas_lu_reset(struct domain_device * device,u8 * lun)1837*4882a593Smuzhiyun static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
1838*4882a593Smuzhiyun {
1839*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
1840*4882a593Smuzhiyun struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
1841*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1842*4882a593Smuzhiyun int rc = TMF_RESP_FUNC_FAILED;
1843*4882a593Smuzhiyun
1844*4882a593Smuzhiyun /* Clear internal IO and then lu reset */
1845*4882a593Smuzhiyun rc = hisi_sas_internal_task_abort(hisi_hba, device,
1846*4882a593Smuzhiyun HISI_SAS_INT_ABT_DEV, 0);
1847*4882a593Smuzhiyun if (rc < 0) {
1848*4882a593Smuzhiyun dev_err(dev, "lu_reset: internal abort failed\n");
1849*4882a593Smuzhiyun goto out;
1850*4882a593Smuzhiyun }
1851*4882a593Smuzhiyun hisi_sas_dereg_device(hisi_hba, device);
1852*4882a593Smuzhiyun
1853*4882a593Smuzhiyun if (dev_is_sata(device)) {
1854*4882a593Smuzhiyun struct sas_phy *phy;
1855*4882a593Smuzhiyun
1856*4882a593Smuzhiyun phy = sas_get_local_phy(device);
1857*4882a593Smuzhiyun
1858*4882a593Smuzhiyun rc = sas_phy_reset(phy, true);
1859*4882a593Smuzhiyun
1860*4882a593Smuzhiyun if (rc == 0)
1861*4882a593Smuzhiyun hisi_sas_release_task(hisi_hba, device);
1862*4882a593Smuzhiyun sas_put_local_phy(phy);
1863*4882a593Smuzhiyun } else {
1864*4882a593Smuzhiyun struct hisi_sas_tmf_task tmf_task = { .tmf = TMF_LU_RESET };
1865*4882a593Smuzhiyun
1866*4882a593Smuzhiyun rc = hisi_sas_debug_issue_ssp_tmf(device, lun, &tmf_task);
1867*4882a593Smuzhiyun if (rc == TMF_RESP_FUNC_COMPLETE)
1868*4882a593Smuzhiyun hisi_sas_release_task(hisi_hba, device);
1869*4882a593Smuzhiyun }
1870*4882a593Smuzhiyun out:
1871*4882a593Smuzhiyun if (rc != TMF_RESP_FUNC_COMPLETE)
1872*4882a593Smuzhiyun dev_err(dev, "lu_reset: for device[%d]:rc= %d\n",
1873*4882a593Smuzhiyun sas_dev->device_id, rc);
1874*4882a593Smuzhiyun return rc;
1875*4882a593Smuzhiyun }
1876*4882a593Smuzhiyun
hisi_sas_clear_nexus_ha(struct sas_ha_struct * sas_ha)1877*4882a593Smuzhiyun static int hisi_sas_clear_nexus_ha(struct sas_ha_struct *sas_ha)
1878*4882a593Smuzhiyun {
1879*4882a593Smuzhiyun struct hisi_hba *hisi_hba = sas_ha->lldd_ha;
1880*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1881*4882a593Smuzhiyun HISI_SAS_DECLARE_RST_WORK_ON_STACK(r);
1882*4882a593Smuzhiyun int rc, i;
1883*4882a593Smuzhiyun
1884*4882a593Smuzhiyun queue_work(hisi_hba->wq, &r.work);
1885*4882a593Smuzhiyun wait_for_completion(r.completion);
1886*4882a593Smuzhiyun if (!r.done)
1887*4882a593Smuzhiyun return TMF_RESP_FUNC_FAILED;
1888*4882a593Smuzhiyun
1889*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
1890*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = &hisi_hba->devices[i];
1891*4882a593Smuzhiyun struct domain_device *device = sas_dev->sas_device;
1892*4882a593Smuzhiyun
1893*4882a593Smuzhiyun if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device ||
1894*4882a593Smuzhiyun dev_is_expander(device->dev_type))
1895*4882a593Smuzhiyun continue;
1896*4882a593Smuzhiyun
1897*4882a593Smuzhiyun rc = hisi_sas_debug_I_T_nexus_reset(device);
1898*4882a593Smuzhiyun if (rc != TMF_RESP_FUNC_COMPLETE)
1899*4882a593Smuzhiyun dev_info(dev, "clear nexus ha: for device[%d] rc=%d\n",
1900*4882a593Smuzhiyun sas_dev->device_id, rc);
1901*4882a593Smuzhiyun }
1902*4882a593Smuzhiyun
1903*4882a593Smuzhiyun hisi_sas_release_tasks(hisi_hba);
1904*4882a593Smuzhiyun
1905*4882a593Smuzhiyun return TMF_RESP_FUNC_COMPLETE;
1906*4882a593Smuzhiyun }
1907*4882a593Smuzhiyun
hisi_sas_query_task(struct sas_task * task)1908*4882a593Smuzhiyun static int hisi_sas_query_task(struct sas_task *task)
1909*4882a593Smuzhiyun {
1910*4882a593Smuzhiyun struct scsi_lun lun;
1911*4882a593Smuzhiyun struct hisi_sas_tmf_task tmf_task;
1912*4882a593Smuzhiyun int rc = TMF_RESP_FUNC_FAILED;
1913*4882a593Smuzhiyun
1914*4882a593Smuzhiyun if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) {
1915*4882a593Smuzhiyun struct scsi_cmnd *cmnd = task->uldd_task;
1916*4882a593Smuzhiyun struct domain_device *device = task->dev;
1917*4882a593Smuzhiyun struct hisi_sas_slot *slot = task->lldd_task;
1918*4882a593Smuzhiyun u32 tag = slot->idx;
1919*4882a593Smuzhiyun
1920*4882a593Smuzhiyun int_to_scsilun(cmnd->device->lun, &lun);
1921*4882a593Smuzhiyun tmf_task.tmf = TMF_QUERY_TASK;
1922*4882a593Smuzhiyun tmf_task.tag_of_task_to_be_managed = tag;
1923*4882a593Smuzhiyun
1924*4882a593Smuzhiyun rc = hisi_sas_debug_issue_ssp_tmf(device,
1925*4882a593Smuzhiyun lun.scsi_lun,
1926*4882a593Smuzhiyun &tmf_task);
1927*4882a593Smuzhiyun switch (rc) {
1928*4882a593Smuzhiyun /* The task is still in Lun, release it then */
1929*4882a593Smuzhiyun case TMF_RESP_FUNC_SUCC:
1930*4882a593Smuzhiyun /* The task is not in Lun or failed, reset the phy */
1931*4882a593Smuzhiyun case TMF_RESP_FUNC_FAILED:
1932*4882a593Smuzhiyun case TMF_RESP_FUNC_COMPLETE:
1933*4882a593Smuzhiyun break;
1934*4882a593Smuzhiyun default:
1935*4882a593Smuzhiyun rc = TMF_RESP_FUNC_FAILED;
1936*4882a593Smuzhiyun break;
1937*4882a593Smuzhiyun }
1938*4882a593Smuzhiyun }
1939*4882a593Smuzhiyun return rc;
1940*4882a593Smuzhiyun }
1941*4882a593Smuzhiyun
1942*4882a593Smuzhiyun static int
hisi_sas_internal_abort_task_exec(struct hisi_hba * hisi_hba,int device_id,struct sas_task * task,int abort_flag,int task_tag,struct hisi_sas_dq * dq)1943*4882a593Smuzhiyun hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, int device_id,
1944*4882a593Smuzhiyun struct sas_task *task, int abort_flag,
1945*4882a593Smuzhiyun int task_tag, struct hisi_sas_dq *dq)
1946*4882a593Smuzhiyun {
1947*4882a593Smuzhiyun struct domain_device *device = task->dev;
1948*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
1949*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
1950*4882a593Smuzhiyun struct hisi_sas_port *port;
1951*4882a593Smuzhiyun struct hisi_sas_slot *slot;
1952*4882a593Smuzhiyun struct asd_sas_port *sas_port = device->port;
1953*4882a593Smuzhiyun struct hisi_sas_cmd_hdr *cmd_hdr_base;
1954*4882a593Smuzhiyun int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
1955*4882a593Smuzhiyun unsigned long flags;
1956*4882a593Smuzhiyun int wr_q_index;
1957*4882a593Smuzhiyun
1958*4882a593Smuzhiyun if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
1959*4882a593Smuzhiyun return -EINVAL;
1960*4882a593Smuzhiyun
1961*4882a593Smuzhiyun if (!device->port)
1962*4882a593Smuzhiyun return -1;
1963*4882a593Smuzhiyun
1964*4882a593Smuzhiyun port = to_hisi_sas_port(sas_port);
1965*4882a593Smuzhiyun
1966*4882a593Smuzhiyun /* simply get a slot and send abort command */
1967*4882a593Smuzhiyun rc = hisi_sas_slot_index_alloc(hisi_hba, NULL);
1968*4882a593Smuzhiyun if (rc < 0)
1969*4882a593Smuzhiyun goto err_out;
1970*4882a593Smuzhiyun
1971*4882a593Smuzhiyun slot_idx = rc;
1972*4882a593Smuzhiyun slot = &hisi_hba->slot_info[slot_idx];
1973*4882a593Smuzhiyun
1974*4882a593Smuzhiyun spin_lock(&dq->lock);
1975*4882a593Smuzhiyun wr_q_index = dq->wr_point;
1976*4882a593Smuzhiyun dq->wr_point = (dq->wr_point + 1) % HISI_SAS_QUEUE_SLOTS;
1977*4882a593Smuzhiyun list_add_tail(&slot->delivery, &dq->list);
1978*4882a593Smuzhiyun spin_unlock(&dq->lock);
1979*4882a593Smuzhiyun spin_lock(&sas_dev->lock);
1980*4882a593Smuzhiyun list_add_tail(&slot->entry, &sas_dev->list);
1981*4882a593Smuzhiyun spin_unlock(&sas_dev->lock);
1982*4882a593Smuzhiyun
1983*4882a593Smuzhiyun dlvry_queue = dq->id;
1984*4882a593Smuzhiyun dlvry_queue_slot = wr_q_index;
1985*4882a593Smuzhiyun
1986*4882a593Smuzhiyun slot->device_id = sas_dev->device_id;
1987*4882a593Smuzhiyun slot->n_elem = n_elem;
1988*4882a593Smuzhiyun slot->dlvry_queue = dlvry_queue;
1989*4882a593Smuzhiyun slot->dlvry_queue_slot = dlvry_queue_slot;
1990*4882a593Smuzhiyun cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
1991*4882a593Smuzhiyun slot->cmd_hdr = &cmd_hdr_base[dlvry_queue_slot];
1992*4882a593Smuzhiyun slot->task = task;
1993*4882a593Smuzhiyun slot->port = port;
1994*4882a593Smuzhiyun slot->is_internal = true;
1995*4882a593Smuzhiyun task->lldd_task = slot;
1996*4882a593Smuzhiyun
1997*4882a593Smuzhiyun memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
1998*4882a593Smuzhiyun memset(hisi_sas_cmd_hdr_addr_mem(slot), 0, HISI_SAS_COMMAND_TABLE_SZ);
1999*4882a593Smuzhiyun memset(hisi_sas_status_buf_addr_mem(slot), 0,
2000*4882a593Smuzhiyun sizeof(struct hisi_sas_err_record));
2001*4882a593Smuzhiyun
2002*4882a593Smuzhiyun hisi_sas_task_prep_abort(hisi_hba, slot, device_id,
2003*4882a593Smuzhiyun abort_flag, task_tag);
2004*4882a593Smuzhiyun
2005*4882a593Smuzhiyun spin_lock_irqsave(&task->task_state_lock, flags);
2006*4882a593Smuzhiyun task->task_state_flags |= SAS_TASK_AT_INITIATOR;
2007*4882a593Smuzhiyun spin_unlock_irqrestore(&task->task_state_lock, flags);
2008*4882a593Smuzhiyun WRITE_ONCE(slot->ready, 1);
2009*4882a593Smuzhiyun /* send abort command to the chip */
2010*4882a593Smuzhiyun spin_lock(&dq->lock);
2011*4882a593Smuzhiyun hisi_hba->hw->start_delivery(dq);
2012*4882a593Smuzhiyun spin_unlock(&dq->lock);
2013*4882a593Smuzhiyun
2014*4882a593Smuzhiyun return 0;
2015*4882a593Smuzhiyun
2016*4882a593Smuzhiyun err_out:
2017*4882a593Smuzhiyun dev_err(dev, "internal abort task prep: failed[%d]!\n", rc);
2018*4882a593Smuzhiyun
2019*4882a593Smuzhiyun return rc;
2020*4882a593Smuzhiyun }
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun /**
2023*4882a593Smuzhiyun * _hisi_sas_internal_task_abort -- execute an internal
2024*4882a593Smuzhiyun * abort command for single IO command or a device
2025*4882a593Smuzhiyun * @hisi_hba: host controller struct
2026*4882a593Smuzhiyun * @device: domain device
2027*4882a593Smuzhiyun * @abort_flag: mode of operation, device or single IO
2028*4882a593Smuzhiyun * @tag: tag of IO to be aborted (only relevant to single
2029*4882a593Smuzhiyun * IO mode)
2030*4882a593Smuzhiyun * @dq: delivery queue for this internal abort command
2031*4882a593Smuzhiyun */
2032*4882a593Smuzhiyun static int
_hisi_sas_internal_task_abort(struct hisi_hba * hisi_hba,struct domain_device * device,int abort_flag,int tag,struct hisi_sas_dq * dq)2033*4882a593Smuzhiyun _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
2034*4882a593Smuzhiyun struct domain_device *device, int abort_flag,
2035*4882a593Smuzhiyun int tag, struct hisi_sas_dq *dq)
2036*4882a593Smuzhiyun {
2037*4882a593Smuzhiyun struct sas_task *task;
2038*4882a593Smuzhiyun struct hisi_sas_device *sas_dev = device->lldd_dev;
2039*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
2040*4882a593Smuzhiyun int res;
2041*4882a593Smuzhiyun
2042*4882a593Smuzhiyun /*
2043*4882a593Smuzhiyun * The interface is not realized means this HW don't support internal
2044*4882a593Smuzhiyun * abort, or don't need to do internal abort. Then here, we return
2045*4882a593Smuzhiyun * TMF_RESP_FUNC_FAILED and let other steps go on, which depends that
2046*4882a593Smuzhiyun * the internal abort has been executed and returned CQ.
2047*4882a593Smuzhiyun */
2048*4882a593Smuzhiyun if (!hisi_hba->hw->prep_abort)
2049*4882a593Smuzhiyun return TMF_RESP_FUNC_FAILED;
2050*4882a593Smuzhiyun
2051*4882a593Smuzhiyun task = sas_alloc_slow_task(GFP_KERNEL);
2052*4882a593Smuzhiyun if (!task)
2053*4882a593Smuzhiyun return -ENOMEM;
2054*4882a593Smuzhiyun
2055*4882a593Smuzhiyun task->dev = device;
2056*4882a593Smuzhiyun task->task_proto = device->tproto;
2057*4882a593Smuzhiyun task->task_done = hisi_sas_task_done;
2058*4882a593Smuzhiyun task->slow_task->timer.function = hisi_sas_tmf_timedout;
2059*4882a593Smuzhiyun task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT * HZ;
2060*4882a593Smuzhiyun add_timer(&task->slow_task->timer);
2061*4882a593Smuzhiyun
2062*4882a593Smuzhiyun res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
2063*4882a593Smuzhiyun task, abort_flag, tag, dq);
2064*4882a593Smuzhiyun if (res) {
2065*4882a593Smuzhiyun del_timer(&task->slow_task->timer);
2066*4882a593Smuzhiyun dev_err(dev, "internal task abort: executing internal task failed: %d\n",
2067*4882a593Smuzhiyun res);
2068*4882a593Smuzhiyun goto exit;
2069*4882a593Smuzhiyun }
2070*4882a593Smuzhiyun wait_for_completion(&task->slow_task->completion);
2071*4882a593Smuzhiyun res = TMF_RESP_FUNC_FAILED;
2072*4882a593Smuzhiyun
2073*4882a593Smuzhiyun /* Internal abort timed out */
2074*4882a593Smuzhiyun if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
2075*4882a593Smuzhiyun if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
2076*4882a593Smuzhiyun queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
2077*4882a593Smuzhiyun
2078*4882a593Smuzhiyun if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
2079*4882a593Smuzhiyun struct hisi_sas_slot *slot = task->lldd_task;
2080*4882a593Smuzhiyun
2081*4882a593Smuzhiyun if (slot) {
2082*4882a593Smuzhiyun struct hisi_sas_cq *cq =
2083*4882a593Smuzhiyun &hisi_hba->cq[slot->dlvry_queue];
2084*4882a593Smuzhiyun /*
2085*4882a593Smuzhiyun * sync irq to avoid free'ing task
2086*4882a593Smuzhiyun * before using task in IO completion
2087*4882a593Smuzhiyun */
2088*4882a593Smuzhiyun synchronize_irq(cq->irq_no);
2089*4882a593Smuzhiyun slot->task = NULL;
2090*4882a593Smuzhiyun }
2091*4882a593Smuzhiyun dev_err(dev, "internal task abort: timeout and not done.\n");
2092*4882a593Smuzhiyun
2093*4882a593Smuzhiyun res = -EIO;
2094*4882a593Smuzhiyun goto exit;
2095*4882a593Smuzhiyun } else
2096*4882a593Smuzhiyun dev_err(dev, "internal task abort: timeout.\n");
2097*4882a593Smuzhiyun }
2098*4882a593Smuzhiyun
2099*4882a593Smuzhiyun if (task->task_status.resp == SAS_TASK_COMPLETE &&
2100*4882a593Smuzhiyun task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
2101*4882a593Smuzhiyun res = TMF_RESP_FUNC_COMPLETE;
2102*4882a593Smuzhiyun goto exit;
2103*4882a593Smuzhiyun }
2104*4882a593Smuzhiyun
2105*4882a593Smuzhiyun if (task->task_status.resp == SAS_TASK_COMPLETE &&
2106*4882a593Smuzhiyun task->task_status.stat == TMF_RESP_FUNC_SUCC) {
2107*4882a593Smuzhiyun res = TMF_RESP_FUNC_SUCC;
2108*4882a593Smuzhiyun goto exit;
2109*4882a593Smuzhiyun }
2110*4882a593Smuzhiyun
2111*4882a593Smuzhiyun exit:
2112*4882a593Smuzhiyun dev_dbg(dev, "internal task abort: task to dev %016llx task=%pK resp: 0x%x sts 0x%x\n",
2113*4882a593Smuzhiyun SAS_ADDR(device->sas_addr), task,
2114*4882a593Smuzhiyun task->task_status.resp, /* 0 is complete, -1 is undelivered */
2115*4882a593Smuzhiyun task->task_status.stat);
2116*4882a593Smuzhiyun sas_free_task(task);
2117*4882a593Smuzhiyun
2118*4882a593Smuzhiyun return res;
2119*4882a593Smuzhiyun }
2120*4882a593Smuzhiyun
2121*4882a593Smuzhiyun static int
hisi_sas_internal_task_abort(struct hisi_hba * hisi_hba,struct domain_device * device,int abort_flag,int tag)2122*4882a593Smuzhiyun hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
2123*4882a593Smuzhiyun struct domain_device *device,
2124*4882a593Smuzhiyun int abort_flag, int tag)
2125*4882a593Smuzhiyun {
2126*4882a593Smuzhiyun struct hisi_sas_slot *slot;
2127*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
2128*4882a593Smuzhiyun struct hisi_sas_dq *dq;
2129*4882a593Smuzhiyun int i, rc;
2130*4882a593Smuzhiyun
2131*4882a593Smuzhiyun switch (abort_flag) {
2132*4882a593Smuzhiyun case HISI_SAS_INT_ABT_CMD:
2133*4882a593Smuzhiyun slot = &hisi_hba->slot_info[tag];
2134*4882a593Smuzhiyun dq = &hisi_hba->dq[slot->dlvry_queue];
2135*4882a593Smuzhiyun return _hisi_sas_internal_task_abort(hisi_hba, device,
2136*4882a593Smuzhiyun abort_flag, tag, dq);
2137*4882a593Smuzhiyun case HISI_SAS_INT_ABT_DEV:
2138*4882a593Smuzhiyun for (i = 0; i < hisi_hba->cq_nvecs; i++) {
2139*4882a593Smuzhiyun struct hisi_sas_cq *cq = &hisi_hba->cq[i];
2140*4882a593Smuzhiyun const struct cpumask *mask = cq->irq_mask;
2141*4882a593Smuzhiyun
2142*4882a593Smuzhiyun if (mask && !cpumask_intersects(cpu_online_mask, mask))
2143*4882a593Smuzhiyun continue;
2144*4882a593Smuzhiyun dq = &hisi_hba->dq[i];
2145*4882a593Smuzhiyun rc = _hisi_sas_internal_task_abort(hisi_hba, device,
2146*4882a593Smuzhiyun abort_flag, tag,
2147*4882a593Smuzhiyun dq);
2148*4882a593Smuzhiyun if (rc)
2149*4882a593Smuzhiyun return rc;
2150*4882a593Smuzhiyun }
2151*4882a593Smuzhiyun break;
2152*4882a593Smuzhiyun default:
2153*4882a593Smuzhiyun dev_err(dev, "Unrecognised internal abort flag (%d)\n",
2154*4882a593Smuzhiyun abort_flag);
2155*4882a593Smuzhiyun return -EINVAL;
2156*4882a593Smuzhiyun }
2157*4882a593Smuzhiyun
2158*4882a593Smuzhiyun return 0;
2159*4882a593Smuzhiyun }
2160*4882a593Smuzhiyun
hisi_sas_port_formed(struct asd_sas_phy * sas_phy)2161*4882a593Smuzhiyun static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
2162*4882a593Smuzhiyun {
2163*4882a593Smuzhiyun hisi_sas_port_notify_formed(sas_phy);
2164*4882a593Smuzhiyun }
2165*4882a593Smuzhiyun
hisi_sas_write_gpio(struct sas_ha_struct * sha,u8 reg_type,u8 reg_index,u8 reg_count,u8 * write_data)2166*4882a593Smuzhiyun static int hisi_sas_write_gpio(struct sas_ha_struct *sha, u8 reg_type,
2167*4882a593Smuzhiyun u8 reg_index, u8 reg_count, u8 *write_data)
2168*4882a593Smuzhiyun {
2169*4882a593Smuzhiyun struct hisi_hba *hisi_hba = sha->lldd_ha;
2170*4882a593Smuzhiyun
2171*4882a593Smuzhiyun if (!hisi_hba->hw->write_gpio)
2172*4882a593Smuzhiyun return -EOPNOTSUPP;
2173*4882a593Smuzhiyun
2174*4882a593Smuzhiyun return hisi_hba->hw->write_gpio(hisi_hba, reg_type,
2175*4882a593Smuzhiyun reg_index, reg_count, write_data);
2176*4882a593Smuzhiyun }
2177*4882a593Smuzhiyun
hisi_sas_phy_disconnected(struct hisi_sas_phy * phy)2178*4882a593Smuzhiyun static void hisi_sas_phy_disconnected(struct hisi_sas_phy *phy)
2179*4882a593Smuzhiyun {
2180*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
2181*4882a593Smuzhiyun struct sas_phy *sphy = sas_phy->phy;
2182*4882a593Smuzhiyun unsigned long flags;
2183*4882a593Smuzhiyun
2184*4882a593Smuzhiyun phy->phy_attached = 0;
2185*4882a593Smuzhiyun phy->phy_type = 0;
2186*4882a593Smuzhiyun phy->port = NULL;
2187*4882a593Smuzhiyun
2188*4882a593Smuzhiyun spin_lock_irqsave(&phy->lock, flags);
2189*4882a593Smuzhiyun if (phy->enable)
2190*4882a593Smuzhiyun sphy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
2191*4882a593Smuzhiyun else
2192*4882a593Smuzhiyun sphy->negotiated_linkrate = SAS_PHY_DISABLED;
2193*4882a593Smuzhiyun spin_unlock_irqrestore(&phy->lock, flags);
2194*4882a593Smuzhiyun }
2195*4882a593Smuzhiyun
hisi_sas_phy_down(struct hisi_hba * hisi_hba,int phy_no,int rdy)2196*4882a593Smuzhiyun void hisi_sas_phy_down(struct hisi_hba *hisi_hba, int phy_no, int rdy)
2197*4882a593Smuzhiyun {
2198*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no];
2199*4882a593Smuzhiyun struct asd_sas_phy *sas_phy = &phy->sas_phy;
2200*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
2201*4882a593Smuzhiyun
2202*4882a593Smuzhiyun if (rdy) {
2203*4882a593Smuzhiyun /* Phy down but ready */
2204*4882a593Smuzhiyun hisi_sas_bytes_dmaed(hisi_hba, phy_no);
2205*4882a593Smuzhiyun hisi_sas_port_notify_formed(sas_phy);
2206*4882a593Smuzhiyun } else {
2207*4882a593Smuzhiyun struct hisi_sas_port *port = phy->port;
2208*4882a593Smuzhiyun
2209*4882a593Smuzhiyun if (test_bit(HISI_SAS_RESET_BIT, &hisi_hba->flags) ||
2210*4882a593Smuzhiyun phy->in_reset) {
2211*4882a593Smuzhiyun dev_info(dev, "ignore flutter phy%d down\n", phy_no);
2212*4882a593Smuzhiyun return;
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun /* Phy down and not ready */
2215*4882a593Smuzhiyun sas_notify_phy_event(sas_phy, PHYE_LOSS_OF_SIGNAL);
2216*4882a593Smuzhiyun sas_phy_disconnected(sas_phy);
2217*4882a593Smuzhiyun
2218*4882a593Smuzhiyun if (port) {
2219*4882a593Smuzhiyun if (phy->phy_type & PORT_TYPE_SAS) {
2220*4882a593Smuzhiyun int port_id = port->id;
2221*4882a593Smuzhiyun
2222*4882a593Smuzhiyun if (!hisi_hba->hw->get_wideport_bitmap(hisi_hba,
2223*4882a593Smuzhiyun port_id))
2224*4882a593Smuzhiyun port->port_attached = 0;
2225*4882a593Smuzhiyun } else if (phy->phy_type & PORT_TYPE_SATA)
2226*4882a593Smuzhiyun port->port_attached = 0;
2227*4882a593Smuzhiyun }
2228*4882a593Smuzhiyun hisi_sas_phy_disconnected(phy);
2229*4882a593Smuzhiyun }
2230*4882a593Smuzhiyun }
2231*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_phy_down);
2232*4882a593Smuzhiyun
hisi_sas_sync_irqs(struct hisi_hba * hisi_hba)2233*4882a593Smuzhiyun void hisi_sas_sync_irqs(struct hisi_hba *hisi_hba)
2234*4882a593Smuzhiyun {
2235*4882a593Smuzhiyun int i;
2236*4882a593Smuzhiyun
2237*4882a593Smuzhiyun for (i = 0; i < hisi_hba->cq_nvecs; i++) {
2238*4882a593Smuzhiyun struct hisi_sas_cq *cq = &hisi_hba->cq[i];
2239*4882a593Smuzhiyun
2240*4882a593Smuzhiyun synchronize_irq(cq->irq_no);
2241*4882a593Smuzhiyun }
2242*4882a593Smuzhiyun }
2243*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_sync_irqs);
2244*4882a593Smuzhiyun
hisi_sas_host_reset(struct Scsi_Host * shost,int reset_type)2245*4882a593Smuzhiyun int hisi_sas_host_reset(struct Scsi_Host *shost, int reset_type)
2246*4882a593Smuzhiyun {
2247*4882a593Smuzhiyun struct hisi_hba *hisi_hba = shost_priv(shost);
2248*4882a593Smuzhiyun
2249*4882a593Smuzhiyun if (reset_type != SCSI_ADAPTER_RESET)
2250*4882a593Smuzhiyun return -EOPNOTSUPP;
2251*4882a593Smuzhiyun
2252*4882a593Smuzhiyun queue_work(hisi_hba->wq, &hisi_hba->rst_work);
2253*4882a593Smuzhiyun
2254*4882a593Smuzhiyun return 0;
2255*4882a593Smuzhiyun }
2256*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_host_reset);
2257*4882a593Smuzhiyun
2258*4882a593Smuzhiyun struct scsi_transport_template *hisi_sas_stt;
2259*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_stt);
2260*4882a593Smuzhiyun
2261*4882a593Smuzhiyun static struct sas_domain_function_template hisi_sas_transport_ops = {
2262*4882a593Smuzhiyun .lldd_dev_found = hisi_sas_dev_found,
2263*4882a593Smuzhiyun .lldd_dev_gone = hisi_sas_dev_gone,
2264*4882a593Smuzhiyun .lldd_execute_task = hisi_sas_queue_command,
2265*4882a593Smuzhiyun .lldd_control_phy = hisi_sas_control_phy,
2266*4882a593Smuzhiyun .lldd_abort_task = hisi_sas_abort_task,
2267*4882a593Smuzhiyun .lldd_abort_task_set = hisi_sas_abort_task_set,
2268*4882a593Smuzhiyun .lldd_clear_aca = hisi_sas_clear_aca,
2269*4882a593Smuzhiyun .lldd_I_T_nexus_reset = hisi_sas_I_T_nexus_reset,
2270*4882a593Smuzhiyun .lldd_lu_reset = hisi_sas_lu_reset,
2271*4882a593Smuzhiyun .lldd_query_task = hisi_sas_query_task,
2272*4882a593Smuzhiyun .lldd_clear_nexus_ha = hisi_sas_clear_nexus_ha,
2273*4882a593Smuzhiyun .lldd_port_formed = hisi_sas_port_formed,
2274*4882a593Smuzhiyun .lldd_write_gpio = hisi_sas_write_gpio,
2275*4882a593Smuzhiyun };
2276*4882a593Smuzhiyun
hisi_sas_init_mem(struct hisi_hba * hisi_hba)2277*4882a593Smuzhiyun void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
2278*4882a593Smuzhiyun {
2279*4882a593Smuzhiyun int i, s, j, max_command_entries = HISI_SAS_MAX_COMMANDS;
2280*4882a593Smuzhiyun struct hisi_sas_breakpoint *sata_breakpoint = hisi_hba->sata_breakpoint;
2281*4882a593Smuzhiyun
2282*4882a593Smuzhiyun for (i = 0; i < hisi_hba->queue_count; i++) {
2283*4882a593Smuzhiyun struct hisi_sas_cq *cq = &hisi_hba->cq[i];
2284*4882a593Smuzhiyun struct hisi_sas_dq *dq = &hisi_hba->dq[i];
2285*4882a593Smuzhiyun struct hisi_sas_cmd_hdr *cmd_hdr = hisi_hba->cmd_hdr[i];
2286*4882a593Smuzhiyun
2287*4882a593Smuzhiyun s = sizeof(struct hisi_sas_cmd_hdr);
2288*4882a593Smuzhiyun for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++)
2289*4882a593Smuzhiyun memset(&cmd_hdr[j], 0, s);
2290*4882a593Smuzhiyun
2291*4882a593Smuzhiyun dq->wr_point = 0;
2292*4882a593Smuzhiyun
2293*4882a593Smuzhiyun s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
2294*4882a593Smuzhiyun memset(hisi_hba->complete_hdr[i], 0, s);
2295*4882a593Smuzhiyun cq->rd_point = 0;
2296*4882a593Smuzhiyun }
2297*4882a593Smuzhiyun
2298*4882a593Smuzhiyun s = sizeof(struct hisi_sas_initial_fis) * hisi_hba->n_phy;
2299*4882a593Smuzhiyun memset(hisi_hba->initial_fis, 0, s);
2300*4882a593Smuzhiyun
2301*4882a593Smuzhiyun s = max_command_entries * sizeof(struct hisi_sas_iost);
2302*4882a593Smuzhiyun memset(hisi_hba->iost, 0, s);
2303*4882a593Smuzhiyun
2304*4882a593Smuzhiyun s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
2305*4882a593Smuzhiyun memset(hisi_hba->breakpoint, 0, s);
2306*4882a593Smuzhiyun
2307*4882a593Smuzhiyun s = sizeof(struct hisi_sas_sata_breakpoint);
2308*4882a593Smuzhiyun for (j = 0; j < HISI_SAS_MAX_ITCT_ENTRIES; j++)
2309*4882a593Smuzhiyun memset(&sata_breakpoint[j], 0, s);
2310*4882a593Smuzhiyun }
2311*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_init_mem);
2312*4882a593Smuzhiyun
hisi_sas_alloc(struct hisi_hba * hisi_hba)2313*4882a593Smuzhiyun int hisi_sas_alloc(struct hisi_hba *hisi_hba)
2314*4882a593Smuzhiyun {
2315*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
2316*4882a593Smuzhiyun int i, j, s, max_command_entries = HISI_SAS_MAX_COMMANDS;
2317*4882a593Smuzhiyun int max_command_entries_ru, sz_slot_buf_ru;
2318*4882a593Smuzhiyun int blk_cnt, slots_per_blk;
2319*4882a593Smuzhiyun
2320*4882a593Smuzhiyun sema_init(&hisi_hba->sem, 1);
2321*4882a593Smuzhiyun spin_lock_init(&hisi_hba->lock);
2322*4882a593Smuzhiyun for (i = 0; i < hisi_hba->n_phy; i++) {
2323*4882a593Smuzhiyun hisi_sas_phy_init(hisi_hba, i);
2324*4882a593Smuzhiyun hisi_hba->port[i].port_attached = 0;
2325*4882a593Smuzhiyun hisi_hba->port[i].id = -1;
2326*4882a593Smuzhiyun }
2327*4882a593Smuzhiyun
2328*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_DEVICES; i++) {
2329*4882a593Smuzhiyun hisi_hba->devices[i].dev_type = SAS_PHY_UNUSED;
2330*4882a593Smuzhiyun hisi_hba->devices[i].device_id = i;
2331*4882a593Smuzhiyun hisi_hba->devices[i].dev_status = HISI_SAS_DEV_INIT;
2332*4882a593Smuzhiyun }
2333*4882a593Smuzhiyun
2334*4882a593Smuzhiyun for (i = 0; i < hisi_hba->queue_count; i++) {
2335*4882a593Smuzhiyun struct hisi_sas_cq *cq = &hisi_hba->cq[i];
2336*4882a593Smuzhiyun struct hisi_sas_dq *dq = &hisi_hba->dq[i];
2337*4882a593Smuzhiyun
2338*4882a593Smuzhiyun /* Completion queue structure */
2339*4882a593Smuzhiyun cq->id = i;
2340*4882a593Smuzhiyun cq->hisi_hba = hisi_hba;
2341*4882a593Smuzhiyun
2342*4882a593Smuzhiyun /* Delivery queue structure */
2343*4882a593Smuzhiyun spin_lock_init(&dq->lock);
2344*4882a593Smuzhiyun INIT_LIST_HEAD(&dq->list);
2345*4882a593Smuzhiyun dq->id = i;
2346*4882a593Smuzhiyun dq->hisi_hba = hisi_hba;
2347*4882a593Smuzhiyun
2348*4882a593Smuzhiyun /* Delivery queue */
2349*4882a593Smuzhiyun s = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
2350*4882a593Smuzhiyun hisi_hba->cmd_hdr[i] = dmam_alloc_coherent(dev, s,
2351*4882a593Smuzhiyun &hisi_hba->cmd_hdr_dma[i],
2352*4882a593Smuzhiyun GFP_KERNEL);
2353*4882a593Smuzhiyun if (!hisi_hba->cmd_hdr[i])
2354*4882a593Smuzhiyun goto err_out;
2355*4882a593Smuzhiyun
2356*4882a593Smuzhiyun /* Completion queue */
2357*4882a593Smuzhiyun s = hisi_hba->hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
2358*4882a593Smuzhiyun hisi_hba->complete_hdr[i] = dmam_alloc_coherent(dev, s,
2359*4882a593Smuzhiyun &hisi_hba->complete_hdr_dma[i],
2360*4882a593Smuzhiyun GFP_KERNEL);
2361*4882a593Smuzhiyun if (!hisi_hba->complete_hdr[i])
2362*4882a593Smuzhiyun goto err_out;
2363*4882a593Smuzhiyun }
2364*4882a593Smuzhiyun
2365*4882a593Smuzhiyun s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
2366*4882a593Smuzhiyun hisi_hba->itct = dmam_alloc_coherent(dev, s, &hisi_hba->itct_dma,
2367*4882a593Smuzhiyun GFP_KERNEL);
2368*4882a593Smuzhiyun if (!hisi_hba->itct)
2369*4882a593Smuzhiyun goto err_out;
2370*4882a593Smuzhiyun
2371*4882a593Smuzhiyun hisi_hba->slot_info = devm_kcalloc(dev, max_command_entries,
2372*4882a593Smuzhiyun sizeof(struct hisi_sas_slot),
2373*4882a593Smuzhiyun GFP_KERNEL);
2374*4882a593Smuzhiyun if (!hisi_hba->slot_info)
2375*4882a593Smuzhiyun goto err_out;
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun /* roundup to avoid overly large block size */
2378*4882a593Smuzhiyun max_command_entries_ru = roundup(max_command_entries, 64);
2379*4882a593Smuzhiyun if (hisi_hba->prot_mask & HISI_SAS_DIX_PROT_MASK)
2380*4882a593Smuzhiyun sz_slot_buf_ru = sizeof(struct hisi_sas_slot_dif_buf_table);
2381*4882a593Smuzhiyun else
2382*4882a593Smuzhiyun sz_slot_buf_ru = sizeof(struct hisi_sas_slot_buf_table);
2383*4882a593Smuzhiyun sz_slot_buf_ru = roundup(sz_slot_buf_ru, 64);
2384*4882a593Smuzhiyun s = max(lcm(max_command_entries_ru, sz_slot_buf_ru), PAGE_SIZE);
2385*4882a593Smuzhiyun blk_cnt = (max_command_entries_ru * sz_slot_buf_ru) / s;
2386*4882a593Smuzhiyun slots_per_blk = s / sz_slot_buf_ru;
2387*4882a593Smuzhiyun
2388*4882a593Smuzhiyun for (i = 0; i < blk_cnt; i++) {
2389*4882a593Smuzhiyun int slot_index = i * slots_per_blk;
2390*4882a593Smuzhiyun dma_addr_t buf_dma;
2391*4882a593Smuzhiyun void *buf;
2392*4882a593Smuzhiyun
2393*4882a593Smuzhiyun buf = dmam_alloc_coherent(dev, s, &buf_dma,
2394*4882a593Smuzhiyun GFP_KERNEL);
2395*4882a593Smuzhiyun if (!buf)
2396*4882a593Smuzhiyun goto err_out;
2397*4882a593Smuzhiyun
2398*4882a593Smuzhiyun for (j = 0; j < slots_per_blk; j++, slot_index++) {
2399*4882a593Smuzhiyun struct hisi_sas_slot *slot;
2400*4882a593Smuzhiyun
2401*4882a593Smuzhiyun slot = &hisi_hba->slot_info[slot_index];
2402*4882a593Smuzhiyun slot->buf = buf;
2403*4882a593Smuzhiyun slot->buf_dma = buf_dma;
2404*4882a593Smuzhiyun slot->idx = slot_index;
2405*4882a593Smuzhiyun
2406*4882a593Smuzhiyun buf += sz_slot_buf_ru;
2407*4882a593Smuzhiyun buf_dma += sz_slot_buf_ru;
2408*4882a593Smuzhiyun }
2409*4882a593Smuzhiyun }
2410*4882a593Smuzhiyun
2411*4882a593Smuzhiyun s = max_command_entries * sizeof(struct hisi_sas_iost);
2412*4882a593Smuzhiyun hisi_hba->iost = dmam_alloc_coherent(dev, s, &hisi_hba->iost_dma,
2413*4882a593Smuzhiyun GFP_KERNEL);
2414*4882a593Smuzhiyun if (!hisi_hba->iost)
2415*4882a593Smuzhiyun goto err_out;
2416*4882a593Smuzhiyun
2417*4882a593Smuzhiyun s = max_command_entries * sizeof(struct hisi_sas_breakpoint);
2418*4882a593Smuzhiyun hisi_hba->breakpoint = dmam_alloc_coherent(dev, s,
2419*4882a593Smuzhiyun &hisi_hba->breakpoint_dma,
2420*4882a593Smuzhiyun GFP_KERNEL);
2421*4882a593Smuzhiyun if (!hisi_hba->breakpoint)
2422*4882a593Smuzhiyun goto err_out;
2423*4882a593Smuzhiyun
2424*4882a593Smuzhiyun hisi_hba->slot_index_count = max_command_entries;
2425*4882a593Smuzhiyun s = hisi_hba->slot_index_count / BITS_PER_BYTE;
2426*4882a593Smuzhiyun hisi_hba->slot_index_tags = devm_kzalloc(dev, s, GFP_KERNEL);
2427*4882a593Smuzhiyun if (!hisi_hba->slot_index_tags)
2428*4882a593Smuzhiyun goto err_out;
2429*4882a593Smuzhiyun
2430*4882a593Smuzhiyun s = sizeof(struct hisi_sas_initial_fis) * HISI_SAS_MAX_PHYS;
2431*4882a593Smuzhiyun hisi_hba->initial_fis = dmam_alloc_coherent(dev, s,
2432*4882a593Smuzhiyun &hisi_hba->initial_fis_dma,
2433*4882a593Smuzhiyun GFP_KERNEL);
2434*4882a593Smuzhiyun if (!hisi_hba->initial_fis)
2435*4882a593Smuzhiyun goto err_out;
2436*4882a593Smuzhiyun
2437*4882a593Smuzhiyun s = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_sata_breakpoint);
2438*4882a593Smuzhiyun hisi_hba->sata_breakpoint = dmam_alloc_coherent(dev, s,
2439*4882a593Smuzhiyun &hisi_hba->sata_breakpoint_dma,
2440*4882a593Smuzhiyun GFP_KERNEL);
2441*4882a593Smuzhiyun if (!hisi_hba->sata_breakpoint)
2442*4882a593Smuzhiyun goto err_out;
2443*4882a593Smuzhiyun
2444*4882a593Smuzhiyun hisi_sas_slot_index_init(hisi_hba);
2445*4882a593Smuzhiyun hisi_hba->last_slot_index = HISI_SAS_UNRESERVED_IPTT;
2446*4882a593Smuzhiyun
2447*4882a593Smuzhiyun hisi_hba->wq = create_singlethread_workqueue(dev_name(dev));
2448*4882a593Smuzhiyun if (!hisi_hba->wq) {
2449*4882a593Smuzhiyun dev_err(dev, "sas_alloc: failed to create workqueue\n");
2450*4882a593Smuzhiyun goto err_out;
2451*4882a593Smuzhiyun }
2452*4882a593Smuzhiyun
2453*4882a593Smuzhiyun return 0;
2454*4882a593Smuzhiyun err_out:
2455*4882a593Smuzhiyun return -ENOMEM;
2456*4882a593Smuzhiyun }
2457*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_alloc);
2458*4882a593Smuzhiyun
hisi_sas_free(struct hisi_hba * hisi_hba)2459*4882a593Smuzhiyun void hisi_sas_free(struct hisi_hba *hisi_hba)
2460*4882a593Smuzhiyun {
2461*4882a593Smuzhiyun int i;
2462*4882a593Smuzhiyun
2463*4882a593Smuzhiyun for (i = 0; i < hisi_hba->n_phy; i++) {
2464*4882a593Smuzhiyun struct hisi_sas_phy *phy = &hisi_hba->phy[i];
2465*4882a593Smuzhiyun
2466*4882a593Smuzhiyun del_timer_sync(&phy->timer);
2467*4882a593Smuzhiyun }
2468*4882a593Smuzhiyun
2469*4882a593Smuzhiyun if (hisi_hba->wq)
2470*4882a593Smuzhiyun destroy_workqueue(hisi_hba->wq);
2471*4882a593Smuzhiyun }
2472*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_free);
2473*4882a593Smuzhiyun
hisi_sas_rst_work_handler(struct work_struct * work)2474*4882a593Smuzhiyun void hisi_sas_rst_work_handler(struct work_struct *work)
2475*4882a593Smuzhiyun {
2476*4882a593Smuzhiyun struct hisi_hba *hisi_hba =
2477*4882a593Smuzhiyun container_of(work, struct hisi_hba, rst_work);
2478*4882a593Smuzhiyun
2479*4882a593Smuzhiyun hisi_sas_controller_reset(hisi_hba);
2480*4882a593Smuzhiyun }
2481*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_rst_work_handler);
2482*4882a593Smuzhiyun
hisi_sas_sync_rst_work_handler(struct work_struct * work)2483*4882a593Smuzhiyun void hisi_sas_sync_rst_work_handler(struct work_struct *work)
2484*4882a593Smuzhiyun {
2485*4882a593Smuzhiyun struct hisi_sas_rst *rst =
2486*4882a593Smuzhiyun container_of(work, struct hisi_sas_rst, work);
2487*4882a593Smuzhiyun
2488*4882a593Smuzhiyun if (!hisi_sas_controller_reset(rst->hisi_hba))
2489*4882a593Smuzhiyun rst->done = true;
2490*4882a593Smuzhiyun complete(rst->completion);
2491*4882a593Smuzhiyun }
2492*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_sync_rst_work_handler);
2493*4882a593Smuzhiyun
hisi_sas_get_fw_info(struct hisi_hba * hisi_hba)2494*4882a593Smuzhiyun int hisi_sas_get_fw_info(struct hisi_hba *hisi_hba)
2495*4882a593Smuzhiyun {
2496*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
2497*4882a593Smuzhiyun struct platform_device *pdev = hisi_hba->platform_dev;
2498*4882a593Smuzhiyun struct device_node *np = pdev ? pdev->dev.of_node : NULL;
2499*4882a593Smuzhiyun struct clk *refclk;
2500*4882a593Smuzhiyun
2501*4882a593Smuzhiyun if (device_property_read_u8_array(dev, "sas-addr", hisi_hba->sas_addr,
2502*4882a593Smuzhiyun SAS_ADDR_SIZE)) {
2503*4882a593Smuzhiyun dev_err(dev, "could not get property sas-addr\n");
2504*4882a593Smuzhiyun return -ENOENT;
2505*4882a593Smuzhiyun }
2506*4882a593Smuzhiyun
2507*4882a593Smuzhiyun if (np) {
2508*4882a593Smuzhiyun /*
2509*4882a593Smuzhiyun * These properties are only required for platform device-based
2510*4882a593Smuzhiyun * controller with DT firmware.
2511*4882a593Smuzhiyun */
2512*4882a593Smuzhiyun hisi_hba->ctrl = syscon_regmap_lookup_by_phandle(np,
2513*4882a593Smuzhiyun "hisilicon,sas-syscon");
2514*4882a593Smuzhiyun if (IS_ERR(hisi_hba->ctrl)) {
2515*4882a593Smuzhiyun dev_err(dev, "could not get syscon\n");
2516*4882a593Smuzhiyun return -ENOENT;
2517*4882a593Smuzhiyun }
2518*4882a593Smuzhiyun
2519*4882a593Smuzhiyun if (device_property_read_u32(dev, "ctrl-reset-reg",
2520*4882a593Smuzhiyun &hisi_hba->ctrl_reset_reg)) {
2521*4882a593Smuzhiyun dev_err(dev, "could not get property ctrl-reset-reg\n");
2522*4882a593Smuzhiyun return -ENOENT;
2523*4882a593Smuzhiyun }
2524*4882a593Smuzhiyun
2525*4882a593Smuzhiyun if (device_property_read_u32(dev, "ctrl-reset-sts-reg",
2526*4882a593Smuzhiyun &hisi_hba->ctrl_reset_sts_reg)) {
2527*4882a593Smuzhiyun dev_err(dev, "could not get property ctrl-reset-sts-reg\n");
2528*4882a593Smuzhiyun return -ENOENT;
2529*4882a593Smuzhiyun }
2530*4882a593Smuzhiyun
2531*4882a593Smuzhiyun if (device_property_read_u32(dev, "ctrl-clock-ena-reg",
2532*4882a593Smuzhiyun &hisi_hba->ctrl_clock_ena_reg)) {
2533*4882a593Smuzhiyun dev_err(dev, "could not get property ctrl-clock-ena-reg\n");
2534*4882a593Smuzhiyun return -ENOENT;
2535*4882a593Smuzhiyun }
2536*4882a593Smuzhiyun }
2537*4882a593Smuzhiyun
2538*4882a593Smuzhiyun refclk = devm_clk_get(dev, NULL);
2539*4882a593Smuzhiyun if (IS_ERR(refclk))
2540*4882a593Smuzhiyun dev_dbg(dev, "no ref clk property\n");
2541*4882a593Smuzhiyun else
2542*4882a593Smuzhiyun hisi_hba->refclk_frequency_mhz = clk_get_rate(refclk) / 1000000;
2543*4882a593Smuzhiyun
2544*4882a593Smuzhiyun if (device_property_read_u32(dev, "phy-count", &hisi_hba->n_phy)) {
2545*4882a593Smuzhiyun dev_err(dev, "could not get property phy-count\n");
2546*4882a593Smuzhiyun return -ENOENT;
2547*4882a593Smuzhiyun }
2548*4882a593Smuzhiyun
2549*4882a593Smuzhiyun if (device_property_read_u32(dev, "queue-count",
2550*4882a593Smuzhiyun &hisi_hba->queue_count)) {
2551*4882a593Smuzhiyun dev_err(dev, "could not get property queue-count\n");
2552*4882a593Smuzhiyun return -ENOENT;
2553*4882a593Smuzhiyun }
2554*4882a593Smuzhiyun
2555*4882a593Smuzhiyun return 0;
2556*4882a593Smuzhiyun }
2557*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_get_fw_info);
2558*4882a593Smuzhiyun
hisi_sas_shost_alloc(struct platform_device * pdev,const struct hisi_sas_hw * hw)2559*4882a593Smuzhiyun static struct Scsi_Host *hisi_sas_shost_alloc(struct platform_device *pdev,
2560*4882a593Smuzhiyun const struct hisi_sas_hw *hw)
2561*4882a593Smuzhiyun {
2562*4882a593Smuzhiyun struct resource *res;
2563*4882a593Smuzhiyun struct Scsi_Host *shost;
2564*4882a593Smuzhiyun struct hisi_hba *hisi_hba;
2565*4882a593Smuzhiyun struct device *dev = &pdev->dev;
2566*4882a593Smuzhiyun int error;
2567*4882a593Smuzhiyun
2568*4882a593Smuzhiyun shost = scsi_host_alloc(hw->sht, sizeof(*hisi_hba));
2569*4882a593Smuzhiyun if (!shost) {
2570*4882a593Smuzhiyun dev_err(dev, "scsi host alloc failed\n");
2571*4882a593Smuzhiyun return NULL;
2572*4882a593Smuzhiyun }
2573*4882a593Smuzhiyun hisi_hba = shost_priv(shost);
2574*4882a593Smuzhiyun
2575*4882a593Smuzhiyun INIT_WORK(&hisi_hba->rst_work, hisi_sas_rst_work_handler);
2576*4882a593Smuzhiyun hisi_hba->hw = hw;
2577*4882a593Smuzhiyun hisi_hba->dev = dev;
2578*4882a593Smuzhiyun hisi_hba->platform_dev = pdev;
2579*4882a593Smuzhiyun hisi_hba->shost = shost;
2580*4882a593Smuzhiyun SHOST_TO_SAS_HA(shost) = &hisi_hba->sha;
2581*4882a593Smuzhiyun
2582*4882a593Smuzhiyun timer_setup(&hisi_hba->timer, NULL, 0);
2583*4882a593Smuzhiyun
2584*4882a593Smuzhiyun if (hisi_sas_get_fw_info(hisi_hba) < 0)
2585*4882a593Smuzhiyun goto err_out;
2586*4882a593Smuzhiyun
2587*4882a593Smuzhiyun error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
2588*4882a593Smuzhiyun if (error)
2589*4882a593Smuzhiyun error = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
2590*4882a593Smuzhiyun
2591*4882a593Smuzhiyun if (error) {
2592*4882a593Smuzhiyun dev_err(dev, "No usable DMA addressing method\n");
2593*4882a593Smuzhiyun goto err_out;
2594*4882a593Smuzhiyun }
2595*4882a593Smuzhiyun
2596*4882a593Smuzhiyun hisi_hba->regs = devm_platform_ioremap_resource(pdev, 0);
2597*4882a593Smuzhiyun if (IS_ERR(hisi_hba->regs))
2598*4882a593Smuzhiyun goto err_out;
2599*4882a593Smuzhiyun
2600*4882a593Smuzhiyun res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
2601*4882a593Smuzhiyun if (res) {
2602*4882a593Smuzhiyun hisi_hba->sgpio_regs = devm_ioremap_resource(dev, res);
2603*4882a593Smuzhiyun if (IS_ERR(hisi_hba->sgpio_regs))
2604*4882a593Smuzhiyun goto err_out;
2605*4882a593Smuzhiyun }
2606*4882a593Smuzhiyun
2607*4882a593Smuzhiyun if (hisi_sas_alloc(hisi_hba)) {
2608*4882a593Smuzhiyun hisi_sas_free(hisi_hba);
2609*4882a593Smuzhiyun goto err_out;
2610*4882a593Smuzhiyun }
2611*4882a593Smuzhiyun
2612*4882a593Smuzhiyun return shost;
2613*4882a593Smuzhiyun err_out:
2614*4882a593Smuzhiyun scsi_host_put(shost);
2615*4882a593Smuzhiyun dev_err(dev, "shost alloc failed\n");
2616*4882a593Smuzhiyun return NULL;
2617*4882a593Smuzhiyun }
2618*4882a593Smuzhiyun
hisi_sas_probe(struct platform_device * pdev,const struct hisi_sas_hw * hw)2619*4882a593Smuzhiyun int hisi_sas_probe(struct platform_device *pdev,
2620*4882a593Smuzhiyun const struct hisi_sas_hw *hw)
2621*4882a593Smuzhiyun {
2622*4882a593Smuzhiyun struct Scsi_Host *shost;
2623*4882a593Smuzhiyun struct hisi_hba *hisi_hba;
2624*4882a593Smuzhiyun struct device *dev = &pdev->dev;
2625*4882a593Smuzhiyun struct asd_sas_phy **arr_phy;
2626*4882a593Smuzhiyun struct asd_sas_port **arr_port;
2627*4882a593Smuzhiyun struct sas_ha_struct *sha;
2628*4882a593Smuzhiyun int rc, phy_nr, port_nr, i;
2629*4882a593Smuzhiyun
2630*4882a593Smuzhiyun shost = hisi_sas_shost_alloc(pdev, hw);
2631*4882a593Smuzhiyun if (!shost)
2632*4882a593Smuzhiyun return -ENOMEM;
2633*4882a593Smuzhiyun
2634*4882a593Smuzhiyun sha = SHOST_TO_SAS_HA(shost);
2635*4882a593Smuzhiyun hisi_hba = shost_priv(shost);
2636*4882a593Smuzhiyun platform_set_drvdata(pdev, sha);
2637*4882a593Smuzhiyun
2638*4882a593Smuzhiyun phy_nr = port_nr = hisi_hba->n_phy;
2639*4882a593Smuzhiyun
2640*4882a593Smuzhiyun arr_phy = devm_kcalloc(dev, phy_nr, sizeof(void *), GFP_KERNEL);
2641*4882a593Smuzhiyun arr_port = devm_kcalloc(dev, port_nr, sizeof(void *), GFP_KERNEL);
2642*4882a593Smuzhiyun if (!arr_phy || !arr_port) {
2643*4882a593Smuzhiyun rc = -ENOMEM;
2644*4882a593Smuzhiyun goto err_out_ha;
2645*4882a593Smuzhiyun }
2646*4882a593Smuzhiyun
2647*4882a593Smuzhiyun sha->sas_phy = arr_phy;
2648*4882a593Smuzhiyun sha->sas_port = arr_port;
2649*4882a593Smuzhiyun sha->lldd_ha = hisi_hba;
2650*4882a593Smuzhiyun
2651*4882a593Smuzhiyun shost->transportt = hisi_sas_stt;
2652*4882a593Smuzhiyun shost->max_id = HISI_SAS_MAX_DEVICES;
2653*4882a593Smuzhiyun shost->max_lun = ~0;
2654*4882a593Smuzhiyun shost->max_channel = 1;
2655*4882a593Smuzhiyun shost->max_cmd_len = 16;
2656*4882a593Smuzhiyun if (hisi_hba->hw->slot_index_alloc) {
2657*4882a593Smuzhiyun shost->can_queue = HISI_SAS_MAX_COMMANDS;
2658*4882a593Smuzhiyun shost->cmd_per_lun = HISI_SAS_MAX_COMMANDS;
2659*4882a593Smuzhiyun } else {
2660*4882a593Smuzhiyun shost->can_queue = HISI_SAS_UNRESERVED_IPTT;
2661*4882a593Smuzhiyun shost->cmd_per_lun = HISI_SAS_UNRESERVED_IPTT;
2662*4882a593Smuzhiyun }
2663*4882a593Smuzhiyun
2664*4882a593Smuzhiyun sha->sas_ha_name = DRV_NAME;
2665*4882a593Smuzhiyun sha->dev = hisi_hba->dev;
2666*4882a593Smuzhiyun sha->lldd_module = THIS_MODULE;
2667*4882a593Smuzhiyun sha->sas_addr = &hisi_hba->sas_addr[0];
2668*4882a593Smuzhiyun sha->num_phys = hisi_hba->n_phy;
2669*4882a593Smuzhiyun sha->core.shost = hisi_hba->shost;
2670*4882a593Smuzhiyun
2671*4882a593Smuzhiyun for (i = 0; i < hisi_hba->n_phy; i++) {
2672*4882a593Smuzhiyun sha->sas_phy[i] = &hisi_hba->phy[i].sas_phy;
2673*4882a593Smuzhiyun sha->sas_port[i] = &hisi_hba->port[i].sas_port;
2674*4882a593Smuzhiyun }
2675*4882a593Smuzhiyun
2676*4882a593Smuzhiyun rc = scsi_add_host(shost, &pdev->dev);
2677*4882a593Smuzhiyun if (rc)
2678*4882a593Smuzhiyun goto err_out_ha;
2679*4882a593Smuzhiyun
2680*4882a593Smuzhiyun rc = sas_register_ha(sha);
2681*4882a593Smuzhiyun if (rc)
2682*4882a593Smuzhiyun goto err_out_register_ha;
2683*4882a593Smuzhiyun
2684*4882a593Smuzhiyun rc = hisi_hba->hw->hw_init(hisi_hba);
2685*4882a593Smuzhiyun if (rc)
2686*4882a593Smuzhiyun goto err_out_register_ha;
2687*4882a593Smuzhiyun
2688*4882a593Smuzhiyun scsi_scan_host(shost);
2689*4882a593Smuzhiyun
2690*4882a593Smuzhiyun return 0;
2691*4882a593Smuzhiyun
2692*4882a593Smuzhiyun err_out_register_ha:
2693*4882a593Smuzhiyun scsi_remove_host(shost);
2694*4882a593Smuzhiyun err_out_ha:
2695*4882a593Smuzhiyun hisi_sas_debugfs_exit(hisi_hba);
2696*4882a593Smuzhiyun hisi_sas_free(hisi_hba);
2697*4882a593Smuzhiyun scsi_host_put(shost);
2698*4882a593Smuzhiyun return rc;
2699*4882a593Smuzhiyun }
2700*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_probe);
2701*4882a593Smuzhiyun
2702*4882a593Smuzhiyun struct dentry *hisi_sas_debugfs_dir;
2703*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba * hisi_hba)2704*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba)
2705*4882a593Smuzhiyun {
2706*4882a593Smuzhiyun int queue_entry_size = hisi_hba->hw->complete_hdr_size;
2707*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2708*4882a593Smuzhiyun int i;
2709*4882a593Smuzhiyun
2710*4882a593Smuzhiyun for (i = 0; i < hisi_hba->queue_count; i++)
2711*4882a593Smuzhiyun memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr,
2712*4882a593Smuzhiyun hisi_hba->complete_hdr[i],
2713*4882a593Smuzhiyun HISI_SAS_QUEUE_SLOTS * queue_entry_size);
2714*4882a593Smuzhiyun }
2715*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba * hisi_hba)2716*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba)
2717*4882a593Smuzhiyun {
2718*4882a593Smuzhiyun int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr);
2719*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2720*4882a593Smuzhiyun int i;
2721*4882a593Smuzhiyun
2722*4882a593Smuzhiyun for (i = 0; i < hisi_hba->queue_count; i++) {
2723*4882a593Smuzhiyun struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr;
2724*4882a593Smuzhiyun int j;
2725*4882a593Smuzhiyun
2726*4882a593Smuzhiyun debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr;
2727*4882a593Smuzhiyun cmd_hdr = hisi_hba->cmd_hdr[i];
2728*4882a593Smuzhiyun
2729*4882a593Smuzhiyun for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++)
2730*4882a593Smuzhiyun memcpy(&debugfs_cmd_hdr[j], &cmd_hdr[j],
2731*4882a593Smuzhiyun queue_entry_size);
2732*4882a593Smuzhiyun }
2733*4882a593Smuzhiyun }
2734*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba * hisi_hba)2735*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba)
2736*4882a593Smuzhiyun {
2737*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2738*4882a593Smuzhiyun const struct hisi_sas_debugfs_reg *port =
2739*4882a593Smuzhiyun hisi_hba->hw->debugfs_reg_port;
2740*4882a593Smuzhiyun int i, phy_cnt;
2741*4882a593Smuzhiyun u32 offset;
2742*4882a593Smuzhiyun u32 *databuf;
2743*4882a593Smuzhiyun
2744*4882a593Smuzhiyun for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) {
2745*4882a593Smuzhiyun databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data;
2746*4882a593Smuzhiyun for (i = 0; i < port->count; i++, databuf++) {
2747*4882a593Smuzhiyun offset = port->base_off + 4 * i;
2748*4882a593Smuzhiyun *databuf = port->read_port_reg(hisi_hba, phy_cnt,
2749*4882a593Smuzhiyun offset);
2750*4882a593Smuzhiyun }
2751*4882a593Smuzhiyun }
2752*4882a593Smuzhiyun }
2753*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba * hisi_hba)2754*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba)
2755*4882a593Smuzhiyun {
2756*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2757*4882a593Smuzhiyun u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data;
2758*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
2759*4882a593Smuzhiyun const struct hisi_sas_debugfs_reg *global =
2760*4882a593Smuzhiyun hw->debugfs_reg_array[DEBUGFS_GLOBAL];
2761*4882a593Smuzhiyun int i;
2762*4882a593Smuzhiyun
2763*4882a593Smuzhiyun for (i = 0; i < global->count; i++, databuf++)
2764*4882a593Smuzhiyun *databuf = global->read_global_reg(hisi_hba, 4 * i);
2765*4882a593Smuzhiyun }
2766*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba * hisi_hba)2767*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba)
2768*4882a593Smuzhiyun {
2769*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2770*4882a593Smuzhiyun u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data;
2771*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
2772*4882a593Smuzhiyun const struct hisi_sas_debugfs_reg *axi =
2773*4882a593Smuzhiyun hw->debugfs_reg_array[DEBUGFS_AXI];
2774*4882a593Smuzhiyun int i;
2775*4882a593Smuzhiyun
2776*4882a593Smuzhiyun for (i = 0; i < axi->count; i++, databuf++)
2777*4882a593Smuzhiyun *databuf = axi->read_global_reg(hisi_hba,
2778*4882a593Smuzhiyun 4 * i + axi->base_off);
2779*4882a593Smuzhiyun }
2780*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba * hisi_hba)2781*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba)
2782*4882a593Smuzhiyun {
2783*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2784*4882a593Smuzhiyun u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data;
2785*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
2786*4882a593Smuzhiyun const struct hisi_sas_debugfs_reg *ras =
2787*4882a593Smuzhiyun hw->debugfs_reg_array[DEBUGFS_RAS];
2788*4882a593Smuzhiyun int i;
2789*4882a593Smuzhiyun
2790*4882a593Smuzhiyun for (i = 0; i < ras->count; i++, databuf++)
2791*4882a593Smuzhiyun *databuf = ras->read_global_reg(hisi_hba,
2792*4882a593Smuzhiyun 4 * i + ras->base_off);
2793*4882a593Smuzhiyun }
2794*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba * hisi_hba)2795*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba)
2796*4882a593Smuzhiyun {
2797*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2798*4882a593Smuzhiyun void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache;
2799*4882a593Smuzhiyun void *databuf = hisi_hba->debugfs_itct[dump_index].itct;
2800*4882a593Smuzhiyun struct hisi_sas_itct *itct;
2801*4882a593Smuzhiyun int i;
2802*4882a593Smuzhiyun
2803*4882a593Smuzhiyun hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_ITCT_CACHE,
2804*4882a593Smuzhiyun cachebuf);
2805*4882a593Smuzhiyun
2806*4882a593Smuzhiyun itct = hisi_hba->itct;
2807*4882a593Smuzhiyun
2808*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
2809*4882a593Smuzhiyun memcpy(databuf, itct, sizeof(struct hisi_sas_itct));
2810*4882a593Smuzhiyun databuf += sizeof(struct hisi_sas_itct);
2811*4882a593Smuzhiyun }
2812*4882a593Smuzhiyun }
2813*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba * hisi_hba)2814*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba)
2815*4882a593Smuzhiyun {
2816*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
2817*4882a593Smuzhiyun int max_command_entries = HISI_SAS_MAX_COMMANDS;
2818*4882a593Smuzhiyun void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache;
2819*4882a593Smuzhiyun void *databuf = hisi_hba->debugfs_iost[dump_index].iost;
2820*4882a593Smuzhiyun struct hisi_sas_iost *iost;
2821*4882a593Smuzhiyun int i;
2822*4882a593Smuzhiyun
2823*4882a593Smuzhiyun hisi_hba->hw->read_iost_itct_cache(hisi_hba, HISI_SAS_IOST_CACHE,
2824*4882a593Smuzhiyun cachebuf);
2825*4882a593Smuzhiyun
2826*4882a593Smuzhiyun iost = hisi_hba->iost;
2827*4882a593Smuzhiyun
2828*4882a593Smuzhiyun for (i = 0; i < max_command_entries; i++, iost++) {
2829*4882a593Smuzhiyun memcpy(databuf, iost, sizeof(struct hisi_sas_iost));
2830*4882a593Smuzhiyun databuf += sizeof(struct hisi_sas_iost);
2831*4882a593Smuzhiyun }
2832*4882a593Smuzhiyun }
2833*4882a593Smuzhiyun
2834*4882a593Smuzhiyun static const char *
hisi_sas_debugfs_to_reg_name(int off,int base_off,const struct hisi_sas_debugfs_reg_lu * lu)2835*4882a593Smuzhiyun hisi_sas_debugfs_to_reg_name(int off, int base_off,
2836*4882a593Smuzhiyun const struct hisi_sas_debugfs_reg_lu *lu)
2837*4882a593Smuzhiyun {
2838*4882a593Smuzhiyun for (; lu->name; lu++) {
2839*4882a593Smuzhiyun if (off == lu->off - base_off)
2840*4882a593Smuzhiyun return lu->name;
2841*4882a593Smuzhiyun }
2842*4882a593Smuzhiyun
2843*4882a593Smuzhiyun return NULL;
2844*4882a593Smuzhiyun }
2845*4882a593Smuzhiyun
hisi_sas_debugfs_print_reg(u32 * regs_val,const void * ptr,struct seq_file * s)2846*4882a593Smuzhiyun static void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr,
2847*4882a593Smuzhiyun struct seq_file *s)
2848*4882a593Smuzhiyun {
2849*4882a593Smuzhiyun const struct hisi_sas_debugfs_reg *reg = ptr;
2850*4882a593Smuzhiyun int i;
2851*4882a593Smuzhiyun
2852*4882a593Smuzhiyun for (i = 0; i < reg->count; i++) {
2853*4882a593Smuzhiyun int off = i * 4;
2854*4882a593Smuzhiyun const char *name;
2855*4882a593Smuzhiyun
2856*4882a593Smuzhiyun name = hisi_sas_debugfs_to_reg_name(off, reg->base_off,
2857*4882a593Smuzhiyun reg->lu);
2858*4882a593Smuzhiyun
2859*4882a593Smuzhiyun if (name)
2860*4882a593Smuzhiyun seq_printf(s, "0x%08x 0x%08x %s\n", off,
2861*4882a593Smuzhiyun regs_val[i], name);
2862*4882a593Smuzhiyun else
2863*4882a593Smuzhiyun seq_printf(s, "0x%08x 0x%08x\n", off,
2864*4882a593Smuzhiyun regs_val[i]);
2865*4882a593Smuzhiyun }
2866*4882a593Smuzhiyun }
2867*4882a593Smuzhiyun
hisi_sas_debugfs_global_show(struct seq_file * s,void * p)2868*4882a593Smuzhiyun static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p)
2869*4882a593Smuzhiyun {
2870*4882a593Smuzhiyun struct hisi_sas_debugfs_regs *global = s->private;
2871*4882a593Smuzhiyun struct hisi_hba *hisi_hba = global->hisi_hba;
2872*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
2873*4882a593Smuzhiyun const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL];
2874*4882a593Smuzhiyun
2875*4882a593Smuzhiyun hisi_sas_debugfs_print_reg(global->data,
2876*4882a593Smuzhiyun reg_global, s);
2877*4882a593Smuzhiyun
2878*4882a593Smuzhiyun return 0;
2879*4882a593Smuzhiyun }
2880*4882a593Smuzhiyun
hisi_sas_debugfs_global_open(struct inode * inode,struct file * filp)2881*4882a593Smuzhiyun static int hisi_sas_debugfs_global_open(struct inode *inode, struct file *filp)
2882*4882a593Smuzhiyun {
2883*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_global_show,
2884*4882a593Smuzhiyun inode->i_private);
2885*4882a593Smuzhiyun }
2886*4882a593Smuzhiyun
2887*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_global_fops = {
2888*4882a593Smuzhiyun .open = hisi_sas_debugfs_global_open,
2889*4882a593Smuzhiyun .read = seq_read,
2890*4882a593Smuzhiyun .llseek = seq_lseek,
2891*4882a593Smuzhiyun .release = single_release,
2892*4882a593Smuzhiyun .owner = THIS_MODULE,
2893*4882a593Smuzhiyun };
2894*4882a593Smuzhiyun
hisi_sas_debugfs_axi_show(struct seq_file * s,void * p)2895*4882a593Smuzhiyun static int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p)
2896*4882a593Smuzhiyun {
2897*4882a593Smuzhiyun struct hisi_sas_debugfs_regs *axi = s->private;
2898*4882a593Smuzhiyun struct hisi_hba *hisi_hba = axi->hisi_hba;
2899*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
2900*4882a593Smuzhiyun const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI];
2901*4882a593Smuzhiyun
2902*4882a593Smuzhiyun hisi_sas_debugfs_print_reg(axi->data,
2903*4882a593Smuzhiyun reg_axi, s);
2904*4882a593Smuzhiyun
2905*4882a593Smuzhiyun return 0;
2906*4882a593Smuzhiyun }
2907*4882a593Smuzhiyun
hisi_sas_debugfs_axi_open(struct inode * inode,struct file * filp)2908*4882a593Smuzhiyun static int hisi_sas_debugfs_axi_open(struct inode *inode, struct file *filp)
2909*4882a593Smuzhiyun {
2910*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_axi_show,
2911*4882a593Smuzhiyun inode->i_private);
2912*4882a593Smuzhiyun }
2913*4882a593Smuzhiyun
2914*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_axi_fops = {
2915*4882a593Smuzhiyun .open = hisi_sas_debugfs_axi_open,
2916*4882a593Smuzhiyun .read = seq_read,
2917*4882a593Smuzhiyun .llseek = seq_lseek,
2918*4882a593Smuzhiyun .release = single_release,
2919*4882a593Smuzhiyun .owner = THIS_MODULE,
2920*4882a593Smuzhiyun };
2921*4882a593Smuzhiyun
hisi_sas_debugfs_ras_show(struct seq_file * s,void * p)2922*4882a593Smuzhiyun static int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p)
2923*4882a593Smuzhiyun {
2924*4882a593Smuzhiyun struct hisi_sas_debugfs_regs *ras = s->private;
2925*4882a593Smuzhiyun struct hisi_hba *hisi_hba = ras->hisi_hba;
2926*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
2927*4882a593Smuzhiyun const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS];
2928*4882a593Smuzhiyun
2929*4882a593Smuzhiyun hisi_sas_debugfs_print_reg(ras->data,
2930*4882a593Smuzhiyun reg_ras, s);
2931*4882a593Smuzhiyun
2932*4882a593Smuzhiyun return 0;
2933*4882a593Smuzhiyun }
2934*4882a593Smuzhiyun
hisi_sas_debugfs_ras_open(struct inode * inode,struct file * filp)2935*4882a593Smuzhiyun static int hisi_sas_debugfs_ras_open(struct inode *inode, struct file *filp)
2936*4882a593Smuzhiyun {
2937*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_ras_show,
2938*4882a593Smuzhiyun inode->i_private);
2939*4882a593Smuzhiyun }
2940*4882a593Smuzhiyun
2941*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_ras_fops = {
2942*4882a593Smuzhiyun .open = hisi_sas_debugfs_ras_open,
2943*4882a593Smuzhiyun .read = seq_read,
2944*4882a593Smuzhiyun .llseek = seq_lseek,
2945*4882a593Smuzhiyun .release = single_release,
2946*4882a593Smuzhiyun .owner = THIS_MODULE,
2947*4882a593Smuzhiyun };
2948*4882a593Smuzhiyun
hisi_sas_debugfs_port_show(struct seq_file * s,void * p)2949*4882a593Smuzhiyun static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p)
2950*4882a593Smuzhiyun {
2951*4882a593Smuzhiyun struct hisi_sas_debugfs_port *port = s->private;
2952*4882a593Smuzhiyun struct hisi_sas_phy *phy = port->phy;
2953*4882a593Smuzhiyun struct hisi_hba *hisi_hba = phy->hisi_hba;
2954*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
2955*4882a593Smuzhiyun const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port;
2956*4882a593Smuzhiyun
2957*4882a593Smuzhiyun hisi_sas_debugfs_print_reg(port->data, reg_port, s);
2958*4882a593Smuzhiyun
2959*4882a593Smuzhiyun return 0;
2960*4882a593Smuzhiyun }
2961*4882a593Smuzhiyun
hisi_sas_debugfs_port_open(struct inode * inode,struct file * filp)2962*4882a593Smuzhiyun static int hisi_sas_debugfs_port_open(struct inode *inode, struct file *filp)
2963*4882a593Smuzhiyun {
2964*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_port_show, inode->i_private);
2965*4882a593Smuzhiyun }
2966*4882a593Smuzhiyun
2967*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_port_fops = {
2968*4882a593Smuzhiyun .open = hisi_sas_debugfs_port_open,
2969*4882a593Smuzhiyun .read = seq_read,
2970*4882a593Smuzhiyun .llseek = seq_lseek,
2971*4882a593Smuzhiyun .release = single_release,
2972*4882a593Smuzhiyun .owner = THIS_MODULE,
2973*4882a593Smuzhiyun };
2974*4882a593Smuzhiyun
hisi_sas_show_row_64(struct seq_file * s,int index,int sz,__le64 * ptr)2975*4882a593Smuzhiyun static void hisi_sas_show_row_64(struct seq_file *s, int index,
2976*4882a593Smuzhiyun int sz, __le64 *ptr)
2977*4882a593Smuzhiyun {
2978*4882a593Smuzhiyun int i;
2979*4882a593Smuzhiyun
2980*4882a593Smuzhiyun /* completion header size not fixed per HW version */
2981*4882a593Smuzhiyun seq_printf(s, "index %04d:\n\t", index);
2982*4882a593Smuzhiyun for (i = 1; i <= sz / 8; i++, ptr++) {
2983*4882a593Smuzhiyun seq_printf(s, " 0x%016llx", le64_to_cpu(*ptr));
2984*4882a593Smuzhiyun if (!(i % 2))
2985*4882a593Smuzhiyun seq_puts(s, "\n\t");
2986*4882a593Smuzhiyun }
2987*4882a593Smuzhiyun
2988*4882a593Smuzhiyun seq_puts(s, "\n");
2989*4882a593Smuzhiyun }
2990*4882a593Smuzhiyun
hisi_sas_show_row_32(struct seq_file * s,int index,int sz,__le32 * ptr)2991*4882a593Smuzhiyun static void hisi_sas_show_row_32(struct seq_file *s, int index,
2992*4882a593Smuzhiyun int sz, __le32 *ptr)
2993*4882a593Smuzhiyun {
2994*4882a593Smuzhiyun int i;
2995*4882a593Smuzhiyun
2996*4882a593Smuzhiyun /* completion header size not fixed per HW version */
2997*4882a593Smuzhiyun seq_printf(s, "index %04d:\n\t", index);
2998*4882a593Smuzhiyun for (i = 1; i <= sz / 4; i++, ptr++) {
2999*4882a593Smuzhiyun seq_printf(s, " 0x%08x", le32_to_cpu(*ptr));
3000*4882a593Smuzhiyun if (!(i % 4))
3001*4882a593Smuzhiyun seq_puts(s, "\n\t");
3002*4882a593Smuzhiyun }
3003*4882a593Smuzhiyun seq_puts(s, "\n");
3004*4882a593Smuzhiyun }
3005*4882a593Smuzhiyun
hisi_sas_cq_show_slot(struct seq_file * s,int slot,struct hisi_sas_debugfs_cq * debugfs_cq)3006*4882a593Smuzhiyun static void hisi_sas_cq_show_slot(struct seq_file *s, int slot,
3007*4882a593Smuzhiyun struct hisi_sas_debugfs_cq *debugfs_cq)
3008*4882a593Smuzhiyun {
3009*4882a593Smuzhiyun struct hisi_sas_cq *cq = debugfs_cq->cq;
3010*4882a593Smuzhiyun struct hisi_hba *hisi_hba = cq->hisi_hba;
3011*4882a593Smuzhiyun __le32 *complete_hdr = debugfs_cq->complete_hdr +
3012*4882a593Smuzhiyun (hisi_hba->hw->complete_hdr_size * slot);
3013*4882a593Smuzhiyun
3014*4882a593Smuzhiyun hisi_sas_show_row_32(s, slot,
3015*4882a593Smuzhiyun hisi_hba->hw->complete_hdr_size,
3016*4882a593Smuzhiyun complete_hdr);
3017*4882a593Smuzhiyun }
3018*4882a593Smuzhiyun
hisi_sas_debugfs_cq_show(struct seq_file * s,void * p)3019*4882a593Smuzhiyun static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p)
3020*4882a593Smuzhiyun {
3021*4882a593Smuzhiyun struct hisi_sas_debugfs_cq *debugfs_cq = s->private;
3022*4882a593Smuzhiyun int slot;
3023*4882a593Smuzhiyun
3024*4882a593Smuzhiyun for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) {
3025*4882a593Smuzhiyun hisi_sas_cq_show_slot(s, slot, debugfs_cq);
3026*4882a593Smuzhiyun }
3027*4882a593Smuzhiyun return 0;
3028*4882a593Smuzhiyun }
3029*4882a593Smuzhiyun
hisi_sas_debugfs_cq_open(struct inode * inode,struct file * filp)3030*4882a593Smuzhiyun static int hisi_sas_debugfs_cq_open(struct inode *inode, struct file *filp)
3031*4882a593Smuzhiyun {
3032*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_cq_show, inode->i_private);
3033*4882a593Smuzhiyun }
3034*4882a593Smuzhiyun
3035*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_cq_fops = {
3036*4882a593Smuzhiyun .open = hisi_sas_debugfs_cq_open,
3037*4882a593Smuzhiyun .read = seq_read,
3038*4882a593Smuzhiyun .llseek = seq_lseek,
3039*4882a593Smuzhiyun .release = single_release,
3040*4882a593Smuzhiyun .owner = THIS_MODULE,
3041*4882a593Smuzhiyun };
3042*4882a593Smuzhiyun
hisi_sas_dq_show_slot(struct seq_file * s,int slot,void * dq_ptr)3043*4882a593Smuzhiyun static void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr)
3044*4882a593Smuzhiyun {
3045*4882a593Smuzhiyun struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr;
3046*4882a593Smuzhiyun void *cmd_queue = debugfs_dq->hdr;
3047*4882a593Smuzhiyun __le32 *cmd_hdr = cmd_queue +
3048*4882a593Smuzhiyun sizeof(struct hisi_sas_cmd_hdr) * slot;
3049*4882a593Smuzhiyun
3050*4882a593Smuzhiyun hisi_sas_show_row_32(s, slot, sizeof(struct hisi_sas_cmd_hdr), cmd_hdr);
3051*4882a593Smuzhiyun }
3052*4882a593Smuzhiyun
hisi_sas_debugfs_dq_show(struct seq_file * s,void * p)3053*4882a593Smuzhiyun static int hisi_sas_debugfs_dq_show(struct seq_file *s, void *p)
3054*4882a593Smuzhiyun {
3055*4882a593Smuzhiyun int slot;
3056*4882a593Smuzhiyun
3057*4882a593Smuzhiyun for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) {
3058*4882a593Smuzhiyun hisi_sas_dq_show_slot(s, slot, s->private);
3059*4882a593Smuzhiyun }
3060*4882a593Smuzhiyun return 0;
3061*4882a593Smuzhiyun }
3062*4882a593Smuzhiyun
hisi_sas_debugfs_dq_open(struct inode * inode,struct file * filp)3063*4882a593Smuzhiyun static int hisi_sas_debugfs_dq_open(struct inode *inode, struct file *filp)
3064*4882a593Smuzhiyun {
3065*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_dq_show, inode->i_private);
3066*4882a593Smuzhiyun }
3067*4882a593Smuzhiyun
3068*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_dq_fops = {
3069*4882a593Smuzhiyun .open = hisi_sas_debugfs_dq_open,
3070*4882a593Smuzhiyun .read = seq_read,
3071*4882a593Smuzhiyun .llseek = seq_lseek,
3072*4882a593Smuzhiyun .release = single_release,
3073*4882a593Smuzhiyun .owner = THIS_MODULE,
3074*4882a593Smuzhiyun };
3075*4882a593Smuzhiyun
hisi_sas_debugfs_iost_show(struct seq_file * s,void * p)3076*4882a593Smuzhiyun static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p)
3077*4882a593Smuzhiyun {
3078*4882a593Smuzhiyun struct hisi_sas_debugfs_iost *debugfs_iost = s->private;
3079*4882a593Smuzhiyun struct hisi_sas_iost *iost = debugfs_iost->iost;
3080*4882a593Smuzhiyun int i, max_command_entries = HISI_SAS_MAX_COMMANDS;
3081*4882a593Smuzhiyun
3082*4882a593Smuzhiyun for (i = 0; i < max_command_entries; i++, iost++) {
3083*4882a593Smuzhiyun __le64 *data = &iost->qw0;
3084*4882a593Smuzhiyun
3085*4882a593Smuzhiyun hisi_sas_show_row_64(s, i, sizeof(*iost), data);
3086*4882a593Smuzhiyun }
3087*4882a593Smuzhiyun
3088*4882a593Smuzhiyun return 0;
3089*4882a593Smuzhiyun }
3090*4882a593Smuzhiyun
hisi_sas_debugfs_iost_open(struct inode * inode,struct file * filp)3091*4882a593Smuzhiyun static int hisi_sas_debugfs_iost_open(struct inode *inode, struct file *filp)
3092*4882a593Smuzhiyun {
3093*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_iost_show, inode->i_private);
3094*4882a593Smuzhiyun }
3095*4882a593Smuzhiyun
3096*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_iost_fops = {
3097*4882a593Smuzhiyun .open = hisi_sas_debugfs_iost_open,
3098*4882a593Smuzhiyun .read = seq_read,
3099*4882a593Smuzhiyun .llseek = seq_lseek,
3100*4882a593Smuzhiyun .release = single_release,
3101*4882a593Smuzhiyun .owner = THIS_MODULE,
3102*4882a593Smuzhiyun };
3103*4882a593Smuzhiyun
hisi_sas_debugfs_iost_cache_show(struct seq_file * s,void * p)3104*4882a593Smuzhiyun static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p)
3105*4882a593Smuzhiyun {
3106*4882a593Smuzhiyun struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private;
3107*4882a593Smuzhiyun struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->cache;
3108*4882a593Smuzhiyun u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
3109*4882a593Smuzhiyun int i, tab_idx;
3110*4882a593Smuzhiyun __le64 *iost;
3111*4882a593Smuzhiyun
3112*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, iost_cache++) {
3113*4882a593Smuzhiyun /*
3114*4882a593Smuzhiyun * Data struct of IOST cache:
3115*4882a593Smuzhiyun * Data[1]: BIT0~15: Table index
3116*4882a593Smuzhiyun * Bit16: Valid mask
3117*4882a593Smuzhiyun * Data[2]~[9]: IOST table
3118*4882a593Smuzhiyun */
3119*4882a593Smuzhiyun tab_idx = (iost_cache->data[1] & 0xffff);
3120*4882a593Smuzhiyun iost = (__le64 *)iost_cache;
3121*4882a593Smuzhiyun
3122*4882a593Smuzhiyun hisi_sas_show_row_64(s, tab_idx, cache_size, iost);
3123*4882a593Smuzhiyun }
3124*4882a593Smuzhiyun
3125*4882a593Smuzhiyun return 0;
3126*4882a593Smuzhiyun }
3127*4882a593Smuzhiyun
hisi_sas_debugfs_iost_cache_open(struct inode * inode,struct file * filp)3128*4882a593Smuzhiyun static int hisi_sas_debugfs_iost_cache_open(struct inode *inode,
3129*4882a593Smuzhiyun struct file *filp)
3130*4882a593Smuzhiyun {
3131*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_iost_cache_show,
3132*4882a593Smuzhiyun inode->i_private);
3133*4882a593Smuzhiyun }
3134*4882a593Smuzhiyun
3135*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_iost_cache_fops = {
3136*4882a593Smuzhiyun .open = hisi_sas_debugfs_iost_cache_open,
3137*4882a593Smuzhiyun .read = seq_read,
3138*4882a593Smuzhiyun .llseek = seq_lseek,
3139*4882a593Smuzhiyun .release = single_release,
3140*4882a593Smuzhiyun .owner = THIS_MODULE,
3141*4882a593Smuzhiyun };
3142*4882a593Smuzhiyun
hisi_sas_debugfs_itct_show(struct seq_file * s,void * p)3143*4882a593Smuzhiyun static int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p)
3144*4882a593Smuzhiyun {
3145*4882a593Smuzhiyun int i;
3146*4882a593Smuzhiyun struct hisi_sas_debugfs_itct *debugfs_itct = s->private;
3147*4882a593Smuzhiyun struct hisi_sas_itct *itct = debugfs_itct->itct;
3148*4882a593Smuzhiyun
3149*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) {
3150*4882a593Smuzhiyun __le64 *data = &itct->qw0;
3151*4882a593Smuzhiyun
3152*4882a593Smuzhiyun hisi_sas_show_row_64(s, i, sizeof(*itct), data);
3153*4882a593Smuzhiyun }
3154*4882a593Smuzhiyun
3155*4882a593Smuzhiyun return 0;
3156*4882a593Smuzhiyun }
3157*4882a593Smuzhiyun
hisi_sas_debugfs_itct_open(struct inode * inode,struct file * filp)3158*4882a593Smuzhiyun static int hisi_sas_debugfs_itct_open(struct inode *inode, struct file *filp)
3159*4882a593Smuzhiyun {
3160*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_itct_show, inode->i_private);
3161*4882a593Smuzhiyun }
3162*4882a593Smuzhiyun
3163*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_itct_fops = {
3164*4882a593Smuzhiyun .open = hisi_sas_debugfs_itct_open,
3165*4882a593Smuzhiyun .read = seq_read,
3166*4882a593Smuzhiyun .llseek = seq_lseek,
3167*4882a593Smuzhiyun .release = single_release,
3168*4882a593Smuzhiyun .owner = THIS_MODULE,
3169*4882a593Smuzhiyun };
3170*4882a593Smuzhiyun
hisi_sas_debugfs_itct_cache_show(struct seq_file * s,void * p)3171*4882a593Smuzhiyun static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p)
3172*4882a593Smuzhiyun {
3173*4882a593Smuzhiyun struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private;
3174*4882a593Smuzhiyun struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->cache;
3175*4882a593Smuzhiyun u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4;
3176*4882a593Smuzhiyun int i, tab_idx;
3177*4882a593Smuzhiyun __le64 *itct;
3178*4882a593Smuzhiyun
3179*4882a593Smuzhiyun for (i = 0; i < HISI_SAS_IOST_ITCT_CACHE_NUM; i++, itct_cache++) {
3180*4882a593Smuzhiyun /*
3181*4882a593Smuzhiyun * Data struct of ITCT cache:
3182*4882a593Smuzhiyun * Data[1]: BIT0~15: Table index
3183*4882a593Smuzhiyun * Bit16: Valid mask
3184*4882a593Smuzhiyun * Data[2]~[9]: ITCT table
3185*4882a593Smuzhiyun */
3186*4882a593Smuzhiyun tab_idx = itct_cache->data[1] & 0xffff;
3187*4882a593Smuzhiyun itct = (__le64 *)itct_cache;
3188*4882a593Smuzhiyun
3189*4882a593Smuzhiyun hisi_sas_show_row_64(s, tab_idx, cache_size, itct);
3190*4882a593Smuzhiyun }
3191*4882a593Smuzhiyun
3192*4882a593Smuzhiyun return 0;
3193*4882a593Smuzhiyun }
3194*4882a593Smuzhiyun
hisi_sas_debugfs_itct_cache_open(struct inode * inode,struct file * filp)3195*4882a593Smuzhiyun static int hisi_sas_debugfs_itct_cache_open(struct inode *inode,
3196*4882a593Smuzhiyun struct file *filp)
3197*4882a593Smuzhiyun {
3198*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_itct_cache_show,
3199*4882a593Smuzhiyun inode->i_private);
3200*4882a593Smuzhiyun }
3201*4882a593Smuzhiyun
3202*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_itct_cache_fops = {
3203*4882a593Smuzhiyun .open = hisi_sas_debugfs_itct_cache_open,
3204*4882a593Smuzhiyun .read = seq_read,
3205*4882a593Smuzhiyun .llseek = seq_lseek,
3206*4882a593Smuzhiyun .release = single_release,
3207*4882a593Smuzhiyun .owner = THIS_MODULE,
3208*4882a593Smuzhiyun };
3209*4882a593Smuzhiyun
hisi_sas_debugfs_create_files(struct hisi_hba * hisi_hba)3210*4882a593Smuzhiyun static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba)
3211*4882a593Smuzhiyun {
3212*4882a593Smuzhiyun u64 *debugfs_timestamp;
3213*4882a593Smuzhiyun int dump_index = hisi_hba->debugfs_dump_index;
3214*4882a593Smuzhiyun struct dentry *dump_dentry;
3215*4882a593Smuzhiyun struct dentry *dentry;
3216*4882a593Smuzhiyun char name[256];
3217*4882a593Smuzhiyun int p;
3218*4882a593Smuzhiyun int c;
3219*4882a593Smuzhiyun int d;
3220*4882a593Smuzhiyun
3221*4882a593Smuzhiyun snprintf(name, 256, "%d", dump_index);
3222*4882a593Smuzhiyun
3223*4882a593Smuzhiyun dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry);
3224*4882a593Smuzhiyun
3225*4882a593Smuzhiyun debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index];
3226*4882a593Smuzhiyun
3227*4882a593Smuzhiyun debugfs_create_u64("timestamp", 0400, dump_dentry,
3228*4882a593Smuzhiyun debugfs_timestamp);
3229*4882a593Smuzhiyun
3230*4882a593Smuzhiyun debugfs_create_file("global", 0400, dump_dentry,
3231*4882a593Smuzhiyun &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL],
3232*4882a593Smuzhiyun &hisi_sas_debugfs_global_fops);
3233*4882a593Smuzhiyun
3234*4882a593Smuzhiyun /* Create port dir and files */
3235*4882a593Smuzhiyun dentry = debugfs_create_dir("port", dump_dentry);
3236*4882a593Smuzhiyun for (p = 0; p < hisi_hba->n_phy; p++) {
3237*4882a593Smuzhiyun snprintf(name, 256, "%d", p);
3238*4882a593Smuzhiyun
3239*4882a593Smuzhiyun debugfs_create_file(name, 0400, dentry,
3240*4882a593Smuzhiyun &hisi_hba->debugfs_port_reg[dump_index][p],
3241*4882a593Smuzhiyun &hisi_sas_debugfs_port_fops);
3242*4882a593Smuzhiyun }
3243*4882a593Smuzhiyun
3244*4882a593Smuzhiyun /* Create CQ dir and files */
3245*4882a593Smuzhiyun dentry = debugfs_create_dir("cq", dump_dentry);
3246*4882a593Smuzhiyun for (c = 0; c < hisi_hba->queue_count; c++) {
3247*4882a593Smuzhiyun snprintf(name, 256, "%d", c);
3248*4882a593Smuzhiyun
3249*4882a593Smuzhiyun debugfs_create_file(name, 0400, dentry,
3250*4882a593Smuzhiyun &hisi_hba->debugfs_cq[dump_index][c],
3251*4882a593Smuzhiyun &hisi_sas_debugfs_cq_fops);
3252*4882a593Smuzhiyun }
3253*4882a593Smuzhiyun
3254*4882a593Smuzhiyun /* Create DQ dir and files */
3255*4882a593Smuzhiyun dentry = debugfs_create_dir("dq", dump_dentry);
3256*4882a593Smuzhiyun for (d = 0; d < hisi_hba->queue_count; d++) {
3257*4882a593Smuzhiyun snprintf(name, 256, "%d", d);
3258*4882a593Smuzhiyun
3259*4882a593Smuzhiyun debugfs_create_file(name, 0400, dentry,
3260*4882a593Smuzhiyun &hisi_hba->debugfs_dq[dump_index][d],
3261*4882a593Smuzhiyun &hisi_sas_debugfs_dq_fops);
3262*4882a593Smuzhiyun }
3263*4882a593Smuzhiyun
3264*4882a593Smuzhiyun debugfs_create_file("iost", 0400, dump_dentry,
3265*4882a593Smuzhiyun &hisi_hba->debugfs_iost[dump_index],
3266*4882a593Smuzhiyun &hisi_sas_debugfs_iost_fops);
3267*4882a593Smuzhiyun
3268*4882a593Smuzhiyun debugfs_create_file("iost_cache", 0400, dump_dentry,
3269*4882a593Smuzhiyun &hisi_hba->debugfs_iost_cache[dump_index],
3270*4882a593Smuzhiyun &hisi_sas_debugfs_iost_cache_fops);
3271*4882a593Smuzhiyun
3272*4882a593Smuzhiyun debugfs_create_file("itct", 0400, dump_dentry,
3273*4882a593Smuzhiyun &hisi_hba->debugfs_itct[dump_index],
3274*4882a593Smuzhiyun &hisi_sas_debugfs_itct_fops);
3275*4882a593Smuzhiyun
3276*4882a593Smuzhiyun debugfs_create_file("itct_cache", 0400, dump_dentry,
3277*4882a593Smuzhiyun &hisi_hba->debugfs_itct_cache[dump_index],
3278*4882a593Smuzhiyun &hisi_sas_debugfs_itct_cache_fops);
3279*4882a593Smuzhiyun
3280*4882a593Smuzhiyun debugfs_create_file("axi", 0400, dump_dentry,
3281*4882a593Smuzhiyun &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI],
3282*4882a593Smuzhiyun &hisi_sas_debugfs_axi_fops);
3283*4882a593Smuzhiyun
3284*4882a593Smuzhiyun debugfs_create_file("ras", 0400, dump_dentry,
3285*4882a593Smuzhiyun &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS],
3286*4882a593Smuzhiyun &hisi_sas_debugfs_ras_fops);
3287*4882a593Smuzhiyun
3288*4882a593Smuzhiyun return;
3289*4882a593Smuzhiyun }
3290*4882a593Smuzhiyun
hisi_sas_debugfs_snapshot_regs(struct hisi_hba * hisi_hba)3291*4882a593Smuzhiyun static void hisi_sas_debugfs_snapshot_regs(struct hisi_hba *hisi_hba)
3292*4882a593Smuzhiyun {
3293*4882a593Smuzhiyun hisi_hba->hw->snapshot_prepare(hisi_hba);
3294*4882a593Smuzhiyun
3295*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_global_reg(hisi_hba);
3296*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_port_reg(hisi_hba);
3297*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_axi_reg(hisi_hba);
3298*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_ras_reg(hisi_hba);
3299*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_cq_reg(hisi_hba);
3300*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_dq_reg(hisi_hba);
3301*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_itct_reg(hisi_hba);
3302*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_iost_reg(hisi_hba);
3303*4882a593Smuzhiyun
3304*4882a593Smuzhiyun hisi_sas_debugfs_create_files(hisi_hba);
3305*4882a593Smuzhiyun
3306*4882a593Smuzhiyun hisi_hba->hw->snapshot_restore(hisi_hba);
3307*4882a593Smuzhiyun }
3308*4882a593Smuzhiyun
hisi_sas_debugfs_trigger_dump_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)3309*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_trigger_dump_write(struct file *file,
3310*4882a593Smuzhiyun const char __user *user_buf,
3311*4882a593Smuzhiyun size_t count, loff_t *ppos)
3312*4882a593Smuzhiyun {
3313*4882a593Smuzhiyun struct hisi_hba *hisi_hba = file->f_inode->i_private;
3314*4882a593Smuzhiyun char buf[8];
3315*4882a593Smuzhiyun
3316*4882a593Smuzhiyun if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count)
3317*4882a593Smuzhiyun return -EFAULT;
3318*4882a593Smuzhiyun
3319*4882a593Smuzhiyun if (count > 8)
3320*4882a593Smuzhiyun return -EFAULT;
3321*4882a593Smuzhiyun
3322*4882a593Smuzhiyun if (copy_from_user(buf, user_buf, count))
3323*4882a593Smuzhiyun return -EFAULT;
3324*4882a593Smuzhiyun
3325*4882a593Smuzhiyun if (buf[0] != '1')
3326*4882a593Smuzhiyun return -EFAULT;
3327*4882a593Smuzhiyun
3328*4882a593Smuzhiyun queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);
3329*4882a593Smuzhiyun
3330*4882a593Smuzhiyun return count;
3331*4882a593Smuzhiyun }
3332*4882a593Smuzhiyun
3333*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_trigger_dump_fops = {
3334*4882a593Smuzhiyun .write = &hisi_sas_debugfs_trigger_dump_write,
3335*4882a593Smuzhiyun .owner = THIS_MODULE,
3336*4882a593Smuzhiyun };
3337*4882a593Smuzhiyun
3338*4882a593Smuzhiyun enum {
3339*4882a593Smuzhiyun HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL = 0,
3340*4882a593Smuzhiyun HISI_SAS_BIST_LOOPBACK_MODE_SERDES,
3341*4882a593Smuzhiyun HISI_SAS_BIST_LOOPBACK_MODE_REMOTE,
3342*4882a593Smuzhiyun };
3343*4882a593Smuzhiyun
3344*4882a593Smuzhiyun static const struct {
3345*4882a593Smuzhiyun int value;
3346*4882a593Smuzhiyun char *name;
3347*4882a593Smuzhiyun } hisi_sas_debugfs_loop_linkrate[] = {
3348*4882a593Smuzhiyun { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" },
3349*4882a593Smuzhiyun { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" },
3350*4882a593Smuzhiyun { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" },
3351*4882a593Smuzhiyun { SAS_LINK_RATE_12_0_GBPS, "12.0 Gbit" },
3352*4882a593Smuzhiyun };
3353*4882a593Smuzhiyun
hisi_sas_debugfs_bist_linkrate_show(struct seq_file * s,void * p)3354*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_linkrate_show(struct seq_file *s, void *p)
3355*4882a593Smuzhiyun {
3356*4882a593Smuzhiyun struct hisi_hba *hisi_hba = s->private;
3357*4882a593Smuzhiyun int i;
3358*4882a593Smuzhiyun
3359*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) {
3360*4882a593Smuzhiyun int match = (hisi_hba->debugfs_bist_linkrate ==
3361*4882a593Smuzhiyun hisi_sas_debugfs_loop_linkrate[i].value);
3362*4882a593Smuzhiyun
3363*4882a593Smuzhiyun seq_printf(s, "%s%s%s ", match ? "[" : "",
3364*4882a593Smuzhiyun hisi_sas_debugfs_loop_linkrate[i].name,
3365*4882a593Smuzhiyun match ? "]" : "");
3366*4882a593Smuzhiyun }
3367*4882a593Smuzhiyun seq_puts(s, "\n");
3368*4882a593Smuzhiyun
3369*4882a593Smuzhiyun return 0;
3370*4882a593Smuzhiyun }
3371*4882a593Smuzhiyun
hisi_sas_debugfs_bist_linkrate_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)3372*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_bist_linkrate_write(struct file *filp,
3373*4882a593Smuzhiyun const char __user *buf,
3374*4882a593Smuzhiyun size_t count, loff_t *ppos)
3375*4882a593Smuzhiyun {
3376*4882a593Smuzhiyun struct seq_file *m = filp->private_data;
3377*4882a593Smuzhiyun struct hisi_hba *hisi_hba = m->private;
3378*4882a593Smuzhiyun char kbuf[16] = {}, *pkbuf;
3379*4882a593Smuzhiyun bool found = false;
3380*4882a593Smuzhiyun int i;
3381*4882a593Smuzhiyun
3382*4882a593Smuzhiyun if (hisi_hba->debugfs_bist_enable)
3383*4882a593Smuzhiyun return -EPERM;
3384*4882a593Smuzhiyun
3385*4882a593Smuzhiyun if (count >= sizeof(kbuf))
3386*4882a593Smuzhiyun return -EOVERFLOW;
3387*4882a593Smuzhiyun
3388*4882a593Smuzhiyun if (copy_from_user(kbuf, buf, count))
3389*4882a593Smuzhiyun return -EINVAL;
3390*4882a593Smuzhiyun
3391*4882a593Smuzhiyun pkbuf = strstrip(kbuf);
3392*4882a593Smuzhiyun
3393*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_linkrate); i++) {
3394*4882a593Smuzhiyun if (!strncmp(hisi_sas_debugfs_loop_linkrate[i].name,
3395*4882a593Smuzhiyun pkbuf, 16)) {
3396*4882a593Smuzhiyun hisi_hba->debugfs_bist_linkrate =
3397*4882a593Smuzhiyun hisi_sas_debugfs_loop_linkrate[i].value;
3398*4882a593Smuzhiyun found = true;
3399*4882a593Smuzhiyun break;
3400*4882a593Smuzhiyun }
3401*4882a593Smuzhiyun }
3402*4882a593Smuzhiyun
3403*4882a593Smuzhiyun if (!found)
3404*4882a593Smuzhiyun return -EINVAL;
3405*4882a593Smuzhiyun
3406*4882a593Smuzhiyun return count;
3407*4882a593Smuzhiyun }
3408*4882a593Smuzhiyun
hisi_sas_debugfs_bist_linkrate_open(struct inode * inode,struct file * filp)3409*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_linkrate_open(struct inode *inode,
3410*4882a593Smuzhiyun struct file *filp)
3411*4882a593Smuzhiyun {
3412*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_bist_linkrate_show,
3413*4882a593Smuzhiyun inode->i_private);
3414*4882a593Smuzhiyun }
3415*4882a593Smuzhiyun
3416*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_bist_linkrate_ops = {
3417*4882a593Smuzhiyun .open = hisi_sas_debugfs_bist_linkrate_open,
3418*4882a593Smuzhiyun .read = seq_read,
3419*4882a593Smuzhiyun .write = hisi_sas_debugfs_bist_linkrate_write,
3420*4882a593Smuzhiyun .llseek = seq_lseek,
3421*4882a593Smuzhiyun .release = single_release,
3422*4882a593Smuzhiyun .owner = THIS_MODULE,
3423*4882a593Smuzhiyun };
3424*4882a593Smuzhiyun
3425*4882a593Smuzhiyun static const struct {
3426*4882a593Smuzhiyun int value;
3427*4882a593Smuzhiyun char *name;
3428*4882a593Smuzhiyun } hisi_sas_debugfs_loop_code_mode[] = {
3429*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_PRBS7, "PRBS7" },
3430*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_PRBS23, "PRBS23" },
3431*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_PRBS31, "PRBS31" },
3432*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_JTPAT, "JTPAT" },
3433*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_CJTPAT, "CJTPAT" },
3434*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_SCRAMBED_0, "SCRAMBED_0" },
3435*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_TRAIN, "TRAIN" },
3436*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_TRAIN_DONE, "TRAIN_DONE" },
3437*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_HFTP, "HFTP" },
3438*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_MFTP, "MFTP" },
3439*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_LFTP, "LFTP" },
3440*4882a593Smuzhiyun { HISI_SAS_BIST_CODE_MODE_FIXED_DATA, "FIXED_DATA" },
3441*4882a593Smuzhiyun };
3442*4882a593Smuzhiyun
hisi_sas_debugfs_bist_code_mode_show(struct seq_file * s,void * p)3443*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_code_mode_show(struct seq_file *s, void *p)
3444*4882a593Smuzhiyun {
3445*4882a593Smuzhiyun struct hisi_hba *hisi_hba = s->private;
3446*4882a593Smuzhiyun int i;
3447*4882a593Smuzhiyun
3448*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) {
3449*4882a593Smuzhiyun int match = (hisi_hba->debugfs_bist_code_mode ==
3450*4882a593Smuzhiyun hisi_sas_debugfs_loop_code_mode[i].value);
3451*4882a593Smuzhiyun
3452*4882a593Smuzhiyun seq_printf(s, "%s%s%s ", match ? "[" : "",
3453*4882a593Smuzhiyun hisi_sas_debugfs_loop_code_mode[i].name,
3454*4882a593Smuzhiyun match ? "]" : "");
3455*4882a593Smuzhiyun }
3456*4882a593Smuzhiyun seq_puts(s, "\n");
3457*4882a593Smuzhiyun
3458*4882a593Smuzhiyun return 0;
3459*4882a593Smuzhiyun }
3460*4882a593Smuzhiyun
hisi_sas_debugfs_bist_code_mode_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)3461*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_bist_code_mode_write(struct file *filp,
3462*4882a593Smuzhiyun const char __user *buf,
3463*4882a593Smuzhiyun size_t count,
3464*4882a593Smuzhiyun loff_t *ppos)
3465*4882a593Smuzhiyun {
3466*4882a593Smuzhiyun struct seq_file *m = filp->private_data;
3467*4882a593Smuzhiyun struct hisi_hba *hisi_hba = m->private;
3468*4882a593Smuzhiyun char kbuf[16] = {}, *pkbuf;
3469*4882a593Smuzhiyun bool found = false;
3470*4882a593Smuzhiyun int i;
3471*4882a593Smuzhiyun
3472*4882a593Smuzhiyun if (hisi_hba->debugfs_bist_enable)
3473*4882a593Smuzhiyun return -EPERM;
3474*4882a593Smuzhiyun
3475*4882a593Smuzhiyun if (count >= sizeof(kbuf))
3476*4882a593Smuzhiyun return -EINVAL;
3477*4882a593Smuzhiyun
3478*4882a593Smuzhiyun if (copy_from_user(kbuf, buf, count))
3479*4882a593Smuzhiyun return -EOVERFLOW;
3480*4882a593Smuzhiyun
3481*4882a593Smuzhiyun pkbuf = strstrip(kbuf);
3482*4882a593Smuzhiyun
3483*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_code_mode); i++) {
3484*4882a593Smuzhiyun if (!strncmp(hisi_sas_debugfs_loop_code_mode[i].name,
3485*4882a593Smuzhiyun pkbuf, 16)) {
3486*4882a593Smuzhiyun hisi_hba->debugfs_bist_code_mode =
3487*4882a593Smuzhiyun hisi_sas_debugfs_loop_code_mode[i].value;
3488*4882a593Smuzhiyun found = true;
3489*4882a593Smuzhiyun break;
3490*4882a593Smuzhiyun }
3491*4882a593Smuzhiyun }
3492*4882a593Smuzhiyun
3493*4882a593Smuzhiyun if (!found)
3494*4882a593Smuzhiyun return -EINVAL;
3495*4882a593Smuzhiyun
3496*4882a593Smuzhiyun return count;
3497*4882a593Smuzhiyun }
3498*4882a593Smuzhiyun
hisi_sas_debugfs_bist_code_mode_open(struct inode * inode,struct file * filp)3499*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_code_mode_open(struct inode *inode,
3500*4882a593Smuzhiyun struct file *filp)
3501*4882a593Smuzhiyun {
3502*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_bist_code_mode_show,
3503*4882a593Smuzhiyun inode->i_private);
3504*4882a593Smuzhiyun }
3505*4882a593Smuzhiyun
3506*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_bist_code_mode_ops = {
3507*4882a593Smuzhiyun .open = hisi_sas_debugfs_bist_code_mode_open,
3508*4882a593Smuzhiyun .read = seq_read,
3509*4882a593Smuzhiyun .write = hisi_sas_debugfs_bist_code_mode_write,
3510*4882a593Smuzhiyun .llseek = seq_lseek,
3511*4882a593Smuzhiyun .release = single_release,
3512*4882a593Smuzhiyun .owner = THIS_MODULE,
3513*4882a593Smuzhiyun };
3514*4882a593Smuzhiyun
hisi_sas_debugfs_bist_phy_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)3515*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_bist_phy_write(struct file *filp,
3516*4882a593Smuzhiyun const char __user *buf,
3517*4882a593Smuzhiyun size_t count, loff_t *ppos)
3518*4882a593Smuzhiyun {
3519*4882a593Smuzhiyun struct seq_file *m = filp->private_data;
3520*4882a593Smuzhiyun struct hisi_hba *hisi_hba = m->private;
3521*4882a593Smuzhiyun unsigned int phy_no;
3522*4882a593Smuzhiyun int val;
3523*4882a593Smuzhiyun
3524*4882a593Smuzhiyun if (hisi_hba->debugfs_bist_enable)
3525*4882a593Smuzhiyun return -EPERM;
3526*4882a593Smuzhiyun
3527*4882a593Smuzhiyun val = kstrtouint_from_user(buf, count, 0, &phy_no);
3528*4882a593Smuzhiyun if (val)
3529*4882a593Smuzhiyun return val;
3530*4882a593Smuzhiyun
3531*4882a593Smuzhiyun if (phy_no >= hisi_hba->n_phy)
3532*4882a593Smuzhiyun return -EINVAL;
3533*4882a593Smuzhiyun
3534*4882a593Smuzhiyun hisi_hba->debugfs_bist_phy_no = phy_no;
3535*4882a593Smuzhiyun
3536*4882a593Smuzhiyun return count;
3537*4882a593Smuzhiyun }
3538*4882a593Smuzhiyun
hisi_sas_debugfs_bist_phy_show(struct seq_file * s,void * p)3539*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_phy_show(struct seq_file *s, void *p)
3540*4882a593Smuzhiyun {
3541*4882a593Smuzhiyun struct hisi_hba *hisi_hba = s->private;
3542*4882a593Smuzhiyun
3543*4882a593Smuzhiyun seq_printf(s, "%d\n", hisi_hba->debugfs_bist_phy_no);
3544*4882a593Smuzhiyun
3545*4882a593Smuzhiyun return 0;
3546*4882a593Smuzhiyun }
3547*4882a593Smuzhiyun
hisi_sas_debugfs_bist_phy_open(struct inode * inode,struct file * filp)3548*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_phy_open(struct inode *inode,
3549*4882a593Smuzhiyun struct file *filp)
3550*4882a593Smuzhiyun {
3551*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_bist_phy_show,
3552*4882a593Smuzhiyun inode->i_private);
3553*4882a593Smuzhiyun }
3554*4882a593Smuzhiyun
3555*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_bist_phy_ops = {
3556*4882a593Smuzhiyun .open = hisi_sas_debugfs_bist_phy_open,
3557*4882a593Smuzhiyun .read = seq_read,
3558*4882a593Smuzhiyun .write = hisi_sas_debugfs_bist_phy_write,
3559*4882a593Smuzhiyun .llseek = seq_lseek,
3560*4882a593Smuzhiyun .release = single_release,
3561*4882a593Smuzhiyun .owner = THIS_MODULE,
3562*4882a593Smuzhiyun };
3563*4882a593Smuzhiyun
3564*4882a593Smuzhiyun static const struct {
3565*4882a593Smuzhiyun int value;
3566*4882a593Smuzhiyun char *name;
3567*4882a593Smuzhiyun } hisi_sas_debugfs_loop_modes[] = {
3568*4882a593Smuzhiyun { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" },
3569*4882a593Smuzhiyun { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" },
3570*4882a593Smuzhiyun { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" },
3571*4882a593Smuzhiyun };
3572*4882a593Smuzhiyun
hisi_sas_debugfs_bist_mode_show(struct seq_file * s,void * p)3573*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_mode_show(struct seq_file *s, void *p)
3574*4882a593Smuzhiyun {
3575*4882a593Smuzhiyun struct hisi_hba *hisi_hba = s->private;
3576*4882a593Smuzhiyun int i;
3577*4882a593Smuzhiyun
3578*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) {
3579*4882a593Smuzhiyun int match = (hisi_hba->debugfs_bist_mode ==
3580*4882a593Smuzhiyun hisi_sas_debugfs_loop_modes[i].value);
3581*4882a593Smuzhiyun
3582*4882a593Smuzhiyun seq_printf(s, "%s%s%s ", match ? "[" : "",
3583*4882a593Smuzhiyun hisi_sas_debugfs_loop_modes[i].name,
3584*4882a593Smuzhiyun match ? "]" : "");
3585*4882a593Smuzhiyun }
3586*4882a593Smuzhiyun seq_puts(s, "\n");
3587*4882a593Smuzhiyun
3588*4882a593Smuzhiyun return 0;
3589*4882a593Smuzhiyun }
3590*4882a593Smuzhiyun
hisi_sas_debugfs_bist_mode_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)3591*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_bist_mode_write(struct file *filp,
3592*4882a593Smuzhiyun const char __user *buf,
3593*4882a593Smuzhiyun size_t count, loff_t *ppos)
3594*4882a593Smuzhiyun {
3595*4882a593Smuzhiyun struct seq_file *m = filp->private_data;
3596*4882a593Smuzhiyun struct hisi_hba *hisi_hba = m->private;
3597*4882a593Smuzhiyun char kbuf[16] = {}, *pkbuf;
3598*4882a593Smuzhiyun bool found = false;
3599*4882a593Smuzhiyun int i;
3600*4882a593Smuzhiyun
3601*4882a593Smuzhiyun if (hisi_hba->debugfs_bist_enable)
3602*4882a593Smuzhiyun return -EPERM;
3603*4882a593Smuzhiyun
3604*4882a593Smuzhiyun if (count >= sizeof(kbuf))
3605*4882a593Smuzhiyun return -EINVAL;
3606*4882a593Smuzhiyun
3607*4882a593Smuzhiyun if (copy_from_user(kbuf, buf, count))
3608*4882a593Smuzhiyun return -EOVERFLOW;
3609*4882a593Smuzhiyun
3610*4882a593Smuzhiyun pkbuf = strstrip(kbuf);
3611*4882a593Smuzhiyun
3612*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(hisi_sas_debugfs_loop_modes); i++) {
3613*4882a593Smuzhiyun if (!strncmp(hisi_sas_debugfs_loop_modes[i].name, pkbuf, 16)) {
3614*4882a593Smuzhiyun hisi_hba->debugfs_bist_mode =
3615*4882a593Smuzhiyun hisi_sas_debugfs_loop_modes[i].value;
3616*4882a593Smuzhiyun found = true;
3617*4882a593Smuzhiyun break;
3618*4882a593Smuzhiyun }
3619*4882a593Smuzhiyun }
3620*4882a593Smuzhiyun
3621*4882a593Smuzhiyun if (!found)
3622*4882a593Smuzhiyun return -EINVAL;
3623*4882a593Smuzhiyun
3624*4882a593Smuzhiyun return count;
3625*4882a593Smuzhiyun }
3626*4882a593Smuzhiyun
hisi_sas_debugfs_bist_mode_open(struct inode * inode,struct file * filp)3627*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_mode_open(struct inode *inode,
3628*4882a593Smuzhiyun struct file *filp)
3629*4882a593Smuzhiyun {
3630*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_bist_mode_show,
3631*4882a593Smuzhiyun inode->i_private);
3632*4882a593Smuzhiyun }
3633*4882a593Smuzhiyun
3634*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_bist_mode_ops = {
3635*4882a593Smuzhiyun .open = hisi_sas_debugfs_bist_mode_open,
3636*4882a593Smuzhiyun .read = seq_read,
3637*4882a593Smuzhiyun .write = hisi_sas_debugfs_bist_mode_write,
3638*4882a593Smuzhiyun .llseek = seq_lseek,
3639*4882a593Smuzhiyun .release = single_release,
3640*4882a593Smuzhiyun .owner = THIS_MODULE,
3641*4882a593Smuzhiyun };
3642*4882a593Smuzhiyun
hisi_sas_debugfs_bist_enable_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)3643*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_bist_enable_write(struct file *filp,
3644*4882a593Smuzhiyun const char __user *buf,
3645*4882a593Smuzhiyun size_t count, loff_t *ppos)
3646*4882a593Smuzhiyun {
3647*4882a593Smuzhiyun struct seq_file *m = filp->private_data;
3648*4882a593Smuzhiyun struct hisi_hba *hisi_hba = m->private;
3649*4882a593Smuzhiyun unsigned int enable;
3650*4882a593Smuzhiyun int val;
3651*4882a593Smuzhiyun
3652*4882a593Smuzhiyun val = kstrtouint_from_user(buf, count, 0, &enable);
3653*4882a593Smuzhiyun if (val)
3654*4882a593Smuzhiyun return val;
3655*4882a593Smuzhiyun
3656*4882a593Smuzhiyun if (enable > 1)
3657*4882a593Smuzhiyun return -EINVAL;
3658*4882a593Smuzhiyun
3659*4882a593Smuzhiyun if (enable == hisi_hba->debugfs_bist_enable)
3660*4882a593Smuzhiyun return count;
3661*4882a593Smuzhiyun
3662*4882a593Smuzhiyun if (!hisi_hba->hw->set_bist)
3663*4882a593Smuzhiyun return -EPERM;
3664*4882a593Smuzhiyun
3665*4882a593Smuzhiyun val = hisi_hba->hw->set_bist(hisi_hba, enable);
3666*4882a593Smuzhiyun if (val < 0)
3667*4882a593Smuzhiyun return val;
3668*4882a593Smuzhiyun
3669*4882a593Smuzhiyun hisi_hba->debugfs_bist_enable = enable;
3670*4882a593Smuzhiyun
3671*4882a593Smuzhiyun return count;
3672*4882a593Smuzhiyun }
3673*4882a593Smuzhiyun
hisi_sas_debugfs_bist_enable_show(struct seq_file * s,void * p)3674*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_enable_show(struct seq_file *s, void *p)
3675*4882a593Smuzhiyun {
3676*4882a593Smuzhiyun struct hisi_hba *hisi_hba = s->private;
3677*4882a593Smuzhiyun
3678*4882a593Smuzhiyun seq_printf(s, "%d\n", hisi_hba->debugfs_bist_enable);
3679*4882a593Smuzhiyun
3680*4882a593Smuzhiyun return 0;
3681*4882a593Smuzhiyun }
3682*4882a593Smuzhiyun
hisi_sas_debugfs_bist_enable_open(struct inode * inode,struct file * filp)3683*4882a593Smuzhiyun static int hisi_sas_debugfs_bist_enable_open(struct inode *inode,
3684*4882a593Smuzhiyun struct file *filp)
3685*4882a593Smuzhiyun {
3686*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_bist_enable_show,
3687*4882a593Smuzhiyun inode->i_private);
3688*4882a593Smuzhiyun }
3689*4882a593Smuzhiyun
3690*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_bist_enable_ops = {
3691*4882a593Smuzhiyun .open = hisi_sas_debugfs_bist_enable_open,
3692*4882a593Smuzhiyun .read = seq_read,
3693*4882a593Smuzhiyun .write = hisi_sas_debugfs_bist_enable_write,
3694*4882a593Smuzhiyun .llseek = seq_lseek,
3695*4882a593Smuzhiyun .release = single_release,
3696*4882a593Smuzhiyun .owner = THIS_MODULE,
3697*4882a593Smuzhiyun };
3698*4882a593Smuzhiyun
3699*4882a593Smuzhiyun static const struct {
3700*4882a593Smuzhiyun char *name;
3701*4882a593Smuzhiyun } hisi_sas_debugfs_ffe_name[FFE_CFG_MAX] = {
3702*4882a593Smuzhiyun { "SAS_1_5_GBPS" },
3703*4882a593Smuzhiyun { "SAS_3_0_GBPS" },
3704*4882a593Smuzhiyun { "SAS_6_0_GBPS" },
3705*4882a593Smuzhiyun { "SAS_12_0_GBPS" },
3706*4882a593Smuzhiyun { "FFE_RESV" },
3707*4882a593Smuzhiyun { "SATA_1_5_GBPS" },
3708*4882a593Smuzhiyun { "SATA_3_0_GBPS" },
3709*4882a593Smuzhiyun { "SATA_6_0_GBPS" },
3710*4882a593Smuzhiyun };
3711*4882a593Smuzhiyun
hisi_sas_debugfs_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)3712*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_write(struct file *filp,
3713*4882a593Smuzhiyun const char __user *buf,
3714*4882a593Smuzhiyun size_t count, loff_t *ppos)
3715*4882a593Smuzhiyun {
3716*4882a593Smuzhiyun struct seq_file *m = filp->private_data;
3717*4882a593Smuzhiyun u32 *val = m->private;
3718*4882a593Smuzhiyun int res;
3719*4882a593Smuzhiyun
3720*4882a593Smuzhiyun res = kstrtouint_from_user(buf, count, 0, val);
3721*4882a593Smuzhiyun if (res)
3722*4882a593Smuzhiyun return res;
3723*4882a593Smuzhiyun
3724*4882a593Smuzhiyun return count;
3725*4882a593Smuzhiyun }
3726*4882a593Smuzhiyun
hisi_sas_debugfs_show(struct seq_file * s,void * p)3727*4882a593Smuzhiyun static int hisi_sas_debugfs_show(struct seq_file *s, void *p)
3728*4882a593Smuzhiyun {
3729*4882a593Smuzhiyun u32 *val = s->private;
3730*4882a593Smuzhiyun
3731*4882a593Smuzhiyun seq_printf(s, "0x%x\n", *val);
3732*4882a593Smuzhiyun
3733*4882a593Smuzhiyun return 0;
3734*4882a593Smuzhiyun }
3735*4882a593Smuzhiyun
hisi_sas_debugfs_open(struct inode * inode,struct file * filp)3736*4882a593Smuzhiyun static int hisi_sas_debugfs_open(struct inode *inode, struct file *filp)
3737*4882a593Smuzhiyun {
3738*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_show,
3739*4882a593Smuzhiyun inode->i_private);
3740*4882a593Smuzhiyun }
3741*4882a593Smuzhiyun
3742*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_ops = {
3743*4882a593Smuzhiyun .open = hisi_sas_debugfs_open,
3744*4882a593Smuzhiyun .read = seq_read,
3745*4882a593Smuzhiyun .write = hisi_sas_debugfs_write,
3746*4882a593Smuzhiyun .llseek = seq_lseek,
3747*4882a593Smuzhiyun .release = single_release,
3748*4882a593Smuzhiyun .owner = THIS_MODULE,
3749*4882a593Smuzhiyun };
3750*4882a593Smuzhiyun
hisi_sas_debugfs_phy_down_cnt_write(struct file * filp,const char __user * buf,size_t count,loff_t * ppos)3751*4882a593Smuzhiyun static ssize_t hisi_sas_debugfs_phy_down_cnt_write(struct file *filp,
3752*4882a593Smuzhiyun const char __user *buf,
3753*4882a593Smuzhiyun size_t count, loff_t *ppos)
3754*4882a593Smuzhiyun {
3755*4882a593Smuzhiyun struct seq_file *s = filp->private_data;
3756*4882a593Smuzhiyun struct hisi_sas_phy *phy = s->private;
3757*4882a593Smuzhiyun unsigned int set_val;
3758*4882a593Smuzhiyun int res;
3759*4882a593Smuzhiyun
3760*4882a593Smuzhiyun res = kstrtouint_from_user(buf, count, 0, &set_val);
3761*4882a593Smuzhiyun if (res)
3762*4882a593Smuzhiyun return res;
3763*4882a593Smuzhiyun
3764*4882a593Smuzhiyun if (set_val > 0)
3765*4882a593Smuzhiyun return -EINVAL;
3766*4882a593Smuzhiyun
3767*4882a593Smuzhiyun atomic_set(&phy->down_cnt, 0);
3768*4882a593Smuzhiyun
3769*4882a593Smuzhiyun return count;
3770*4882a593Smuzhiyun }
3771*4882a593Smuzhiyun
hisi_sas_debugfs_phy_down_cnt_show(struct seq_file * s,void * p)3772*4882a593Smuzhiyun static int hisi_sas_debugfs_phy_down_cnt_show(struct seq_file *s, void *p)
3773*4882a593Smuzhiyun {
3774*4882a593Smuzhiyun struct hisi_sas_phy *phy = s->private;
3775*4882a593Smuzhiyun
3776*4882a593Smuzhiyun seq_printf(s, "%d\n", atomic_read(&phy->down_cnt));
3777*4882a593Smuzhiyun
3778*4882a593Smuzhiyun return 0;
3779*4882a593Smuzhiyun }
3780*4882a593Smuzhiyun
hisi_sas_debugfs_phy_down_cnt_open(struct inode * inode,struct file * filp)3781*4882a593Smuzhiyun static int hisi_sas_debugfs_phy_down_cnt_open(struct inode *inode,
3782*4882a593Smuzhiyun struct file *filp)
3783*4882a593Smuzhiyun {
3784*4882a593Smuzhiyun return single_open(filp, hisi_sas_debugfs_phy_down_cnt_show,
3785*4882a593Smuzhiyun inode->i_private);
3786*4882a593Smuzhiyun }
3787*4882a593Smuzhiyun
3788*4882a593Smuzhiyun static const struct file_operations hisi_sas_debugfs_phy_down_cnt_ops = {
3789*4882a593Smuzhiyun .open = hisi_sas_debugfs_phy_down_cnt_open,
3790*4882a593Smuzhiyun .read = seq_read,
3791*4882a593Smuzhiyun .write = hisi_sas_debugfs_phy_down_cnt_write,
3792*4882a593Smuzhiyun .llseek = seq_lseek,
3793*4882a593Smuzhiyun .release = single_release,
3794*4882a593Smuzhiyun .owner = THIS_MODULE,
3795*4882a593Smuzhiyun };
3796*4882a593Smuzhiyun
hisi_sas_debugfs_work_handler(struct work_struct * work)3797*4882a593Smuzhiyun void hisi_sas_debugfs_work_handler(struct work_struct *work)
3798*4882a593Smuzhiyun {
3799*4882a593Smuzhiyun struct hisi_hba *hisi_hba =
3800*4882a593Smuzhiyun container_of(work, struct hisi_hba, debugfs_work);
3801*4882a593Smuzhiyun int debugfs_dump_index = hisi_hba->debugfs_dump_index;
3802*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
3803*4882a593Smuzhiyun u64 timestamp = local_clock();
3804*4882a593Smuzhiyun
3805*4882a593Smuzhiyun if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) {
3806*4882a593Smuzhiyun dev_warn(dev, "dump count exceeded!\n");
3807*4882a593Smuzhiyun return;
3808*4882a593Smuzhiyun }
3809*4882a593Smuzhiyun
3810*4882a593Smuzhiyun do_div(timestamp, NSEC_PER_MSEC);
3811*4882a593Smuzhiyun hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp;
3812*4882a593Smuzhiyun
3813*4882a593Smuzhiyun hisi_sas_debugfs_snapshot_regs(hisi_hba);
3814*4882a593Smuzhiyun hisi_hba->debugfs_dump_index++;
3815*4882a593Smuzhiyun }
3816*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler);
3817*4882a593Smuzhiyun
hisi_sas_debugfs_release(struct hisi_hba * hisi_hba,int dump_index)3818*4882a593Smuzhiyun static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba, int dump_index)
3819*4882a593Smuzhiyun {
3820*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
3821*4882a593Smuzhiyun int i;
3822*4882a593Smuzhiyun
3823*4882a593Smuzhiyun devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache);
3824*4882a593Smuzhiyun devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache);
3825*4882a593Smuzhiyun devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost);
3826*4882a593Smuzhiyun devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct);
3827*4882a593Smuzhiyun
3828*4882a593Smuzhiyun for (i = 0; i < hisi_hba->queue_count; i++)
3829*4882a593Smuzhiyun devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr);
3830*4882a593Smuzhiyun
3831*4882a593Smuzhiyun for (i = 0; i < hisi_hba->queue_count; i++)
3832*4882a593Smuzhiyun devm_kfree(dev,
3833*4882a593Smuzhiyun hisi_hba->debugfs_cq[dump_index][i].complete_hdr);
3834*4882a593Smuzhiyun
3835*4882a593Smuzhiyun for (i = 0; i < DEBUGFS_REGS_NUM; i++)
3836*4882a593Smuzhiyun devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data);
3837*4882a593Smuzhiyun
3838*4882a593Smuzhiyun for (i = 0; i < hisi_hba->n_phy; i++)
3839*4882a593Smuzhiyun devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data);
3840*4882a593Smuzhiyun }
3841*4882a593Smuzhiyun
hisi_sas_debugfs_alloc(struct hisi_hba * hisi_hba,int dump_index)3842*4882a593Smuzhiyun static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index)
3843*4882a593Smuzhiyun {
3844*4882a593Smuzhiyun const struct hisi_sas_hw *hw = hisi_hba->hw;
3845*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
3846*4882a593Smuzhiyun int p, c, d, r, i;
3847*4882a593Smuzhiyun size_t sz;
3848*4882a593Smuzhiyun
3849*4882a593Smuzhiyun for (r = 0; r < DEBUGFS_REGS_NUM; r++) {
3850*4882a593Smuzhiyun struct hisi_sas_debugfs_regs *regs =
3851*4882a593Smuzhiyun &hisi_hba->debugfs_regs[dump_index][r];
3852*4882a593Smuzhiyun
3853*4882a593Smuzhiyun sz = hw->debugfs_reg_array[r]->count * 4;
3854*4882a593Smuzhiyun regs->data = devm_kmalloc(dev, sz, GFP_KERNEL);
3855*4882a593Smuzhiyun if (!regs->data)
3856*4882a593Smuzhiyun goto fail;
3857*4882a593Smuzhiyun regs->hisi_hba = hisi_hba;
3858*4882a593Smuzhiyun }
3859*4882a593Smuzhiyun
3860*4882a593Smuzhiyun sz = hw->debugfs_reg_port->count * 4;
3861*4882a593Smuzhiyun for (p = 0; p < hisi_hba->n_phy; p++) {
3862*4882a593Smuzhiyun struct hisi_sas_debugfs_port *port =
3863*4882a593Smuzhiyun &hisi_hba->debugfs_port_reg[dump_index][p];
3864*4882a593Smuzhiyun
3865*4882a593Smuzhiyun port->data = devm_kmalloc(dev, sz, GFP_KERNEL);
3866*4882a593Smuzhiyun if (!port->data)
3867*4882a593Smuzhiyun goto fail;
3868*4882a593Smuzhiyun port->phy = &hisi_hba->phy[p];
3869*4882a593Smuzhiyun }
3870*4882a593Smuzhiyun
3871*4882a593Smuzhiyun sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS;
3872*4882a593Smuzhiyun for (c = 0; c < hisi_hba->queue_count; c++) {
3873*4882a593Smuzhiyun struct hisi_sas_debugfs_cq *cq =
3874*4882a593Smuzhiyun &hisi_hba->debugfs_cq[dump_index][c];
3875*4882a593Smuzhiyun
3876*4882a593Smuzhiyun cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
3877*4882a593Smuzhiyun if (!cq->complete_hdr)
3878*4882a593Smuzhiyun goto fail;
3879*4882a593Smuzhiyun cq->cq = &hisi_hba->cq[c];
3880*4882a593Smuzhiyun }
3881*4882a593Smuzhiyun
3882*4882a593Smuzhiyun sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS;
3883*4882a593Smuzhiyun for (d = 0; d < hisi_hba->queue_count; d++) {
3884*4882a593Smuzhiyun struct hisi_sas_debugfs_dq *dq =
3885*4882a593Smuzhiyun &hisi_hba->debugfs_dq[dump_index][d];
3886*4882a593Smuzhiyun
3887*4882a593Smuzhiyun dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL);
3888*4882a593Smuzhiyun if (!dq->hdr)
3889*4882a593Smuzhiyun goto fail;
3890*4882a593Smuzhiyun dq->dq = &hisi_hba->dq[d];
3891*4882a593Smuzhiyun }
3892*4882a593Smuzhiyun
3893*4882a593Smuzhiyun sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost);
3894*4882a593Smuzhiyun
3895*4882a593Smuzhiyun hisi_hba->debugfs_iost[dump_index].iost =
3896*4882a593Smuzhiyun devm_kmalloc(dev, sz, GFP_KERNEL);
3897*4882a593Smuzhiyun if (!hisi_hba->debugfs_iost[dump_index].iost)
3898*4882a593Smuzhiyun goto fail;
3899*4882a593Smuzhiyun
3900*4882a593Smuzhiyun sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
3901*4882a593Smuzhiyun sizeof(struct hisi_sas_iost_itct_cache);
3902*4882a593Smuzhiyun
3903*4882a593Smuzhiyun hisi_hba->debugfs_iost_cache[dump_index].cache =
3904*4882a593Smuzhiyun devm_kmalloc(dev, sz, GFP_KERNEL);
3905*4882a593Smuzhiyun if (!hisi_hba->debugfs_iost_cache[dump_index].cache)
3906*4882a593Smuzhiyun goto fail;
3907*4882a593Smuzhiyun
3908*4882a593Smuzhiyun sz = HISI_SAS_IOST_ITCT_CACHE_NUM *
3909*4882a593Smuzhiyun sizeof(struct hisi_sas_iost_itct_cache);
3910*4882a593Smuzhiyun
3911*4882a593Smuzhiyun hisi_hba->debugfs_itct_cache[dump_index].cache =
3912*4882a593Smuzhiyun devm_kmalloc(dev, sz, GFP_KERNEL);
3913*4882a593Smuzhiyun if (!hisi_hba->debugfs_itct_cache[dump_index].cache)
3914*4882a593Smuzhiyun goto fail;
3915*4882a593Smuzhiyun
3916*4882a593Smuzhiyun /* New memory allocation must be locate before itct */
3917*4882a593Smuzhiyun sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct);
3918*4882a593Smuzhiyun
3919*4882a593Smuzhiyun hisi_hba->debugfs_itct[dump_index].itct =
3920*4882a593Smuzhiyun devm_kmalloc(dev, sz, GFP_KERNEL);
3921*4882a593Smuzhiyun if (!hisi_hba->debugfs_itct[dump_index].itct)
3922*4882a593Smuzhiyun goto fail;
3923*4882a593Smuzhiyun
3924*4882a593Smuzhiyun return 0;
3925*4882a593Smuzhiyun fail:
3926*4882a593Smuzhiyun for (i = 0; i < hisi_sas_debugfs_dump_count; i++)
3927*4882a593Smuzhiyun hisi_sas_debugfs_release(hisi_hba, i);
3928*4882a593Smuzhiyun return -ENOMEM;
3929*4882a593Smuzhiyun }
3930*4882a593Smuzhiyun
hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba * hisi_hba)3931*4882a593Smuzhiyun static void hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba *hisi_hba)
3932*4882a593Smuzhiyun {
3933*4882a593Smuzhiyun struct dentry *dir = debugfs_create_dir("phy_down_cnt",
3934*4882a593Smuzhiyun hisi_hba->debugfs_dir);
3935*4882a593Smuzhiyun char name[16];
3936*4882a593Smuzhiyun int phy_no;
3937*4882a593Smuzhiyun
3938*4882a593Smuzhiyun for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
3939*4882a593Smuzhiyun snprintf(name, 16, "%d", phy_no);
3940*4882a593Smuzhiyun debugfs_create_file(name, 0600, dir,
3941*4882a593Smuzhiyun &hisi_hba->phy[phy_no],
3942*4882a593Smuzhiyun &hisi_sas_debugfs_phy_down_cnt_ops);
3943*4882a593Smuzhiyun }
3944*4882a593Smuzhiyun }
3945*4882a593Smuzhiyun
hisi_sas_debugfs_bist_init(struct hisi_hba * hisi_hba)3946*4882a593Smuzhiyun static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba)
3947*4882a593Smuzhiyun {
3948*4882a593Smuzhiyun struct dentry *ports_dentry;
3949*4882a593Smuzhiyun int phy_no;
3950*4882a593Smuzhiyun
3951*4882a593Smuzhiyun hisi_hba->debugfs_bist_dentry =
3952*4882a593Smuzhiyun debugfs_create_dir("bist", hisi_hba->debugfs_dir);
3953*4882a593Smuzhiyun debugfs_create_file("link_rate", 0600,
3954*4882a593Smuzhiyun hisi_hba->debugfs_bist_dentry, hisi_hba,
3955*4882a593Smuzhiyun &hisi_sas_debugfs_bist_linkrate_ops);
3956*4882a593Smuzhiyun
3957*4882a593Smuzhiyun debugfs_create_file("code_mode", 0600,
3958*4882a593Smuzhiyun hisi_hba->debugfs_bist_dentry, hisi_hba,
3959*4882a593Smuzhiyun &hisi_sas_debugfs_bist_code_mode_ops);
3960*4882a593Smuzhiyun
3961*4882a593Smuzhiyun debugfs_create_file("fixed_code", 0600,
3962*4882a593Smuzhiyun hisi_hba->debugfs_bist_dentry,
3963*4882a593Smuzhiyun &hisi_hba->debugfs_bist_fixed_code[0],
3964*4882a593Smuzhiyun &hisi_sas_debugfs_ops);
3965*4882a593Smuzhiyun
3966*4882a593Smuzhiyun debugfs_create_file("fixed_code_1", 0600,
3967*4882a593Smuzhiyun hisi_hba->debugfs_bist_dentry,
3968*4882a593Smuzhiyun &hisi_hba->debugfs_bist_fixed_code[1],
3969*4882a593Smuzhiyun &hisi_sas_debugfs_ops);
3970*4882a593Smuzhiyun
3971*4882a593Smuzhiyun debugfs_create_file("phy_id", 0600, hisi_hba->debugfs_bist_dentry,
3972*4882a593Smuzhiyun hisi_hba, &hisi_sas_debugfs_bist_phy_ops);
3973*4882a593Smuzhiyun
3974*4882a593Smuzhiyun debugfs_create_u32("cnt", 0600, hisi_hba->debugfs_bist_dentry,
3975*4882a593Smuzhiyun &hisi_hba->debugfs_bist_cnt);
3976*4882a593Smuzhiyun
3977*4882a593Smuzhiyun debugfs_create_file("loopback_mode", 0600,
3978*4882a593Smuzhiyun hisi_hba->debugfs_bist_dentry,
3979*4882a593Smuzhiyun hisi_hba, &hisi_sas_debugfs_bist_mode_ops);
3980*4882a593Smuzhiyun
3981*4882a593Smuzhiyun debugfs_create_file("enable", 0600, hisi_hba->debugfs_bist_dentry,
3982*4882a593Smuzhiyun hisi_hba, &hisi_sas_debugfs_bist_enable_ops);
3983*4882a593Smuzhiyun
3984*4882a593Smuzhiyun ports_dentry = debugfs_create_dir("port", hisi_hba->debugfs_bist_dentry);
3985*4882a593Smuzhiyun
3986*4882a593Smuzhiyun for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) {
3987*4882a593Smuzhiyun struct dentry *port_dentry;
3988*4882a593Smuzhiyun struct dentry *ffe_dentry;
3989*4882a593Smuzhiyun char name[256];
3990*4882a593Smuzhiyun int i;
3991*4882a593Smuzhiyun
3992*4882a593Smuzhiyun snprintf(name, 256, "%d", phy_no);
3993*4882a593Smuzhiyun port_dentry = debugfs_create_dir(name, ports_dentry);
3994*4882a593Smuzhiyun ffe_dentry = debugfs_create_dir("ffe", port_dentry);
3995*4882a593Smuzhiyun for (i = 0; i < FFE_CFG_MAX; i++) {
3996*4882a593Smuzhiyun if (i == FFE_RESV)
3997*4882a593Smuzhiyun continue;
3998*4882a593Smuzhiyun debugfs_create_file(hisi_sas_debugfs_ffe_name[i].name,
3999*4882a593Smuzhiyun 0600, ffe_dentry,
4000*4882a593Smuzhiyun &hisi_hba->debugfs_bist_ffe[phy_no][i],
4001*4882a593Smuzhiyun &hisi_sas_debugfs_ops);
4002*4882a593Smuzhiyun }
4003*4882a593Smuzhiyun }
4004*4882a593Smuzhiyun
4005*4882a593Smuzhiyun hisi_hba->debugfs_bist_linkrate = SAS_LINK_RATE_1_5_GBPS;
4006*4882a593Smuzhiyun }
4007*4882a593Smuzhiyun
hisi_sas_debugfs_init(struct hisi_hba * hisi_hba)4008*4882a593Smuzhiyun void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba)
4009*4882a593Smuzhiyun {
4010*4882a593Smuzhiyun struct device *dev = hisi_hba->dev;
4011*4882a593Smuzhiyun int i;
4012*4882a593Smuzhiyun
4013*4882a593Smuzhiyun hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev),
4014*4882a593Smuzhiyun hisi_sas_debugfs_dir);
4015*4882a593Smuzhiyun debugfs_create_file("trigger_dump", 0200,
4016*4882a593Smuzhiyun hisi_hba->debugfs_dir,
4017*4882a593Smuzhiyun hisi_hba,
4018*4882a593Smuzhiyun &hisi_sas_debugfs_trigger_dump_fops);
4019*4882a593Smuzhiyun
4020*4882a593Smuzhiyun /* create bist structures */
4021*4882a593Smuzhiyun hisi_sas_debugfs_bist_init(hisi_hba);
4022*4882a593Smuzhiyun
4023*4882a593Smuzhiyun hisi_hba->debugfs_dump_dentry =
4024*4882a593Smuzhiyun debugfs_create_dir("dump", hisi_hba->debugfs_dir);
4025*4882a593Smuzhiyun
4026*4882a593Smuzhiyun hisi_sas_debugfs_phy_down_cnt_init(hisi_hba);
4027*4882a593Smuzhiyun
4028*4882a593Smuzhiyun for (i = 0; i < hisi_sas_debugfs_dump_count; i++) {
4029*4882a593Smuzhiyun if (hisi_sas_debugfs_alloc(hisi_hba, i)) {
4030*4882a593Smuzhiyun debugfs_remove_recursive(hisi_hba->debugfs_dir);
4031*4882a593Smuzhiyun dev_dbg(dev, "failed to init debugfs!\n");
4032*4882a593Smuzhiyun break;
4033*4882a593Smuzhiyun }
4034*4882a593Smuzhiyun }
4035*4882a593Smuzhiyun }
4036*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init);
4037*4882a593Smuzhiyun
hisi_sas_debugfs_exit(struct hisi_hba * hisi_hba)4038*4882a593Smuzhiyun void hisi_sas_debugfs_exit(struct hisi_hba *hisi_hba)
4039*4882a593Smuzhiyun {
4040*4882a593Smuzhiyun debugfs_remove_recursive(hisi_hba->debugfs_dir);
4041*4882a593Smuzhiyun }
4042*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_debugfs_exit);
4043*4882a593Smuzhiyun
hisi_sas_remove(struct platform_device * pdev)4044*4882a593Smuzhiyun int hisi_sas_remove(struct platform_device *pdev)
4045*4882a593Smuzhiyun {
4046*4882a593Smuzhiyun struct sas_ha_struct *sha = platform_get_drvdata(pdev);
4047*4882a593Smuzhiyun struct hisi_hba *hisi_hba = sha->lldd_ha;
4048*4882a593Smuzhiyun struct Scsi_Host *shost = sha->core.shost;
4049*4882a593Smuzhiyun
4050*4882a593Smuzhiyun if (timer_pending(&hisi_hba->timer))
4051*4882a593Smuzhiyun del_timer(&hisi_hba->timer);
4052*4882a593Smuzhiyun
4053*4882a593Smuzhiyun sas_unregister_ha(sha);
4054*4882a593Smuzhiyun sas_remove_host(sha->core.shost);
4055*4882a593Smuzhiyun
4056*4882a593Smuzhiyun hisi_sas_free(hisi_hba);
4057*4882a593Smuzhiyun scsi_host_put(shost);
4058*4882a593Smuzhiyun return 0;
4059*4882a593Smuzhiyun }
4060*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_remove);
4061*4882a593Smuzhiyun
4062*4882a593Smuzhiyun bool hisi_sas_debugfs_enable;
4063*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_debugfs_enable);
4064*4882a593Smuzhiyun module_param_named(debugfs_enable, hisi_sas_debugfs_enable, bool, 0444);
4065*4882a593Smuzhiyun MODULE_PARM_DESC(hisi_sas_debugfs_enable, "Enable driver debugfs (default disabled)");
4066*4882a593Smuzhiyun
4067*4882a593Smuzhiyun u32 hisi_sas_debugfs_dump_count = 1;
4068*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count);
4069*4882a593Smuzhiyun module_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444);
4070*4882a593Smuzhiyun MODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow");
4071*4882a593Smuzhiyun
hisi_sas_init(void)4072*4882a593Smuzhiyun static __init int hisi_sas_init(void)
4073*4882a593Smuzhiyun {
4074*4882a593Smuzhiyun hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops);
4075*4882a593Smuzhiyun if (!hisi_sas_stt)
4076*4882a593Smuzhiyun return -ENOMEM;
4077*4882a593Smuzhiyun
4078*4882a593Smuzhiyun if (hisi_sas_debugfs_enable) {
4079*4882a593Smuzhiyun hisi_sas_debugfs_dir = debugfs_create_dir("hisi_sas", NULL);
4080*4882a593Smuzhiyun if (hisi_sas_debugfs_dump_count > HISI_SAS_MAX_DEBUGFS_DUMP) {
4081*4882a593Smuzhiyun pr_info("hisi_sas: Limiting debugfs dump count\n");
4082*4882a593Smuzhiyun hisi_sas_debugfs_dump_count = HISI_SAS_MAX_DEBUGFS_DUMP;
4083*4882a593Smuzhiyun }
4084*4882a593Smuzhiyun }
4085*4882a593Smuzhiyun
4086*4882a593Smuzhiyun return 0;
4087*4882a593Smuzhiyun }
4088*4882a593Smuzhiyun
hisi_sas_exit(void)4089*4882a593Smuzhiyun static __exit void hisi_sas_exit(void)
4090*4882a593Smuzhiyun {
4091*4882a593Smuzhiyun sas_release_transport(hisi_sas_stt);
4092*4882a593Smuzhiyun
4093*4882a593Smuzhiyun debugfs_remove(hisi_sas_debugfs_dir);
4094*4882a593Smuzhiyun }
4095*4882a593Smuzhiyun
4096*4882a593Smuzhiyun module_init(hisi_sas_init);
4097*4882a593Smuzhiyun module_exit(hisi_sas_exit);
4098*4882a593Smuzhiyun
4099*4882a593Smuzhiyun MODULE_LICENSE("GPL");
4100*4882a593Smuzhiyun MODULE_AUTHOR("John Garry <john.garry@huawei.com>");
4101*4882a593Smuzhiyun MODULE_DESCRIPTION("HISILICON SAS controller driver");
4102*4882a593Smuzhiyun MODULE_ALIAS("platform:" DRV_NAME);
4103