1 | /* |
2 | * PMC-Sierra SPCv/ve 8088/8089 SAS/SATA based host adapters driver |
3 | * |
4 | * Copyright (c) 2008-2009 PMC-Sierra, Inc., |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions, and the following disclaimer, |
12 | * without modification. |
13 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
14 | * substantially similar to the "NO WARRANTY" disclaimer below |
15 | * ("Disclaimer") and any redistribution must be conditioned upon |
16 | * including a substantially similar Disclaimer requirement for further |
17 | * binary redistribution. |
18 | * 3. Neither the names of the above-listed copyright holders nor the names |
19 | * of any contributors may be used to endorse or promote products derived |
20 | * from this software without specific prior written permission. |
21 | * |
22 | * Alternatively, this software may be distributed under the terms of the |
23 | * GNU General Public License ("GPL") version 2 as published by the Free |
24 | * Software Foundation. |
25 | * |
26 | * NO WARRANTY |
27 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
28 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
29 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
30 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
31 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
35 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
36 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
37 | * POSSIBILITY OF SUCH DAMAGES. |
38 | * |
39 | */ |
40 | #include <linux/slab.h> |
41 | #include "pm8001_sas.h" |
42 | #include "pm80xx_hwi.h" |
43 | #include "pm8001_chips.h" |
44 | #include "pm8001_ctl.h" |
45 | #include "pm80xx_tracepoints.h" |
46 | |
47 | #define SMP_DIRECT 1 |
48 | #define SMP_INDIRECT 2 |
49 | |
50 | |
51 | int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value) |
52 | { |
53 | u32 reg_val; |
54 | unsigned long start; |
55 | pm8001_cw32(pm8001_ha, bar: 0, MEMBASE_II_SHIFT_REGISTER, val: shift_value); |
56 | /* confirm the setting is written */ |
57 | start = jiffies + HZ; /* 1 sec */ |
58 | do { |
59 | reg_val = pm8001_cr32(pm8001_ha, bar: 0, MEMBASE_II_SHIFT_REGISTER); |
60 | } while ((reg_val != shift_value) && time_before(jiffies, start)); |
61 | if (reg_val != shift_value) { |
62 | pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:MEMBASE_II_SHIFT_REGISTER = 0x%x\n" , |
63 | reg_val); |
64 | return -1; |
65 | } |
66 | return 0; |
67 | } |
68 | |
69 | static void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset, |
70 | __le32 *destination, |
71 | u32 dw_count, u32 bus_base_number) |
72 | { |
73 | u32 index, value, offset; |
74 | |
75 | for (index = 0; index < dw_count; index += 4, destination++) { |
76 | offset = (soffset + index); |
77 | if (offset < (64 * 1024)) { |
78 | value = pm8001_cr32(pm8001_ha, bar: bus_base_number, offset); |
79 | *destination = cpu_to_le32(value); |
80 | } |
81 | } |
82 | return; |
83 | } |
84 | |
85 | ssize_t pm80xx_get_fatal_dump(struct device *cdev, |
86 | struct device_attribute *attr, char *buf) |
87 | { |
88 | struct Scsi_Host *shost = class_to_shost(cdev); |
89 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); |
90 | struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; |
91 | void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr; |
92 | u32 accum_len, reg_val, index, *temp; |
93 | u32 status = 1; |
94 | unsigned long start; |
95 | u8 *direct_data; |
96 | char *fatal_error_data = buf; |
97 | u32 length_to_read; |
98 | u32 offset; |
99 | |
100 | pm8001_ha->forensic_info.data_buf.direct_data = buf; |
101 | if (pm8001_ha->chip_id == chip_8001) { |
102 | pm8001_ha->forensic_info.data_buf.direct_data += |
103 | sprintf(buf: pm8001_ha->forensic_info.data_buf.direct_data, |
104 | fmt: "Not supported for SPC controller" ); |
105 | return (char *)pm8001_ha->forensic_info.data_buf.direct_data - |
106 | (char *)buf; |
107 | } |
108 | /* initialize variables for very first call from host application */ |
109 | if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { |
110 | pm8001_dbg(pm8001_ha, IO, |
111 | "forensic_info TYPE_NON_FATAL..............\n" ); |
112 | direct_data = (u8 *)fatal_error_data; |
113 | pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; |
114 | pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; |
115 | pm8001_ha->forensic_info.data_buf.direct_offset = 0; |
116 | pm8001_ha->forensic_info.data_buf.read_len = 0; |
117 | pm8001_ha->forensic_preserved_accumulated_transfer = 0; |
118 | |
119 | /* Write signature to fatal dump table */ |
120 | pm8001_mw32(addr: fatal_table_address, |
121 | MPI_FATAL_EDUMP_TABLE_SIGNATURE, val: 0x1234abcd); |
122 | |
123 | pm8001_ha->forensic_info.data_buf.direct_data = direct_data; |
124 | pm8001_dbg(pm8001_ha, IO, "ossaHwCB: status1 %d\n" , status); |
125 | pm8001_dbg(pm8001_ha, IO, "ossaHwCB: read_len 0x%x\n" , |
126 | pm8001_ha->forensic_info.data_buf.read_len); |
127 | pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_len 0x%x\n" , |
128 | pm8001_ha->forensic_info.data_buf.direct_len); |
129 | pm8001_dbg(pm8001_ha, IO, "ossaHwCB: direct_offset 0x%x\n" , |
130 | pm8001_ha->forensic_info.data_buf.direct_offset); |
131 | } |
132 | if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { |
133 | /* start to get data */ |
134 | /* Program the MEMBASE II Shifting Register with 0x00.*/ |
135 | pm8001_cw32(pm8001_ha, bar: 0, MEMBASE_II_SHIFT_REGISTER, |
136 | val: pm8001_ha->fatal_forensic_shift_offset); |
137 | pm8001_ha->forensic_last_offset = 0; |
138 | pm8001_ha->forensic_fatal_step = 0; |
139 | pm8001_ha->fatal_bar_loc = 0; |
140 | } |
141 | |
142 | /* Read until accum_len is retrieved */ |
143 | accum_len = pm8001_mr32(addr: fatal_table_address, |
144 | MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); |
145 | /* Determine length of data between previously stored transfer length |
146 | * and current accumulated transfer length |
147 | */ |
148 | length_to_read = |
149 | accum_len - pm8001_ha->forensic_preserved_accumulated_transfer; |
150 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: accum_len 0x%x\n" , |
151 | accum_len); |
152 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: length_to_read 0x%x\n" , |
153 | length_to_read); |
154 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: last_offset 0x%x\n" , |
155 | pm8001_ha->forensic_last_offset); |
156 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: read_len 0x%x\n" , |
157 | pm8001_ha->forensic_info.data_buf.read_len); |
158 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_len 0x%x\n" , |
159 | pm8001_ha->forensic_info.data_buf.direct_len); |
160 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv:: direct_offset 0x%x\n" , |
161 | pm8001_ha->forensic_info.data_buf.direct_offset); |
162 | |
163 | /* If accumulated length failed to read correctly fail the attempt.*/ |
164 | if (accum_len == 0xFFFFFFFF) { |
165 | pm8001_dbg(pm8001_ha, IO, |
166 | "Possible PCI issue 0x%x not expected\n" , |
167 | accum_len); |
168 | return status; |
169 | } |
170 | /* If accumulated length is zero fail the attempt */ |
171 | if (accum_len == 0) { |
172 | pm8001_ha->forensic_info.data_buf.direct_data += |
173 | sprintf(buf: pm8001_ha->forensic_info.data_buf.direct_data, |
174 | fmt: "%08x " , 0xFFFFFFFF); |
175 | return (char *)pm8001_ha->forensic_info.data_buf.direct_data - |
176 | (char *)buf; |
177 | } |
178 | /* Accumulated length is good so start capturing the first data */ |
179 | temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; |
180 | if (pm8001_ha->forensic_fatal_step == 0) { |
181 | moreData: |
182 | /* If data to read is less than SYSFS_OFFSET then reduce the |
183 | * length of dataLen |
184 | */ |
185 | if (pm8001_ha->forensic_last_offset + SYSFS_OFFSET |
186 | > length_to_read) { |
187 | pm8001_ha->forensic_info.data_buf.direct_len = |
188 | length_to_read - |
189 | pm8001_ha->forensic_last_offset; |
190 | } else { |
191 | pm8001_ha->forensic_info.data_buf.direct_len = |
192 | SYSFS_OFFSET; |
193 | } |
194 | if (pm8001_ha->forensic_info.data_buf.direct_data) { |
195 | /* Data is in bar, copy to host memory */ |
196 | pm80xx_pci_mem_copy(pm8001_ha, |
197 | soffset: pm8001_ha->fatal_bar_loc, |
198 | destination: pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, |
199 | dw_count: pm8001_ha->forensic_info.data_buf.direct_len, bus_base_number: 1); |
200 | } |
201 | pm8001_ha->fatal_bar_loc += |
202 | pm8001_ha->forensic_info.data_buf.direct_len; |
203 | pm8001_ha->forensic_info.data_buf.direct_offset += |
204 | pm8001_ha->forensic_info.data_buf.direct_len; |
205 | pm8001_ha->forensic_last_offset += |
206 | pm8001_ha->forensic_info.data_buf.direct_len; |
207 | pm8001_ha->forensic_info.data_buf.read_len = |
208 | pm8001_ha->forensic_info.data_buf.direct_len; |
209 | |
210 | if (pm8001_ha->forensic_last_offset >= length_to_read) { |
211 | pm8001_ha->forensic_info.data_buf.direct_data += |
212 | sprintf(buf: pm8001_ha->forensic_info.data_buf.direct_data, |
213 | fmt: "%08x " , 3); |
214 | for (index = 0; index < |
215 | (pm8001_ha->forensic_info.data_buf.direct_len |
216 | / 4); index++) { |
217 | pm8001_ha->forensic_info.data_buf.direct_data += |
218 | sprintf( |
219 | buf: pm8001_ha->forensic_info.data_buf.direct_data, |
220 | fmt: "%08x " , *(temp + index)); |
221 | } |
222 | |
223 | pm8001_ha->fatal_bar_loc = 0; |
224 | pm8001_ha->forensic_fatal_step = 1; |
225 | pm8001_ha->fatal_forensic_shift_offset = 0; |
226 | pm8001_ha->forensic_last_offset = 0; |
227 | status = 0; |
228 | offset = (int) |
229 | ((char *)pm8001_ha->forensic_info.data_buf.direct_data |
230 | - (char *)buf); |
231 | pm8001_dbg(pm8001_ha, IO, |
232 | "get_fatal_spcv:return1 0x%x\n" , offset); |
233 | return (char *)pm8001_ha-> |
234 | forensic_info.data_buf.direct_data - |
235 | (char *)buf; |
236 | } |
237 | if (pm8001_ha->fatal_bar_loc < (64 * 1024)) { |
238 | pm8001_ha->forensic_info.data_buf.direct_data += |
239 | sprintf(buf: pm8001_ha-> |
240 | forensic_info.data_buf.direct_data, |
241 | fmt: "%08x " , 2); |
242 | for (index = 0; index < |
243 | (pm8001_ha->forensic_info.data_buf.direct_len |
244 | / 4); index++) { |
245 | pm8001_ha->forensic_info.data_buf.direct_data |
246 | += sprintf(buf: pm8001_ha-> |
247 | forensic_info.data_buf.direct_data, |
248 | fmt: "%08x " , *(temp + index)); |
249 | } |
250 | status = 0; |
251 | offset = (int) |
252 | ((char *)pm8001_ha->forensic_info.data_buf.direct_data |
253 | - (char *)buf); |
254 | pm8001_dbg(pm8001_ha, IO, |
255 | "get_fatal_spcv:return2 0x%x\n" , offset); |
256 | return (char *)pm8001_ha-> |
257 | forensic_info.data_buf.direct_data - |
258 | (char *)buf; |
259 | } |
260 | |
261 | /* Increment the MEMBASE II Shifting Register value by 0x100.*/ |
262 | pm8001_ha->forensic_info.data_buf.direct_data += |
263 | sprintf(buf: pm8001_ha->forensic_info.data_buf.direct_data, |
264 | fmt: "%08x " , 2); |
265 | for (index = 0; index < |
266 | (pm8001_ha->forensic_info.data_buf.direct_len |
267 | / 4) ; index++) { |
268 | pm8001_ha->forensic_info.data_buf.direct_data += |
269 | sprintf(buf: pm8001_ha-> |
270 | forensic_info.data_buf.direct_data, |
271 | fmt: "%08x " , *(temp + index)); |
272 | } |
273 | pm8001_ha->fatal_forensic_shift_offset += 0x100; |
274 | pm8001_cw32(pm8001_ha, bar: 0, MEMBASE_II_SHIFT_REGISTER, |
275 | val: pm8001_ha->fatal_forensic_shift_offset); |
276 | pm8001_ha->fatal_bar_loc = 0; |
277 | status = 0; |
278 | offset = (int) |
279 | ((char *)pm8001_ha->forensic_info.data_buf.direct_data |
280 | - (char *)buf); |
281 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return3 0x%x\n" , |
282 | offset); |
283 | return (char *)pm8001_ha->forensic_info.data_buf.direct_data - |
284 | (char *)buf; |
285 | } |
286 | if (pm8001_ha->forensic_fatal_step == 1) { |
287 | /* store previous accumulated length before triggering next |
288 | * accumulated length update |
289 | */ |
290 | pm8001_ha->forensic_preserved_accumulated_transfer = |
291 | pm8001_mr32(addr: fatal_table_address, |
292 | MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); |
293 | |
294 | /* continue capturing the fatal log until Dump status is 0x3 */ |
295 | if (pm8001_mr32(addr: fatal_table_address, |
296 | MPI_FATAL_EDUMP_TABLE_STATUS) < |
297 | MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { |
298 | |
299 | /* reset fddstat bit by writing to zero*/ |
300 | pm8001_mw32(addr: fatal_table_address, |
301 | MPI_FATAL_EDUMP_TABLE_STATUS, val: 0x0); |
302 | |
303 | /* set dump control value to '1' so that new data will |
304 | * be transferred to shared memory |
305 | */ |
306 | pm8001_mw32(addr: fatal_table_address, |
307 | MPI_FATAL_EDUMP_TABLE_HANDSHAKE, |
308 | MPI_FATAL_EDUMP_HANDSHAKE_RDY); |
309 | |
310 | /*Poll FDDHSHK until clear */ |
311 | start = jiffies + (2 * HZ); /* 2 sec */ |
312 | |
313 | do { |
314 | reg_val = pm8001_mr32(addr: fatal_table_address, |
315 | MPI_FATAL_EDUMP_TABLE_HANDSHAKE); |
316 | } while ((reg_val) && time_before(jiffies, start)); |
317 | |
318 | if (reg_val != 0) { |
319 | pm8001_dbg(pm8001_ha, FAIL, |
320 | "TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n" , |
321 | reg_val); |
322 | /* Fail the dump if a timeout occurs */ |
323 | pm8001_ha->forensic_info.data_buf.direct_data += |
324 | sprintf( |
325 | buf: pm8001_ha->forensic_info.data_buf.direct_data, |
326 | fmt: "%08x " , 0xFFFFFFFF); |
327 | return((char *) |
328 | pm8001_ha->forensic_info.data_buf.direct_data |
329 | - (char *)buf); |
330 | } |
331 | /* Poll status register until set to 2 or |
332 | * 3 for up to 2 seconds |
333 | */ |
334 | start = jiffies + (2 * HZ); /* 2 sec */ |
335 | |
336 | do { |
337 | reg_val = pm8001_mr32(addr: fatal_table_address, |
338 | MPI_FATAL_EDUMP_TABLE_STATUS); |
339 | } while (((reg_val != 2) && (reg_val != 3)) && |
340 | time_before(jiffies, start)); |
341 | |
342 | if (reg_val < 2) { |
343 | pm8001_dbg(pm8001_ha, FAIL, |
344 | "TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n" , |
345 | reg_val); |
346 | /* Fail the dump if a timeout occurs */ |
347 | pm8001_ha->forensic_info.data_buf.direct_data += |
348 | sprintf( |
349 | buf: pm8001_ha->forensic_info.data_buf.direct_data, |
350 | fmt: "%08x " , 0xFFFFFFFF); |
351 | return((char *)pm8001_ha->forensic_info.data_buf.direct_data - |
352 | (char *)buf); |
353 | } |
354 | /* reset fatal_forensic_shift_offset back to zero and reset MEMBASE 2 register to zero */ |
355 | pm8001_ha->fatal_forensic_shift_offset = 0; /* location in 64k region */ |
356 | pm8001_cw32(pm8001_ha, bar: 0, |
357 | MEMBASE_II_SHIFT_REGISTER, |
358 | val: pm8001_ha->fatal_forensic_shift_offset); |
359 | } |
360 | /* Read the next block of the debug data.*/ |
361 | length_to_read = pm8001_mr32(addr: fatal_table_address, |
362 | MPI_FATAL_EDUMP_TABLE_ACCUM_LEN) - |
363 | pm8001_ha->forensic_preserved_accumulated_transfer; |
364 | if (length_to_read != 0x0) { |
365 | pm8001_ha->forensic_fatal_step = 0; |
366 | goto moreData; |
367 | } else { |
368 | pm8001_ha->forensic_info.data_buf.direct_data += |
369 | sprintf(buf: pm8001_ha->forensic_info.data_buf.direct_data, |
370 | fmt: "%08x " , 4); |
371 | pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF; |
372 | pm8001_ha->forensic_info.data_buf.direct_len = 0; |
373 | pm8001_ha->forensic_info.data_buf.direct_offset = 0; |
374 | pm8001_ha->forensic_info.data_buf.read_len = 0; |
375 | } |
376 | } |
377 | offset = (int)((char *)pm8001_ha->forensic_info.data_buf.direct_data |
378 | - (char *)buf); |
379 | pm8001_dbg(pm8001_ha, IO, "get_fatal_spcv: return4 0x%x\n" , offset); |
380 | return ((char *)pm8001_ha->forensic_info.data_buf.direct_data - |
381 | (char *)buf); |
382 | } |
383 | |
384 | /* pm80xx_get_non_fatal_dump - dump the nonfatal data from the dma |
385 | * location by the firmware. |
386 | */ |
387 | ssize_t pm80xx_get_non_fatal_dump(struct device *cdev, |
388 | struct device_attribute *attr, char *buf) |
389 | { |
390 | struct Scsi_Host *shost = class_to_shost(cdev); |
391 | struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); |
392 | struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; |
393 | void __iomem *nonfatal_table_address = pm8001_ha->fatal_tbl_addr; |
394 | u32 accum_len = 0; |
395 | u32 total_len = 0; |
396 | u32 reg_val = 0; |
397 | u32 *temp = NULL; |
398 | u32 index = 0; |
399 | u32 output_length; |
400 | unsigned long start = 0; |
401 | char *buf_copy = buf; |
402 | |
403 | temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; |
404 | if (++pm8001_ha->non_fatal_count == 1) { |
405 | if (pm8001_ha->chip_id == chip_8001) { |
406 | snprintf(buf: pm8001_ha->forensic_info.data_buf.direct_data, |
407 | PAGE_SIZE, fmt: "Not supported for SPC controller" ); |
408 | return 0; |
409 | } |
410 | pm8001_dbg(pm8001_ha, IO, "forensic_info TYPE_NON_FATAL...\n" ); |
411 | /* |
412 | * Step 1: Write the host buffer parameters in the MPI Fatal and |
413 | * Non-Fatal Error Dump Capture Table.This is the buffer |
414 | * where debug data will be DMAed to. |
415 | */ |
416 | pm8001_mw32(addr: nonfatal_table_address, |
417 | MPI_FATAL_EDUMP_TABLE_LO_OFFSET, |
418 | val: pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_lo); |
419 | |
420 | pm8001_mw32(addr: nonfatal_table_address, |
421 | MPI_FATAL_EDUMP_TABLE_HI_OFFSET, |
422 | val: pm8001_ha->memoryMap.region[FORENSIC_MEM].phys_addr_hi); |
423 | |
424 | pm8001_mw32(addr: nonfatal_table_address, |
425 | MPI_FATAL_EDUMP_TABLE_LENGTH, SYSFS_OFFSET); |
426 | |
427 | /* Optionally, set the DUMPCTRL bit to 1 if the host |
428 | * keeps sending active I/Os while capturing the non-fatal |
429 | * debug data. Otherwise, leave this bit set to zero |
430 | */ |
431 | pm8001_mw32(addr: nonfatal_table_address, |
432 | MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_HANDSHAKE_RDY); |
433 | |
434 | /* |
435 | * Step 2: Clear Accumulative Length of Debug Data Transferred |
436 | * [ACCDDLEN] field in the MPI Fatal and Non-Fatal Error Dump |
437 | * Capture Table to zero. |
438 | */ |
439 | pm8001_mw32(addr: nonfatal_table_address, |
440 | MPI_FATAL_EDUMP_TABLE_ACCUM_LEN, val: 0); |
441 | |
442 | /* initiallize previous accumulated length to 0 */ |
443 | pm8001_ha->forensic_preserved_accumulated_transfer = 0; |
444 | pm8001_ha->non_fatal_read_length = 0; |
445 | } |
446 | |
447 | total_len = pm8001_mr32(addr: nonfatal_table_address, |
448 | MPI_FATAL_EDUMP_TABLE_TOTAL_LEN); |
449 | /* |
450 | * Step 3:Clear Fatal/Non-Fatal Debug Data Transfer Status [FDDTSTAT] |
451 | * field and then request that the SPCv controller transfer the debug |
452 | * data by setting bit 7 of the Inbound Doorbell Set Register. |
453 | */ |
454 | pm8001_mw32(addr: nonfatal_table_address, MPI_FATAL_EDUMP_TABLE_STATUS, val: 0); |
455 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_IBDB_SET, |
456 | SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP); |
457 | |
458 | /* |
459 | * Step 4.1: Read back the Inbound Doorbell Set Register (by polling for |
460 | * 2 seconds) until register bit 7 is cleared. |
461 | * This step only indicates the request is accepted by the controller. |
462 | */ |
463 | start = jiffies + (2 * HZ); /* 2 sec */ |
464 | do { |
465 | reg_val = pm8001_cr32(pm8001_ha, bar: 0, MSGU_IBDB_SET) & |
466 | SPCv_MSGU_CFG_TABLE_NONFATAL_DUMP; |
467 | } while ((reg_val != 0) && time_before(jiffies, start)); |
468 | |
469 | /* Step 4.2: To check the completion of the transfer, poll the Fatal/Non |
470 | * Fatal Debug Data Transfer Status [FDDTSTAT] field for 2 seconds in |
471 | * the MPI Fatal and Non-Fatal Error Dump Capture Table. |
472 | */ |
473 | start = jiffies + (2 * HZ); /* 2 sec */ |
474 | do { |
475 | reg_val = pm8001_mr32(addr: nonfatal_table_address, |
476 | MPI_FATAL_EDUMP_TABLE_STATUS); |
477 | } while ((!reg_val) && time_before(jiffies, start)); |
478 | |
479 | if ((reg_val == 0x00) || |
480 | (reg_val == MPI_FATAL_EDUMP_TABLE_STAT_DMA_FAILED) || |
481 | (reg_val > MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE)) { |
482 | pm8001_ha->non_fatal_read_length = 0; |
483 | buf_copy += snprintf(buf: buf_copy, PAGE_SIZE, fmt: "%08x " , 0xFFFFFFFF); |
484 | pm8001_ha->non_fatal_count = 0; |
485 | return (buf_copy - buf); |
486 | } else if (reg_val == |
487 | MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_MORE_DATA) { |
488 | buf_copy += snprintf(buf: buf_copy, PAGE_SIZE, fmt: "%08x " , 2); |
489 | } else if ((reg_val == MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) || |
490 | (pm8001_ha->non_fatal_read_length >= total_len)) { |
491 | pm8001_ha->non_fatal_read_length = 0; |
492 | buf_copy += snprintf(buf: buf_copy, PAGE_SIZE, fmt: "%08x " , 4); |
493 | pm8001_ha->non_fatal_count = 0; |
494 | } |
495 | accum_len = pm8001_mr32(addr: nonfatal_table_address, |
496 | MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); |
497 | output_length = accum_len - |
498 | pm8001_ha->forensic_preserved_accumulated_transfer; |
499 | |
500 | for (index = 0; index < output_length/4; index++) |
501 | buf_copy += snprintf(buf: buf_copy, PAGE_SIZE, |
502 | fmt: "%08x " , *(temp+index)); |
503 | |
504 | pm8001_ha->non_fatal_read_length += output_length; |
505 | |
506 | /* store current accumulated length to use in next iteration as |
507 | * the previous accumulated length |
508 | */ |
509 | pm8001_ha->forensic_preserved_accumulated_transfer = accum_len; |
510 | return (buf_copy - buf); |
511 | } |
512 | |
513 | /** |
514 | * read_main_config_table - read the configure table and save it. |
515 | * @pm8001_ha: our hba card information |
516 | */ |
517 | static void read_main_config_table(struct pm8001_hba_info *pm8001_ha) |
518 | { |
519 | void __iomem *address = pm8001_ha->main_cfg_tbl_addr; |
520 | |
521 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature = |
522 | pm8001_mr32(addr: address, MAIN_SIGNATURE_OFFSET); |
523 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev = |
524 | pm8001_mr32(addr: address, MAIN_INTERFACE_REVISION); |
525 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev = |
526 | pm8001_mr32(addr: address, MAIN_FW_REVISION); |
527 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io = |
528 | pm8001_mr32(addr: address, MAIN_MAX_OUTSTANDING_IO_OFFSET); |
529 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl = |
530 | pm8001_mr32(addr: address, MAIN_MAX_SGL_OFFSET); |
531 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.ctrl_cap_flag = |
532 | pm8001_mr32(addr: address, MAIN_CNTRL_CAP_OFFSET); |
533 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset = |
534 | pm8001_mr32(addr: address, MAIN_GST_OFFSET); |
535 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset = |
536 | pm8001_mr32(addr: address, MAIN_IBQ_OFFSET); |
537 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset = |
538 | pm8001_mr32(addr: address, MAIN_OBQ_OFFSET); |
539 | |
540 | /* read Error Dump Offset and Length */ |
541 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_offset0 = |
542 | pm8001_mr32(addr: address, MAIN_FATAL_ERROR_RDUMP0_OFFSET); |
543 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_length0 = |
544 | pm8001_mr32(addr: address, MAIN_FATAL_ERROR_RDUMP0_LENGTH); |
545 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_offset1 = |
546 | pm8001_mr32(addr: address, MAIN_FATAL_ERROR_RDUMP1_OFFSET); |
547 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_dump_length1 = |
548 | pm8001_mr32(addr: address, MAIN_FATAL_ERROR_RDUMP1_LENGTH); |
549 | |
550 | /* read GPIO LED settings from the configuration table */ |
551 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping = |
552 | pm8001_mr32(addr: address, MAIN_GPIO_LED_FLAGS_OFFSET); |
553 | |
554 | /* read analog Setting offset from the configuration table */ |
555 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.analog_setup_table_offset = |
556 | pm8001_mr32(addr: address, MAIN_ANALOG_SETUP_OFFSET); |
557 | |
558 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset = |
559 | pm8001_mr32(addr: address, MAIN_INT_VECTOR_TABLE_OFFSET); |
560 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset = |
561 | pm8001_mr32(addr: address, MAIN_SAS_PHY_ATTR_TABLE_OFFSET); |
562 | /* read port recover and reset timeout */ |
563 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer = |
564 | pm8001_mr32(addr: address, MAIN_PORT_RECOVERY_TIMER); |
565 | /* read ILA and inactive firmware version */ |
566 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version = |
567 | pm8001_mr32(addr: address, MAIN_MPI_ILA_RELEASE_TYPE); |
568 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version = |
569 | pm8001_mr32(addr: address, MAIN_MPI_INACTIVE_FW_VERSION); |
570 | |
571 | pm8001_dbg(pm8001_ha, DEV, |
572 | "Main cfg table: sign:%x interface rev:%x fw_rev:%x\n" , |
573 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature, |
574 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev, |
575 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev); |
576 | |
577 | pm8001_dbg(pm8001_ha, DEV, |
578 | "table offset: gst:%x iq:%x oq:%x int vec:%x phy attr:%x\n" , |
579 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset, |
580 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset, |
581 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset, |
582 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset, |
583 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset); |
584 | |
585 | pm8001_dbg(pm8001_ha, DEV, |
586 | "Main cfg table; ila rev:%x Inactive fw rev:%x\n" , |
587 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version, |
588 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version); |
589 | } |
590 | |
591 | /** |
592 | * read_general_status_table - read the general status table and save it. |
593 | * @pm8001_ha: our hba card information |
594 | */ |
595 | static void read_general_status_table(struct pm8001_hba_info *pm8001_ha) |
596 | { |
597 | void __iomem *address = pm8001_ha->general_stat_tbl_addr; |
598 | pm8001_ha->gs_tbl.pm80xx_tbl.gst_len_mpistate = |
599 | pm8001_mr32(addr: address, GST_GSTLEN_MPIS_OFFSET); |
600 | pm8001_ha->gs_tbl.pm80xx_tbl.iq_freeze_state0 = |
601 | pm8001_mr32(addr: address, GST_IQ_FREEZE_STATE0_OFFSET); |
602 | pm8001_ha->gs_tbl.pm80xx_tbl.iq_freeze_state1 = |
603 | pm8001_mr32(addr: address, GST_IQ_FREEZE_STATE1_OFFSET); |
604 | pm8001_ha->gs_tbl.pm80xx_tbl.msgu_tcnt = |
605 | pm8001_mr32(addr: address, GST_MSGUTCNT_OFFSET); |
606 | pm8001_ha->gs_tbl.pm80xx_tbl.iop_tcnt = |
607 | pm8001_mr32(addr: address, GST_IOPTCNT_OFFSET); |
608 | pm8001_ha->gs_tbl.pm80xx_tbl.gpio_input_val = |
609 | pm8001_mr32(addr: address, GST_GPIO_INPUT_VAL); |
610 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[0] = |
611 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET0); |
612 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[1] = |
613 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET1); |
614 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[2] = |
615 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET2); |
616 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[3] = |
617 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET3); |
618 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[4] = |
619 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET4); |
620 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[5] = |
621 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET5); |
622 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[6] = |
623 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET6); |
624 | pm8001_ha->gs_tbl.pm80xx_tbl.recover_err_info[7] = |
625 | pm8001_mr32(addr: address, GST_RERRINFO_OFFSET7); |
626 | } |
627 | /** |
628 | * read_phy_attr_table - read the phy attribute table and save it. |
629 | * @pm8001_ha: our hba card information |
630 | */ |
631 | static void read_phy_attr_table(struct pm8001_hba_info *pm8001_ha) |
632 | { |
633 | void __iomem *address = pm8001_ha->pspa_q_tbl_addr; |
634 | pm8001_ha->phy_attr_table.phystart1_16[0] = |
635 | pm8001_mr32(addr: address, PSPA_PHYSTATE0_OFFSET); |
636 | pm8001_ha->phy_attr_table.phystart1_16[1] = |
637 | pm8001_mr32(addr: address, PSPA_PHYSTATE1_OFFSET); |
638 | pm8001_ha->phy_attr_table.phystart1_16[2] = |
639 | pm8001_mr32(addr: address, PSPA_PHYSTATE2_OFFSET); |
640 | pm8001_ha->phy_attr_table.phystart1_16[3] = |
641 | pm8001_mr32(addr: address, PSPA_PHYSTATE3_OFFSET); |
642 | pm8001_ha->phy_attr_table.phystart1_16[4] = |
643 | pm8001_mr32(addr: address, PSPA_PHYSTATE4_OFFSET); |
644 | pm8001_ha->phy_attr_table.phystart1_16[5] = |
645 | pm8001_mr32(addr: address, PSPA_PHYSTATE5_OFFSET); |
646 | pm8001_ha->phy_attr_table.phystart1_16[6] = |
647 | pm8001_mr32(addr: address, PSPA_PHYSTATE6_OFFSET); |
648 | pm8001_ha->phy_attr_table.phystart1_16[7] = |
649 | pm8001_mr32(addr: address, PSPA_PHYSTATE7_OFFSET); |
650 | pm8001_ha->phy_attr_table.phystart1_16[8] = |
651 | pm8001_mr32(addr: address, PSPA_PHYSTATE8_OFFSET); |
652 | pm8001_ha->phy_attr_table.phystart1_16[9] = |
653 | pm8001_mr32(addr: address, PSPA_PHYSTATE9_OFFSET); |
654 | pm8001_ha->phy_attr_table.phystart1_16[10] = |
655 | pm8001_mr32(addr: address, PSPA_PHYSTATE10_OFFSET); |
656 | pm8001_ha->phy_attr_table.phystart1_16[11] = |
657 | pm8001_mr32(addr: address, PSPA_PHYSTATE11_OFFSET); |
658 | pm8001_ha->phy_attr_table.phystart1_16[12] = |
659 | pm8001_mr32(addr: address, PSPA_PHYSTATE12_OFFSET); |
660 | pm8001_ha->phy_attr_table.phystart1_16[13] = |
661 | pm8001_mr32(addr: address, PSPA_PHYSTATE13_OFFSET); |
662 | pm8001_ha->phy_attr_table.phystart1_16[14] = |
663 | pm8001_mr32(addr: address, PSPA_PHYSTATE14_OFFSET); |
664 | pm8001_ha->phy_attr_table.phystart1_16[15] = |
665 | pm8001_mr32(addr: address, PSPA_PHYSTATE15_OFFSET); |
666 | |
667 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[0] = |
668 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID0_OFFSET); |
669 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[1] = |
670 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID1_OFFSET); |
671 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[2] = |
672 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID2_OFFSET); |
673 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[3] = |
674 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID3_OFFSET); |
675 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[4] = |
676 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID4_OFFSET); |
677 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[5] = |
678 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID5_OFFSET); |
679 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[6] = |
680 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID6_OFFSET); |
681 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[7] = |
682 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID7_OFFSET); |
683 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[8] = |
684 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID8_OFFSET); |
685 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[9] = |
686 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID9_OFFSET); |
687 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[10] = |
688 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID10_OFFSET); |
689 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[11] = |
690 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID11_OFFSET); |
691 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[12] = |
692 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID12_OFFSET); |
693 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[13] = |
694 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID13_OFFSET); |
695 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[14] = |
696 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID14_OFFSET); |
697 | pm8001_ha->phy_attr_table.outbound_hw_event_pid1_16[15] = |
698 | pm8001_mr32(addr: address, PSPA_OB_HW_EVENT_PID15_OFFSET); |
699 | |
700 | } |
701 | |
702 | /** |
703 | * read_inbnd_queue_table - read the inbound queue table and save it. |
704 | * @pm8001_ha: our hba card information |
705 | */ |
706 | static void read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha) |
707 | { |
708 | int i; |
709 | void __iomem *address = pm8001_ha->inbnd_q_tbl_addr; |
710 | for (i = 0; i < PM8001_MAX_INB_NUM; i++) { |
711 | u32 offset = i * 0x20; |
712 | pm8001_ha->inbnd_q_tbl[i].pi_pci_bar = |
713 | get_pci_bar_index(pcibar: pm8001_mr32(addr: address, |
714 | offset: (offset + IB_PIPCI_BAR))); |
715 | pm8001_ha->inbnd_q_tbl[i].pi_offset = |
716 | pm8001_mr32(addr: address, offset: (offset + IB_PIPCI_BAR_OFFSET)); |
717 | } |
718 | } |
719 | |
720 | /** |
721 | * read_outbnd_queue_table - read the outbound queue table and save it. |
722 | * @pm8001_ha: our hba card information |
723 | */ |
724 | static void read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha) |
725 | { |
726 | int i; |
727 | void __iomem *address = pm8001_ha->outbnd_q_tbl_addr; |
728 | for (i = 0; i < PM8001_MAX_OUTB_NUM; i++) { |
729 | u32 offset = i * 0x24; |
730 | pm8001_ha->outbnd_q_tbl[i].ci_pci_bar = |
731 | get_pci_bar_index(pcibar: pm8001_mr32(addr: address, |
732 | offset: (offset + OB_CIPCI_BAR))); |
733 | pm8001_ha->outbnd_q_tbl[i].ci_offset = |
734 | pm8001_mr32(addr: address, offset: (offset + OB_CIPCI_BAR_OFFSET)); |
735 | } |
736 | } |
737 | |
738 | /** |
739 | * init_default_table_values - init the default table. |
740 | * @pm8001_ha: our hba card information |
741 | */ |
742 | static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) |
743 | { |
744 | int i; |
745 | u32 offsetib, offsetob; |
746 | void __iomem *addressib = pm8001_ha->inbnd_q_tbl_addr; |
747 | void __iomem *addressob = pm8001_ha->outbnd_q_tbl_addr; |
748 | u32 ib_offset = pm8001_ha->ib_offset; |
749 | u32 ob_offset = pm8001_ha->ob_offset; |
750 | u32 ci_offset = pm8001_ha->ci_offset; |
751 | u32 pi_offset = pm8001_ha->pi_offset; |
752 | |
753 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_event_log_addr = |
754 | pm8001_ha->memoryMap.region[AAP1].phys_addr_hi; |
755 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_event_log_addr = |
756 | pm8001_ha->memoryMap.region[AAP1].phys_addr_lo; |
757 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size = |
758 | PM8001_EVENT_LOG_SIZE; |
759 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_severity = 0x01; |
760 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_pcs_event_log_addr = |
761 | pm8001_ha->memoryMap.region[IOP].phys_addr_hi; |
762 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_pcs_event_log_addr = |
763 | pm8001_ha->memoryMap.region[IOP].phys_addr_lo; |
764 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size = |
765 | PM8001_EVENT_LOG_SIZE; |
766 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity = 0x01; |
767 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt = 0x01; |
768 | |
769 | /* Enable higher IQs and OQs, 32 to 63, bit 16 */ |
770 | if (pm8001_ha->max_q_num > 32) |
771 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |= |
772 | 1 << 16; |
773 | /* Disable end to end CRC checking */ |
774 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump = (0x1 << 16); |
775 | |
776 | for (i = 0; i < pm8001_ha->max_q_num; i++) { |
777 | pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt = |
778 | PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x00<<30); |
779 | pm8001_ha->inbnd_q_tbl[i].upper_base_addr = |
780 | pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_hi; |
781 | pm8001_ha->inbnd_q_tbl[i].lower_base_addr = |
782 | pm8001_ha->memoryMap.region[ib_offset + i].phys_addr_lo; |
783 | pm8001_ha->inbnd_q_tbl[i].base_virt = |
784 | (u8 *)pm8001_ha->memoryMap.region[ib_offset + i].virt_ptr; |
785 | pm8001_ha->inbnd_q_tbl[i].total_length = |
786 | pm8001_ha->memoryMap.region[ib_offset + i].total_len; |
787 | pm8001_ha->inbnd_q_tbl[i].ci_upper_base_addr = |
788 | pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_hi; |
789 | pm8001_ha->inbnd_q_tbl[i].ci_lower_base_addr = |
790 | pm8001_ha->memoryMap.region[ci_offset + i].phys_addr_lo; |
791 | pm8001_ha->inbnd_q_tbl[i].ci_virt = |
792 | pm8001_ha->memoryMap.region[ci_offset + i].virt_ptr; |
793 | pm8001_write_32(addr: pm8001_ha->inbnd_q_tbl[i].ci_virt, offset: 0, val: 0); |
794 | offsetib = i * 0x20; |
795 | pm8001_ha->inbnd_q_tbl[i].pi_pci_bar = |
796 | get_pci_bar_index(pcibar: pm8001_mr32(addr: addressib, |
797 | offset: (offsetib + 0x14))); |
798 | pm8001_ha->inbnd_q_tbl[i].pi_offset = |
799 | pm8001_mr32(addr: addressib, offset: (offsetib + 0x18)); |
800 | pm8001_ha->inbnd_q_tbl[i].producer_idx = 0; |
801 | pm8001_ha->inbnd_q_tbl[i].consumer_index = 0; |
802 | |
803 | pm8001_dbg(pm8001_ha, DEV, |
804 | "IQ %d pi_bar 0x%x pi_offset 0x%x\n" , i, |
805 | pm8001_ha->inbnd_q_tbl[i].pi_pci_bar, |
806 | pm8001_ha->inbnd_q_tbl[i].pi_offset); |
807 | } |
808 | for (i = 0; i < pm8001_ha->max_q_num; i++) { |
809 | pm8001_ha->outbnd_q_tbl[i].element_size_cnt = |
810 | PM8001_MPI_QUEUE | (pm8001_ha->iomb_size << 16) | (0x01<<30); |
811 | pm8001_ha->outbnd_q_tbl[i].upper_base_addr = |
812 | pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_hi; |
813 | pm8001_ha->outbnd_q_tbl[i].lower_base_addr = |
814 | pm8001_ha->memoryMap.region[ob_offset + i].phys_addr_lo; |
815 | pm8001_ha->outbnd_q_tbl[i].base_virt = |
816 | (u8 *)pm8001_ha->memoryMap.region[ob_offset + i].virt_ptr; |
817 | pm8001_ha->outbnd_q_tbl[i].total_length = |
818 | pm8001_ha->memoryMap.region[ob_offset + i].total_len; |
819 | pm8001_ha->outbnd_q_tbl[i].pi_upper_base_addr = |
820 | pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_hi; |
821 | pm8001_ha->outbnd_q_tbl[i].pi_lower_base_addr = |
822 | pm8001_ha->memoryMap.region[pi_offset + i].phys_addr_lo; |
823 | /* interrupt vector based on oq */ |
824 | pm8001_ha->outbnd_q_tbl[i].interrup_vec_cnt_delay = (i << 24); |
825 | pm8001_ha->outbnd_q_tbl[i].pi_virt = |
826 | pm8001_ha->memoryMap.region[pi_offset + i].virt_ptr; |
827 | pm8001_write_32(addr: pm8001_ha->outbnd_q_tbl[i].pi_virt, offset: 0, val: 0); |
828 | offsetob = i * 0x24; |
829 | pm8001_ha->outbnd_q_tbl[i].ci_pci_bar = |
830 | get_pci_bar_index(pcibar: pm8001_mr32(addr: addressob, |
831 | offset: offsetob + 0x14)); |
832 | pm8001_ha->outbnd_q_tbl[i].ci_offset = |
833 | pm8001_mr32(addr: addressob, offset: (offsetob + 0x18)); |
834 | pm8001_ha->outbnd_q_tbl[i].consumer_idx = 0; |
835 | pm8001_ha->outbnd_q_tbl[i].producer_index = 0; |
836 | |
837 | pm8001_dbg(pm8001_ha, DEV, |
838 | "OQ %d ci_bar 0x%x ci_offset 0x%x\n" , i, |
839 | pm8001_ha->outbnd_q_tbl[i].ci_pci_bar, |
840 | pm8001_ha->outbnd_q_tbl[i].ci_offset); |
841 | } |
842 | } |
843 | |
844 | /** |
845 | * update_main_config_table - update the main default table to the HBA. |
846 | * @pm8001_ha: our hba card information |
847 | */ |
848 | static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) |
849 | { |
850 | void __iomem *address = pm8001_ha->main_cfg_tbl_addr; |
851 | pm8001_mw32(addr: address, MAIN_IQNPPD_HPPD_OFFSET, |
852 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_q_nppd_hppd); |
853 | pm8001_mw32(addr: address, MAIN_EVENT_LOG_ADDR_HI, |
854 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_event_log_addr); |
855 | pm8001_mw32(addr: address, MAIN_EVENT_LOG_ADDR_LO, |
856 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_event_log_addr); |
857 | pm8001_mw32(addr: address, MAIN_EVENT_LOG_BUFF_SIZE, |
858 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_size); |
859 | pm8001_mw32(addr: address, MAIN_EVENT_LOG_OPTION, |
860 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.event_log_severity); |
861 | pm8001_mw32(addr: address, MAIN_PCS_EVENT_LOG_ADDR_HI, |
862 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.upper_pcs_event_log_addr); |
863 | pm8001_mw32(addr: address, MAIN_PCS_EVENT_LOG_ADDR_LO, |
864 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.lower_pcs_event_log_addr); |
865 | pm8001_mw32(addr: address, MAIN_PCS_EVENT_LOG_BUFF_SIZE, |
866 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size); |
867 | pm8001_mw32(addr: address, MAIN_PCS_EVENT_LOG_OPTION, |
868 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); |
869 | /* Update Fatal error interrupt vector */ |
870 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |= |
871 | ((pm8001_ha->max_q_num - 1) << 8); |
872 | pm8001_mw32(addr: address, MAIN_FATAL_ERROR_INTERRUPT, |
873 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); |
874 | pm8001_dbg(pm8001_ha, DEV, |
875 | "Updated Fatal error interrupt vector 0x%x\n" , |
876 | pm8001_mr32(address, MAIN_FATAL_ERROR_INTERRUPT)); |
877 | |
878 | pm8001_mw32(addr: address, MAIN_EVENT_CRC_CHECK, |
879 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump); |
880 | |
881 | /* SPCv specific */ |
882 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping &= 0xCFFFFFFF; |
883 | /* Set GPIOLED to 0x2 for LED indicator */ |
884 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping |= 0x20000000; |
885 | pm8001_mw32(addr: address, MAIN_GPIO_LED_FLAGS_OFFSET, |
886 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping); |
887 | pm8001_dbg(pm8001_ha, DEV, |
888 | "Programming DW 0x21 in main cfg table with 0x%x\n" , |
889 | pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET)); |
890 | |
891 | pm8001_mw32(addr: address, MAIN_PORT_RECOVERY_TIMER, |
892 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); |
893 | pm8001_mw32(addr: address, MAIN_INT_REASSERTION_DELAY, |
894 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.interrupt_reassertion_delay); |
895 | |
896 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= 0xffff0000; |
897 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |= |
898 | PORT_RECOVERY_TIMEOUT; |
899 | if (pm8001_ha->chip_id == chip_8006) { |
900 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= |
901 | 0x0000ffff; |
902 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |= |
903 | CHIP_8006_PORT_RECOVERY_TIMEOUT; |
904 | } |
905 | pm8001_mw32(addr: address, MAIN_PORT_RECOVERY_TIMER, |
906 | val: pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); |
907 | } |
908 | |
909 | /** |
910 | * update_inbnd_queue_table - update the inbound queue table to the HBA. |
911 | * @pm8001_ha: our hba card information |
912 | * @number: entry in the queue |
913 | */ |
914 | static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, |
915 | int number) |
916 | { |
917 | void __iomem *address = pm8001_ha->inbnd_q_tbl_addr; |
918 | u16 offset = number * 0x20; |
919 | pm8001_mw32(addr: address, offset: offset + IB_PROPERITY_OFFSET, |
920 | val: pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt); |
921 | pm8001_mw32(addr: address, offset: offset + IB_BASE_ADDR_HI_OFFSET, |
922 | val: pm8001_ha->inbnd_q_tbl[number].upper_base_addr); |
923 | pm8001_mw32(addr: address, offset: offset + IB_BASE_ADDR_LO_OFFSET, |
924 | val: pm8001_ha->inbnd_q_tbl[number].lower_base_addr); |
925 | pm8001_mw32(addr: address, offset: offset + IB_CI_BASE_ADDR_HI_OFFSET, |
926 | val: pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr); |
927 | pm8001_mw32(addr: address, offset: offset + IB_CI_BASE_ADDR_LO_OFFSET, |
928 | val: pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); |
929 | |
930 | pm8001_dbg(pm8001_ha, DEV, |
931 | "IQ %d: Element pri size 0x%x\n" , |
932 | number, |
933 | pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt); |
934 | |
935 | pm8001_dbg(pm8001_ha, DEV, |
936 | "IQ upr base addr 0x%x IQ lwr base addr 0x%x\n" , |
937 | pm8001_ha->inbnd_q_tbl[number].upper_base_addr, |
938 | pm8001_ha->inbnd_q_tbl[number].lower_base_addr); |
939 | |
940 | pm8001_dbg(pm8001_ha, DEV, |
941 | "CI upper base addr 0x%x CI lower base addr 0x%x\n" , |
942 | pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr, |
943 | pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); |
944 | } |
945 | |
946 | /** |
947 | * update_outbnd_queue_table - update the outbound queue table to the HBA. |
948 | * @pm8001_ha: our hba card information |
949 | * @number: entry in the queue |
950 | */ |
951 | static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, |
952 | int number) |
953 | { |
954 | void __iomem *address = pm8001_ha->outbnd_q_tbl_addr; |
955 | u16 offset = number * 0x24; |
956 | pm8001_mw32(addr: address, offset: offset + OB_PROPERITY_OFFSET, |
957 | val: pm8001_ha->outbnd_q_tbl[number].element_size_cnt); |
958 | pm8001_mw32(addr: address, offset: offset + OB_BASE_ADDR_HI_OFFSET, |
959 | val: pm8001_ha->outbnd_q_tbl[number].upper_base_addr); |
960 | pm8001_mw32(addr: address, offset: offset + OB_BASE_ADDR_LO_OFFSET, |
961 | val: pm8001_ha->outbnd_q_tbl[number].lower_base_addr); |
962 | pm8001_mw32(addr: address, offset: offset + OB_PI_BASE_ADDR_HI_OFFSET, |
963 | val: pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr); |
964 | pm8001_mw32(addr: address, offset: offset + OB_PI_BASE_ADDR_LO_OFFSET, |
965 | val: pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr); |
966 | pm8001_mw32(addr: address, offset: offset + OB_INTERRUPT_COALES_OFFSET, |
967 | val: pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay); |
968 | |
969 | pm8001_dbg(pm8001_ha, DEV, |
970 | "OQ %d: Element pri size 0x%x\n" , |
971 | number, |
972 | pm8001_ha->outbnd_q_tbl[number].element_size_cnt); |
973 | |
974 | pm8001_dbg(pm8001_ha, DEV, |
975 | "OQ upr base addr 0x%x OQ lwr base addr 0x%x\n" , |
976 | pm8001_ha->outbnd_q_tbl[number].upper_base_addr, |
977 | pm8001_ha->outbnd_q_tbl[number].lower_base_addr); |
978 | |
979 | pm8001_dbg(pm8001_ha, DEV, |
980 | "PI upper base addr 0x%x PI lower base addr 0x%x\n" , |
981 | pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr, |
982 | pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr); |
983 | } |
984 | |
985 | /** |
986 | * mpi_init_check - check firmware initialization status. |
987 | * @pm8001_ha: our hba card information |
988 | */ |
989 | static int mpi_init_check(struct pm8001_hba_info *pm8001_ha) |
990 | { |
991 | u32 max_wait_count; |
992 | u32 value; |
993 | u32 gst_len_mpistate; |
994 | |
995 | /* Write bit0=1 to Inbound DoorBell Register to tell the SPC FW the |
996 | table is updated */ |
997 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_UPDATE); |
998 | /* wait until Inbound DoorBell Clear Register toggled */ |
999 | if (IS_SPCV_12G(pm8001_ha->pdev)) { |
1000 | max_wait_count = SPCV_DOORBELL_CLEAR_TIMEOUT; |
1001 | } else { |
1002 | max_wait_count = SPC_DOORBELL_CLEAR_TIMEOUT; |
1003 | } |
1004 | do { |
1005 | msleep(FW_READY_INTERVAL); |
1006 | value = pm8001_cr32(pm8001_ha, bar: 0, MSGU_IBDB_SET); |
1007 | value &= SPCv_MSGU_CFG_TABLE_UPDATE; |
1008 | } while ((value != 0) && (--max_wait_count)); |
1009 | |
1010 | if (!max_wait_count) { |
1011 | /* additional check */ |
1012 | pm8001_dbg(pm8001_ha, FAIL, |
1013 | "Inb doorbell clear not toggled[value:%x]\n" , |
1014 | value); |
1015 | return -EBUSY; |
1016 | } |
1017 | /* check the MPI-State for initialization up to 100ms*/ |
1018 | max_wait_count = 5;/* 100 msec */ |
1019 | do { |
1020 | msleep(FW_READY_INTERVAL); |
1021 | gst_len_mpistate = |
1022 | pm8001_mr32(addr: pm8001_ha->general_stat_tbl_addr, |
1023 | GST_GSTLEN_MPIS_OFFSET); |
1024 | } while ((GST_MPI_STATE_INIT != |
1025 | (gst_len_mpistate & GST_MPI_STATE_MASK)) && (--max_wait_count)); |
1026 | if (!max_wait_count) |
1027 | return -EBUSY; |
1028 | |
1029 | /* check MPI Initialization error */ |
1030 | gst_len_mpistate = gst_len_mpistate >> 16; |
1031 | if (0x0000 != gst_len_mpistate) |
1032 | return -EBUSY; |
1033 | |
1034 | /* |
1035 | * As per controller datasheet, after successful MPI |
1036 | * initialization minimum 500ms delay is required before |
1037 | * issuing commands. |
1038 | */ |
1039 | msleep(msecs: 500); |
1040 | |
1041 | return 0; |
1042 | } |
1043 | |
1044 | /** |
1045 | * check_fw_ready - The LLDD check if the FW is ready, if not, return error. |
1046 | * This function sleeps hence it must not be used in atomic context. |
1047 | * @pm8001_ha: our hba card information |
1048 | */ |
1049 | static int check_fw_ready(struct pm8001_hba_info *pm8001_ha) |
1050 | { |
1051 | u32 value; |
1052 | u32 max_wait_count; |
1053 | u32 max_wait_time; |
1054 | u32 expected_mask; |
1055 | int ret = 0; |
1056 | |
1057 | /* reset / PCIe ready */ |
1058 | max_wait_time = max_wait_count = 5; /* 100 milli sec */ |
1059 | do { |
1060 | msleep(FW_READY_INTERVAL); |
1061 | value = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_1); |
1062 | } while ((value == 0xFFFFFFFF) && (--max_wait_count)); |
1063 | |
1064 | /* check ila, RAAE and iops status */ |
1065 | if ((pm8001_ha->chip_id != chip_8008) && |
1066 | (pm8001_ha->chip_id != chip_8009)) { |
1067 | max_wait_time = max_wait_count = 180; /* 3600 milli sec */ |
1068 | expected_mask = SCRATCH_PAD_ILA_READY | |
1069 | SCRATCH_PAD_RAAE_READY | |
1070 | SCRATCH_PAD_IOP0_READY | |
1071 | SCRATCH_PAD_IOP1_READY; |
1072 | } else { |
1073 | max_wait_time = max_wait_count = 170; /* 3400 milli sec */ |
1074 | expected_mask = SCRATCH_PAD_ILA_READY | |
1075 | SCRATCH_PAD_RAAE_READY | |
1076 | SCRATCH_PAD_IOP0_READY; |
1077 | } |
1078 | do { |
1079 | msleep(FW_READY_INTERVAL); |
1080 | value = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_1); |
1081 | } while (((value & expected_mask) != |
1082 | expected_mask) && (--max_wait_count)); |
1083 | if (!max_wait_count) { |
1084 | pm8001_dbg(pm8001_ha, INIT, |
1085 | "At least one FW component failed to load within %d millisec: Scratchpad1: 0x%x\n" , |
1086 | max_wait_time * FW_READY_INTERVAL, value); |
1087 | ret = -1; |
1088 | } else { |
1089 | pm8001_dbg(pm8001_ha, MSG, |
1090 | "All FW components ready by %d ms\n" , |
1091 | (max_wait_time - max_wait_count) * FW_READY_INTERVAL); |
1092 | } |
1093 | return ret; |
1094 | } |
1095 | |
1096 | static int init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) |
1097 | { |
1098 | void __iomem *base_addr; |
1099 | u32 value; |
1100 | u32 offset; |
1101 | u32 pcibar; |
1102 | u32 pcilogic; |
1103 | |
1104 | value = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_0); |
1105 | |
1106 | /* |
1107 | * lower 26 bits of SCRATCHPAD0 register describes offset within the |
1108 | * PCIe BAR where the MPI configuration table is present |
1109 | */ |
1110 | offset = value & 0x03FFFFFF; /* scratch pad 0 TBL address */ |
1111 | |
1112 | pm8001_dbg(pm8001_ha, DEV, "Scratchpad 0 Offset: 0x%x value 0x%x\n" , |
1113 | offset, value); |
1114 | /* |
1115 | * Upper 6 bits describe the offset within PCI config space where BAR |
1116 | * is located. |
1117 | */ |
1118 | pcilogic = (value & 0xFC000000) >> 26; |
1119 | pcibar = get_pci_bar_index(pcibar: pcilogic); |
1120 | pm8001_dbg(pm8001_ha, INIT, "Scratchpad 0 PCI BAR: %d\n" , pcibar); |
1121 | |
1122 | /* |
1123 | * Make sure the offset falls inside the ioremapped PCI BAR |
1124 | */ |
1125 | if (offset > pm8001_ha->io_mem[pcibar].memsize) { |
1126 | pm8001_dbg(pm8001_ha, FAIL, |
1127 | "Main cfg tbl offset outside %u > %u\n" , |
1128 | offset, pm8001_ha->io_mem[pcibar].memsize); |
1129 | return -EBUSY; |
1130 | } |
1131 | pm8001_ha->main_cfg_tbl_addr = base_addr = |
1132 | pm8001_ha->io_mem[pcibar].memvirtaddr + offset; |
1133 | |
1134 | /* |
1135 | * Validate main configuration table address: first DWord should read |
1136 | * "PMCS" |
1137 | */ |
1138 | value = pm8001_mr32(addr: pm8001_ha->main_cfg_tbl_addr, offset: 0); |
1139 | if (memcmp(p: &value, q: "PMCS" , size: 4) != 0) { |
1140 | pm8001_dbg(pm8001_ha, FAIL, |
1141 | "BAD main config signature 0x%x\n" , |
1142 | value); |
1143 | return -EBUSY; |
1144 | } |
1145 | pm8001_dbg(pm8001_ha, INIT, |
1146 | "VALID main config signature 0x%x\n" , value); |
1147 | pm8001_ha->general_stat_tbl_addr = |
1148 | base_addr + (pm8001_cr32(pm8001_ha, bar: pcibar, offset: offset + 0x18) & |
1149 | 0xFFFFFF); |
1150 | pm8001_ha->inbnd_q_tbl_addr = |
1151 | base_addr + (pm8001_cr32(pm8001_ha, bar: pcibar, offset: offset + 0x1C) & |
1152 | 0xFFFFFF); |
1153 | pm8001_ha->outbnd_q_tbl_addr = |
1154 | base_addr + (pm8001_cr32(pm8001_ha, bar: pcibar, offset: offset + 0x20) & |
1155 | 0xFFFFFF); |
1156 | pm8001_ha->ivt_tbl_addr = |
1157 | base_addr + (pm8001_cr32(pm8001_ha, bar: pcibar, offset: offset + 0x8C) & |
1158 | 0xFFFFFF); |
1159 | pm8001_ha->pspa_q_tbl_addr = |
1160 | base_addr + (pm8001_cr32(pm8001_ha, bar: pcibar, offset: offset + 0x90) & |
1161 | 0xFFFFFF); |
1162 | pm8001_ha->fatal_tbl_addr = |
1163 | base_addr + (pm8001_cr32(pm8001_ha, bar: pcibar, offset: offset + 0xA0) & |
1164 | 0xFFFFFF); |
1165 | |
1166 | pm8001_dbg(pm8001_ha, INIT, "GST OFFSET 0x%x\n" , |
1167 | pm8001_cr32(pm8001_ha, pcibar, offset + 0x18)); |
1168 | pm8001_dbg(pm8001_ha, INIT, "INBND OFFSET 0x%x\n" , |
1169 | pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C)); |
1170 | pm8001_dbg(pm8001_ha, INIT, "OBND OFFSET 0x%x\n" , |
1171 | pm8001_cr32(pm8001_ha, pcibar, offset + 0x20)); |
1172 | pm8001_dbg(pm8001_ha, INIT, "IVT OFFSET 0x%x\n" , |
1173 | pm8001_cr32(pm8001_ha, pcibar, offset + 0x8C)); |
1174 | pm8001_dbg(pm8001_ha, INIT, "PSPA OFFSET 0x%x\n" , |
1175 | pm8001_cr32(pm8001_ha, pcibar, offset + 0x90)); |
1176 | pm8001_dbg(pm8001_ha, INIT, "addr - main cfg %p general status %p\n" , |
1177 | pm8001_ha->main_cfg_tbl_addr, |
1178 | pm8001_ha->general_stat_tbl_addr); |
1179 | pm8001_dbg(pm8001_ha, INIT, "addr - inbnd %p obnd %p\n" , |
1180 | pm8001_ha->inbnd_q_tbl_addr, |
1181 | pm8001_ha->outbnd_q_tbl_addr); |
1182 | pm8001_dbg(pm8001_ha, INIT, "addr - pspa %p ivt %p\n" , |
1183 | pm8001_ha->pspa_q_tbl_addr, |
1184 | pm8001_ha->ivt_tbl_addr); |
1185 | return 0; |
1186 | } |
1187 | |
1188 | /** |
1189 | * pm80xx_set_thermal_config - support the thermal configuration |
1190 | * @pm8001_ha: our hba card information. |
1191 | */ |
1192 | int |
1193 | pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) |
1194 | { |
1195 | struct set_ctrl_cfg_req payload; |
1196 | int rc; |
1197 | u32 tag; |
1198 | u32 opc = OPC_INB_SET_CONTROLLER_CONFIG; |
1199 | u32 page_code; |
1200 | |
1201 | memset(&payload, 0, sizeof(struct set_ctrl_cfg_req)); |
1202 | rc = pm8001_tag_alloc(pm8001_ha, tag_out: &tag); |
1203 | if (rc) |
1204 | return rc; |
1205 | |
1206 | payload.tag = cpu_to_le32(tag); |
1207 | |
1208 | if (IS_SPCV_12G(pm8001_ha->pdev)) |
1209 | page_code = THERMAL_PAGE_CODE_7H; |
1210 | else |
1211 | page_code = THERMAL_PAGE_CODE_8H; |
1212 | |
1213 | payload.cfg_pg[0] = |
1214 | cpu_to_le32((THERMAL_LOG_ENABLE << 9) | |
1215 | (THERMAL_ENABLE << 8) | page_code); |
1216 | payload.cfg_pg[1] = |
1217 | cpu_to_le32((LTEMPHIL << 24) | (RTEMPHIL << 8)); |
1218 | |
1219 | pm8001_dbg(pm8001_ha, DEV, |
1220 | "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n" , |
1221 | payload.cfg_pg[0], payload.cfg_pg[1]); |
1222 | |
1223 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &payload, |
1224 | nb: sizeof(payload), responseQueue: 0); |
1225 | if (rc) |
1226 | pm8001_tag_free(pm8001_ha, tag); |
1227 | return rc; |
1228 | |
1229 | } |
1230 | |
1231 | /** |
1232 | * pm80xx_set_sas_protocol_timer_config - support the SAS Protocol |
1233 | * Timer configuration page |
1234 | * @pm8001_ha: our hba card information. |
1235 | */ |
1236 | static int |
1237 | pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) |
1238 | { |
1239 | struct set_ctrl_cfg_req payload; |
1240 | SASProtocolTimerConfig_t SASConfigPage; |
1241 | int rc; |
1242 | u32 tag; |
1243 | u32 opc = OPC_INB_SET_CONTROLLER_CONFIG; |
1244 | |
1245 | memset(&payload, 0, sizeof(struct set_ctrl_cfg_req)); |
1246 | memset(&SASConfigPage, 0, sizeof(SASProtocolTimerConfig_t)); |
1247 | |
1248 | rc = pm8001_tag_alloc(pm8001_ha, tag_out: &tag); |
1249 | if (rc) |
1250 | return rc; |
1251 | |
1252 | payload.tag = cpu_to_le32(tag); |
1253 | |
1254 | SASConfigPage.pageCode = cpu_to_le32(SAS_PROTOCOL_TIMER_CONFIG_PAGE); |
1255 | SASConfigPage.MST_MSI = cpu_to_le32(3 << 15); |
1256 | SASConfigPage.STP_SSP_MCT_TMO = |
1257 | cpu_to_le32((STP_MCT_TMO << 16) | SSP_MCT_TMO); |
1258 | SASConfigPage.STP_FRM_TMO = |
1259 | cpu_to_le32((SAS_MAX_OPEN_TIME << 24) | |
1260 | (SMP_MAX_CONN_TIMER << 16) | STP_FRM_TIMER); |
1261 | SASConfigPage.STP_IDLE_TMO = cpu_to_le32(STP_IDLE_TIME); |
1262 | |
1263 | SASConfigPage.OPNRJT_RTRY_INTVL = |
1264 | cpu_to_le32((SAS_MFD << 16) | SAS_OPNRJT_RTRY_INTVL); |
1265 | SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO = |
1266 | cpu_to_le32((SAS_DOPNRJT_RTRY_TMO << 16) | SAS_COPNRJT_RTRY_TMO); |
1267 | SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR = |
1268 | cpu_to_le32((SAS_DOPNRJT_RTRY_THR << 16) | SAS_COPNRJT_RTRY_THR); |
1269 | SASConfigPage.MAX_AIP = cpu_to_le32(SAS_MAX_AIP); |
1270 | |
1271 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.pageCode 0x%08x\n" , |
1272 | le32_to_cpu(SASConfigPage.pageCode)); |
1273 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MST_MSI 0x%08x\n" , |
1274 | le32_to_cpu(SASConfigPage.MST_MSI)); |
1275 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_SSP_MCT_TMO 0x%08x\n" , |
1276 | le32_to_cpu(SASConfigPage.STP_SSP_MCT_TMO)); |
1277 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_FRM_TMO 0x%08x\n" , |
1278 | le32_to_cpu(SASConfigPage.STP_FRM_TMO)); |
1279 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.STP_IDLE_TMO 0x%08x\n" , |
1280 | le32_to_cpu(SASConfigPage.STP_IDLE_TMO)); |
1281 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.OPNRJT_RTRY_INTVL 0x%08x\n" , |
1282 | le32_to_cpu(SASConfigPage.OPNRJT_RTRY_INTVL)); |
1283 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO 0x%08x\n" , |
1284 | le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_TMO)); |
1285 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR 0x%08x\n" , |
1286 | le32_to_cpu(SASConfigPage.Data_Cmd_OPNRJT_RTRY_THR)); |
1287 | pm8001_dbg(pm8001_ha, INIT, "SASConfigPage.MAX_AIP 0x%08x\n" , |
1288 | le32_to_cpu(SASConfigPage.MAX_AIP)); |
1289 | |
1290 | memcpy(&payload.cfg_pg, &SASConfigPage, |
1291 | sizeof(SASProtocolTimerConfig_t)); |
1292 | |
1293 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &payload, |
1294 | nb: sizeof(payload), responseQueue: 0); |
1295 | if (rc) |
1296 | pm8001_tag_free(pm8001_ha, tag); |
1297 | |
1298 | return rc; |
1299 | } |
1300 | |
1301 | /** |
1302 | * pm80xx_get_encrypt_info - Check for encryption |
1303 | * @pm8001_ha: our hba card information. |
1304 | */ |
1305 | static int |
1306 | pm80xx_get_encrypt_info(struct pm8001_hba_info *pm8001_ha) |
1307 | { |
1308 | u32 scratch3_value; |
1309 | int ret = -1; |
1310 | |
1311 | /* Read encryption status from SCRATCH PAD 3 */ |
1312 | scratch3_value = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_3); |
1313 | |
1314 | if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) == |
1315 | SCRATCH_PAD3_ENC_READY) { |
1316 | if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED) |
1317 | pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS; |
1318 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1319 | SCRATCH_PAD3_SMF_ENABLED) |
1320 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF; |
1321 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1322 | SCRATCH_PAD3_SMA_ENABLED) |
1323 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA; |
1324 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1325 | SCRATCH_PAD3_SMB_ENABLED) |
1326 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; |
1327 | pm8001_ha->encrypt_info.status = 0; |
1328 | pm8001_dbg(pm8001_ha, INIT, |
1329 | "Encryption: SCRATCH_PAD3_ENC_READY 0x%08X.Cipher mode 0x%x Sec mode 0x%x status 0x%x\n" , |
1330 | scratch3_value, |
1331 | pm8001_ha->encrypt_info.cipher_mode, |
1332 | pm8001_ha->encrypt_info.sec_mode, |
1333 | pm8001_ha->encrypt_info.status); |
1334 | ret = 0; |
1335 | } else if ((scratch3_value & SCRATCH_PAD3_ENC_READY) == |
1336 | SCRATCH_PAD3_ENC_DISABLED) { |
1337 | pm8001_dbg(pm8001_ha, INIT, |
1338 | "Encryption: SCRATCH_PAD3_ENC_DISABLED 0x%08X\n" , |
1339 | scratch3_value); |
1340 | pm8001_ha->encrypt_info.status = 0xFFFFFFFF; |
1341 | pm8001_ha->encrypt_info.cipher_mode = 0; |
1342 | pm8001_ha->encrypt_info.sec_mode = 0; |
1343 | ret = 0; |
1344 | } else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) == |
1345 | SCRATCH_PAD3_ENC_DIS_ERR) { |
1346 | pm8001_ha->encrypt_info.status = |
1347 | (scratch3_value & SCRATCH_PAD3_ERR_CODE) >> 16; |
1348 | if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED) |
1349 | pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS; |
1350 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1351 | SCRATCH_PAD3_SMF_ENABLED) |
1352 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF; |
1353 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1354 | SCRATCH_PAD3_SMA_ENABLED) |
1355 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA; |
1356 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1357 | SCRATCH_PAD3_SMB_ENABLED) |
1358 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; |
1359 | pm8001_dbg(pm8001_ha, INIT, |
1360 | "Encryption: SCRATCH_PAD3_DIS_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n" , |
1361 | scratch3_value, |
1362 | pm8001_ha->encrypt_info.cipher_mode, |
1363 | pm8001_ha->encrypt_info.sec_mode, |
1364 | pm8001_ha->encrypt_info.status); |
1365 | } else if ((scratch3_value & SCRATCH_PAD3_ENC_MASK) == |
1366 | SCRATCH_PAD3_ENC_ENA_ERR) { |
1367 | |
1368 | pm8001_ha->encrypt_info.status = |
1369 | (scratch3_value & SCRATCH_PAD3_ERR_CODE) >> 16; |
1370 | if (scratch3_value & SCRATCH_PAD3_XTS_ENABLED) |
1371 | pm8001_ha->encrypt_info.cipher_mode = CIPHER_MODE_XTS; |
1372 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1373 | SCRATCH_PAD3_SMF_ENABLED) |
1374 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMF; |
1375 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1376 | SCRATCH_PAD3_SMA_ENABLED) |
1377 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMA; |
1378 | if ((scratch3_value & SCRATCH_PAD3_SM_MASK) == |
1379 | SCRATCH_PAD3_SMB_ENABLED) |
1380 | pm8001_ha->encrypt_info.sec_mode = SEC_MODE_SMB; |
1381 | |
1382 | pm8001_dbg(pm8001_ha, INIT, |
1383 | "Encryption: SCRATCH_PAD3_ENA_ERR 0x%08X.Cipher mode 0x%x sec mode 0x%x status 0x%x\n" , |
1384 | scratch3_value, |
1385 | pm8001_ha->encrypt_info.cipher_mode, |
1386 | pm8001_ha->encrypt_info.sec_mode, |
1387 | pm8001_ha->encrypt_info.status); |
1388 | } |
1389 | return ret; |
1390 | } |
1391 | |
1392 | /** |
1393 | * pm80xx_encrypt_update - update flash with encryption information |
1394 | * @pm8001_ha: our hba card information. |
1395 | */ |
1396 | static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) |
1397 | { |
1398 | struct kek_mgmt_req payload; |
1399 | int rc; |
1400 | u32 tag; |
1401 | u32 opc = OPC_INB_KEK_MANAGEMENT; |
1402 | |
1403 | memset(&payload, 0, sizeof(struct kek_mgmt_req)); |
1404 | rc = pm8001_tag_alloc(pm8001_ha, tag_out: &tag); |
1405 | if (rc) |
1406 | return rc; |
1407 | |
1408 | payload.tag = cpu_to_le32(tag); |
1409 | /* Currently only one key is used. New KEK index is 1. |
1410 | * Current KEK index is 1. Store KEK to NVRAM is 1. |
1411 | */ |
1412 | payload.new_curidx_ksop = |
1413 | cpu_to_le32(((1 << 24) | (1 << 16) | (1 << 8) | |
1414 | KEK_MGMT_SUBOP_KEYCARDUPDATE)); |
1415 | |
1416 | pm8001_dbg(pm8001_ha, DEV, |
1417 | "Saving Encryption info to flash. payload 0x%x\n" , |
1418 | le32_to_cpu(payload.new_curidx_ksop)); |
1419 | |
1420 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &payload, |
1421 | nb: sizeof(payload), responseQueue: 0); |
1422 | if (rc) |
1423 | pm8001_tag_free(pm8001_ha, tag); |
1424 | |
1425 | return rc; |
1426 | } |
1427 | |
1428 | /** |
1429 | * pm80xx_chip_init - the main init function that initializes whole PM8001 chip. |
1430 | * @pm8001_ha: our hba card information |
1431 | */ |
1432 | static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) |
1433 | { |
1434 | int ret; |
1435 | u8 i = 0; |
1436 | |
1437 | /* check the firmware status */ |
1438 | if (-1 == check_fw_ready(pm8001_ha)) { |
1439 | pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n" ); |
1440 | return -EBUSY; |
1441 | } |
1442 | |
1443 | /* Initialize the controller fatal error flag */ |
1444 | pm8001_ha->controller_fatal_error = false; |
1445 | |
1446 | /* Initialize pci space address eg: mpi offset */ |
1447 | ret = init_pci_device_addresses(pm8001_ha); |
1448 | if (ret) { |
1449 | pm8001_dbg(pm8001_ha, FAIL, |
1450 | "Failed to init pci addresses" ); |
1451 | return ret; |
1452 | } |
1453 | init_default_table_values(pm8001_ha); |
1454 | read_main_config_table(pm8001_ha); |
1455 | read_general_status_table(pm8001_ha); |
1456 | read_inbnd_queue_table(pm8001_ha); |
1457 | read_outbnd_queue_table(pm8001_ha); |
1458 | read_phy_attr_table(pm8001_ha); |
1459 | |
1460 | /* update main config table ,inbound table and outbound table */ |
1461 | update_main_config_table(pm8001_ha); |
1462 | for (i = 0; i < pm8001_ha->max_q_num; i++) { |
1463 | update_inbnd_queue_table(pm8001_ha, number: i); |
1464 | update_outbnd_queue_table(pm8001_ha, number: i); |
1465 | } |
1466 | /* notify firmware update finished and check initialization status */ |
1467 | if (0 == mpi_init_check(pm8001_ha)) { |
1468 | pm8001_dbg(pm8001_ha, INIT, "MPI initialize successful!\n" ); |
1469 | } else |
1470 | return -EBUSY; |
1471 | |
1472 | return 0; |
1473 | } |
1474 | |
1475 | static void pm80xx_chip_post_init(struct pm8001_hba_info *pm8001_ha) |
1476 | { |
1477 | /* send SAS protocol timer configuration page to FW */ |
1478 | pm80xx_set_sas_protocol_timer_config(pm8001_ha); |
1479 | |
1480 | /* Check for encryption */ |
1481 | if (pm8001_ha->chip->encrypt) { |
1482 | int ret; |
1483 | |
1484 | pm8001_dbg(pm8001_ha, INIT, "Checking for encryption\n" ); |
1485 | ret = pm80xx_get_encrypt_info(pm8001_ha); |
1486 | if (ret == -1) { |
1487 | pm8001_dbg(pm8001_ha, INIT, "Encryption error !!\n" ); |
1488 | if (pm8001_ha->encrypt_info.status == 0x81) { |
1489 | pm8001_dbg(pm8001_ha, INIT, |
1490 | "Encryption enabled with error.Saving encryption key to flash\n" ); |
1491 | pm80xx_encrypt_update(pm8001_ha); |
1492 | } |
1493 | } |
1494 | } |
1495 | } |
1496 | |
1497 | static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) |
1498 | { |
1499 | u32 max_wait_count; |
1500 | u32 value; |
1501 | u32 gst_len_mpistate; |
1502 | int ret; |
1503 | |
1504 | ret = init_pci_device_addresses(pm8001_ha); |
1505 | if (ret) { |
1506 | pm8001_dbg(pm8001_ha, FAIL, |
1507 | "Failed to init pci addresses" ); |
1508 | return ret; |
1509 | } |
1510 | |
1511 | /* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the |
1512 | table is stop */ |
1513 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_RESET); |
1514 | |
1515 | /* wait until Inbound DoorBell Clear Register toggled */ |
1516 | if (IS_SPCV_12G(pm8001_ha->pdev)) { |
1517 | max_wait_count = SPCV_DOORBELL_CLEAR_TIMEOUT; |
1518 | } else { |
1519 | max_wait_count = SPC_DOORBELL_CLEAR_TIMEOUT; |
1520 | } |
1521 | do { |
1522 | msleep(FW_READY_INTERVAL); |
1523 | value = pm8001_cr32(pm8001_ha, bar: 0, MSGU_IBDB_SET); |
1524 | value &= SPCv_MSGU_CFG_TABLE_RESET; |
1525 | } while ((value != 0) && (--max_wait_count)); |
1526 | |
1527 | if (!max_wait_count) { |
1528 | pm8001_dbg(pm8001_ha, FAIL, "TIMEOUT:IBDB value/=%x\n" , value); |
1529 | return -1; |
1530 | } |
1531 | |
1532 | /* check the MPI-State for termination in progress */ |
1533 | /* wait until Inbound DoorBell Clear Register toggled */ |
1534 | max_wait_count = 100; /* 2 sec for spcv/ve */ |
1535 | do { |
1536 | msleep(FW_READY_INTERVAL); |
1537 | gst_len_mpistate = |
1538 | pm8001_mr32(addr: pm8001_ha->general_stat_tbl_addr, |
1539 | GST_GSTLEN_MPIS_OFFSET); |
1540 | if (GST_MPI_STATE_UNINIT == |
1541 | (gst_len_mpistate & GST_MPI_STATE_MASK)) |
1542 | break; |
1543 | } while (--max_wait_count); |
1544 | if (!max_wait_count) { |
1545 | pm8001_dbg(pm8001_ha, FAIL, " TIME OUT MPI State = 0x%x\n" , |
1546 | gst_len_mpistate & GST_MPI_STATE_MASK); |
1547 | return -1; |
1548 | } |
1549 | |
1550 | return 0; |
1551 | } |
1552 | |
1553 | /** |
1554 | * pm80xx_fatal_errors - returns non-zero *ONLY* when fatal errors |
1555 | * @pm8001_ha: our hba card information |
1556 | * |
1557 | * Fatal errors are recoverable only after a host reboot. |
1558 | */ |
1559 | int |
1560 | pm80xx_fatal_errors(struct pm8001_hba_info *pm8001_ha) |
1561 | { |
1562 | int ret = 0; |
1563 | u32 scratch_pad_rsvd0 = pm8001_cr32(pm8001_ha, bar: 0, |
1564 | MSGU_SCRATCH_PAD_RSVD_0); |
1565 | u32 scratch_pad_rsvd1 = pm8001_cr32(pm8001_ha, bar: 0, |
1566 | MSGU_SCRATCH_PAD_RSVD_1); |
1567 | u32 scratch_pad1 = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_1); |
1568 | u32 scratch_pad2 = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_2); |
1569 | u32 scratch_pad3 = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_3); |
1570 | |
1571 | if (pm8001_ha->chip_id != chip_8006 && |
1572 | pm8001_ha->chip_id != chip_8074 && |
1573 | pm8001_ha->chip_id != chip_8076) { |
1574 | return 0; |
1575 | } |
1576 | |
1577 | if (MSGU_SCRATCHPAD1_STATE_FATAL_ERROR(scratch_pad1)) { |
1578 | pm8001_dbg(pm8001_ha, FAIL, |
1579 | "Fatal error SCRATCHPAD1 = 0x%x SCRATCHPAD2 = 0x%x SCRATCHPAD3 = 0x%x SCRATCHPAD_RSVD0 = 0x%x SCRATCHPAD_RSVD1 = 0x%x\n" , |
1580 | scratch_pad1, scratch_pad2, scratch_pad3, |
1581 | scratch_pad_rsvd0, scratch_pad_rsvd1); |
1582 | ret = 1; |
1583 | } |
1584 | |
1585 | return ret; |
1586 | } |
1587 | |
1588 | /** |
1589 | * pm80xx_chip_soft_rst - soft reset the PM8001 chip, so that all |
1590 | * FW register status are reset to the originated status. |
1591 | * @pm8001_ha: our hba card information |
1592 | */ |
1593 | |
1594 | static int |
1595 | pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) |
1596 | { |
1597 | u32 regval; |
1598 | u32 bootloader_state; |
1599 | u32 ibutton0, ibutton1; |
1600 | |
1601 | /* Process MPI table uninitialization only if FW is ready */ |
1602 | if (!pm8001_ha->controller_fatal_error) { |
1603 | /* Check if MPI is in ready state to reset */ |
1604 | if (mpi_uninit_check(pm8001_ha) != 0) { |
1605 | u32 r0 = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_0); |
1606 | u32 r1 = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_1); |
1607 | u32 r2 = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_2); |
1608 | u32 r3 = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_3); |
1609 | pm8001_dbg(pm8001_ha, FAIL, |
1610 | "MPI state is not ready scratch: %x:%x:%x:%x\n" , |
1611 | r0, r1, r2, r3); |
1612 | /* if things aren't ready but the bootloader is ok then |
1613 | * try the reset anyway. |
1614 | */ |
1615 | if (r1 & SCRATCH_PAD1_BOOTSTATE_MASK) |
1616 | return -1; |
1617 | } |
1618 | } |
1619 | /* checked for reset register normal state; 0x0 */ |
1620 | regval = pm8001_cr32(pm8001_ha, bar: 0, SPC_REG_SOFT_RESET); |
1621 | pm8001_dbg(pm8001_ha, INIT, "reset register before write : 0x%x\n" , |
1622 | regval); |
1623 | |
1624 | pm8001_cw32(pm8001_ha, bar: 0, SPC_REG_SOFT_RESET, SPCv_NORMAL_RESET_VALUE); |
1625 | msleep(msecs: 500); |
1626 | |
1627 | regval = pm8001_cr32(pm8001_ha, bar: 0, SPC_REG_SOFT_RESET); |
1628 | pm8001_dbg(pm8001_ha, INIT, "reset register after write 0x%x\n" , |
1629 | regval); |
1630 | |
1631 | if ((regval & SPCv_SOFT_RESET_READ_MASK) == |
1632 | SPCv_SOFT_RESET_NORMAL_RESET_OCCURED) { |
1633 | pm8001_dbg(pm8001_ha, MSG, |
1634 | " soft reset successful [regval: 0x%x]\n" , |
1635 | regval); |
1636 | } else { |
1637 | pm8001_dbg(pm8001_ha, MSG, |
1638 | " soft reset failed [regval: 0x%x]\n" , |
1639 | regval); |
1640 | |
1641 | /* check bootloader is successfully executed or in HDA mode */ |
1642 | bootloader_state = |
1643 | pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_1) & |
1644 | SCRATCH_PAD1_BOOTSTATE_MASK; |
1645 | |
1646 | if (bootloader_state == SCRATCH_PAD1_BOOTSTATE_HDA_SEEPROM) { |
1647 | pm8001_dbg(pm8001_ha, MSG, |
1648 | "Bootloader state - HDA mode SEEPROM\n" ); |
1649 | } else if (bootloader_state == |
1650 | SCRATCH_PAD1_BOOTSTATE_HDA_BOOTSTRAP) { |
1651 | pm8001_dbg(pm8001_ha, MSG, |
1652 | "Bootloader state - HDA mode Bootstrap Pin\n" ); |
1653 | } else if (bootloader_state == |
1654 | SCRATCH_PAD1_BOOTSTATE_HDA_SOFTRESET) { |
1655 | pm8001_dbg(pm8001_ha, MSG, |
1656 | "Bootloader state - HDA mode soft reset\n" ); |
1657 | } else if (bootloader_state == |
1658 | SCRATCH_PAD1_BOOTSTATE_CRIT_ERROR) { |
1659 | pm8001_dbg(pm8001_ha, MSG, |
1660 | "Bootloader state-HDA mode critical error\n" ); |
1661 | } |
1662 | return -EBUSY; |
1663 | } |
1664 | |
1665 | /* check the firmware status after reset */ |
1666 | if (-1 == check_fw_ready(pm8001_ha)) { |
1667 | pm8001_dbg(pm8001_ha, FAIL, "Firmware is not ready!\n" ); |
1668 | /* check iButton feature support for motherboard controller */ |
1669 | if (pm8001_ha->pdev->subsystem_vendor != |
1670 | PCI_VENDOR_ID_ADAPTEC2 && |
1671 | pm8001_ha->pdev->subsystem_vendor != |
1672 | PCI_VENDOR_ID_ATTO && |
1673 | pm8001_ha->pdev->subsystem_vendor != 0) { |
1674 | ibutton0 = pm8001_cr32(pm8001_ha, bar: 0, |
1675 | MSGU_SCRATCH_PAD_RSVD_0); |
1676 | ibutton1 = pm8001_cr32(pm8001_ha, bar: 0, |
1677 | MSGU_SCRATCH_PAD_RSVD_1); |
1678 | if (!ibutton0 && !ibutton1) { |
1679 | pm8001_dbg(pm8001_ha, FAIL, |
1680 | "iButton Feature is not Available!!!\n" ); |
1681 | return -EBUSY; |
1682 | } |
1683 | if (ibutton0 == 0xdeadbeef && ibutton1 == 0xdeadbeef) { |
1684 | pm8001_dbg(pm8001_ha, FAIL, |
1685 | "CRC Check for iButton Feature Failed!!!\n" ); |
1686 | return -EBUSY; |
1687 | } |
1688 | } |
1689 | } |
1690 | pm8001_dbg(pm8001_ha, INIT, "SPCv soft reset Complete\n" ); |
1691 | return 0; |
1692 | } |
1693 | |
1694 | static void pm80xx_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) |
1695 | { |
1696 | u32 i; |
1697 | |
1698 | pm8001_dbg(pm8001_ha, INIT, "chip reset start\n" ); |
1699 | |
1700 | /* do SPCv chip reset. */ |
1701 | pm8001_cw32(pm8001_ha, bar: 0, SPC_REG_SOFT_RESET, val: 0x11); |
1702 | pm8001_dbg(pm8001_ha, INIT, "SPC soft reset Complete\n" ); |
1703 | |
1704 | /* Check this ..whether delay is required or no */ |
1705 | /* delay 10 usec */ |
1706 | udelay(10); |
1707 | |
1708 | /* wait for 20 msec until the firmware gets reloaded */ |
1709 | i = 20; |
1710 | do { |
1711 | mdelay(1); |
1712 | } while ((--i) != 0); |
1713 | |
1714 | pm8001_dbg(pm8001_ha, INIT, "chip reset finished\n" ); |
1715 | } |
1716 | |
1717 | /** |
1718 | * pm80xx_chip_interrupt_enable - enable PM8001 chip interrupt |
1719 | * @pm8001_ha: our hba card information |
1720 | * @vec: interrupt number to enable |
1721 | */ |
1722 | static void |
1723 | pm80xx_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha, u8 vec) |
1724 | { |
1725 | if (!pm8001_ha->use_msix) { |
1726 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR, ODMR_CLEAR_ALL); |
1727 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODCR, ODCR_CLEAR_ALL); |
1728 | return; |
1729 | } |
1730 | |
1731 | if (vec < 32) |
1732 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR_CLR, val: 1U << vec); |
1733 | else |
1734 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR_CLR_U, val: 1U << (vec - 32)); |
1735 | } |
1736 | |
1737 | /** |
1738 | * pm80xx_chip_interrupt_disable - disable PM8001 chip interrupt |
1739 | * @pm8001_ha: our hba card information |
1740 | * @vec: interrupt number to disable |
1741 | */ |
1742 | static void |
1743 | pm80xx_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha, u8 vec) |
1744 | { |
1745 | if (!pm8001_ha->use_msix) { |
1746 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR_CLR, ODMR_MASK_ALL); |
1747 | return; |
1748 | } |
1749 | |
1750 | if (vec == 0xFF) { |
1751 | /* disable all vectors 0-31, 32-63 */ |
1752 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR, val: 0xFFFFFFFF); |
1753 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR_U, val: 0xFFFFFFFF); |
1754 | } else if (vec < 32) { |
1755 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR, val: 1U << vec); |
1756 | } else { |
1757 | pm8001_cw32(pm8001_ha, bar: 0, MSGU_ODMR_U, val: 1U << (vec - 32)); |
1758 | } |
1759 | } |
1760 | |
1761 | /** |
1762 | * mpi_ssp_completion - process the event that FW response to the SSP request. |
1763 | * @pm8001_ha: our hba card information |
1764 | * @piomb: the message contents of this outbound message. |
1765 | * |
1766 | * When FW has completed a ssp request for example a IO request, after it has |
1767 | * filled the SG data with the data, it will trigger this event representing |
1768 | * that he has finished the job; please check the corresponding buffer. |
1769 | * So we will tell the caller who maybe waiting the result to tell upper layer |
1770 | * that the task has been finished. |
1771 | */ |
1772 | static void |
1773 | mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) |
1774 | { |
1775 | struct sas_task *t; |
1776 | struct pm8001_ccb_info *ccb; |
1777 | unsigned long flags; |
1778 | u32 status; |
1779 | u32 param; |
1780 | u32 tag; |
1781 | struct ssp_completion_resp *psspPayload; |
1782 | struct task_status_struct *ts; |
1783 | struct ssp_response_iu *iu; |
1784 | struct pm8001_device *pm8001_dev; |
1785 | psspPayload = (struct ssp_completion_resp *)(piomb + 4); |
1786 | status = le32_to_cpu(psspPayload->status); |
1787 | tag = le32_to_cpu(psspPayload->tag); |
1788 | ccb = &pm8001_ha->ccb_info[tag]; |
1789 | if ((status == IO_ABORTED) && ccb->open_retry) { |
1790 | /* Being completed by another */ |
1791 | ccb->open_retry = 0; |
1792 | return; |
1793 | } |
1794 | pm8001_dev = ccb->device; |
1795 | param = le32_to_cpu(psspPayload->param); |
1796 | t = ccb->task; |
1797 | |
1798 | if (status && status != IO_UNDERFLOW) |
1799 | pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n" , status); |
1800 | if (unlikely(!t || !t->lldd_task || !t->dev)) |
1801 | return; |
1802 | ts = &t->task_status; |
1803 | |
1804 | pm8001_dbg(pm8001_ha, DEV, |
1805 | "tag::0x%x, status::0x%x task::0x%p\n" , tag, status, t); |
1806 | |
1807 | /* Print sas address of IO failed device */ |
1808 | if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && |
1809 | (status != IO_UNDERFLOW)) |
1810 | pm8001_dbg(pm8001_ha, FAIL, "SAS Address of IO Failure Drive:%016llx\n" , |
1811 | SAS_ADDR(t->dev->sas_addr)); |
1812 | |
1813 | switch (status) { |
1814 | case IO_SUCCESS: |
1815 | pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS ,param = 0x%x\n" , |
1816 | param); |
1817 | if (param == 0) { |
1818 | ts->resp = SAS_TASK_COMPLETE; |
1819 | ts->stat = SAS_SAM_STAT_GOOD; |
1820 | } else { |
1821 | ts->resp = SAS_TASK_COMPLETE; |
1822 | ts->stat = SAS_PROTO_RESPONSE; |
1823 | ts->residual = param; |
1824 | iu = &psspPayload->ssp_resp_iu; |
1825 | sas_ssp_task_response(dev: pm8001_ha->dev, task: t, iu); |
1826 | } |
1827 | if (pm8001_dev) |
1828 | atomic_dec(v: &pm8001_dev->running_req); |
1829 | break; |
1830 | case IO_ABORTED: |
1831 | pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n" ); |
1832 | ts->resp = SAS_TASK_COMPLETE; |
1833 | ts->stat = SAS_ABORTED_TASK; |
1834 | if (pm8001_dev) |
1835 | atomic_dec(v: &pm8001_dev->running_req); |
1836 | break; |
1837 | case IO_UNDERFLOW: |
1838 | /* SSP Completion with error */ |
1839 | pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW ,param = 0x%x\n" , |
1840 | param); |
1841 | ts->resp = SAS_TASK_COMPLETE; |
1842 | ts->stat = SAS_DATA_UNDERRUN; |
1843 | ts->residual = param; |
1844 | if (pm8001_dev) |
1845 | atomic_dec(v: &pm8001_dev->running_req); |
1846 | break; |
1847 | case IO_NO_DEVICE: |
1848 | pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n" ); |
1849 | ts->resp = SAS_TASK_UNDELIVERED; |
1850 | ts->stat = SAS_PHY_DOWN; |
1851 | if (pm8001_dev) |
1852 | atomic_dec(v: &pm8001_dev->running_req); |
1853 | break; |
1854 | case IO_XFER_ERROR_BREAK: |
1855 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n" ); |
1856 | ts->resp = SAS_TASK_COMPLETE; |
1857 | ts->stat = SAS_OPEN_REJECT; |
1858 | /* Force the midlayer to retry */ |
1859 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
1860 | if (pm8001_dev) |
1861 | atomic_dec(v: &pm8001_dev->running_req); |
1862 | break; |
1863 | case IO_XFER_ERROR_PHY_NOT_READY: |
1864 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n" ); |
1865 | ts->resp = SAS_TASK_COMPLETE; |
1866 | ts->stat = SAS_OPEN_REJECT; |
1867 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
1868 | if (pm8001_dev) |
1869 | atomic_dec(v: &pm8001_dev->running_req); |
1870 | break; |
1871 | case IO_XFER_ERROR_INVALID_SSP_RSP_FRAME: |
1872 | pm8001_dbg(pm8001_ha, IO, |
1873 | "IO_XFER_ERROR_INVALID_SSP_RSP_FRAME\n" ); |
1874 | ts->resp = SAS_TASK_COMPLETE; |
1875 | ts->stat = SAS_OPEN_REJECT; |
1876 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
1877 | if (pm8001_dev) |
1878 | atomic_dec(v: &pm8001_dev->running_req); |
1879 | break; |
1880 | case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: |
1881 | pm8001_dbg(pm8001_ha, IO, |
1882 | "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n" ); |
1883 | ts->resp = SAS_TASK_COMPLETE; |
1884 | ts->stat = SAS_OPEN_REJECT; |
1885 | ts->open_rej_reason = SAS_OREJ_EPROTO; |
1886 | if (pm8001_dev) |
1887 | atomic_dec(v: &pm8001_dev->running_req); |
1888 | break; |
1889 | case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: |
1890 | pm8001_dbg(pm8001_ha, IO, |
1891 | "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n" ); |
1892 | ts->resp = SAS_TASK_COMPLETE; |
1893 | ts->stat = SAS_OPEN_REJECT; |
1894 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
1895 | if (pm8001_dev) |
1896 | atomic_dec(v: &pm8001_dev->running_req); |
1897 | break; |
1898 | case IO_OPEN_CNX_ERROR_BREAK: |
1899 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n" ); |
1900 | ts->resp = SAS_TASK_COMPLETE; |
1901 | ts->stat = SAS_OPEN_REJECT; |
1902 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
1903 | if (pm8001_dev) |
1904 | atomic_dec(v: &pm8001_dev->running_req); |
1905 | break; |
1906 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: |
1907 | case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: |
1908 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: |
1909 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: |
1910 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: |
1911 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: |
1912 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n" ); |
1913 | ts->resp = SAS_TASK_COMPLETE; |
1914 | ts->stat = SAS_OPEN_REJECT; |
1915 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
1916 | if (!t->uldd_task) |
1917 | pm8001_handle_event(pm8001_ha, |
1918 | data: pm8001_dev, |
1919 | IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); |
1920 | break; |
1921 | case IO_OPEN_CNX_ERROR_BAD_DESTINATION: |
1922 | pm8001_dbg(pm8001_ha, IO, |
1923 | "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n" ); |
1924 | ts->resp = SAS_TASK_COMPLETE; |
1925 | ts->stat = SAS_OPEN_REJECT; |
1926 | ts->open_rej_reason = SAS_OREJ_BAD_DEST; |
1927 | if (pm8001_dev) |
1928 | atomic_dec(v: &pm8001_dev->running_req); |
1929 | break; |
1930 | case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: |
1931 | pm8001_dbg(pm8001_ha, IO, |
1932 | "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n" ); |
1933 | ts->resp = SAS_TASK_COMPLETE; |
1934 | ts->stat = SAS_OPEN_REJECT; |
1935 | ts->open_rej_reason = SAS_OREJ_CONN_RATE; |
1936 | if (pm8001_dev) |
1937 | atomic_dec(v: &pm8001_dev->running_req); |
1938 | break; |
1939 | case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: |
1940 | pm8001_dbg(pm8001_ha, IO, |
1941 | "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n" ); |
1942 | ts->resp = SAS_TASK_UNDELIVERED; |
1943 | ts->stat = SAS_OPEN_REJECT; |
1944 | ts->open_rej_reason = SAS_OREJ_WRONG_DEST; |
1945 | if (pm8001_dev) |
1946 | atomic_dec(v: &pm8001_dev->running_req); |
1947 | break; |
1948 | case IO_XFER_ERROR_NAK_RECEIVED: |
1949 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n" ); |
1950 | ts->resp = SAS_TASK_COMPLETE; |
1951 | ts->stat = SAS_OPEN_REJECT; |
1952 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
1953 | if (pm8001_dev) |
1954 | atomic_dec(v: &pm8001_dev->running_req); |
1955 | break; |
1956 | case IO_XFER_ERROR_ACK_NAK_TIMEOUT: |
1957 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n" ); |
1958 | ts->resp = SAS_TASK_COMPLETE; |
1959 | ts->stat = SAS_NAK_R_ERR; |
1960 | if (pm8001_dev) |
1961 | atomic_dec(v: &pm8001_dev->running_req); |
1962 | break; |
1963 | case IO_XFER_ERROR_DMA: |
1964 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n" ); |
1965 | ts->resp = SAS_TASK_COMPLETE; |
1966 | ts->stat = SAS_OPEN_REJECT; |
1967 | if (pm8001_dev) |
1968 | atomic_dec(v: &pm8001_dev->running_req); |
1969 | break; |
1970 | case IO_XFER_OPEN_RETRY_TIMEOUT: |
1971 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n" ); |
1972 | ts->resp = SAS_TASK_COMPLETE; |
1973 | ts->stat = SAS_OPEN_REJECT; |
1974 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
1975 | if (pm8001_dev) |
1976 | atomic_dec(v: &pm8001_dev->running_req); |
1977 | break; |
1978 | case IO_XFER_ERROR_OFFSET_MISMATCH: |
1979 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n" ); |
1980 | ts->resp = SAS_TASK_COMPLETE; |
1981 | ts->stat = SAS_OPEN_REJECT; |
1982 | if (pm8001_dev) |
1983 | atomic_dec(v: &pm8001_dev->running_req); |
1984 | break; |
1985 | case IO_PORT_IN_RESET: |
1986 | pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n" ); |
1987 | ts->resp = SAS_TASK_COMPLETE; |
1988 | ts->stat = SAS_OPEN_REJECT; |
1989 | if (pm8001_dev) |
1990 | atomic_dec(v: &pm8001_dev->running_req); |
1991 | break; |
1992 | case IO_DS_NON_OPERATIONAL: |
1993 | pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n" ); |
1994 | ts->resp = SAS_TASK_COMPLETE; |
1995 | ts->stat = SAS_OPEN_REJECT; |
1996 | if (!t->uldd_task) |
1997 | pm8001_handle_event(pm8001_ha, |
1998 | data: pm8001_dev, |
1999 | IO_DS_NON_OPERATIONAL); |
2000 | break; |
2001 | case IO_DS_IN_RECOVERY: |
2002 | pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n" ); |
2003 | ts->resp = SAS_TASK_COMPLETE; |
2004 | ts->stat = SAS_OPEN_REJECT; |
2005 | if (pm8001_dev) |
2006 | atomic_dec(v: &pm8001_dev->running_req); |
2007 | break; |
2008 | case IO_TM_TAG_NOT_FOUND: |
2009 | pm8001_dbg(pm8001_ha, IO, "IO_TM_TAG_NOT_FOUND\n" ); |
2010 | ts->resp = SAS_TASK_COMPLETE; |
2011 | ts->stat = SAS_OPEN_REJECT; |
2012 | if (pm8001_dev) |
2013 | atomic_dec(v: &pm8001_dev->running_req); |
2014 | break; |
2015 | case IO_SSP_EXT_IU_ZERO_LEN_ERROR: |
2016 | pm8001_dbg(pm8001_ha, IO, "IO_SSP_EXT_IU_ZERO_LEN_ERROR\n" ); |
2017 | ts->resp = SAS_TASK_COMPLETE; |
2018 | ts->stat = SAS_OPEN_REJECT; |
2019 | if (pm8001_dev) |
2020 | atomic_dec(v: &pm8001_dev->running_req); |
2021 | break; |
2022 | case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: |
2023 | pm8001_dbg(pm8001_ha, IO, |
2024 | "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n" ); |
2025 | ts->resp = SAS_TASK_COMPLETE; |
2026 | ts->stat = SAS_OPEN_REJECT; |
2027 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
2028 | if (pm8001_dev) |
2029 | atomic_dec(v: &pm8001_dev->running_req); |
2030 | break; |
2031 | default: |
2032 | pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n" , status); |
2033 | /* not allowed case. Therefore, return failed status */ |
2034 | ts->resp = SAS_TASK_COMPLETE; |
2035 | ts->stat = SAS_OPEN_REJECT; |
2036 | if (pm8001_dev) |
2037 | atomic_dec(v: &pm8001_dev->running_req); |
2038 | break; |
2039 | } |
2040 | pm8001_dbg(pm8001_ha, IO, "scsi_status = 0x%x\n " , |
2041 | psspPayload->ssp_resp_iu.status); |
2042 | spin_lock_irqsave(&t->task_state_lock, flags); |
2043 | t->task_state_flags &= ~SAS_TASK_STATE_PENDING; |
2044 | t->task_state_flags |= SAS_TASK_STATE_DONE; |
2045 | if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { |
2046 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
2047 | pm8001_dbg(pm8001_ha, FAIL, |
2048 | "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n" , |
2049 | t, status, ts->resp, ts->stat); |
2050 | pm8001_ccb_task_free(pm8001_ha, ccb); |
2051 | if (t->slow_task) |
2052 | complete(&t->slow_task->completion); |
2053 | } else { |
2054 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
2055 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2056 | } |
2057 | } |
2058 | |
2059 | /*See the comments for mpi_ssp_completion */ |
2060 | static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha, void *piomb) |
2061 | { |
2062 | struct sas_task *t; |
2063 | unsigned long flags; |
2064 | struct task_status_struct *ts; |
2065 | struct pm8001_ccb_info *ccb; |
2066 | struct pm8001_device *pm8001_dev; |
2067 | struct ssp_event_resp *psspPayload = |
2068 | (struct ssp_event_resp *)(piomb + 4); |
2069 | u32 event = le32_to_cpu(psspPayload->event); |
2070 | u32 tag = le32_to_cpu(psspPayload->tag); |
2071 | u32 port_id = le32_to_cpu(psspPayload->port_id); |
2072 | |
2073 | ccb = &pm8001_ha->ccb_info[tag]; |
2074 | t = ccb->task; |
2075 | pm8001_dev = ccb->device; |
2076 | if (event) |
2077 | pm8001_dbg(pm8001_ha, FAIL, "sas IO status 0x%x\n" , event); |
2078 | if (unlikely(!t || !t->lldd_task || !t->dev)) |
2079 | return; |
2080 | ts = &t->task_status; |
2081 | pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n" , |
2082 | port_id, tag, event); |
2083 | switch (event) { |
2084 | case IO_OVERFLOW: |
2085 | pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n" ); |
2086 | ts->resp = SAS_TASK_COMPLETE; |
2087 | ts->stat = SAS_DATA_OVERRUN; |
2088 | ts->residual = 0; |
2089 | if (pm8001_dev) |
2090 | atomic_dec(v: &pm8001_dev->running_req); |
2091 | break; |
2092 | case IO_XFER_ERROR_BREAK: |
2093 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n" ); |
2094 | pm8001_handle_event(pm8001_ha, data: t, IO_XFER_ERROR_BREAK); |
2095 | return; |
2096 | case IO_XFER_ERROR_PHY_NOT_READY: |
2097 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n" ); |
2098 | ts->resp = SAS_TASK_COMPLETE; |
2099 | ts->stat = SAS_OPEN_REJECT; |
2100 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
2101 | break; |
2102 | case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: |
2103 | pm8001_dbg(pm8001_ha, IO, |
2104 | "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n" ); |
2105 | ts->resp = SAS_TASK_COMPLETE; |
2106 | ts->stat = SAS_OPEN_REJECT; |
2107 | ts->open_rej_reason = SAS_OREJ_EPROTO; |
2108 | break; |
2109 | case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: |
2110 | pm8001_dbg(pm8001_ha, IO, |
2111 | "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n" ); |
2112 | ts->resp = SAS_TASK_COMPLETE; |
2113 | ts->stat = SAS_OPEN_REJECT; |
2114 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
2115 | break; |
2116 | case IO_OPEN_CNX_ERROR_BREAK: |
2117 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n" ); |
2118 | ts->resp = SAS_TASK_COMPLETE; |
2119 | ts->stat = SAS_OPEN_REJECT; |
2120 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
2121 | break; |
2122 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: |
2123 | case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: |
2124 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: |
2125 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: |
2126 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: |
2127 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: |
2128 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n" ); |
2129 | ts->resp = SAS_TASK_COMPLETE; |
2130 | ts->stat = SAS_OPEN_REJECT; |
2131 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
2132 | if (!t->uldd_task) |
2133 | pm8001_handle_event(pm8001_ha, |
2134 | data: pm8001_dev, |
2135 | IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); |
2136 | break; |
2137 | case IO_OPEN_CNX_ERROR_BAD_DESTINATION: |
2138 | pm8001_dbg(pm8001_ha, IO, |
2139 | "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n" ); |
2140 | ts->resp = SAS_TASK_COMPLETE; |
2141 | ts->stat = SAS_OPEN_REJECT; |
2142 | ts->open_rej_reason = SAS_OREJ_BAD_DEST; |
2143 | break; |
2144 | case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: |
2145 | pm8001_dbg(pm8001_ha, IO, |
2146 | "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n" ); |
2147 | ts->resp = SAS_TASK_COMPLETE; |
2148 | ts->stat = SAS_OPEN_REJECT; |
2149 | ts->open_rej_reason = SAS_OREJ_CONN_RATE; |
2150 | break; |
2151 | case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: |
2152 | pm8001_dbg(pm8001_ha, IO, |
2153 | "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n" ); |
2154 | ts->resp = SAS_TASK_COMPLETE; |
2155 | ts->stat = SAS_OPEN_REJECT; |
2156 | ts->open_rej_reason = SAS_OREJ_WRONG_DEST; |
2157 | break; |
2158 | case IO_XFER_ERROR_NAK_RECEIVED: |
2159 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n" ); |
2160 | ts->resp = SAS_TASK_COMPLETE; |
2161 | ts->stat = SAS_OPEN_REJECT; |
2162 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
2163 | break; |
2164 | case IO_XFER_ERROR_ACK_NAK_TIMEOUT: |
2165 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n" ); |
2166 | ts->resp = SAS_TASK_COMPLETE; |
2167 | ts->stat = SAS_NAK_R_ERR; |
2168 | break; |
2169 | case IO_XFER_OPEN_RETRY_TIMEOUT: |
2170 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n" ); |
2171 | pm8001_handle_event(pm8001_ha, data: t, IO_XFER_OPEN_RETRY_TIMEOUT); |
2172 | return; |
2173 | case IO_XFER_ERROR_UNEXPECTED_PHASE: |
2174 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n" ); |
2175 | ts->resp = SAS_TASK_COMPLETE; |
2176 | ts->stat = SAS_DATA_OVERRUN; |
2177 | break; |
2178 | case IO_XFER_ERROR_XFER_RDY_OVERRUN: |
2179 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n" ); |
2180 | ts->resp = SAS_TASK_COMPLETE; |
2181 | ts->stat = SAS_DATA_OVERRUN; |
2182 | break; |
2183 | case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: |
2184 | pm8001_dbg(pm8001_ha, IO, |
2185 | "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n" ); |
2186 | ts->resp = SAS_TASK_COMPLETE; |
2187 | ts->stat = SAS_DATA_OVERRUN; |
2188 | break; |
2189 | case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT: |
2190 | pm8001_dbg(pm8001_ha, IO, |
2191 | "IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n" ); |
2192 | ts->resp = SAS_TASK_COMPLETE; |
2193 | ts->stat = SAS_DATA_OVERRUN; |
2194 | break; |
2195 | case IO_XFER_ERROR_OFFSET_MISMATCH: |
2196 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n" ); |
2197 | ts->resp = SAS_TASK_COMPLETE; |
2198 | ts->stat = SAS_DATA_OVERRUN; |
2199 | break; |
2200 | case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: |
2201 | pm8001_dbg(pm8001_ha, IO, |
2202 | "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n" ); |
2203 | ts->resp = SAS_TASK_COMPLETE; |
2204 | ts->stat = SAS_DATA_OVERRUN; |
2205 | break; |
2206 | case IO_XFER_ERROR_INTERNAL_CRC_ERROR: |
2207 | pm8001_dbg(pm8001_ha, IOERR, |
2208 | "IO_XFR_ERROR_INTERNAL_CRC_ERROR\n" ); |
2209 | /* TBC: used default set values */ |
2210 | ts->resp = SAS_TASK_COMPLETE; |
2211 | ts->stat = SAS_DATA_OVERRUN; |
2212 | break; |
2213 | case IO_XFER_CMD_FRAME_ISSUED: |
2214 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n" ); |
2215 | return; |
2216 | default: |
2217 | pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n" , event); |
2218 | /* not allowed case. Therefore, return failed status */ |
2219 | ts->resp = SAS_TASK_COMPLETE; |
2220 | ts->stat = SAS_DATA_OVERRUN; |
2221 | break; |
2222 | } |
2223 | spin_lock_irqsave(&t->task_state_lock, flags); |
2224 | t->task_state_flags &= ~SAS_TASK_STATE_PENDING; |
2225 | t->task_state_flags |= SAS_TASK_STATE_DONE; |
2226 | if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { |
2227 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
2228 | pm8001_dbg(pm8001_ha, FAIL, |
2229 | "task 0x%p done with event 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n" , |
2230 | t, event, ts->resp, ts->stat); |
2231 | pm8001_ccb_task_free(pm8001_ha, ccb); |
2232 | } else { |
2233 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
2234 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2235 | } |
2236 | } |
2237 | |
2238 | /*See the comments for mpi_ssp_completion */ |
2239 | static void |
2240 | mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, |
2241 | struct outbound_queue_table *circularQ, void *piomb) |
2242 | { |
2243 | struct sas_task *t; |
2244 | struct pm8001_ccb_info *ccb; |
2245 | u32 param; |
2246 | u32 status; |
2247 | u32 tag; |
2248 | int i, j; |
2249 | u8 sata_addr_low[4]; |
2250 | u32 temp_sata_addr_low, temp_sata_addr_hi; |
2251 | u8 sata_addr_hi[4]; |
2252 | struct sata_completion_resp *psataPayload; |
2253 | struct task_status_struct *ts; |
2254 | struct ata_task_resp *resp ; |
2255 | u32 *sata_resp; |
2256 | struct pm8001_device *pm8001_dev; |
2257 | unsigned long flags; |
2258 | |
2259 | psataPayload = (struct sata_completion_resp *)(piomb + 4); |
2260 | status = le32_to_cpu(psataPayload->status); |
2261 | param = le32_to_cpu(psataPayload->param); |
2262 | tag = le32_to_cpu(psataPayload->tag); |
2263 | |
2264 | ccb = &pm8001_ha->ccb_info[tag]; |
2265 | t = ccb->task; |
2266 | pm8001_dev = ccb->device; |
2267 | |
2268 | if (t) { |
2269 | if (t->dev && (t->dev->lldd_dev)) |
2270 | pm8001_dev = t->dev->lldd_dev; |
2271 | } else { |
2272 | pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n" , |
2273 | ccb->ccb_tag); |
2274 | pm8001_ccb_free(pm8001_ha, ccb); |
2275 | return; |
2276 | } |
2277 | |
2278 | |
2279 | if (pm8001_dev && unlikely(!t->lldd_task || !t->dev)) |
2280 | return; |
2281 | |
2282 | ts = &t->task_status; |
2283 | |
2284 | if (status != IO_SUCCESS) { |
2285 | pm8001_dbg(pm8001_ha, FAIL, |
2286 | "IO failed device_id %u status 0x%x tag %d\n" , |
2287 | pm8001_dev->device_id, status, tag); |
2288 | } |
2289 | |
2290 | /* Print sas address of IO failed device */ |
2291 | if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && |
2292 | (status != IO_UNDERFLOW)) { |
2293 | if (!((t->dev->parent) && |
2294 | (dev_is_expander(type: t->dev->parent->dev_type)))) { |
2295 | for (i = 0, j = 4; i <= 3 && j <= 7; i++, j++) |
2296 | sata_addr_low[i] = pm8001_ha->sas_addr[j]; |
2297 | for (i = 0, j = 0; i <= 3 && j <= 3; i++, j++) |
2298 | sata_addr_hi[i] = pm8001_ha->sas_addr[j]; |
2299 | memcpy(&temp_sata_addr_low, sata_addr_low, |
2300 | sizeof(sata_addr_low)); |
2301 | memcpy(&temp_sata_addr_hi, sata_addr_hi, |
2302 | sizeof(sata_addr_hi)); |
2303 | temp_sata_addr_hi = (((temp_sata_addr_hi >> 24) & 0xff) |
2304 | |((temp_sata_addr_hi << 8) & |
2305 | 0xff0000) | |
2306 | ((temp_sata_addr_hi >> 8) |
2307 | & 0xff00) | |
2308 | ((temp_sata_addr_hi << 24) & |
2309 | 0xff000000)); |
2310 | temp_sata_addr_low = ((((temp_sata_addr_low >> 24) |
2311 | & 0xff) | |
2312 | ((temp_sata_addr_low << 8) |
2313 | & 0xff0000) | |
2314 | ((temp_sata_addr_low >> 8) |
2315 | & 0xff00) | |
2316 | ((temp_sata_addr_low << 24) |
2317 | & 0xff000000)) + |
2318 | pm8001_dev->attached_phy + |
2319 | 0x10); |
2320 | pm8001_dbg(pm8001_ha, FAIL, |
2321 | "SAS Address of IO Failure Drive:%08x%08x\n" , |
2322 | temp_sata_addr_hi, |
2323 | temp_sata_addr_low); |
2324 | |
2325 | } else { |
2326 | pm8001_dbg(pm8001_ha, FAIL, |
2327 | "SAS Address of IO Failure Drive:%016llx\n" , |
2328 | SAS_ADDR(t->dev->sas_addr)); |
2329 | } |
2330 | } |
2331 | switch (status) { |
2332 | case IO_SUCCESS: |
2333 | pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n" ); |
2334 | if (param == 0) { |
2335 | ts->resp = SAS_TASK_COMPLETE; |
2336 | ts->stat = SAS_SAM_STAT_GOOD; |
2337 | } else { |
2338 | u8 len; |
2339 | ts->resp = SAS_TASK_COMPLETE; |
2340 | ts->stat = SAS_PROTO_RESPONSE; |
2341 | ts->residual = param; |
2342 | pm8001_dbg(pm8001_ha, IO, |
2343 | "SAS_PROTO_RESPONSE len = %d\n" , |
2344 | param); |
2345 | sata_resp = &psataPayload->sata_resp[0]; |
2346 | resp = (struct ata_task_resp *)ts->buf; |
2347 | if (t->ata_task.dma_xfer == 0 && |
2348 | t->data_dir == DMA_FROM_DEVICE) { |
2349 | len = sizeof(struct pio_setup_fis); |
2350 | pm8001_dbg(pm8001_ha, IO, |
2351 | "PIO read len = %d\n" , len); |
2352 | } else if (t->ata_task.use_ncq && |
2353 | t->data_dir != DMA_NONE) { |
2354 | len = sizeof(struct set_dev_bits_fis); |
2355 | pm8001_dbg(pm8001_ha, IO, "FPDMA len = %d\n" , |
2356 | len); |
2357 | } else { |
2358 | len = sizeof(struct dev_to_host_fis); |
2359 | pm8001_dbg(pm8001_ha, IO, "other len = %d\n" , |
2360 | len); |
2361 | } |
2362 | if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { |
2363 | resp->frame_len = len; |
2364 | memcpy(&resp->ending_fis[0], sata_resp, len); |
2365 | ts->buf_valid_size = sizeof(*resp); |
2366 | } else |
2367 | pm8001_dbg(pm8001_ha, IO, |
2368 | "response too large\n" ); |
2369 | } |
2370 | if (pm8001_dev) |
2371 | atomic_dec(v: &pm8001_dev->running_req); |
2372 | break; |
2373 | case IO_ABORTED: |
2374 | pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB Tag\n" ); |
2375 | ts->resp = SAS_TASK_COMPLETE; |
2376 | ts->stat = SAS_ABORTED_TASK; |
2377 | if (pm8001_dev) |
2378 | atomic_dec(v: &pm8001_dev->running_req); |
2379 | break; |
2380 | /* following cases are to do cases */ |
2381 | case IO_UNDERFLOW: |
2382 | /* SATA Completion with error */ |
2383 | pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW param = %d\n" , param); |
2384 | ts->resp = SAS_TASK_COMPLETE; |
2385 | ts->stat = SAS_DATA_UNDERRUN; |
2386 | ts->residual = param; |
2387 | if (pm8001_dev) |
2388 | atomic_dec(v: &pm8001_dev->running_req); |
2389 | break; |
2390 | case IO_NO_DEVICE: |
2391 | pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n" ); |
2392 | ts->resp = SAS_TASK_UNDELIVERED; |
2393 | ts->stat = SAS_PHY_DOWN; |
2394 | if (pm8001_dev) |
2395 | atomic_dec(v: &pm8001_dev->running_req); |
2396 | break; |
2397 | case IO_XFER_ERROR_BREAK: |
2398 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n" ); |
2399 | ts->resp = SAS_TASK_COMPLETE; |
2400 | ts->stat = SAS_INTERRUPTED; |
2401 | if (pm8001_dev) |
2402 | atomic_dec(v: &pm8001_dev->running_req); |
2403 | break; |
2404 | case IO_XFER_ERROR_PHY_NOT_READY: |
2405 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n" ); |
2406 | ts->resp = SAS_TASK_COMPLETE; |
2407 | ts->stat = SAS_OPEN_REJECT; |
2408 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
2409 | if (pm8001_dev) |
2410 | atomic_dec(v: &pm8001_dev->running_req); |
2411 | break; |
2412 | case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: |
2413 | pm8001_dbg(pm8001_ha, IO, |
2414 | "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n" ); |
2415 | ts->resp = SAS_TASK_COMPLETE; |
2416 | ts->stat = SAS_OPEN_REJECT; |
2417 | ts->open_rej_reason = SAS_OREJ_EPROTO; |
2418 | if (pm8001_dev) |
2419 | atomic_dec(v: &pm8001_dev->running_req); |
2420 | break; |
2421 | case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: |
2422 | pm8001_dbg(pm8001_ha, IO, |
2423 | "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n" ); |
2424 | ts->resp = SAS_TASK_COMPLETE; |
2425 | ts->stat = SAS_OPEN_REJECT; |
2426 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
2427 | if (pm8001_dev) |
2428 | atomic_dec(v: &pm8001_dev->running_req); |
2429 | break; |
2430 | case IO_OPEN_CNX_ERROR_BREAK: |
2431 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n" ); |
2432 | ts->resp = SAS_TASK_COMPLETE; |
2433 | ts->stat = SAS_OPEN_REJECT; |
2434 | ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; |
2435 | if (pm8001_dev) |
2436 | atomic_dec(v: &pm8001_dev->running_req); |
2437 | break; |
2438 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: |
2439 | case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: |
2440 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: |
2441 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: |
2442 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: |
2443 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: |
2444 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n" ); |
2445 | ts->resp = SAS_TASK_COMPLETE; |
2446 | ts->stat = SAS_DEV_NO_RESPONSE; |
2447 | if (!t->uldd_task) { |
2448 | pm8001_handle_event(pm8001_ha, |
2449 | data: pm8001_dev, |
2450 | IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); |
2451 | ts->resp = SAS_TASK_UNDELIVERED; |
2452 | ts->stat = SAS_QUEUE_FULL; |
2453 | spin_unlock_irqrestore(lock: &circularQ->oq_lock, |
2454 | flags: circularQ->lock_flags); |
2455 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2456 | spin_lock_irqsave(&circularQ->oq_lock, |
2457 | circularQ->lock_flags); |
2458 | return; |
2459 | } |
2460 | break; |
2461 | case IO_OPEN_CNX_ERROR_BAD_DESTINATION: |
2462 | pm8001_dbg(pm8001_ha, IO, |
2463 | "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n" ); |
2464 | ts->resp = SAS_TASK_UNDELIVERED; |
2465 | ts->stat = SAS_OPEN_REJECT; |
2466 | ts->open_rej_reason = SAS_OREJ_BAD_DEST; |
2467 | if (!t->uldd_task) { |
2468 | pm8001_handle_event(pm8001_ha, |
2469 | data: pm8001_dev, |
2470 | IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); |
2471 | ts->resp = SAS_TASK_UNDELIVERED; |
2472 | ts->stat = SAS_QUEUE_FULL; |
2473 | spin_unlock_irqrestore(lock: &circularQ->oq_lock, |
2474 | flags: circularQ->lock_flags); |
2475 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2476 | spin_lock_irqsave(&circularQ->oq_lock, |
2477 | circularQ->lock_flags); |
2478 | return; |
2479 | } |
2480 | break; |
2481 | case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: |
2482 | pm8001_dbg(pm8001_ha, IO, |
2483 | "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n" ); |
2484 | ts->resp = SAS_TASK_COMPLETE; |
2485 | ts->stat = SAS_OPEN_REJECT; |
2486 | ts->open_rej_reason = SAS_OREJ_CONN_RATE; |
2487 | if (pm8001_dev) |
2488 | atomic_dec(v: &pm8001_dev->running_req); |
2489 | break; |
2490 | case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: |
2491 | pm8001_dbg(pm8001_ha, IO, |
2492 | "IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY\n" ); |
2493 | ts->resp = SAS_TASK_COMPLETE; |
2494 | ts->stat = SAS_DEV_NO_RESPONSE; |
2495 | if (!t->uldd_task) { |
2496 | pm8001_handle_event(pm8001_ha, |
2497 | data: pm8001_dev, |
2498 | IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY); |
2499 | ts->resp = SAS_TASK_UNDELIVERED; |
2500 | ts->stat = SAS_QUEUE_FULL; |
2501 | spin_unlock_irqrestore(lock: &circularQ->oq_lock, |
2502 | flags: circularQ->lock_flags); |
2503 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2504 | spin_lock_irqsave(&circularQ->oq_lock, |
2505 | circularQ->lock_flags); |
2506 | return; |
2507 | } |
2508 | break; |
2509 | case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: |
2510 | pm8001_dbg(pm8001_ha, IO, |
2511 | "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n" ); |
2512 | ts->resp = SAS_TASK_COMPLETE; |
2513 | ts->stat = SAS_OPEN_REJECT; |
2514 | ts->open_rej_reason = SAS_OREJ_WRONG_DEST; |
2515 | if (pm8001_dev) |
2516 | atomic_dec(v: &pm8001_dev->running_req); |
2517 | break; |
2518 | case IO_XFER_ERROR_NAK_RECEIVED: |
2519 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n" ); |
2520 | ts->resp = SAS_TASK_COMPLETE; |
2521 | ts->stat = SAS_NAK_R_ERR; |
2522 | if (pm8001_dev) |
2523 | atomic_dec(v: &pm8001_dev->running_req); |
2524 | break; |
2525 | case IO_XFER_ERROR_ACK_NAK_TIMEOUT: |
2526 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_ACK_NAK_TIMEOUT\n" ); |
2527 | ts->resp = SAS_TASK_COMPLETE; |
2528 | ts->stat = SAS_NAK_R_ERR; |
2529 | if (pm8001_dev) |
2530 | atomic_dec(v: &pm8001_dev->running_req); |
2531 | break; |
2532 | case IO_XFER_ERROR_DMA: |
2533 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_DMA\n" ); |
2534 | ts->resp = SAS_TASK_COMPLETE; |
2535 | ts->stat = SAS_ABORTED_TASK; |
2536 | if (pm8001_dev) |
2537 | atomic_dec(v: &pm8001_dev->running_req); |
2538 | break; |
2539 | case IO_XFER_ERROR_SATA_LINK_TIMEOUT: |
2540 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_SATA_LINK_TIMEOUT\n" ); |
2541 | ts->resp = SAS_TASK_UNDELIVERED; |
2542 | ts->stat = SAS_DEV_NO_RESPONSE; |
2543 | if (pm8001_dev) |
2544 | atomic_dec(v: &pm8001_dev->running_req); |
2545 | break; |
2546 | case IO_XFER_ERROR_REJECTED_NCQ_MODE: |
2547 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n" ); |
2548 | ts->resp = SAS_TASK_COMPLETE; |
2549 | ts->stat = SAS_DATA_UNDERRUN; |
2550 | if (pm8001_dev) |
2551 | atomic_dec(v: &pm8001_dev->running_req); |
2552 | break; |
2553 | case IO_XFER_OPEN_RETRY_TIMEOUT: |
2554 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n" ); |
2555 | ts->resp = SAS_TASK_COMPLETE; |
2556 | ts->stat = SAS_OPEN_TO; |
2557 | if (pm8001_dev) |
2558 | atomic_dec(v: &pm8001_dev->running_req); |
2559 | break; |
2560 | case IO_PORT_IN_RESET: |
2561 | pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n" ); |
2562 | ts->resp = SAS_TASK_COMPLETE; |
2563 | ts->stat = SAS_DEV_NO_RESPONSE; |
2564 | if (pm8001_dev) |
2565 | atomic_dec(v: &pm8001_dev->running_req); |
2566 | break; |
2567 | case IO_DS_NON_OPERATIONAL: |
2568 | pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n" ); |
2569 | ts->resp = SAS_TASK_COMPLETE; |
2570 | ts->stat = SAS_DEV_NO_RESPONSE; |
2571 | if (!t->uldd_task) { |
2572 | pm8001_handle_event(pm8001_ha, data: pm8001_dev, |
2573 | IO_DS_NON_OPERATIONAL); |
2574 | ts->resp = SAS_TASK_UNDELIVERED; |
2575 | ts->stat = SAS_QUEUE_FULL; |
2576 | spin_unlock_irqrestore(lock: &circularQ->oq_lock, |
2577 | flags: circularQ->lock_flags); |
2578 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2579 | spin_lock_irqsave(&circularQ->oq_lock, |
2580 | circularQ->lock_flags); |
2581 | return; |
2582 | } |
2583 | break; |
2584 | case IO_DS_IN_RECOVERY: |
2585 | pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n" ); |
2586 | ts->resp = SAS_TASK_COMPLETE; |
2587 | ts->stat = SAS_DEV_NO_RESPONSE; |
2588 | if (pm8001_dev) |
2589 | atomic_dec(v: &pm8001_dev->running_req); |
2590 | break; |
2591 | case IO_DS_IN_ERROR: |
2592 | pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_ERROR\n" ); |
2593 | ts->resp = SAS_TASK_COMPLETE; |
2594 | ts->stat = SAS_DEV_NO_RESPONSE; |
2595 | if (!t->uldd_task) { |
2596 | pm8001_handle_event(pm8001_ha, data: pm8001_dev, |
2597 | IO_DS_IN_ERROR); |
2598 | ts->resp = SAS_TASK_UNDELIVERED; |
2599 | ts->stat = SAS_QUEUE_FULL; |
2600 | spin_unlock_irqrestore(lock: &circularQ->oq_lock, |
2601 | flags: circularQ->lock_flags); |
2602 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2603 | spin_lock_irqsave(&circularQ->oq_lock, |
2604 | circularQ->lock_flags); |
2605 | return; |
2606 | } |
2607 | break; |
2608 | case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: |
2609 | pm8001_dbg(pm8001_ha, IO, |
2610 | "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n" ); |
2611 | ts->resp = SAS_TASK_COMPLETE; |
2612 | ts->stat = SAS_OPEN_REJECT; |
2613 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
2614 | if (pm8001_dev) |
2615 | atomic_dec(v: &pm8001_dev->running_req); |
2616 | break; |
2617 | default: |
2618 | pm8001_dbg(pm8001_ha, DEVIO, |
2619 | "Unknown status device_id %u status 0x%x tag %d\n" , |
2620 | pm8001_dev->device_id, status, tag); |
2621 | /* not allowed case. Therefore, return failed status */ |
2622 | ts->resp = SAS_TASK_COMPLETE; |
2623 | ts->stat = SAS_DEV_NO_RESPONSE; |
2624 | if (pm8001_dev) |
2625 | atomic_dec(v: &pm8001_dev->running_req); |
2626 | break; |
2627 | } |
2628 | spin_lock_irqsave(&t->task_state_lock, flags); |
2629 | t->task_state_flags &= ~SAS_TASK_STATE_PENDING; |
2630 | t->task_state_flags |= SAS_TASK_STATE_DONE; |
2631 | if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { |
2632 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
2633 | pm8001_dbg(pm8001_ha, FAIL, |
2634 | "task 0x%p done with io_status 0x%x resp 0x%x stat 0x%x but aborted by upper layer!\n" , |
2635 | t, status, ts->resp, ts->stat); |
2636 | pm8001_ccb_task_free(pm8001_ha, ccb); |
2637 | if (t->slow_task) |
2638 | complete(&t->slow_task->completion); |
2639 | } else { |
2640 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
2641 | spin_unlock_irqrestore(lock: &circularQ->oq_lock, |
2642 | flags: circularQ->lock_flags); |
2643 | pm8001_ccb_task_free_done(pm8001_ha, ccb); |
2644 | spin_lock_irqsave(&circularQ->oq_lock, |
2645 | circularQ->lock_flags); |
2646 | } |
2647 | } |
2648 | |
2649 | /*See the comments for mpi_ssp_completion */ |
2650 | static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha, |
2651 | struct outbound_queue_table *circularQ, void *piomb) |
2652 | { |
2653 | struct sas_task *t; |
2654 | struct task_status_struct *ts; |
2655 | struct pm8001_ccb_info *ccb; |
2656 | struct pm8001_device *pm8001_dev; |
2657 | struct sata_event_resp *psataPayload = |
2658 | (struct sata_event_resp *)(piomb + 4); |
2659 | u32 event = le32_to_cpu(psataPayload->event); |
2660 | u32 tag = le32_to_cpu(psataPayload->tag); |
2661 | u32 port_id = le32_to_cpu(psataPayload->port_id); |
2662 | u32 dev_id = le32_to_cpu(psataPayload->device_id); |
2663 | |
2664 | if (event) |
2665 | pm8001_dbg(pm8001_ha, FAIL, "SATA EVENT 0x%x\n" , event); |
2666 | |
2667 | /* Check if this is NCQ error */ |
2668 | if (event == IO_XFER_ERROR_ABORTED_NCQ_MODE) { |
2669 | /* find device using device id */ |
2670 | pm8001_dev = pm8001_find_dev(pm8001_ha, device_id: dev_id); |
2671 | /* send read log extension by aborting the link - libata does what we want */ |
2672 | if (pm8001_dev) |
2673 | pm8001_handle_event(pm8001_ha, |
2674 | data: pm8001_dev, |
2675 | IO_XFER_ERROR_ABORTED_NCQ_MODE); |
2676 | return; |
2677 | } |
2678 | |
2679 | ccb = &pm8001_ha->ccb_info[tag]; |
2680 | t = ccb->task; |
2681 | pm8001_dev = ccb->device; |
2682 | if (unlikely(!t)) { |
2683 | pm8001_dbg(pm8001_ha, FAIL, "task null, freeing CCB tag %d\n" , |
2684 | ccb->ccb_tag); |
2685 | pm8001_ccb_free(pm8001_ha, ccb); |
2686 | return; |
2687 | } |
2688 | |
2689 | if (unlikely(!t->lldd_task || !t->dev)) |
2690 | return; |
2691 | |
2692 | ts = &t->task_status; |
2693 | pm8001_dbg(pm8001_ha, IOERR, "port_id:0x%x, tag:0x%x, event:0x%x\n" , |
2694 | port_id, tag, event); |
2695 | switch (event) { |
2696 | case IO_OVERFLOW: |
2697 | pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n" ); |
2698 | ts->resp = SAS_TASK_COMPLETE; |
2699 | ts->stat = SAS_DATA_OVERRUN; |
2700 | ts->residual = 0; |
2701 | break; |
2702 | case IO_XFER_ERROR_BREAK: |
2703 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n" ); |
2704 | ts->resp = SAS_TASK_COMPLETE; |
2705 | ts->stat = SAS_INTERRUPTED; |
2706 | break; |
2707 | case IO_XFER_ERROR_PHY_NOT_READY: |
2708 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n" ); |
2709 | ts->resp = SAS_TASK_COMPLETE; |
2710 | ts->stat = SAS_OPEN_REJECT; |
2711 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
2712 | break; |
2713 | case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: |
2714 | pm8001_dbg(pm8001_ha, IO, |
2715 | "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n" ); |
2716 | ts->resp = SAS_TASK_COMPLETE; |
2717 | ts->stat = SAS_OPEN_REJECT; |
2718 | ts->open_rej_reason = SAS_OREJ_EPROTO; |
2719 | break; |
2720 | case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: |
2721 | pm8001_dbg(pm8001_ha, IO, |
2722 | "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n" ); |
2723 | ts->resp = SAS_TASK_COMPLETE; |
2724 | ts->stat = SAS_OPEN_REJECT; |
2725 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
2726 | break; |
2727 | case IO_OPEN_CNX_ERROR_BREAK: |
2728 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n" ); |
2729 | ts->resp = SAS_TASK_COMPLETE; |
2730 | ts->stat = SAS_OPEN_REJECT; |
2731 | ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; |
2732 | break; |
2733 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: |
2734 | case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: |
2735 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: |
2736 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: |
2737 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: |
2738 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: |
2739 | pm8001_dbg(pm8001_ha, FAIL, |
2740 | "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n" ); |
2741 | ts->resp = SAS_TASK_UNDELIVERED; |
2742 | ts->stat = SAS_DEV_NO_RESPONSE; |
2743 | if (!t->uldd_task) { |
2744 | pm8001_handle_event(pm8001_ha, |
2745 | data: pm8001_dev, |
2746 | IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); |
2747 | ts->resp = SAS_TASK_COMPLETE; |
2748 | ts->stat = SAS_QUEUE_FULL; |
2749 | return; |
2750 | } |
2751 | break; |
2752 | case IO_OPEN_CNX_ERROR_BAD_DESTINATION: |
2753 | pm8001_dbg(pm8001_ha, IO, |
2754 | "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n" ); |
2755 | ts->resp = SAS_TASK_UNDELIVERED; |
2756 | ts->stat = SAS_OPEN_REJECT; |
2757 | ts->open_rej_reason = SAS_OREJ_BAD_DEST; |
2758 | break; |
2759 | case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: |
2760 | pm8001_dbg(pm8001_ha, IO, |
2761 | "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n" ); |
2762 | ts->resp = SAS_TASK_COMPLETE; |
2763 | ts->stat = SAS_OPEN_REJECT; |
2764 | ts->open_rej_reason = SAS_OREJ_CONN_RATE; |
2765 | break; |
2766 | case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: |
2767 | pm8001_dbg(pm8001_ha, IO, |
2768 | "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n" ); |
2769 | ts->resp = SAS_TASK_COMPLETE; |
2770 | ts->stat = SAS_OPEN_REJECT; |
2771 | ts->open_rej_reason = SAS_OREJ_WRONG_DEST; |
2772 | break; |
2773 | case IO_XFER_ERROR_NAK_RECEIVED: |
2774 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_NAK_RECEIVED\n" ); |
2775 | ts->resp = SAS_TASK_COMPLETE; |
2776 | ts->stat = SAS_NAK_R_ERR; |
2777 | break; |
2778 | case IO_XFER_ERROR_PEER_ABORTED: |
2779 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PEER_ABORTED\n" ); |
2780 | ts->resp = SAS_TASK_COMPLETE; |
2781 | ts->stat = SAS_NAK_R_ERR; |
2782 | break; |
2783 | case IO_XFER_ERROR_REJECTED_NCQ_MODE: |
2784 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_REJECTED_NCQ_MODE\n" ); |
2785 | ts->resp = SAS_TASK_COMPLETE; |
2786 | ts->stat = SAS_DATA_UNDERRUN; |
2787 | break; |
2788 | case IO_XFER_OPEN_RETRY_TIMEOUT: |
2789 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n" ); |
2790 | ts->resp = SAS_TASK_COMPLETE; |
2791 | ts->stat = SAS_OPEN_TO; |
2792 | break; |
2793 | case IO_XFER_ERROR_UNEXPECTED_PHASE: |
2794 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_UNEXPECTED_PHASE\n" ); |
2795 | ts->resp = SAS_TASK_COMPLETE; |
2796 | ts->stat = SAS_OPEN_TO; |
2797 | break; |
2798 | case IO_XFER_ERROR_XFER_RDY_OVERRUN: |
2799 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_XFER_RDY_OVERRUN\n" ); |
2800 | ts->resp = SAS_TASK_COMPLETE; |
2801 | ts->stat = SAS_OPEN_TO; |
2802 | break; |
2803 | case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: |
2804 | pm8001_dbg(pm8001_ha, IO, |
2805 | "IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n" ); |
2806 | ts->resp = SAS_TASK_COMPLETE; |
2807 | ts->stat = SAS_OPEN_TO; |
2808 | break; |
2809 | case IO_XFER_ERROR_OFFSET_MISMATCH: |
2810 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_OFFSET_MISMATCH\n" ); |
2811 | ts->resp = SAS_TASK_COMPLETE; |
2812 | ts->stat = SAS_OPEN_TO; |
2813 | break; |
2814 | case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: |
2815 | pm8001_dbg(pm8001_ha, IO, |
2816 | "IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n" ); |
2817 | ts->resp = SAS_TASK_COMPLETE; |
2818 | ts->stat = SAS_OPEN_TO; |
2819 | break; |
2820 | case IO_XFER_CMD_FRAME_ISSUED: |
2821 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_CMD_FRAME_ISSUED\n" ); |
2822 | break; |
2823 | case IO_XFER_PIO_SETUP_ERROR: |
2824 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_PIO_SETUP_ERROR\n" ); |
2825 | ts->resp = SAS_TASK_COMPLETE; |
2826 | ts->stat = SAS_OPEN_TO; |
2827 | break; |
2828 | case IO_XFER_ERROR_INTERNAL_CRC_ERROR: |
2829 | pm8001_dbg(pm8001_ha, FAIL, |
2830 | "IO_XFR_ERROR_INTERNAL_CRC_ERROR\n" ); |
2831 | /* TBC: used default set values */ |
2832 | ts->resp = SAS_TASK_COMPLETE; |
2833 | ts->stat = SAS_OPEN_TO; |
2834 | break; |
2835 | case IO_XFER_DMA_ACTIVATE_TIMEOUT: |
2836 | pm8001_dbg(pm8001_ha, FAIL, "IO_XFR_DMA_ACTIVATE_TIMEOUT\n" ); |
2837 | /* TBC: used default set values */ |
2838 | ts->resp = SAS_TASK_COMPLETE; |
2839 | ts->stat = SAS_OPEN_TO; |
2840 | break; |
2841 | default: |
2842 | pm8001_dbg(pm8001_ha, IO, "Unknown status 0x%x\n" , event); |
2843 | /* not allowed case. Therefore, return failed status */ |
2844 | ts->resp = SAS_TASK_COMPLETE; |
2845 | ts->stat = SAS_OPEN_TO; |
2846 | break; |
2847 | } |
2848 | } |
2849 | |
2850 | /*See the comments for mpi_ssp_completion */ |
2851 | static void |
2852 | mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) |
2853 | { |
2854 | u32 param, i; |
2855 | struct sas_task *t; |
2856 | struct pm8001_ccb_info *ccb; |
2857 | unsigned long flags; |
2858 | u32 status; |
2859 | u32 tag; |
2860 | struct smp_completion_resp *psmpPayload; |
2861 | struct task_status_struct *ts; |
2862 | struct pm8001_device *pm8001_dev; |
2863 | |
2864 | psmpPayload = (struct smp_completion_resp *)(piomb + 4); |
2865 | status = le32_to_cpu(psmpPayload->status); |
2866 | tag = le32_to_cpu(psmpPayload->tag); |
2867 | |
2868 | ccb = &pm8001_ha->ccb_info[tag]; |
2869 | param = le32_to_cpu(psmpPayload->param); |
2870 | t = ccb->task; |
2871 | ts = &t->task_status; |
2872 | pm8001_dev = ccb->device; |
2873 | if (status) |
2874 | pm8001_dbg(pm8001_ha, FAIL, "smp IO status 0x%x\n" , status); |
2875 | if (unlikely(!t || !t->lldd_task || !t->dev)) |
2876 | return; |
2877 | |
2878 | pm8001_dbg(pm8001_ha, DEV, "tag::0x%x status::0x%x\n" , tag, status); |
2879 | |
2880 | switch (status) { |
2881 | |
2882 | case IO_SUCCESS: |
2883 | pm8001_dbg(pm8001_ha, IO, "IO_SUCCESS\n" ); |
2884 | ts->resp = SAS_TASK_COMPLETE; |
2885 | ts->stat = SAS_SAM_STAT_GOOD; |
2886 | if (pm8001_dev) |
2887 | atomic_dec(v: &pm8001_dev->running_req); |
2888 | if (pm8001_ha->smp_exp_mode == SMP_DIRECT) { |
2889 | struct scatterlist *sg_resp = &t->smp_task.smp_resp; |
2890 | u8 *payload; |
2891 | void *to; |
2892 | |
2893 | pm8001_dbg(pm8001_ha, IO, |
2894 | "DIRECT RESPONSE Length:%d\n" , |
2895 | param); |
2896 | to = kmap_atomic(page: sg_page(sg: sg_resp)); |
2897 | payload = to + sg_resp->offset; |
2898 | for (i = 0; i < param; i++) { |
2899 | *(payload + i) = psmpPayload->_r_a[i]; |
2900 | pm8001_dbg(pm8001_ha, IO, |
2901 | "SMP Byte%d DMA data 0x%x psmp 0x%x\n" , |
2902 | i, *(payload + i), |
2903 | psmpPayload->_r_a[i]); |
2904 | } |
2905 | kunmap_atomic(to); |
2906 | } |
2907 | break; |
2908 | case IO_ABORTED: |
2909 | pm8001_dbg(pm8001_ha, IO, "IO_ABORTED IOMB\n" ); |
2910 | ts->resp = SAS_TASK_COMPLETE; |
2911 | ts->stat = SAS_ABORTED_TASK; |
2912 | if (pm8001_dev) |
2913 | atomic_dec(v: &pm8001_dev->running_req); |
2914 | break; |
2915 | case IO_OVERFLOW: |
2916 | pm8001_dbg(pm8001_ha, IO, "IO_UNDERFLOW\n" ); |
2917 | ts->resp = SAS_TASK_COMPLETE; |
2918 | ts->stat = SAS_DATA_OVERRUN; |
2919 | ts->residual = 0; |
2920 | if (pm8001_dev) |
2921 | atomic_dec(v: &pm8001_dev->running_req); |
2922 | break; |
2923 | case IO_NO_DEVICE: |
2924 | pm8001_dbg(pm8001_ha, IO, "IO_NO_DEVICE\n" ); |
2925 | ts->resp = SAS_TASK_COMPLETE; |
2926 | ts->stat = SAS_PHY_DOWN; |
2927 | break; |
2928 | case IO_ERROR_HW_TIMEOUT: |
2929 | pm8001_dbg(pm8001_ha, IO, "IO_ERROR_HW_TIMEOUT\n" ); |
2930 | ts->resp = SAS_TASK_COMPLETE; |
2931 | ts->stat = SAS_SAM_STAT_BUSY; |
2932 | break; |
2933 | case IO_XFER_ERROR_BREAK: |
2934 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_BREAK\n" ); |
2935 | ts->resp = SAS_TASK_COMPLETE; |
2936 | ts->stat = SAS_SAM_STAT_BUSY; |
2937 | break; |
2938 | case IO_XFER_ERROR_PHY_NOT_READY: |
2939 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_PHY_NOT_READY\n" ); |
2940 | ts->resp = SAS_TASK_COMPLETE; |
2941 | ts->stat = SAS_SAM_STAT_BUSY; |
2942 | break; |
2943 | case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: |
2944 | pm8001_dbg(pm8001_ha, IO, |
2945 | "IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n" ); |
2946 | ts->resp = SAS_TASK_COMPLETE; |
2947 | ts->stat = SAS_OPEN_REJECT; |
2948 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
2949 | break; |
2950 | case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: |
2951 | pm8001_dbg(pm8001_ha, IO, |
2952 | "IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n" ); |
2953 | ts->resp = SAS_TASK_COMPLETE; |
2954 | ts->stat = SAS_OPEN_REJECT; |
2955 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
2956 | break; |
2957 | case IO_OPEN_CNX_ERROR_BREAK: |
2958 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_BREAK\n" ); |
2959 | ts->resp = SAS_TASK_COMPLETE; |
2960 | ts->stat = SAS_OPEN_REJECT; |
2961 | ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; |
2962 | break; |
2963 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: |
2964 | case IO_XFER_OPEN_RETRY_BACKOFF_THRESHOLD_REACHED: |
2965 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_TMO: |
2966 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_NO_DEST: |
2967 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_OPEN_COLLIDE: |
2968 | case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS_PATHWAY_BLOCKED: |
2969 | pm8001_dbg(pm8001_ha, IO, "IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n" ); |
2970 | ts->resp = SAS_TASK_COMPLETE; |
2971 | ts->stat = SAS_OPEN_REJECT; |
2972 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; |
2973 | pm8001_handle_event(pm8001_ha, |
2974 | data: pm8001_dev, |
2975 | IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); |
2976 | break; |
2977 | case IO_OPEN_CNX_ERROR_BAD_DESTINATION: |
2978 | pm8001_dbg(pm8001_ha, IO, |
2979 | "IO_OPEN_CNX_ERROR_BAD_DESTINATION\n" ); |
2980 | ts->resp = SAS_TASK_COMPLETE; |
2981 | ts->stat = SAS_OPEN_REJECT; |
2982 | ts->open_rej_reason = SAS_OREJ_BAD_DEST; |
2983 | break; |
2984 | case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: |
2985 | pm8001_dbg(pm8001_ha, IO, |
2986 | "IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED\n" ); |
2987 | ts->resp = SAS_TASK_COMPLETE; |
2988 | ts->stat = SAS_OPEN_REJECT; |
2989 | ts->open_rej_reason = SAS_OREJ_CONN_RATE; |
2990 | break; |
2991 | case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: |
2992 | pm8001_dbg(pm8001_ha, IO, |
2993 | "IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n" ); |
2994 | ts->resp = SAS_TASK_COMPLETE; |
2995 | ts->stat = SAS_OPEN_REJECT; |
2996 | ts->open_rej_reason = SAS_OREJ_WRONG_DEST; |
2997 | break; |
2998 | case IO_XFER_ERROR_RX_FRAME: |
2999 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_ERROR_RX_FRAME\n" ); |
3000 | ts->resp = SAS_TASK_COMPLETE; |
3001 | ts->stat = SAS_DEV_NO_RESPONSE; |
3002 | break; |
3003 | case IO_XFER_OPEN_RETRY_TIMEOUT: |
3004 | pm8001_dbg(pm8001_ha, IO, "IO_XFER_OPEN_RETRY_TIMEOUT\n" ); |
3005 | ts->resp = SAS_TASK_COMPLETE; |
3006 | ts->stat = SAS_OPEN_REJECT; |
3007 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
3008 | break; |
3009 | case IO_ERROR_INTERNAL_SMP_RESOURCE: |
3010 | pm8001_dbg(pm8001_ha, IO, "IO_ERROR_INTERNAL_SMP_RESOURCE\n" ); |
3011 | ts->resp = SAS_TASK_COMPLETE; |
3012 | ts->stat = SAS_QUEUE_FULL; |
3013 | break; |
3014 | case IO_PORT_IN_RESET: |
3015 | pm8001_dbg(pm8001_ha, IO, "IO_PORT_IN_RESET\n" ); |
3016 | ts->resp = SAS_TASK_COMPLETE; |
3017 | ts->stat = SAS_OPEN_REJECT; |
3018 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
3019 | break; |
3020 | case IO_DS_NON_OPERATIONAL: |
3021 | pm8001_dbg(pm8001_ha, IO, "IO_DS_NON_OPERATIONAL\n" ); |
3022 | ts->resp = SAS_TASK_COMPLETE; |
3023 | ts->stat = SAS_DEV_NO_RESPONSE; |
3024 | break; |
3025 | case IO_DS_IN_RECOVERY: |
3026 | pm8001_dbg(pm8001_ha, IO, "IO_DS_IN_RECOVERY\n" ); |
3027 | ts->resp = SAS_TASK_COMPLETE; |
3028 | ts->stat = SAS_OPEN_REJECT; |
3029 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
3030 | break; |
3031 | case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: |
3032 | pm8001_dbg(pm8001_ha, IO, |
3033 | "IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n" ); |
3034 | ts->resp = SAS_TASK_COMPLETE; |
3035 | ts->stat = SAS_OPEN_REJECT; |
3036 | ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; |
3037 | break; |
3038 | default: |
3039 | pm8001_dbg(pm8001_ha, DEVIO, "Unknown status 0x%x\n" , status); |
3040 | ts->resp = SAS_TASK_COMPLETE; |
3041 | ts->stat = SAS_DEV_NO_RESPONSE; |
3042 | /* not allowed case. Therefore, return failed status */ |
3043 | break; |
3044 | } |
3045 | spin_lock_irqsave(&t->task_state_lock, flags); |
3046 | t->task_state_flags &= ~SAS_TASK_STATE_PENDING; |
3047 | t->task_state_flags |= SAS_TASK_STATE_DONE; |
3048 | if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { |
3049 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
3050 | pm8001_dbg(pm8001_ha, FAIL, |
3051 | "task 0x%p done with io_status 0x%x resp 0x%xstat 0x%x but aborted by upper layer!\n" , |
3052 | t, status, ts->resp, ts->stat); |
3053 | pm8001_ccb_task_free(pm8001_ha, ccb); |
3054 | } else { |
3055 | spin_unlock_irqrestore(lock: &t->task_state_lock, flags); |
3056 | pm8001_ccb_task_free(pm8001_ha, ccb); |
3057 | mb();/* in order to force CPU ordering */ |
3058 | t->task_done(t); |
3059 | } |
3060 | } |
3061 | |
3062 | /** |
3063 | * pm80xx_hw_event_ack_req- For PM8001, some events need to acknowledge to FW. |
3064 | * @pm8001_ha: our hba card information |
3065 | * @Qnum: the outbound queue message number. |
3066 | * @SEA: source of event to ack |
3067 | * @port_id: port id. |
3068 | * @phyId: phy id. |
3069 | * @param0: parameter 0. |
3070 | * @param1: parameter 1. |
3071 | */ |
3072 | static void pm80xx_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, |
3073 | u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, u32 param1) |
3074 | { |
3075 | struct hw_event_ack_req payload; |
3076 | u32 opc = OPC_INB_SAS_HW_EVENT_ACK; |
3077 | |
3078 | memset((u8 *)&payload, 0, sizeof(payload)); |
3079 | payload.tag = cpu_to_le32(1); |
3080 | payload.phyid_sea_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) | |
3081 | ((phyId & 0xFF) << 24) | (port_id & 0xFF)); |
3082 | payload.param0 = cpu_to_le32(param0); |
3083 | payload.param1 = cpu_to_le32(param1); |
3084 | |
3085 | pm8001_mpi_build_cmd(pm8001_ha, q_index: Qnum, opCode: opc, payload: &payload, |
3086 | nb: sizeof(payload), responseQueue: 0); |
3087 | } |
3088 | |
3089 | static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, |
3090 | u32 phyId, u32 phy_op); |
3091 | |
3092 | static void hw_event_port_recover(struct pm8001_hba_info *pm8001_ha, |
3093 | void *piomb) |
3094 | { |
3095 | struct hw_event_resp *pPayload = (struct hw_event_resp *)(piomb + 4); |
3096 | u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); |
3097 | u8 phy_id = (u8)((phyid_npip_portstate & 0xFF0000) >> 16); |
3098 | u32 lr_status_evt_portid = |
3099 | le32_to_cpu(pPayload->lr_status_evt_portid); |
3100 | u8 deviceType = pPayload->sas_identify.dev_type; |
3101 | u8 link_rate = (u8)((lr_status_evt_portid & 0xF0000000) >> 28); |
3102 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
3103 | u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); |
3104 | struct pm8001_port *port = &pm8001_ha->port[port_id]; |
3105 | |
3106 | if (deviceType == SAS_END_DEVICE) { |
3107 | pm80xx_chip_phy_ctl_req(pm8001_ha, phyId: phy_id, |
3108 | phy_op: PHY_NOTIFY_ENABLE_SPINUP); |
3109 | } |
3110 | |
3111 | port->wide_port_phymap |= (1U << phy_id); |
3112 | pm8001_get_lrate_mode(phy, link_rate); |
3113 | phy->sas_phy.oob_mode = SAS_OOB_MODE; |
3114 | phy->phy_state = PHY_STATE_LINK_UP_SPCV; |
3115 | phy->phy_attached = 1; |
3116 | } |
3117 | |
3118 | /** |
3119 | * hw_event_sas_phy_up - FW tells me a SAS phy up event. |
3120 | * @pm8001_ha: our hba card information |
3121 | * @piomb: IO message buffer |
3122 | */ |
3123 | static void |
3124 | hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3125 | { |
3126 | struct hw_event_resp *pPayload = |
3127 | (struct hw_event_resp *)(piomb + 4); |
3128 | u32 lr_status_evt_portid = |
3129 | le32_to_cpu(pPayload->lr_status_evt_portid); |
3130 | u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); |
3131 | |
3132 | u8 link_rate = |
3133 | (u8)((lr_status_evt_portid & 0xF0000000) >> 28); |
3134 | u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); |
3135 | u8 phy_id = |
3136 | (u8)((phyid_npip_portstate & 0xFF0000) >> 16); |
3137 | u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F); |
3138 | |
3139 | struct pm8001_port *port = &pm8001_ha->port[port_id]; |
3140 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
3141 | unsigned long flags; |
3142 | u8 deviceType = pPayload->sas_identify.dev_type; |
3143 | phy->port = port; |
3144 | port->port_id = port_id; |
3145 | port->port_state = portstate; |
3146 | port->wide_port_phymap |= (1U << phy_id); |
3147 | phy->phy_state = PHY_STATE_LINK_UP_SPCV; |
3148 | pm8001_dbg(pm8001_ha, MSG, |
3149 | "portid:%d; phyid:%d; linkrate:%d; portstate:%x; devicetype:%x\n" , |
3150 | port_id, phy_id, link_rate, portstate, deviceType); |
3151 | |
3152 | switch (deviceType) { |
3153 | case SAS_PHY_UNUSED: |
3154 | pm8001_dbg(pm8001_ha, MSG, "device type no device.\n" ); |
3155 | break; |
3156 | case SAS_END_DEVICE: |
3157 | pm8001_dbg(pm8001_ha, MSG, "end device.\n" ); |
3158 | pm80xx_chip_phy_ctl_req(pm8001_ha, phyId: phy_id, |
3159 | phy_op: PHY_NOTIFY_ENABLE_SPINUP); |
3160 | port->port_attached = 1; |
3161 | pm8001_get_lrate_mode(phy, link_rate); |
3162 | break; |
3163 | case SAS_EDGE_EXPANDER_DEVICE: |
3164 | pm8001_dbg(pm8001_ha, MSG, "expander device.\n" ); |
3165 | port->port_attached = 1; |
3166 | pm8001_get_lrate_mode(phy, link_rate); |
3167 | break; |
3168 | case SAS_FANOUT_EXPANDER_DEVICE: |
3169 | pm8001_dbg(pm8001_ha, MSG, "fanout expander device.\n" ); |
3170 | port->port_attached = 1; |
3171 | pm8001_get_lrate_mode(phy, link_rate); |
3172 | break; |
3173 | default: |
3174 | pm8001_dbg(pm8001_ha, DEVIO, "unknown device type(%x)\n" , |
3175 | deviceType); |
3176 | break; |
3177 | } |
3178 | phy->phy_type |= PORT_TYPE_SAS; |
3179 | phy->identify.device_type = deviceType; |
3180 | phy->phy_attached = 1; |
3181 | if (phy->identify.device_type == SAS_END_DEVICE) |
3182 | phy->identify.target_port_protocols = SAS_PROTOCOL_SSP; |
3183 | else if (phy->identify.device_type != SAS_PHY_UNUSED) |
3184 | phy->identify.target_port_protocols = SAS_PROTOCOL_SMP; |
3185 | phy->sas_phy.oob_mode = SAS_OOB_MODE; |
3186 | sas_notify_phy_event(phy: &phy->sas_phy, event: PHYE_OOB_DONE, GFP_ATOMIC); |
3187 | spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); |
3188 | memcpy(phy->frame_rcvd, &pPayload->sas_identify, |
3189 | sizeof(struct sas_identify_frame)-4); |
3190 | phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4; |
3191 | pm8001_get_attached_sas_addr(phy, sas_addr: phy->sas_phy.attached_sas_addr); |
3192 | spin_unlock_irqrestore(lock: &phy->sas_phy.frame_rcvd_lock, flags); |
3193 | if (pm8001_ha->flags == PM8001F_RUN_TIME) |
3194 | mdelay(200); /* delay a moment to wait for disk to spin up */ |
3195 | pm8001_bytes_dmaed(pm8001_ha, i: phy_id); |
3196 | } |
3197 | |
3198 | /** |
3199 | * hw_event_sata_phy_up - FW tells me a SATA phy up event. |
3200 | * @pm8001_ha: our hba card information |
3201 | * @piomb: IO message buffer |
3202 | */ |
3203 | static void |
3204 | hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3205 | { |
3206 | struct hw_event_resp *pPayload = |
3207 | (struct hw_event_resp *)(piomb + 4); |
3208 | u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); |
3209 | u32 lr_status_evt_portid = |
3210 | le32_to_cpu(pPayload->lr_status_evt_portid); |
3211 | u8 link_rate = |
3212 | (u8)((lr_status_evt_portid & 0xF0000000) >> 28); |
3213 | u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); |
3214 | u8 phy_id = |
3215 | (u8)((phyid_npip_portstate & 0xFF0000) >> 16); |
3216 | |
3217 | u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F); |
3218 | |
3219 | struct pm8001_port *port = &pm8001_ha->port[port_id]; |
3220 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
3221 | unsigned long flags; |
3222 | pm8001_dbg(pm8001_ha, EVENT, |
3223 | "HW_EVENT_SATA_PHY_UP phyid:%#x port_id:%#x link_rate:%d portstate:%#x\n" , |
3224 | phy_id, port_id, link_rate, portstate); |
3225 | |
3226 | phy->port = port; |
3227 | port->port_id = port_id; |
3228 | port->port_state = portstate; |
3229 | phy->phy_state = PHY_STATE_LINK_UP_SPCV; |
3230 | port->port_attached = 1; |
3231 | pm8001_get_lrate_mode(phy, link_rate); |
3232 | phy->phy_type |= PORT_TYPE_SATA; |
3233 | phy->phy_attached = 1; |
3234 | phy->sas_phy.oob_mode = SATA_OOB_MODE; |
3235 | sas_notify_phy_event(phy: &phy->sas_phy, event: PHYE_OOB_DONE, GFP_ATOMIC); |
3236 | spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); |
3237 | memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4), |
3238 | sizeof(struct dev_to_host_fis)); |
3239 | phy->frame_rcvd_size = sizeof(struct dev_to_host_fis); |
3240 | phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; |
3241 | phy->identify.device_type = SAS_SATA_DEV; |
3242 | pm8001_get_attached_sas_addr(phy, sas_addr: phy->sas_phy.attached_sas_addr); |
3243 | spin_unlock_irqrestore(lock: &phy->sas_phy.frame_rcvd_lock, flags); |
3244 | pm8001_bytes_dmaed(pm8001_ha, i: phy_id); |
3245 | } |
3246 | |
3247 | /** |
3248 | * hw_event_phy_down - we should notify the libsas the phy is down. |
3249 | * @pm8001_ha: our hba card information |
3250 | * @piomb: IO message buffer |
3251 | */ |
3252 | static void |
3253 | hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3254 | { |
3255 | struct hw_event_resp *pPayload = |
3256 | (struct hw_event_resp *)(piomb + 4); |
3257 | |
3258 | u32 lr_status_evt_portid = |
3259 | le32_to_cpu(pPayload->lr_status_evt_portid); |
3260 | u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); |
3261 | u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); |
3262 | u8 phy_id = |
3263 | (u8)((phyid_npip_portstate & 0xFF0000) >> 16); |
3264 | u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F); |
3265 | |
3266 | struct pm8001_port *port = &pm8001_ha->port[port_id]; |
3267 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
3268 | u32 port_sata = (phy->phy_type & PORT_TYPE_SATA); |
3269 | port->port_state = portstate; |
3270 | phy->identify.device_type = 0; |
3271 | phy->phy_attached = 0; |
3272 | switch (portstate) { |
3273 | case PORT_VALID: |
3274 | pm8001_dbg(pm8001_ha, EVENT, |
3275 | "HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_VALID\n" , |
3276 | phy_id, port_id); |
3277 | break; |
3278 | case PORT_INVALID: |
3279 | pm8001_dbg(pm8001_ha, EVENT, |
3280 | "HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_INVALID\n" , |
3281 | phy_id, port_id); |
3282 | pm8001_dbg(pm8001_ha, MSG, |
3283 | " Last phy Down and port invalid\n" ); |
3284 | if (port_sata) { |
3285 | phy->phy_type = 0; |
3286 | port->port_attached = 0; |
3287 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, HW_EVENT_PHY_DOWN, |
3288 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3289 | } |
3290 | sas_phy_disconnected(phy: &phy->sas_phy); |
3291 | break; |
3292 | case PORT_IN_RESET: |
3293 | pm8001_dbg(pm8001_ha, EVENT, |
3294 | "HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_IN_RESET\n" , |
3295 | phy_id, port_id); |
3296 | break; |
3297 | case PORT_NOT_ESTABLISHED: |
3298 | pm8001_dbg(pm8001_ha, EVENT, |
3299 | "HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_NOT_ESTABLISHED\n" , |
3300 | phy_id, port_id); |
3301 | port->port_attached = 0; |
3302 | break; |
3303 | case PORT_LOSTCOMM: |
3304 | pm8001_dbg(pm8001_ha, EVENT, |
3305 | "HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate: PORT_LOSTCOMM\n" , |
3306 | phy_id, port_id); |
3307 | pm8001_dbg(pm8001_ha, MSG, " Last phy Down and port invalid\n" ); |
3308 | if (port_sata) { |
3309 | port->port_attached = 0; |
3310 | phy->phy_type = 0; |
3311 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, HW_EVENT_PHY_DOWN, |
3312 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3313 | } |
3314 | sas_phy_disconnected(phy: &phy->sas_phy); |
3315 | break; |
3316 | default: |
3317 | port->port_attached = 0; |
3318 | pm8001_dbg(pm8001_ha, EVENT, |
3319 | "HW_EVENT_PHY_DOWN phyid:%#x port_id:%#x portstate:%#x\n" , |
3320 | phy_id, port_id, portstate); |
3321 | break; |
3322 | |
3323 | } |
3324 | if (port_sata && (portstate != PORT_IN_RESET)) |
3325 | sas_notify_phy_event(phy: &phy->sas_phy, event: PHYE_LOSS_OF_SIGNAL, |
3326 | GFP_ATOMIC); |
3327 | } |
3328 | |
3329 | static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3330 | { |
3331 | struct phy_start_resp *pPayload = |
3332 | (struct phy_start_resp *)(piomb + 4); |
3333 | u32 status = |
3334 | le32_to_cpu(pPayload->status); |
3335 | u32 phy_id = |
3336 | le32_to_cpu(pPayload->phyid) & 0xFF; |
3337 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
3338 | |
3339 | pm8001_dbg(pm8001_ha, INIT, |
3340 | "phy start resp status:0x%x, phyid:0x%x\n" , |
3341 | status, phy_id); |
3342 | if (status == 0) |
3343 | phy->phy_state = PHY_LINK_DOWN; |
3344 | |
3345 | if (pm8001_ha->flags == PM8001F_RUN_TIME && |
3346 | phy->enable_completion != NULL) { |
3347 | complete(phy->enable_completion); |
3348 | phy->enable_completion = NULL; |
3349 | } |
3350 | return 0; |
3351 | |
3352 | } |
3353 | |
3354 | /** |
3355 | * mpi_thermal_hw_event - a thermal hw event has come. |
3356 | * @pm8001_ha: our hba card information |
3357 | * @piomb: IO message buffer |
3358 | */ |
3359 | static int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3360 | { |
3361 | struct thermal_hw_event *pPayload = |
3362 | (struct thermal_hw_event *)(piomb + 4); |
3363 | |
3364 | u32 thermal_event = le32_to_cpu(pPayload->thermal_event); |
3365 | u32 rht_lht = le32_to_cpu(pPayload->rht_lht); |
3366 | |
3367 | if (thermal_event & 0x40) { |
3368 | pm8001_dbg(pm8001_ha, IO, |
3369 | "Thermal Event: Local high temperature violated!\n" ); |
3370 | pm8001_dbg(pm8001_ha, IO, |
3371 | "Thermal Event: Measured local high temperature %d\n" , |
3372 | ((rht_lht & 0xFF00) >> 8)); |
3373 | } |
3374 | if (thermal_event & 0x10) { |
3375 | pm8001_dbg(pm8001_ha, IO, |
3376 | "Thermal Event: Remote high temperature violated!\n" ); |
3377 | pm8001_dbg(pm8001_ha, IO, |
3378 | "Thermal Event: Measured remote high temperature %d\n" , |
3379 | ((rht_lht & 0xFF000000) >> 24)); |
3380 | } |
3381 | return 0; |
3382 | } |
3383 | |
3384 | /** |
3385 | * mpi_hw_event - The hw event has come. |
3386 | * @pm8001_ha: our hba card information |
3387 | * @piomb: IO message buffer |
3388 | */ |
3389 | static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3390 | { |
3391 | unsigned long flags, i; |
3392 | struct hw_event_resp *pPayload = |
3393 | (struct hw_event_resp *)(piomb + 4); |
3394 | u32 lr_status_evt_portid = |
3395 | le32_to_cpu(pPayload->lr_status_evt_portid); |
3396 | u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); |
3397 | u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); |
3398 | u8 phy_id = |
3399 | (u8)((phyid_npip_portstate & 0xFF0000) >> 16); |
3400 | u8 portstate = (u8)(phyid_npip_portstate & 0x0000000F); |
3401 | u16 eventType = |
3402 | (u16)((lr_status_evt_portid & 0x00FFFF00) >> 8); |
3403 | u8 status = |
3404 | (u8)((lr_status_evt_portid & 0x0F000000) >> 24); |
3405 | struct sas_ha_struct *sas_ha = pm8001_ha->sas; |
3406 | struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; |
3407 | struct pm8001_port *port = &pm8001_ha->port[port_id]; |
3408 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; |
3409 | pm8001_dbg(pm8001_ha, DEV, |
3410 | "portid:%d phyid:%d event:0x%x status:0x%x\n" , |
3411 | port_id, phy_id, eventType, status); |
3412 | |
3413 | switch (eventType) { |
3414 | |
3415 | case HW_EVENT_SAS_PHY_UP: |
3416 | pm8001_dbg(pm8001_ha, EVENT, |
3417 | "HW_EVENT_SAS_PHY_UP phyid:%#x port_id:%#x\n" , |
3418 | phy_id, port_id); |
3419 | hw_event_sas_phy_up(pm8001_ha, piomb); |
3420 | break; |
3421 | case HW_EVENT_SATA_PHY_UP: |
3422 | hw_event_sata_phy_up(pm8001_ha, piomb); |
3423 | break; |
3424 | case HW_EVENT_SATA_SPINUP_HOLD: |
3425 | pm8001_dbg(pm8001_ha, EVENT, |
3426 | "HW_EVENT_SATA_SPINUP_HOLD phyid:%#x port_id:%#x\n" , |
3427 | phy_id, port_id); |
3428 | sas_notify_phy_event(phy: &phy->sas_phy, event: PHYE_SPINUP_HOLD, |
3429 | GFP_ATOMIC); |
3430 | break; |
3431 | case HW_EVENT_PHY_DOWN: |
3432 | hw_event_phy_down(pm8001_ha, piomb); |
3433 | phy->phy_state = PHY_LINK_DISABLE; |
3434 | break; |
3435 | case HW_EVENT_PORT_INVALID: |
3436 | pm8001_dbg(pm8001_ha, EVENT, |
3437 | "HW_EVENT_PORT_INVALID phyid:%#x port_id:%#x\n" , |
3438 | phy_id, port_id); |
3439 | sas_phy_disconnected(phy: sas_phy); |
3440 | phy->phy_attached = 0; |
3441 | sas_notify_port_event(phy: sas_phy, event: PORTE_LINK_RESET_ERR, |
3442 | GFP_ATOMIC); |
3443 | break; |
3444 | /* the broadcast change primitive received, tell the LIBSAS this event |
3445 | to revalidate the sas domain*/ |
3446 | case HW_EVENT_BROADCAST_CHANGE: |
3447 | pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_CHANGE\n" ); |
3448 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, HW_EVENT_BROADCAST_CHANGE, |
3449 | port_id, phyId: phy_id, param0: 1, param1: 0); |
3450 | spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); |
3451 | sas_phy->sas_prim = HW_EVENT_BROADCAST_CHANGE; |
3452 | spin_unlock_irqrestore(lock: &sas_phy->sas_prim_lock, flags); |
3453 | sas_notify_port_event(phy: sas_phy, event: PORTE_BROADCAST_RCVD, |
3454 | GFP_ATOMIC); |
3455 | break; |
3456 | case HW_EVENT_PHY_ERROR: |
3457 | pm8001_dbg(pm8001_ha, EVENT, |
3458 | "HW_EVENT_PHY_ERROR phyid:%#x port_id:%#x\n" , |
3459 | phy_id, port_id); |
3460 | sas_phy_disconnected(phy: &phy->sas_phy); |
3461 | phy->phy_attached = 0; |
3462 | sas_notify_phy_event(phy: &phy->sas_phy, event: PHYE_OOB_ERROR, GFP_ATOMIC); |
3463 | break; |
3464 | case HW_EVENT_BROADCAST_EXP: |
3465 | pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_EXP\n" ); |
3466 | spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); |
3467 | sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP; |
3468 | spin_unlock_irqrestore(lock: &sas_phy->sas_prim_lock, flags); |
3469 | sas_notify_port_event(phy: sas_phy, event: PORTE_BROADCAST_RCVD, |
3470 | GFP_ATOMIC); |
3471 | break; |
3472 | case HW_EVENT_LINK_ERR_INVALID_DWORD: |
3473 | pm8001_dbg(pm8001_ha, EVENT, |
3474 | "HW_EVENT_LINK_ERR_INVALID_DWORD phyid:%#x port_id:%#x\n" , |
3475 | phy_id, port_id); |
3476 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, |
3477 | HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phyId: phy_id, param0: 0, param1: 0); |
3478 | break; |
3479 | case HW_EVENT_LINK_ERR_DISPARITY_ERROR: |
3480 | pm8001_dbg(pm8001_ha, EVENT, |
3481 | "HW_EVENT_LINK_ERR_DISPARITY_ERROR phyid:%#x port_id:%#x\n" , |
3482 | phy_id, port_id); |
3483 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, |
3484 | HW_EVENT_LINK_ERR_DISPARITY_ERROR, |
3485 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3486 | break; |
3487 | case HW_EVENT_LINK_ERR_CODE_VIOLATION: |
3488 | pm8001_dbg(pm8001_ha, EVENT, |
3489 | "HW_EVENT_LINK_ERR_CODE_VIOLATION phyid:%#x port_id:%#x\n" , |
3490 | phy_id, port_id); |
3491 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, |
3492 | HW_EVENT_LINK_ERR_CODE_VIOLATION, |
3493 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3494 | break; |
3495 | case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH: |
3496 | pm8001_dbg(pm8001_ha, EVENT, |
3497 | "HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH phyid:%#x port_id:%#x\n" , |
3498 | phy_id, port_id); |
3499 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, |
3500 | HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH, |
3501 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3502 | break; |
3503 | case HW_EVENT_MALFUNCTION: |
3504 | pm8001_dbg(pm8001_ha, EVENT, |
3505 | "HW_EVENT_MALFUNCTION phyid:%#x\n" , phy_id); |
3506 | break; |
3507 | case HW_EVENT_BROADCAST_SES: |
3508 | pm8001_dbg(pm8001_ha, MSG, "HW_EVENT_BROADCAST_SES\n" ); |
3509 | spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); |
3510 | sas_phy->sas_prim = HW_EVENT_BROADCAST_SES; |
3511 | spin_unlock_irqrestore(lock: &sas_phy->sas_prim_lock, flags); |
3512 | sas_notify_port_event(phy: sas_phy, event: PORTE_BROADCAST_RCVD, |
3513 | GFP_ATOMIC); |
3514 | break; |
3515 | case HW_EVENT_INBOUND_CRC_ERROR: |
3516 | pm8001_dbg(pm8001_ha, EVENT, |
3517 | "HW_EVENT_INBOUND_CRC_ERROR phyid:%#x port_id:%#x\n" , |
3518 | phy_id, port_id); |
3519 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, |
3520 | HW_EVENT_INBOUND_CRC_ERROR, |
3521 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3522 | break; |
3523 | case HW_EVENT_HARD_RESET_RECEIVED: |
3524 | pm8001_dbg(pm8001_ha, EVENT, |
3525 | "HW_EVENT_HARD_RESET_RECEIVED phyid:%#x\n" , phy_id); |
3526 | sas_notify_port_event(phy: sas_phy, event: PORTE_HARD_RESET, GFP_ATOMIC); |
3527 | break; |
3528 | case HW_EVENT_ID_FRAME_TIMEOUT: |
3529 | pm8001_dbg(pm8001_ha, EVENT, |
3530 | "HW_EVENT_ID_FRAME_TIMEOUT phyid:%#x\n" , phy_id); |
3531 | sas_phy_disconnected(phy: sas_phy); |
3532 | phy->phy_attached = 0; |
3533 | sas_notify_port_event(phy: sas_phy, event: PORTE_LINK_RESET_ERR, |
3534 | GFP_ATOMIC); |
3535 | break; |
3536 | case HW_EVENT_LINK_ERR_PHY_RESET_FAILED: |
3537 | pm8001_dbg(pm8001_ha, EVENT, |
3538 | "HW_EVENT_LINK_ERR_PHY_RESET_FAILED phyid:%#x port_id:%#x\n" , |
3539 | phy_id, port_id); |
3540 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, |
3541 | HW_EVENT_LINK_ERR_PHY_RESET_FAILED, |
3542 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3543 | sas_phy_disconnected(phy: sas_phy); |
3544 | phy->phy_attached = 0; |
3545 | sas_notify_port_event(phy: sas_phy, event: PORTE_LINK_RESET_ERR, |
3546 | GFP_ATOMIC); |
3547 | break; |
3548 | case HW_EVENT_PORT_RESET_TIMER_TMO: |
3549 | pm8001_dbg(pm8001_ha, EVENT, |
3550 | "HW_EVENT_PORT_RESET_TIMER_TMO phyid:%#x port_id:%#x portstate:%#x\n" , |
3551 | phy_id, port_id, portstate); |
3552 | if (!pm8001_ha->phy[phy_id].reset_completion) { |
3553 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, HW_EVENT_PHY_DOWN, |
3554 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3555 | } |
3556 | sas_phy_disconnected(phy: sas_phy); |
3557 | phy->phy_attached = 0; |
3558 | port->port_state = portstate; |
3559 | sas_notify_port_event(phy: sas_phy, event: PORTE_LINK_RESET_ERR, |
3560 | GFP_ATOMIC); |
3561 | if (pm8001_ha->phy[phy_id].reset_completion) { |
3562 | pm8001_ha->phy[phy_id].port_reset_status = |
3563 | PORT_RESET_TMO; |
3564 | complete(pm8001_ha->phy[phy_id].reset_completion); |
3565 | pm8001_ha->phy[phy_id].reset_completion = NULL; |
3566 | } |
3567 | break; |
3568 | case HW_EVENT_PORT_RECOVERY_TIMER_TMO: |
3569 | pm8001_dbg(pm8001_ha, EVENT, |
3570 | "HW_EVENT_PORT_RECOVERY_TIMER_TMO phyid:%#x port_id:%#x\n" , |
3571 | phy_id, port_id); |
3572 | pm80xx_hw_event_ack_req(pm8001_ha, Qnum: 0, |
3573 | HW_EVENT_PORT_RECOVERY_TIMER_TMO, |
3574 | port_id, phyId: phy_id, param0: 0, param1: 0); |
3575 | for (i = 0; i < pm8001_ha->chip->n_phy; i++) { |
3576 | if (port->wide_port_phymap & (1 << i)) { |
3577 | phy = &pm8001_ha->phy[i]; |
3578 | sas_notify_phy_event(phy: &phy->sas_phy, |
3579 | event: PHYE_LOSS_OF_SIGNAL, GFP_ATOMIC); |
3580 | port->wide_port_phymap &= ~(1 << i); |
3581 | } |
3582 | } |
3583 | break; |
3584 | case HW_EVENT_PORT_RECOVER: |
3585 | pm8001_dbg(pm8001_ha, EVENT, |
3586 | "HW_EVENT_PORT_RECOVER phyid:%#x port_id:%#x\n" , |
3587 | phy_id, port_id); |
3588 | hw_event_port_recover(pm8001_ha, piomb); |
3589 | break; |
3590 | case HW_EVENT_PORT_RESET_COMPLETE: |
3591 | pm8001_dbg(pm8001_ha, EVENT, |
3592 | "HW_EVENT_PORT_RESET_COMPLETE phyid:%#x port_id:%#x portstate:%#x\n" , |
3593 | phy_id, port_id, portstate); |
3594 | if (pm8001_ha->phy[phy_id].reset_completion) { |
3595 | pm8001_ha->phy[phy_id].port_reset_status = |
3596 | PORT_RESET_SUCCESS; |
3597 | complete(pm8001_ha->phy[phy_id].reset_completion); |
3598 | pm8001_ha->phy[phy_id].reset_completion = NULL; |
3599 | } |
3600 | phy->phy_attached = 1; |
3601 | phy->phy_state = PHY_STATE_LINK_UP_SPCV; |
3602 | port->port_state = portstate; |
3603 | break; |
3604 | case EVENT_BROADCAST_ASYNCH_EVENT: |
3605 | pm8001_dbg(pm8001_ha, MSG, "EVENT_BROADCAST_ASYNCH_EVENT\n" ); |
3606 | break; |
3607 | default: |
3608 | pm8001_dbg(pm8001_ha, DEVIO, |
3609 | "Unknown event portid:%d phyid:%d event:0x%x status:0x%x\n" , |
3610 | port_id, phy_id, eventType, status); |
3611 | break; |
3612 | } |
3613 | return 0; |
3614 | } |
3615 | |
3616 | /** |
3617 | * mpi_phy_stop_resp - SPCv specific |
3618 | * @pm8001_ha: our hba card information |
3619 | * @piomb: IO message buffer |
3620 | */ |
3621 | static int mpi_phy_stop_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3622 | { |
3623 | struct phy_stop_resp *pPayload = |
3624 | (struct phy_stop_resp *)(piomb + 4); |
3625 | u32 status = |
3626 | le32_to_cpu(pPayload->status); |
3627 | u32 phyid = |
3628 | le32_to_cpu(pPayload->phyid) & 0xFF; |
3629 | struct pm8001_phy *phy = &pm8001_ha->phy[phyid]; |
3630 | pm8001_dbg(pm8001_ha, MSG, "phy:0x%x status:0x%x\n" , |
3631 | phyid, status); |
3632 | if (status == PHY_STOP_SUCCESS || |
3633 | status == PHY_STOP_ERR_DEVICE_ATTACHED) { |
3634 | phy->phy_state = PHY_LINK_DISABLE; |
3635 | phy->sas_phy.phy->negotiated_linkrate = SAS_PHY_DISABLED; |
3636 | phy->sas_phy.linkrate = SAS_PHY_DISABLED; |
3637 | } |
3638 | |
3639 | return 0; |
3640 | } |
3641 | |
3642 | /** |
3643 | * mpi_set_controller_config_resp - SPCv specific |
3644 | * @pm8001_ha: our hba card information |
3645 | * @piomb: IO message buffer |
3646 | */ |
3647 | static int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha, |
3648 | void *piomb) |
3649 | { |
3650 | struct set_ctrl_cfg_resp *pPayload = |
3651 | (struct set_ctrl_cfg_resp *)(piomb + 4); |
3652 | u32 status = le32_to_cpu(pPayload->status); |
3653 | u32 err_qlfr_pgcd = le32_to_cpu(pPayload->err_qlfr_pgcd); |
3654 | u32 tag = le32_to_cpu(pPayload->tag); |
3655 | |
3656 | pm8001_dbg(pm8001_ha, MSG, |
3657 | "SET CONTROLLER RESP: status 0x%x qlfr_pgcd 0x%x\n" , |
3658 | status, err_qlfr_pgcd); |
3659 | pm8001_tag_free(pm8001_ha, tag); |
3660 | |
3661 | return 0; |
3662 | } |
3663 | |
3664 | /** |
3665 | * mpi_get_controller_config_resp - SPCv specific |
3666 | * @pm8001_ha: our hba card information |
3667 | * @piomb: IO message buffer |
3668 | */ |
3669 | static int mpi_get_controller_config_resp(struct pm8001_hba_info *pm8001_ha, |
3670 | void *piomb) |
3671 | { |
3672 | pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n" ); |
3673 | |
3674 | return 0; |
3675 | } |
3676 | |
3677 | /** |
3678 | * mpi_get_phy_profile_resp - SPCv specific |
3679 | * @pm8001_ha: our hba card information |
3680 | * @piomb: IO message buffer |
3681 | */ |
3682 | static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, |
3683 | void *piomb) |
3684 | { |
3685 | pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n" ); |
3686 | |
3687 | return 0; |
3688 | } |
3689 | |
3690 | /** |
3691 | * mpi_flash_op_ext_resp - SPCv specific |
3692 | * @pm8001_ha: our hba card information |
3693 | * @piomb: IO message buffer |
3694 | */ |
3695 | static int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) |
3696 | { |
3697 | pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n" ); |
3698 | |
3699 | return 0; |
3700 | } |
3701 | |
3702 | /** |
3703 | * mpi_set_phy_profile_resp - SPCv specific |
3704 | * @pm8001_ha: our hba card information |
3705 | * @piomb: IO message buffer |
3706 | */ |
3707 | static int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha, |
3708 | void *piomb) |
3709 | { |
3710 | u32 tag; |
3711 | u8 page_code; |
3712 | int rc = 0; |
3713 | struct set_phy_profile_resp *pPayload = |
3714 | (struct set_phy_profile_resp *)(piomb + 4); |
3715 | u32 ppc_phyid = le32_to_cpu(pPayload->ppc_phyid); |
3716 | u32 status = le32_to_cpu(pPayload->status); |
3717 | |
3718 | tag = le32_to_cpu(pPayload->tag); |
3719 | page_code = (u8)((ppc_phyid & 0xFF00) >> 8); |
3720 | if (status) { |
3721 | /* status is FAILED */ |
3722 | pm8001_dbg(pm8001_ha, FAIL, |
3723 | "PhyProfile command failed with status 0x%08X\n" , |
3724 | status); |
3725 | rc = -1; |
3726 | } else { |
3727 | if (page_code != SAS_PHY_ANALOG_SETTINGS_PAGE) { |
3728 | pm8001_dbg(pm8001_ha, FAIL, "Invalid page code 0x%X\n" , |
3729 | page_code); |
3730 | rc = -1; |
3731 | } |
3732 | } |
3733 | pm8001_tag_free(pm8001_ha, tag); |
3734 | return rc; |
3735 | } |
3736 | |
3737 | /** |
3738 | * mpi_kek_management_resp - SPCv specific |
3739 | * @pm8001_ha: our hba card information |
3740 | * @piomb: IO message buffer |
3741 | */ |
3742 | static int mpi_kek_management_resp(struct pm8001_hba_info *pm8001_ha, |
3743 | void *piomb) |
3744 | { |
3745 | struct kek_mgmt_resp *pPayload = (struct kek_mgmt_resp *)(piomb + 4); |
3746 | |
3747 | u32 status = le32_to_cpu(pPayload->status); |
3748 | u32 kidx_new_curr_ksop = le32_to_cpu(pPayload->kidx_new_curr_ksop); |
3749 | u32 err_qlfr = le32_to_cpu(pPayload->err_qlfr); |
3750 | |
3751 | pm8001_dbg(pm8001_ha, MSG, |
3752 | "KEK MGMT RESP. Status 0x%x idx_ksop 0x%x err_qlfr 0x%x\n" , |
3753 | status, kidx_new_curr_ksop, err_qlfr); |
3754 | |
3755 | return 0; |
3756 | } |
3757 | |
3758 | /** |
3759 | * mpi_dek_management_resp - SPCv specific |
3760 | * @pm8001_ha: our hba card information |
3761 | * @piomb: IO message buffer |
3762 | */ |
3763 | static int mpi_dek_management_resp(struct pm8001_hba_info *pm8001_ha, |
3764 | void *piomb) |
3765 | { |
3766 | pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n" ); |
3767 | |
3768 | return 0; |
3769 | } |
3770 | |
3771 | /** |
3772 | * ssp_coalesced_comp_resp - SPCv specific |
3773 | * @pm8001_ha: our hba card information |
3774 | * @piomb: IO message buffer |
3775 | */ |
3776 | static int ssp_coalesced_comp_resp(struct pm8001_hba_info *pm8001_ha, |
3777 | void *piomb) |
3778 | { |
3779 | pm8001_dbg(pm8001_ha, MSG, " pm80xx_addition_functionality\n" ); |
3780 | |
3781 | return 0; |
3782 | } |
3783 | |
3784 | /** |
3785 | * process_one_iomb - process one outbound Queue memory block |
3786 | * @pm8001_ha: our hba card information |
3787 | * @circularQ: outbound circular queue |
3788 | * @piomb: IO message buffer |
3789 | */ |
3790 | static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, |
3791 | struct outbound_queue_table *circularQ, void *piomb) |
3792 | { |
3793 | __le32 = *(__le32 *)piomb; |
3794 | u32 opc = (u32)((le32_to_cpu(pHeader)) & 0xFFF); |
3795 | |
3796 | switch (opc) { |
3797 | case OPC_OUB_ECHO: |
3798 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_ECHO\n" ); |
3799 | break; |
3800 | case OPC_OUB_HW_EVENT: |
3801 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_HW_EVENT\n" ); |
3802 | mpi_hw_event(pm8001_ha, piomb); |
3803 | break; |
3804 | case OPC_OUB_THERM_HW_EVENT: |
3805 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_THERMAL_EVENT\n" ); |
3806 | mpi_thermal_hw_event(pm8001_ha, piomb); |
3807 | break; |
3808 | case OPC_OUB_SSP_COMP: |
3809 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_COMP\n" ); |
3810 | mpi_ssp_completion(pm8001_ha, piomb); |
3811 | break; |
3812 | case OPC_OUB_SMP_COMP: |
3813 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_COMP\n" ); |
3814 | mpi_smp_completion(pm8001_ha, piomb); |
3815 | break; |
3816 | case OPC_OUB_LOCAL_PHY_CNTRL: |
3817 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_LOCAL_PHY_CNTRL\n" ); |
3818 | pm8001_mpi_local_phy_ctl(pm8001_ha, piomb); |
3819 | break; |
3820 | case OPC_OUB_DEV_REGIST: |
3821 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_REGIST\n" ); |
3822 | pm8001_mpi_reg_resp(pm8001_ha, piomb); |
3823 | break; |
3824 | case OPC_OUB_DEREG_DEV: |
3825 | pm8001_dbg(pm8001_ha, MSG, "unregister the device\n" ); |
3826 | pm8001_mpi_dereg_resp(pm8001_ha, piomb); |
3827 | break; |
3828 | case OPC_OUB_GET_DEV_HANDLE: |
3829 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEV_HANDLE\n" ); |
3830 | break; |
3831 | case OPC_OUB_SATA_COMP: |
3832 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_COMP\n" ); |
3833 | mpi_sata_completion(pm8001_ha, circularQ, piomb); |
3834 | break; |
3835 | case OPC_OUB_SATA_EVENT: |
3836 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_EVENT\n" ); |
3837 | mpi_sata_event(pm8001_ha, circularQ, piomb); |
3838 | break; |
3839 | case OPC_OUB_SSP_EVENT: |
3840 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_EVENT\n" ); |
3841 | mpi_ssp_event(pm8001_ha, piomb); |
3842 | break; |
3843 | case OPC_OUB_DEV_HANDLE_ARRIV: |
3844 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEV_HANDLE_ARRIV\n" ); |
3845 | /*This is for target*/ |
3846 | break; |
3847 | case OPC_OUB_SSP_RECV_EVENT: |
3848 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_RECV_EVENT\n" ); |
3849 | /*This is for target*/ |
3850 | break; |
3851 | case OPC_OUB_FW_FLASH_UPDATE: |
3852 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_FW_FLASH_UPDATE\n" ); |
3853 | pm8001_mpi_fw_flash_update_resp(pm8001_ha, piomb); |
3854 | break; |
3855 | case OPC_OUB_GPIO_RESPONSE: |
3856 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_RESPONSE\n" ); |
3857 | break; |
3858 | case OPC_OUB_GPIO_EVENT: |
3859 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GPIO_EVENT\n" ); |
3860 | break; |
3861 | case OPC_OUB_GENERAL_EVENT: |
3862 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GENERAL_EVENT\n" ); |
3863 | pm8001_mpi_general_event(pm8001_ha, piomb); |
3864 | break; |
3865 | case OPC_OUB_SSP_ABORT_RSP: |
3866 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SSP_ABORT_RSP\n" ); |
3867 | pm8001_mpi_task_abort_resp(pm8001_ha, piomb); |
3868 | break; |
3869 | case OPC_OUB_SATA_ABORT_RSP: |
3870 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SATA_ABORT_RSP\n" ); |
3871 | pm8001_mpi_task_abort_resp(pm8001_ha, piomb); |
3872 | break; |
3873 | case OPC_OUB_SAS_DIAG_MODE_START_END: |
3874 | pm8001_dbg(pm8001_ha, MSG, |
3875 | "OPC_OUB_SAS_DIAG_MODE_START_END\n" ); |
3876 | break; |
3877 | case OPC_OUB_SAS_DIAG_EXECUTE: |
3878 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_DIAG_EXECUTE\n" ); |
3879 | break; |
3880 | case OPC_OUB_GET_TIME_STAMP: |
3881 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_TIME_STAMP\n" ); |
3882 | break; |
3883 | case OPC_OUB_SAS_HW_EVENT_ACK: |
3884 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SAS_HW_EVENT_ACK\n" ); |
3885 | break; |
3886 | case OPC_OUB_PORT_CONTROL: |
3887 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_PORT_CONTROL\n" ); |
3888 | break; |
3889 | case OPC_OUB_SMP_ABORT_RSP: |
3890 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SMP_ABORT_RSP\n" ); |
3891 | pm8001_mpi_task_abort_resp(pm8001_ha, piomb); |
3892 | break; |
3893 | case OPC_OUB_GET_NVMD_DATA: |
3894 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_NVMD_DATA\n" ); |
3895 | pm8001_mpi_get_nvmd_resp(pm8001_ha, piomb); |
3896 | break; |
3897 | case OPC_OUB_SET_NVMD_DATA: |
3898 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_NVMD_DATA\n" ); |
3899 | pm8001_mpi_set_nvmd_resp(pm8001_ha, piomb); |
3900 | break; |
3901 | case OPC_OUB_DEVICE_HANDLE_REMOVAL: |
3902 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_DEVICE_HANDLE_REMOVAL\n" ); |
3903 | break; |
3904 | case OPC_OUB_SET_DEVICE_STATE: |
3905 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEVICE_STATE\n" ); |
3906 | pm8001_mpi_set_dev_state_resp(pm8001_ha, piomb); |
3907 | break; |
3908 | case OPC_OUB_GET_DEVICE_STATE: |
3909 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_GET_DEVICE_STATE\n" ); |
3910 | break; |
3911 | case OPC_OUB_SET_DEV_INFO: |
3912 | pm8001_dbg(pm8001_ha, MSG, "OPC_OUB_SET_DEV_INFO\n" ); |
3913 | break; |
3914 | /* spcv specific commands */ |
3915 | case OPC_OUB_PHY_START_RESP: |
3916 | pm8001_dbg(pm8001_ha, MSG, |
3917 | "OPC_OUB_PHY_START_RESP opcode:%x\n" , opc); |
3918 | mpi_phy_start_resp(pm8001_ha, piomb); |
3919 | break; |
3920 | case OPC_OUB_PHY_STOP_RESP: |
3921 | pm8001_dbg(pm8001_ha, MSG, |
3922 | "OPC_OUB_PHY_STOP_RESP opcode:%x\n" , opc); |
3923 | mpi_phy_stop_resp(pm8001_ha, piomb); |
3924 | break; |
3925 | case OPC_OUB_SET_CONTROLLER_CONFIG: |
3926 | pm8001_dbg(pm8001_ha, MSG, |
3927 | "OPC_OUB_SET_CONTROLLER_CONFIG opcode:%x\n" , opc); |
3928 | mpi_set_controller_config_resp(pm8001_ha, piomb); |
3929 | break; |
3930 | case OPC_OUB_GET_CONTROLLER_CONFIG: |
3931 | pm8001_dbg(pm8001_ha, MSG, |
3932 | "OPC_OUB_GET_CONTROLLER_CONFIG opcode:%x\n" , opc); |
3933 | mpi_get_controller_config_resp(pm8001_ha, piomb); |
3934 | break; |
3935 | case OPC_OUB_GET_PHY_PROFILE: |
3936 | pm8001_dbg(pm8001_ha, MSG, |
3937 | "OPC_OUB_GET_PHY_PROFILE opcode:%x\n" , opc); |
3938 | mpi_get_phy_profile_resp(pm8001_ha, piomb); |
3939 | break; |
3940 | case OPC_OUB_FLASH_OP_EXT: |
3941 | pm8001_dbg(pm8001_ha, MSG, |
3942 | "OPC_OUB_FLASH_OP_EXT opcode:%x\n" , opc); |
3943 | mpi_flash_op_ext_resp(pm8001_ha, piomb); |
3944 | break; |
3945 | case OPC_OUB_SET_PHY_PROFILE: |
3946 | pm8001_dbg(pm8001_ha, MSG, |
3947 | "OPC_OUB_SET_PHY_PROFILE opcode:%x\n" , opc); |
3948 | mpi_set_phy_profile_resp(pm8001_ha, piomb); |
3949 | break; |
3950 | case OPC_OUB_KEK_MANAGEMENT_RESP: |
3951 | pm8001_dbg(pm8001_ha, MSG, |
3952 | "OPC_OUB_KEK_MANAGEMENT_RESP opcode:%x\n" , opc); |
3953 | mpi_kek_management_resp(pm8001_ha, piomb); |
3954 | break; |
3955 | case OPC_OUB_DEK_MANAGEMENT_RESP: |
3956 | pm8001_dbg(pm8001_ha, MSG, |
3957 | "OPC_OUB_DEK_MANAGEMENT_RESP opcode:%x\n" , opc); |
3958 | mpi_dek_management_resp(pm8001_ha, piomb); |
3959 | break; |
3960 | case OPC_OUB_SSP_COALESCED_COMP_RESP: |
3961 | pm8001_dbg(pm8001_ha, MSG, |
3962 | "OPC_OUB_SSP_COALESCED_COMP_RESP opcode:%x\n" , opc); |
3963 | ssp_coalesced_comp_resp(pm8001_ha, piomb); |
3964 | break; |
3965 | default: |
3966 | pm8001_dbg(pm8001_ha, DEVIO, |
3967 | "Unknown outbound Queue IOMB OPC = 0x%x\n" , opc); |
3968 | break; |
3969 | } |
3970 | } |
3971 | |
3972 | static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha) |
3973 | { |
3974 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_0: 0x%x\n" , |
3975 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0)); |
3976 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_1:0x%x\n" , |
3977 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1)); |
3978 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_2: 0x%x\n" , |
3979 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2)); |
3980 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_SCRATCH_PAD_3: 0x%x\n" , |
3981 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3)); |
3982 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_0: 0x%x\n" , |
3983 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0)); |
3984 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_1: 0x%x\n" , |
3985 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1)); |
3986 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_2: 0x%x\n" , |
3987 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2)); |
3988 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_3: 0x%x\n" , |
3989 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3)); |
3990 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_4: 0x%x\n" , |
3991 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4)); |
3992 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_HOST_SCRATCH_PAD_5: 0x%x\n" , |
3993 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5)); |
3994 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n" , |
3995 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_RSVD_0)); |
3996 | pm8001_dbg(pm8001_ha, FAIL, "MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n" , |
3997 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_RSVD_1)); |
3998 | } |
3999 | |
4000 | static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) |
4001 | { |
4002 | struct outbound_queue_table *circularQ; |
4003 | void *pMsg1 = NULL; |
4004 | u8 bc; |
4005 | u32 ret = MPI_IO_STATUS_FAIL; |
4006 | u32 regval; |
4007 | |
4008 | /* |
4009 | * Fatal errors are programmed to be signalled in irq vector |
4010 | * pm8001_ha->max_q_num - 1 through pm8001_ha->main_cfg_tbl.pm80xx_tbl. |
4011 | * fatal_err_interrupt |
4012 | */ |
4013 | if (vec == (pm8001_ha->max_q_num - 1)) { |
4014 | u32 mipsall_ready; |
4015 | |
4016 | if (pm8001_ha->chip_id == chip_8008 || |
4017 | pm8001_ha->chip_id == chip_8009) |
4018 | mipsall_ready = SCRATCH_PAD_MIPSALL_READY_8PORT; |
4019 | else |
4020 | mipsall_ready = SCRATCH_PAD_MIPSALL_READY_16PORT; |
4021 | |
4022 | regval = pm8001_cr32(pm8001_ha, bar: 0, MSGU_SCRATCH_PAD_1); |
4023 | if ((regval & mipsall_ready) != mipsall_ready) { |
4024 | pm8001_ha->controller_fatal_error = true; |
4025 | pm8001_dbg(pm8001_ha, FAIL, |
4026 | "Firmware Fatal error! Regval:0x%x\n" , |
4027 | regval); |
4028 | pm8001_handle_event(pm8001_ha, NULL, IO_FATAL_ERROR); |
4029 | print_scratchpad_registers(pm8001_ha); |
4030 | return ret; |
4031 | } else { |
4032 | /*read scratchpad rsvd 0 register*/ |
4033 | regval = pm8001_cr32(pm8001_ha, bar: 0, |
4034 | MSGU_SCRATCH_PAD_RSVD_0); |
4035 | switch (regval) { |
4036 | case NON_FATAL_SPBC_LBUS_ECC_ERR: |
4037 | case NON_FATAL_BDMA_ERR: |
4038 | case NON_FATAL_THERM_OVERTEMP_ERR: |
4039 | /*Clear the register*/ |
4040 | pm8001_cw32(pm8001_ha, bar: 0, |
4041 | MSGU_SCRATCH_PAD_RSVD_0, |
4042 | val: 0x00000000); |
4043 | break; |
4044 | default: |
4045 | break; |
4046 | } |
4047 | } |
4048 | } |
4049 | circularQ = &pm8001_ha->outbnd_q_tbl[vec]; |
4050 | spin_lock_irqsave(&circularQ->oq_lock, circularQ->lock_flags); |
4051 | do { |
4052 | /* spurious interrupt during setup if kexec-ing and |
4053 | * driver doing a doorbell access w/ the pre-kexec oq |
4054 | * interrupt setup. |
4055 | */ |
4056 | if (!circularQ->pi_virt) |
4057 | break; |
4058 | ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, messagePtr1: &pMsg1, pBC: &bc); |
4059 | if (MPI_IO_STATUS_SUCCESS == ret) { |
4060 | /* process the outbound message */ |
4061 | process_one_iomb(pm8001_ha, circularQ, |
4062 | piomb: (void *)(pMsg1 - 4)); |
4063 | /* free the message from the outbound circular buffer */ |
4064 | pm8001_mpi_msg_free_set(pm8001_ha, pMsg: pMsg1, |
4065 | circularQ, bc); |
4066 | } |
4067 | if (MPI_IO_STATUS_BUSY == ret) { |
4068 | /* Update the producer index from SPC */ |
4069 | circularQ->producer_index = |
4070 | cpu_to_le32(pm8001_read_32(circularQ->pi_virt)); |
4071 | if (le32_to_cpu(circularQ->producer_index) == |
4072 | circularQ->consumer_idx) |
4073 | /* OQ is empty */ |
4074 | break; |
4075 | } |
4076 | } while (1); |
4077 | spin_unlock_irqrestore(lock: &circularQ->oq_lock, flags: circularQ->lock_flags); |
4078 | return ret; |
4079 | } |
4080 | |
4081 | /* DMA_... to our direction translation. */ |
4082 | static const u8 data_dir_flags[] = { |
4083 | [DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ |
4084 | [DMA_TO_DEVICE] = DATA_DIR_OUT, /* OUTBOUND */ |
4085 | [DMA_FROM_DEVICE] = DATA_DIR_IN, /* INBOUND */ |
4086 | [DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ |
4087 | }; |
4088 | |
4089 | static void build_smp_cmd(u32 deviceID, __le32 hTag, |
4090 | struct smp_req *psmp_cmd, int mode, int length) |
4091 | { |
4092 | psmp_cmd->tag = hTag; |
4093 | psmp_cmd->device_id = cpu_to_le32(deviceID); |
4094 | if (mode == SMP_DIRECT) { |
4095 | length = length - 4; /* subtract crc */ |
4096 | psmp_cmd->len_ip_ir = cpu_to_le32(length << 16); |
4097 | } else { |
4098 | psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1)); |
4099 | } |
4100 | } |
4101 | |
4102 | /** |
4103 | * pm80xx_chip_smp_req - send an SMP task to FW |
4104 | * @pm8001_ha: our hba card information. |
4105 | * @ccb: the ccb information this request used. |
4106 | */ |
4107 | static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, |
4108 | struct pm8001_ccb_info *ccb) |
4109 | { |
4110 | int elem, rc; |
4111 | struct sas_task *task = ccb->task; |
4112 | struct domain_device *dev = task->dev; |
4113 | struct pm8001_device *pm8001_dev = dev->lldd_dev; |
4114 | struct scatterlist *sg_req, *sg_resp, *smp_req; |
4115 | u32 req_len, resp_len; |
4116 | struct smp_req smp_cmd; |
4117 | u32 opc; |
4118 | u32 i, length; |
4119 | u8 *payload; |
4120 | u8 *to; |
4121 | |
4122 | memset(&smp_cmd, 0, sizeof(smp_cmd)); |
4123 | /* |
4124 | * DMA-map SMP request, response buffers |
4125 | */ |
4126 | sg_req = &task->smp_task.smp_req; |
4127 | elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, DMA_TO_DEVICE); |
4128 | if (!elem) |
4129 | return -ENOMEM; |
4130 | req_len = sg_dma_len(sg_req); |
4131 | |
4132 | sg_resp = &task->smp_task.smp_resp; |
4133 | elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, DMA_FROM_DEVICE); |
4134 | if (!elem) { |
4135 | rc = -ENOMEM; |
4136 | goto err_out; |
4137 | } |
4138 | resp_len = sg_dma_len(sg_resp); |
4139 | /* must be in dwords */ |
4140 | if ((req_len & 0x3) || (resp_len & 0x3)) { |
4141 | rc = -EINVAL; |
4142 | goto err_out_2; |
4143 | } |
4144 | |
4145 | opc = OPC_INB_SMP_REQUEST; |
4146 | smp_cmd.tag = cpu_to_le32(ccb->ccb_tag); |
4147 | |
4148 | length = sg_req->length; |
4149 | pm8001_dbg(pm8001_ha, IO, "SMP Frame Length %d\n" , sg_req->length); |
4150 | if (!(length - 8)) |
4151 | pm8001_ha->smp_exp_mode = SMP_DIRECT; |
4152 | else |
4153 | pm8001_ha->smp_exp_mode = SMP_INDIRECT; |
4154 | |
4155 | |
4156 | smp_req = &task->smp_task.smp_req; |
4157 | to = kmap_atomic(page: sg_page(sg: smp_req)); |
4158 | payload = to + smp_req->offset; |
4159 | |
4160 | /* INDIRECT MODE command settings. Use DMA */ |
4161 | if (pm8001_ha->smp_exp_mode == SMP_INDIRECT) { |
4162 | pm8001_dbg(pm8001_ha, IO, "SMP REQUEST INDIRECT MODE\n" ); |
4163 | /* for SPCv indirect mode. Place the top 4 bytes of |
4164 | * SMP Request header here. */ |
4165 | for (i = 0; i < 4; i++) |
4166 | smp_cmd.smp_req16[i] = *(payload + i); |
4167 | /* exclude top 4 bytes for SMP req header */ |
4168 | smp_cmd.long_smp_req.long_req_addr = |
4169 | cpu_to_le64((u64)sg_dma_address |
4170 | (&task->smp_task.smp_req) + 4); |
4171 | /* exclude 4 bytes for SMP req header and CRC */ |
4172 | smp_cmd.long_smp_req.long_req_size = |
4173 | cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-8); |
4174 | smp_cmd.long_smp_req.long_resp_addr = |
4175 | cpu_to_le64((u64)sg_dma_address |
4176 | (&task->smp_task.smp_resp)); |
4177 | smp_cmd.long_smp_req.long_resp_size = |
4178 | cpu_to_le32((u32)sg_dma_len |
4179 | (&task->smp_task.smp_resp)-4); |
4180 | } else { /* DIRECT MODE */ |
4181 | smp_cmd.long_smp_req.long_req_addr = |
4182 | cpu_to_le64((u64)sg_dma_address |
4183 | (&task->smp_task.smp_req)); |
4184 | smp_cmd.long_smp_req.long_req_size = |
4185 | cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4); |
4186 | smp_cmd.long_smp_req.long_resp_addr = |
4187 | cpu_to_le64((u64)sg_dma_address |
4188 | (&task->smp_task.smp_resp)); |
4189 | smp_cmd.long_smp_req.long_resp_size = |
4190 | cpu_to_le32 |
4191 | ((u32)sg_dma_len(&task->smp_task.smp_resp)-4); |
4192 | } |
4193 | if (pm8001_ha->smp_exp_mode == SMP_DIRECT) { |
4194 | pm8001_dbg(pm8001_ha, IO, "SMP REQUEST DIRECT MODE\n" ); |
4195 | for (i = 0; i < length; i++) |
4196 | if (i < 16) { |
4197 | smp_cmd.smp_req16[i] = *(payload + i); |
4198 | pm8001_dbg(pm8001_ha, IO, |
4199 | "Byte[%d]:%x (DMA data:%x)\n" , |
4200 | i, smp_cmd.smp_req16[i], |
4201 | *(payload)); |
4202 | } else { |
4203 | smp_cmd.smp_req[i] = *(payload + i); |
4204 | pm8001_dbg(pm8001_ha, IO, |
4205 | "Byte[%d]:%x (DMA data:%x)\n" , |
4206 | i, smp_cmd.smp_req[i], |
4207 | *(payload)); |
4208 | } |
4209 | } |
4210 | kunmap_atomic(to); |
4211 | build_smp_cmd(deviceID: pm8001_dev->device_id, hTag: smp_cmd.tag, |
4212 | psmp_cmd: &smp_cmd, mode: pm8001_ha->smp_exp_mode, length); |
4213 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &smp_cmd, |
4214 | nb: sizeof(smp_cmd), responseQueue: 0); |
4215 | if (rc) |
4216 | goto err_out_2; |
4217 | return 0; |
4218 | |
4219 | err_out_2: |
4220 | dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1, |
4221 | DMA_FROM_DEVICE); |
4222 | err_out: |
4223 | dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1, |
4224 | DMA_TO_DEVICE); |
4225 | return rc; |
4226 | } |
4227 | |
4228 | static int check_enc_sas_cmd(struct sas_task *task) |
4229 | { |
4230 | u8 cmd = task->ssp_task.cmd->cmnd[0]; |
4231 | |
4232 | if (cmd == READ_10 || cmd == WRITE_10 || cmd == WRITE_VERIFY) |
4233 | return 1; |
4234 | else |
4235 | return 0; |
4236 | } |
4237 | |
4238 | static int check_enc_sat_cmd(struct sas_task *task) |
4239 | { |
4240 | int ret = 0; |
4241 | switch (task->ata_task.fis.command) { |
4242 | case ATA_CMD_FPDMA_READ: |
4243 | case ATA_CMD_READ_EXT: |
4244 | case ATA_CMD_READ: |
4245 | case ATA_CMD_FPDMA_WRITE: |
4246 | case ATA_CMD_WRITE_EXT: |
4247 | case ATA_CMD_WRITE: |
4248 | case ATA_CMD_PIO_READ: |
4249 | case ATA_CMD_PIO_READ_EXT: |
4250 | case ATA_CMD_PIO_WRITE: |
4251 | case ATA_CMD_PIO_WRITE_EXT: |
4252 | ret = 1; |
4253 | break; |
4254 | default: |
4255 | ret = 0; |
4256 | break; |
4257 | } |
4258 | return ret; |
4259 | } |
4260 | |
4261 | static u32 pm80xx_chip_get_q_index(struct sas_task *task) |
4262 | { |
4263 | struct request *rq = sas_task_find_rq(task); |
4264 | |
4265 | if (!rq) |
4266 | return 0; |
4267 | |
4268 | return blk_mq_unique_tag_to_hwq(unique_tag: blk_mq_unique_tag(rq)); |
4269 | } |
4270 | |
4271 | /** |
4272 | * pm80xx_chip_ssp_io_req - send an SSP task to FW |
4273 | * @pm8001_ha: our hba card information. |
4274 | * @ccb: the ccb information this request used. |
4275 | */ |
4276 | static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, |
4277 | struct pm8001_ccb_info *ccb) |
4278 | { |
4279 | struct sas_task *task = ccb->task; |
4280 | struct domain_device *dev = task->dev; |
4281 | struct pm8001_device *pm8001_dev = dev->lldd_dev; |
4282 | struct ssp_ini_io_start_req ssp_cmd; |
4283 | u32 tag = ccb->ccb_tag; |
4284 | u64 phys_addr, end_addr; |
4285 | u32 end_addr_high, end_addr_low; |
4286 | u32 q_index; |
4287 | u32 opc = OPC_INB_SSPINIIOSTART; |
4288 | |
4289 | memset(&ssp_cmd, 0, sizeof(ssp_cmd)); |
4290 | memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8); |
4291 | |
4292 | /* data address domain added for spcv; set to 0 by host, |
4293 | * used internally by controller |
4294 | * 0 for SAS 1.1 and SAS 2.0 compatible TLR |
4295 | */ |
4296 | ssp_cmd.dad_dir_m_tlr = |
4297 | cpu_to_le32(data_dir_flags[task->data_dir] << 8 | 0x0); |
4298 | ssp_cmd.data_len = cpu_to_le32(task->total_xfer_len); |
4299 | ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id); |
4300 | ssp_cmd.tag = cpu_to_le32(tag); |
4301 | ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7); |
4302 | memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cmd->cmnd, |
4303 | task->ssp_task.cmd->cmd_len); |
4304 | q_index = pm80xx_chip_get_q_index(task); |
4305 | |
4306 | /* Check if encryption is set */ |
4307 | if (pm8001_ha->chip->encrypt && |
4308 | !(pm8001_ha->encrypt_info.status) && check_enc_sas_cmd(task)) { |
4309 | pm8001_dbg(pm8001_ha, IO, |
4310 | "Encryption enabled.Sending Encrypt SAS command 0x%x\n" , |
4311 | task->ssp_task.cmd->cmnd[0]); |
4312 | opc = OPC_INB_SSP_INI_DIF_ENC_IO; |
4313 | /* enable encryption. 0 for SAS 1.1 and SAS 2.0 compatible TLR*/ |
4314 | ssp_cmd.dad_dir_m_tlr = cpu_to_le32 |
4315 | ((data_dir_flags[task->data_dir] << 8) | 0x20 | 0x0); |
4316 | |
4317 | /* fill in PRD (scatter/gather) table, if any */ |
4318 | if (task->num_scatter > 1) { |
4319 | pm8001_chip_make_sg(scatter: task->scatter, |
4320 | nr: ccb->n_elem, prd: ccb->buf_prd); |
4321 | phys_addr = ccb->ccb_dma_handle; |
4322 | ssp_cmd.enc_addr_low = |
4323 | cpu_to_le32(lower_32_bits(phys_addr)); |
4324 | ssp_cmd.enc_addr_high = |
4325 | cpu_to_le32(upper_32_bits(phys_addr)); |
4326 | ssp_cmd.enc_esgl = cpu_to_le32(1<<31); |
4327 | } else if (task->num_scatter == 1) { |
4328 | u64 dma_addr = sg_dma_address(task->scatter); |
4329 | |
4330 | ssp_cmd.enc_addr_low = |
4331 | cpu_to_le32(lower_32_bits(dma_addr)); |
4332 | ssp_cmd.enc_addr_high = |
4333 | cpu_to_le32(upper_32_bits(dma_addr)); |
4334 | ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); |
4335 | ssp_cmd.enc_esgl = 0; |
4336 | |
4337 | /* Check 4G Boundary */ |
4338 | end_addr = dma_addr + le32_to_cpu(ssp_cmd.enc_len) - 1; |
4339 | end_addr_low = lower_32_bits(end_addr); |
4340 | end_addr_high = upper_32_bits(end_addr); |
4341 | |
4342 | if (end_addr_high != le32_to_cpu(ssp_cmd.enc_addr_high)) { |
4343 | pm8001_dbg(pm8001_ha, FAIL, |
4344 | "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n" , |
4345 | dma_addr, |
4346 | le32_to_cpu(ssp_cmd.enc_len), |
4347 | end_addr_high, end_addr_low); |
4348 | pm8001_chip_make_sg(scatter: task->scatter, nr: 1, |
4349 | prd: ccb->buf_prd); |
4350 | phys_addr = ccb->ccb_dma_handle; |
4351 | ssp_cmd.enc_addr_low = |
4352 | cpu_to_le32(lower_32_bits(phys_addr)); |
4353 | ssp_cmd.enc_addr_high = |
4354 | cpu_to_le32(upper_32_bits(phys_addr)); |
4355 | ssp_cmd.enc_esgl = cpu_to_le32(1U<<31); |
4356 | } |
4357 | } else if (task->num_scatter == 0) { |
4358 | ssp_cmd.enc_addr_low = 0; |
4359 | ssp_cmd.enc_addr_high = 0; |
4360 | ssp_cmd.enc_len = cpu_to_le32(task->total_xfer_len); |
4361 | ssp_cmd.enc_esgl = 0; |
4362 | } |
4363 | |
4364 | /* XTS mode. All other fields are 0 */ |
4365 | ssp_cmd.key_cmode = cpu_to_le32(0x6 << 4); |
4366 | |
4367 | /* set tweak values. Should be the start lba */ |
4368 | ssp_cmd.twk_val0 = cpu_to_le32((task->ssp_task.cmd->cmnd[2] << 24) | |
4369 | (task->ssp_task.cmd->cmnd[3] << 16) | |
4370 | (task->ssp_task.cmd->cmnd[4] << 8) | |
4371 | (task->ssp_task.cmd->cmnd[5])); |
4372 | } else { |
4373 | pm8001_dbg(pm8001_ha, IO, |
4374 | "Sending Normal SAS command 0x%x inb q %x\n" , |
4375 | task->ssp_task.cmd->cmnd[0], q_index); |
4376 | /* fill in PRD (scatter/gather) table, if any */ |
4377 | if (task->num_scatter > 1) { |
4378 | pm8001_chip_make_sg(scatter: task->scatter, nr: ccb->n_elem, |
4379 | prd: ccb->buf_prd); |
4380 | phys_addr = ccb->ccb_dma_handle; |
4381 | ssp_cmd.addr_low = |
4382 | cpu_to_le32(lower_32_bits(phys_addr)); |
4383 | ssp_cmd.addr_high = |
4384 | cpu_to_le32(upper_32_bits(phys_addr)); |
4385 | ssp_cmd.esgl = cpu_to_le32(1<<31); |
4386 | } else if (task->num_scatter == 1) { |
4387 | u64 dma_addr = sg_dma_address(task->scatter); |
4388 | |
4389 | ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr)); |
4390 | ssp_cmd.addr_high = |
4391 | cpu_to_le32(upper_32_bits(dma_addr)); |
4392 | ssp_cmd.len = cpu_to_le32(task->total_xfer_len); |
4393 | ssp_cmd.esgl = 0; |
4394 | |
4395 | /* Check 4G Boundary */ |
4396 | end_addr = dma_addr + le32_to_cpu(ssp_cmd.len) - 1; |
4397 | end_addr_low = lower_32_bits(end_addr); |
4398 | end_addr_high = upper_32_bits(end_addr); |
4399 | if (end_addr_high != le32_to_cpu(ssp_cmd.addr_high)) { |
4400 | pm8001_dbg(pm8001_ha, FAIL, |
4401 | "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n" , |
4402 | dma_addr, |
4403 | le32_to_cpu(ssp_cmd.len), |
4404 | end_addr_high, end_addr_low); |
4405 | pm8001_chip_make_sg(scatter: task->scatter, nr: 1, |
4406 | prd: ccb->buf_prd); |
4407 | phys_addr = ccb->ccb_dma_handle; |
4408 | ssp_cmd.addr_low = |
4409 | cpu_to_le32(lower_32_bits(phys_addr)); |
4410 | ssp_cmd.addr_high = |
4411 | cpu_to_le32(upper_32_bits(phys_addr)); |
4412 | ssp_cmd.esgl = cpu_to_le32(1<<31); |
4413 | } |
4414 | } else if (task->num_scatter == 0) { |
4415 | ssp_cmd.addr_low = 0; |
4416 | ssp_cmd.addr_high = 0; |
4417 | ssp_cmd.len = cpu_to_le32(task->total_xfer_len); |
4418 | ssp_cmd.esgl = 0; |
4419 | } |
4420 | } |
4421 | |
4422 | return pm8001_mpi_build_cmd(pm8001_ha, q_index, opCode: opc, payload: &ssp_cmd, |
4423 | nb: sizeof(ssp_cmd), responseQueue: q_index); |
4424 | } |
4425 | |
4426 | static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, |
4427 | struct pm8001_ccb_info *ccb) |
4428 | { |
4429 | struct sas_task *task = ccb->task; |
4430 | struct domain_device *dev = task->dev; |
4431 | struct pm8001_device *pm8001_ha_dev = dev->lldd_dev; |
4432 | struct ata_queued_cmd *qc = task->uldd_task; |
4433 | u32 tag = ccb->ccb_tag, q_index; |
4434 | struct sata_start_req sata_cmd; |
4435 | u32 hdr_tag, ncg_tag = 0; |
4436 | u64 phys_addr, end_addr; |
4437 | u32 end_addr_high, end_addr_low; |
4438 | u32 ATAP = 0x0; |
4439 | u32 dir, retfis = 0; |
4440 | u32 opc = OPC_INB_SATA_HOST_OPSTART; |
4441 | memset(&sata_cmd, 0, sizeof(sata_cmd)); |
4442 | |
4443 | q_index = pm80xx_chip_get_q_index(task); |
4444 | |
4445 | if (task->data_dir == DMA_NONE && !task->ata_task.use_ncq) { |
4446 | ATAP = 0x04; /* no data*/ |
4447 | pm8001_dbg(pm8001_ha, IO, "no data\n" ); |
4448 | } else if (likely(!task->ata_task.device_control_reg_update)) { |
4449 | if (task->ata_task.use_ncq && |
4450 | dev->sata_dev.class != ATA_DEV_ATAPI) { |
4451 | ATAP = 0x07; /* FPDMA */ |
4452 | pm8001_dbg(pm8001_ha, IO, "FPDMA\n" ); |
4453 | } else if (task->ata_task.dma_xfer) { |
4454 | ATAP = 0x06; /* DMA */ |
4455 | pm8001_dbg(pm8001_ha, IO, "DMA\n" ); |
4456 | } else { |
4457 | ATAP = 0x05; /* PIO*/ |
4458 | pm8001_dbg(pm8001_ha, IO, "PIO\n" ); |
4459 | } |
4460 | } |
4461 | if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, tag: &hdr_tag)) { |
4462 | task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); |
4463 | ncg_tag = hdr_tag; |
4464 | } |
4465 | dir = data_dir_flags[task->data_dir] << 8; |
4466 | sata_cmd.tag = cpu_to_le32(tag); |
4467 | sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); |
4468 | sata_cmd.data_len = cpu_to_le32(task->total_xfer_len); |
4469 | if (task->ata_task.return_fis_on_success) |
4470 | retfis = 1; |
4471 | sata_cmd.sata_fis = task->ata_task.fis; |
4472 | if (likely(!task->ata_task.device_control_reg_update)) |
4473 | sata_cmd.sata_fis.flags |= 0x80;/* C=1: update ATA cmd reg */ |
4474 | sata_cmd.sata_fis.flags &= 0xF0;/* PM_PORT field shall be 0 */ |
4475 | |
4476 | /* Check if encryption is set */ |
4477 | if (pm8001_ha->chip->encrypt && |
4478 | !(pm8001_ha->encrypt_info.status) && check_enc_sat_cmd(task)) { |
4479 | pm8001_dbg(pm8001_ha, IO, |
4480 | "Encryption enabled.Sending Encrypt SATA cmd 0x%x\n" , |
4481 | sata_cmd.sata_fis.command); |
4482 | opc = OPC_INB_SATA_DIF_ENC_IO; |
4483 | /* set encryption bit; dad (bits 0-1) is 0 */ |
4484 | sata_cmd.retfis_ncqtag_atap_dir_m_dad = |
4485 | cpu_to_le32((retfis << 24) | ((ncg_tag & 0xff) << 16) | |
4486 | ((ATAP & 0x3f) << 10) | 0x20 | dir); |
4487 | /* fill in PRD (scatter/gather) table, if any */ |
4488 | if (task->num_scatter > 1) { |
4489 | pm8001_chip_make_sg(scatter: task->scatter, |
4490 | nr: ccb->n_elem, prd: ccb->buf_prd); |
4491 | phys_addr = ccb->ccb_dma_handle; |
4492 | sata_cmd.enc_addr_low = |
4493 | cpu_to_le32(lower_32_bits(phys_addr)); |
4494 | sata_cmd.enc_addr_high = |
4495 | cpu_to_le32(upper_32_bits(phys_addr)); |
4496 | sata_cmd.enc_esgl = cpu_to_le32(1 << 31); |
4497 | } else if (task->num_scatter == 1) { |
4498 | u64 dma_addr = sg_dma_address(task->scatter); |
4499 | |
4500 | sata_cmd.enc_addr_low = |
4501 | cpu_to_le32(lower_32_bits(dma_addr)); |
4502 | sata_cmd.enc_addr_high = |
4503 | cpu_to_le32(upper_32_bits(dma_addr)); |
4504 | sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len); |
4505 | sata_cmd.enc_esgl = 0; |
4506 | |
4507 | /* Check 4G Boundary */ |
4508 | end_addr = dma_addr + le32_to_cpu(sata_cmd.enc_len) - 1; |
4509 | end_addr_low = lower_32_bits(end_addr); |
4510 | end_addr_high = upper_32_bits(end_addr); |
4511 | if (end_addr_high != le32_to_cpu(sata_cmd.enc_addr_high)) { |
4512 | pm8001_dbg(pm8001_ha, FAIL, |
4513 | "The sg list address start_addr=0x%016llx data_len=0x%x end_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n" , |
4514 | dma_addr, |
4515 | le32_to_cpu(sata_cmd.enc_len), |
4516 | end_addr_high, end_addr_low); |
4517 | pm8001_chip_make_sg(scatter: task->scatter, nr: 1, |
4518 | prd: ccb->buf_prd); |
4519 | phys_addr = ccb->ccb_dma_handle; |
4520 | sata_cmd.enc_addr_low = |
4521 | cpu_to_le32(lower_32_bits(phys_addr)); |
4522 | sata_cmd.enc_addr_high = |
4523 | cpu_to_le32(upper_32_bits(phys_addr)); |
4524 | sata_cmd.enc_esgl = |
4525 | cpu_to_le32(1 << 31); |
4526 | } |
4527 | } else if (task->num_scatter == 0) { |
4528 | sata_cmd.enc_addr_low = 0; |
4529 | sata_cmd.enc_addr_high = 0; |
4530 | sata_cmd.enc_len = cpu_to_le32(task->total_xfer_len); |
4531 | sata_cmd.enc_esgl = 0; |
4532 | } |
4533 | /* XTS mode. All other fields are 0 */ |
4534 | sata_cmd.key_index_mode = cpu_to_le32(0x6 << 4); |
4535 | |
4536 | /* set tweak values. Should be the start lba */ |
4537 | sata_cmd.twk_val0 = |
4538 | cpu_to_le32((sata_cmd.sata_fis.lbal_exp << 24) | |
4539 | (sata_cmd.sata_fis.lbah << 16) | |
4540 | (sata_cmd.sata_fis.lbam << 8) | |
4541 | (sata_cmd.sata_fis.lbal)); |
4542 | sata_cmd.twk_val1 = |
4543 | cpu_to_le32((sata_cmd.sata_fis.lbah_exp << 8) | |
4544 | (sata_cmd.sata_fis.lbam_exp)); |
4545 | } else { |
4546 | pm8001_dbg(pm8001_ha, IO, |
4547 | "Sending Normal SATA command 0x%x inb %x\n" , |
4548 | sata_cmd.sata_fis.command, q_index); |
4549 | /* dad (bits 0-1) is 0 */ |
4550 | sata_cmd.retfis_ncqtag_atap_dir_m_dad = |
4551 | cpu_to_le32((retfis << 24) | ((ncg_tag & 0xff) << 16) | |
4552 | ((ATAP & 0x3f) << 10) | dir); |
4553 | /* fill in PRD (scatter/gather) table, if any */ |
4554 | if (task->num_scatter > 1) { |
4555 | pm8001_chip_make_sg(scatter: task->scatter, |
4556 | nr: ccb->n_elem, prd: ccb->buf_prd); |
4557 | phys_addr = ccb->ccb_dma_handle; |
4558 | sata_cmd.addr_low = lower_32_bits(phys_addr); |
4559 | sata_cmd.addr_high = upper_32_bits(phys_addr); |
4560 | sata_cmd.esgl = cpu_to_le32(1U << 31); |
4561 | } else if (task->num_scatter == 1) { |
4562 | u64 dma_addr = sg_dma_address(task->scatter); |
4563 | |
4564 | sata_cmd.addr_low = lower_32_bits(dma_addr); |
4565 | sata_cmd.addr_high = upper_32_bits(dma_addr); |
4566 | sata_cmd.len = cpu_to_le32(task->total_xfer_len); |
4567 | sata_cmd.esgl = 0; |
4568 | |
4569 | /* Check 4G Boundary */ |
4570 | end_addr = dma_addr + le32_to_cpu(sata_cmd.len) - 1; |
4571 | end_addr_low = lower_32_bits(end_addr); |
4572 | end_addr_high = upper_32_bits(end_addr); |
4573 | if (end_addr_high != sata_cmd.addr_high) { |
4574 | pm8001_dbg(pm8001_ha, FAIL, |
4575 | "The sg list address start_addr=0x%016llx data_len=0x%xend_addr_high=0x%08x end_addr_low=0x%08x has crossed 4G boundary\n" , |
4576 | dma_addr, |
4577 | le32_to_cpu(sata_cmd.len), |
4578 | end_addr_high, end_addr_low); |
4579 | pm8001_chip_make_sg(scatter: task->scatter, nr: 1, |
4580 | prd: ccb->buf_prd); |
4581 | phys_addr = ccb->ccb_dma_handle; |
4582 | sata_cmd.addr_low = lower_32_bits(phys_addr); |
4583 | sata_cmd.addr_high = upper_32_bits(phys_addr); |
4584 | sata_cmd.esgl = cpu_to_le32(1U << 31); |
4585 | } |
4586 | } else if (task->num_scatter == 0) { |
4587 | sata_cmd.addr_low = 0; |
4588 | sata_cmd.addr_high = 0; |
4589 | sata_cmd.len = cpu_to_le32(task->total_xfer_len); |
4590 | sata_cmd.esgl = 0; |
4591 | } |
4592 | |
4593 | /* scsi cdb */ |
4594 | sata_cmd.atapi_scsi_cdb[0] = |
4595 | cpu_to_le32(((task->ata_task.atapi_packet[0]) | |
4596 | (task->ata_task.atapi_packet[1] << 8) | |
4597 | (task->ata_task.atapi_packet[2] << 16) | |
4598 | (task->ata_task.atapi_packet[3] << 24))); |
4599 | sata_cmd.atapi_scsi_cdb[1] = |
4600 | cpu_to_le32(((task->ata_task.atapi_packet[4]) | |
4601 | (task->ata_task.atapi_packet[5] << 8) | |
4602 | (task->ata_task.atapi_packet[6] << 16) | |
4603 | (task->ata_task.atapi_packet[7] << 24))); |
4604 | sata_cmd.atapi_scsi_cdb[2] = |
4605 | cpu_to_le32(((task->ata_task.atapi_packet[8]) | |
4606 | (task->ata_task.atapi_packet[9] << 8) | |
4607 | (task->ata_task.atapi_packet[10] << 16) | |
4608 | (task->ata_task.atapi_packet[11] << 24))); |
4609 | sata_cmd.atapi_scsi_cdb[3] = |
4610 | cpu_to_le32(((task->ata_task.atapi_packet[12]) | |
4611 | (task->ata_task.atapi_packet[13] << 8) | |
4612 | (task->ata_task.atapi_packet[14] << 16) | |
4613 | (task->ata_task.atapi_packet[15] << 24))); |
4614 | } |
4615 | |
4616 | trace_pm80xx_request_issue(id: pm8001_ha->id, |
4617 | phy_id: ccb->device ? ccb->device->attached_phy : PM8001_MAX_PHYS, |
4618 | htag: ccb->ccb_tag, ctlr_opcode: opc, |
4619 | ata_opcode: qc ? qc->tf.command : 0, // ata opcode |
4620 | running_req: ccb->device ? atomic_read(v: &ccb->device->running_req) : 0); |
4621 | return pm8001_mpi_build_cmd(pm8001_ha, q_index, opCode: opc, payload: &sata_cmd, |
4622 | nb: sizeof(sata_cmd), responseQueue: q_index); |
4623 | } |
4624 | |
4625 | /** |
4626 | * pm80xx_chip_phy_start_req - start phy via PHY_START COMMAND |
4627 | * @pm8001_ha: our hba card information. |
4628 | * @phy_id: the phy id which we wanted to start up. |
4629 | */ |
4630 | static int |
4631 | pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) |
4632 | { |
4633 | struct phy_start_req payload; |
4634 | u32 tag = 0x01; |
4635 | u32 opcode = OPC_INB_PHYSTART; |
4636 | |
4637 | memset(&payload, 0, sizeof(payload)); |
4638 | payload.tag = cpu_to_le32(tag); |
4639 | |
4640 | pm8001_dbg(pm8001_ha, INIT, "PHY START REQ for phy_id %d\n" , phy_id); |
4641 | |
4642 | payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | |
4643 | LINKMODE_AUTO | pm8001_ha->link_rate | phy_id); |
4644 | /* SSC Disable and SAS Analog ST configuration */ |
4645 | /* |
4646 | payload.ase_sh_lm_slr_phyid = |
4647 | cpu_to_le32(SSC_DISABLE_30 | SAS_ASE | SPINHOLD_DISABLE | |
4648 | LINKMODE_AUTO | LINKRATE_15 | LINKRATE_30 | LINKRATE_60 | |
4649 | phy_id); |
4650 | Have to add "SAS PHY Analog Setup SPASTI 1 Byte" Based on need |
4651 | */ |
4652 | |
4653 | payload.sas_identify.dev_type = SAS_END_DEVICE; |
4654 | payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL; |
4655 | memcpy(payload.sas_identify.sas_addr, |
4656 | &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE); |
4657 | payload.sas_identify.phy_id = phy_id; |
4658 | |
4659 | return pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opcode, payload: &payload, |
4660 | nb: sizeof(payload), responseQueue: 0); |
4661 | } |
4662 | |
4663 | /** |
4664 | * pm80xx_chip_phy_stop_req - start phy via PHY_STOP COMMAND |
4665 | * @pm8001_ha: our hba card information. |
4666 | * @phy_id: the phy id which we wanted to start up. |
4667 | */ |
4668 | static int pm80xx_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, |
4669 | u8 phy_id) |
4670 | { |
4671 | struct phy_stop_req payload; |
4672 | u32 tag = 0x01; |
4673 | u32 opcode = OPC_INB_PHYSTOP; |
4674 | |
4675 | memset(&payload, 0, sizeof(payload)); |
4676 | payload.tag = cpu_to_le32(tag); |
4677 | payload.phy_id = cpu_to_le32(phy_id); |
4678 | |
4679 | return pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opcode, payload: &payload, |
4680 | nb: sizeof(payload), responseQueue: 0); |
4681 | } |
4682 | |
4683 | /* |
4684 | * see comments on pm8001_mpi_reg_resp. |
4685 | */ |
4686 | static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, |
4687 | struct pm8001_device *pm8001_dev, u32 flag) |
4688 | { |
4689 | struct reg_dev_req payload; |
4690 | u32 opc; |
4691 | u32 stp_sspsmp_sata = 0x4; |
4692 | u32 linkrate, phy_id; |
4693 | int rc; |
4694 | struct pm8001_ccb_info *ccb; |
4695 | u8 retryFlag = 0x1; |
4696 | u16 firstBurstSize = 0; |
4697 | u16 ITNT = 2000; |
4698 | struct domain_device *dev = pm8001_dev->sas_device; |
4699 | struct domain_device *parent_dev = dev->parent; |
4700 | struct pm8001_port *port = dev->port->lldd_port; |
4701 | |
4702 | memset(&payload, 0, sizeof(payload)); |
4703 | ccb = pm8001_ccb_alloc(pm8001_ha, dev: pm8001_dev, NULL); |
4704 | if (!ccb) |
4705 | return -SAS_QUEUE_FULL; |
4706 | |
4707 | payload.tag = cpu_to_le32(ccb->ccb_tag); |
4708 | |
4709 | if (flag == 1) { |
4710 | stp_sspsmp_sata = 0x02; /*direct attached sata */ |
4711 | } else { |
4712 | if (pm8001_dev->dev_type == SAS_SATA_DEV) |
4713 | stp_sspsmp_sata = 0x00; /* stp*/ |
4714 | else if (pm8001_dev->dev_type == SAS_END_DEVICE || |
4715 | dev_is_expander(type: pm8001_dev->dev_type)) |
4716 | stp_sspsmp_sata = 0x01; /*ssp or smp*/ |
4717 | } |
4718 | if (parent_dev && dev_is_expander(type: parent_dev->dev_type)) |
4719 | phy_id = parent_dev->ex_dev.ex_phy->phy_id; |
4720 | else |
4721 | phy_id = pm8001_dev->attached_phy; |
4722 | |
4723 | opc = OPC_INB_REG_DEV; |
4724 | |
4725 | linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? |
4726 | pm8001_dev->sas_device->linkrate : dev->port->linkrate; |
4727 | |
4728 | payload.phyid_portid = |
4729 | cpu_to_le32(((port->port_id) & 0xFF) | |
4730 | ((phy_id & 0xFF) << 8)); |
4731 | |
4732 | payload.dtype_dlr_mcn_ir_retry = cpu_to_le32((retryFlag & 0x01) | |
4733 | ((linkrate & 0x0F) << 24) | |
4734 | ((stp_sspsmp_sata & 0x03) << 28)); |
4735 | payload.firstburstsize_ITNexustimeout = |
4736 | cpu_to_le32(ITNT | (firstBurstSize * 0x10000)); |
4737 | |
4738 | memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr, |
4739 | SAS_ADDR_SIZE); |
4740 | |
4741 | pm8001_dbg(pm8001_ha, INIT, |
4742 | "register device req phy_id 0x%x port_id 0x%x\n" , phy_id, |
4743 | (port->port_id & 0xFF)); |
4744 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &payload, |
4745 | nb: sizeof(payload), responseQueue: 0); |
4746 | if (rc) |
4747 | pm8001_ccb_free(pm8001_ha, ccb); |
4748 | |
4749 | return rc; |
4750 | } |
4751 | |
4752 | /** |
4753 | * pm80xx_chip_phy_ctl_req - support the local phy operation |
4754 | * @pm8001_ha: our hba card information. |
4755 | * @phyId: the phy id which we wanted to operate |
4756 | * @phy_op: phy operation to request |
4757 | */ |
4758 | static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, |
4759 | u32 phyId, u32 phy_op) |
4760 | { |
4761 | u32 tag; |
4762 | int rc; |
4763 | struct local_phy_ctl_req payload; |
4764 | u32 opc = OPC_INB_LOCAL_PHY_CONTROL; |
4765 | |
4766 | memset(&payload, 0, sizeof(payload)); |
4767 | rc = pm8001_tag_alloc(pm8001_ha, tag_out: &tag); |
4768 | if (rc) |
4769 | return rc; |
4770 | |
4771 | payload.tag = cpu_to_le32(tag); |
4772 | payload.phyop_phyid = |
4773 | cpu_to_le32(((phy_op & 0xFF) << 8) | (phyId & 0xFF)); |
4774 | |
4775 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &payload, |
4776 | nb: sizeof(payload), responseQueue: 0); |
4777 | if (rc) |
4778 | pm8001_tag_free(pm8001_ha, tag); |
4779 | |
4780 | return rc; |
4781 | } |
4782 | |
4783 | static u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha) |
4784 | { |
4785 | u32 value; |
4786 | |
4787 | if (pm8001_ha->use_msix) |
4788 | return 1; |
4789 | |
4790 | value = pm8001_cr32(pm8001_ha, bar: 0, MSGU_ODR); |
4791 | if (value) |
4792 | return 1; |
4793 | return 0; |
4794 | } |
4795 | |
4796 | /** |
4797 | * pm80xx_chip_isr - PM8001 isr handler. |
4798 | * @pm8001_ha: our hba card information. |
4799 | * @vec: irq number. |
4800 | */ |
4801 | static irqreturn_t |
4802 | pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) |
4803 | { |
4804 | pm80xx_chip_interrupt_disable(pm8001_ha, vec); |
4805 | pm8001_dbg(pm8001_ha, DEVIO, |
4806 | "irq vec %d, ODMR:0x%x\n" , |
4807 | vec, pm8001_cr32(pm8001_ha, 0, 0x30)); |
4808 | process_oq(pm8001_ha, vec); |
4809 | pm80xx_chip_interrupt_enable(pm8001_ha, vec); |
4810 | return IRQ_HANDLED; |
4811 | } |
4812 | |
4813 | static void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha, |
4814 | u32 operation, u32 phyid, |
4815 | u32 length, u32 *buf) |
4816 | { |
4817 | u32 tag, i, j = 0; |
4818 | int rc; |
4819 | struct set_phy_profile_req payload; |
4820 | u32 opc = OPC_INB_SET_PHY_PROFILE; |
4821 | |
4822 | memset(&payload, 0, sizeof(payload)); |
4823 | rc = pm8001_tag_alloc(pm8001_ha, tag_out: &tag); |
4824 | if (rc) { |
4825 | pm8001_dbg(pm8001_ha, FAIL, "Invalid tag\n" ); |
4826 | return; |
4827 | } |
4828 | |
4829 | payload.tag = cpu_to_le32(tag); |
4830 | payload.ppc_phyid = |
4831 | cpu_to_le32(((operation & 0xF) << 8) | (phyid & 0xFF)); |
4832 | pm8001_dbg(pm8001_ha, DISC, |
4833 | " phy profile command for phy %x ,length is %d\n" , |
4834 | le32_to_cpu(payload.ppc_phyid), length); |
4835 | for (i = length; i < (length + PHY_DWORD_LENGTH - 1); i++) { |
4836 | payload.reserved[j] = cpu_to_le32(*((u32 *)buf + i)); |
4837 | j++; |
4838 | } |
4839 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &payload, |
4840 | nb: sizeof(payload), responseQueue: 0); |
4841 | if (rc) |
4842 | pm8001_tag_free(pm8001_ha, tag); |
4843 | } |
4844 | |
4845 | void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha, |
4846 | u32 length, u8 *buf) |
4847 | { |
4848 | u32 i; |
4849 | |
4850 | for (i = 0; i < pm8001_ha->chip->n_phy; i++) { |
4851 | mpi_set_phy_profile_req(pm8001_ha, |
4852 | SAS_PHY_ANALOG_SETTINGS_PAGE, phyid: i, length, buf: (u32 *)buf); |
4853 | length = length + PHY_DWORD_LENGTH; |
4854 | } |
4855 | pm8001_dbg(pm8001_ha, INIT, "phy settings completed\n" ); |
4856 | } |
4857 | |
4858 | void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, |
4859 | u32 phy, u32 length, u32 *buf) |
4860 | { |
4861 | u32 tag, opc; |
4862 | int rc, i; |
4863 | struct set_phy_profile_req payload; |
4864 | |
4865 | memset(&payload, 0, sizeof(payload)); |
4866 | |
4867 | rc = pm8001_tag_alloc(pm8001_ha, tag_out: &tag); |
4868 | if (rc) { |
4869 | pm8001_dbg(pm8001_ha, INIT, "Invalid tag\n" ); |
4870 | return; |
4871 | } |
4872 | |
4873 | opc = OPC_INB_SET_PHY_PROFILE; |
4874 | |
4875 | payload.tag = cpu_to_le32(tag); |
4876 | payload.ppc_phyid = |
4877 | cpu_to_le32(((SAS_PHY_ANALOG_SETTINGS_PAGE & 0xF) << 8) |
4878 | | (phy & 0xFF)); |
4879 | |
4880 | for (i = 0; i < length; i++) |
4881 | payload.reserved[i] = cpu_to_le32(*(buf + i)); |
4882 | |
4883 | rc = pm8001_mpi_build_cmd(pm8001_ha, q_index: 0, opCode: opc, payload: &payload, |
4884 | nb: sizeof(payload), responseQueue: 0); |
4885 | if (rc) |
4886 | pm8001_tag_free(pm8001_ha, tag); |
4887 | |
4888 | pm8001_dbg(pm8001_ha, INIT, "PHY %d settings applied\n" , phy); |
4889 | } |
4890 | const struct pm8001_dispatch pm8001_80xx_dispatch = { |
4891 | .name = "pmc80xx" , |
4892 | .chip_init = pm80xx_chip_init, |
4893 | .chip_post_init = pm80xx_chip_post_init, |
4894 | .chip_soft_rst = pm80xx_chip_soft_rst, |
4895 | .chip_rst = pm80xx_hw_chip_rst, |
4896 | .chip_iounmap = pm8001_chip_iounmap, |
4897 | .isr = pm80xx_chip_isr, |
4898 | .is_our_interrupt = pm80xx_chip_is_our_interrupt, |
4899 | .isr_process_oq = process_oq, |
4900 | .interrupt_enable = pm80xx_chip_interrupt_enable, |
4901 | .interrupt_disable = pm80xx_chip_interrupt_disable, |
4902 | .make_prd = pm8001_chip_make_sg, |
4903 | .smp_req = pm80xx_chip_smp_req, |
4904 | .ssp_io_req = pm80xx_chip_ssp_io_req, |
4905 | .sata_req = pm80xx_chip_sata_req, |
4906 | .phy_start_req = pm80xx_chip_phy_start_req, |
4907 | .phy_stop_req = pm80xx_chip_phy_stop_req, |
4908 | .reg_dev_req = pm80xx_chip_reg_dev_req, |
4909 | .dereg_dev_req = pm8001_chip_dereg_dev_req, |
4910 | .phy_ctl_req = pm80xx_chip_phy_ctl_req, |
4911 | .task_abort = pm8001_chip_abort_task, |
4912 | .ssp_tm_req = pm8001_chip_ssp_tm_req, |
4913 | .get_nvmd_req = pm8001_chip_get_nvmd_req, |
4914 | .set_nvmd_req = pm8001_chip_set_nvmd_req, |
4915 | .fw_flash_update_req = pm8001_chip_fw_flash_update_req, |
4916 | .set_dev_state_req = pm8001_chip_set_dev_state_req, |
4917 | .fatal_errors = pm80xx_fatal_errors, |
4918 | .hw_event_ack_req = pm80xx_hw_event_ack_req, |
4919 | }; |
4920 | |