aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/pm8001/pm80xx_hwi.c
diff options
context:
space:
mode:
authorAnand Kumar Santhanam <AnandKumar.Santhanam@pmcs.com>2013-09-04 03:27:00 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-10-25 04:58:16 -0400
commitd078b5117f18dce57b895df640d9bf2614864829 (patch)
tree6d6141a83ba64f24848a0348804e3522866ae815 /drivers/scsi/pm8001/pm80xx_hwi.c
parent279094079a442c19ff7e7c0fd9511d9404cb2518 (diff)
[SCSI] pm80xx: Firmware logging support.
Supports below logging facilities, Inbound outbound queues dump. Non fatal dump in case of IO failures. Fatal dump in case of firmware failure. [jejb: checkpatch spacing fixes] Signed-off-by: Anandkumar.Santhanam@pmcs.com Reviewed-by: Jack Wang <jinpu.wang@profitbricks.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/pm8001/pm80xx_hwi.c')
-rw-r--r--drivers/scsi/pm8001/pm80xx_hwi.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c
index 91cf4242a03d..8987b1706216 100644
--- a/drivers/scsi/pm8001/pm80xx_hwi.c
+++ b/drivers/scsi/pm8001/pm80xx_hwi.c
@@ -45,6 +45,228 @@
45 45
46#define SMP_DIRECT 1 46#define SMP_DIRECT 1
47#define SMP_INDIRECT 2 47#define SMP_INDIRECT 2
48
49
50int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shift_value)
51{
52 u32 reg_val;
53 unsigned long start;
54 pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, shift_value);
55 /* confirm the setting is written */
56 start = jiffies + HZ; /* 1 sec */
57 do {
58 reg_val = pm8001_cr32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER);
59 } while ((reg_val != shift_value) && time_before(jiffies, start));
60 if (reg_val != shift_value) {
61 PM8001_FAIL_DBG(pm8001_ha,
62 pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER"
63 " = 0x%x\n", reg_val));
64 return -1;
65 }
66 return 0;
67}
68
69void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset,
70 const void *destination,
71 u32 dw_count, u32 bus_base_number)
72{
73 u32 index, value, offset;
74 u32 *destination1;
75 destination1 = (u32 *)destination;
76
77 for (index = 0; index < dw_count; index += 4, destination1++) {
78 offset = (soffset + index / 4);
79 if (offset < (64 * 1024)) {
80 value = pm8001_cr32(pm8001_ha, bus_base_number, offset);
81 *destination1 = cpu_to_le32(value);
82 }
83 }
84 return;
85}
86
87ssize_t pm80xx_get_fatal_dump(struct device *cdev,
88 struct device_attribute *attr, char *buf)
89{
90 struct Scsi_Host *shost = class_to_shost(cdev);
91 struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
92 struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
93 void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr;
94 u32 status = 1;
95 u32 accum_len , reg_val, index, *temp;
96 unsigned long start;
97 u8 *direct_data;
98 char *fatal_error_data = buf;
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(pm8001_ha->forensic_info.data_buf.direct_data,
104 "Not supported for SPC controller");
105 return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
106 (char *)buf;
107 }
108 if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
109 PM8001_IO_DBG(pm8001_ha,
110 pm8001_printk("forensic_info TYPE_NON_FATAL..............\n"));
111 direct_data = (u8 *)fatal_error_data;
112 pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL;
113 pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET;
114 pm8001_ha->forensic_info.data_buf.direct_offset = 0;
115 pm8001_ha->forensic_info.data_buf.read_len = 0;
116
117 pm8001_ha->forensic_info.data_buf.direct_data = direct_data;
118 }
119
120 if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) {
121 /* start to get data */
122 /* Program the MEMBASE II Shifting Register with 0x00.*/
123 pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
124 pm8001_ha->fatal_forensic_shift_offset);
125 pm8001_ha->forensic_last_offset = 0;
126 pm8001_ha->forensic_fatal_step = 0;
127 pm8001_ha->fatal_bar_loc = 0;
128 }
129 /* Read until accum_len is retrived */
130 accum_len = pm8001_mr32(fatal_table_address,
131 MPI_FATAL_EDUMP_TABLE_ACCUM_LEN);
132 PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n",
133 accum_len));
134 if (accum_len == 0xFFFFFFFF) {
135 PM8001_IO_DBG(pm8001_ha,
136 pm8001_printk("Possible PCI issue 0x%x not expected\n",
137 accum_len));
138 return status;
139 }
140 if (accum_len == 0 || accum_len >= 0x100000) {
141 pm8001_ha->forensic_info.data_buf.direct_data +=
142 sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
143 "%08x ", 0xFFFFFFFF);
144 return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
145 (char *)buf;
146 }
147 temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr;
148 if (pm8001_ha->forensic_fatal_step == 0) {
149moreData:
150 if (pm8001_ha->forensic_info.data_buf.direct_data) {
151 /* Data is in bar, copy to host memory */
152 pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc,
153 pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr,
154 pm8001_ha->forensic_info.data_buf.direct_len ,
155 1);
156 }
157 pm8001_ha->fatal_bar_loc +=
158 pm8001_ha->forensic_info.data_buf.direct_len;
159 pm8001_ha->forensic_info.data_buf.direct_offset +=
160 pm8001_ha->forensic_info.data_buf.direct_len;
161 pm8001_ha->forensic_last_offset +=
162 pm8001_ha->forensic_info.data_buf.direct_len;
163 pm8001_ha->forensic_info.data_buf.read_len =
164 pm8001_ha->forensic_info.data_buf.direct_len;
165
166 if (pm8001_ha->forensic_last_offset >= accum_len) {
167 pm8001_ha->forensic_info.data_buf.direct_data +=
168 sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
169 "%08x ", 3);
170 for (index = 0; index < (SYSFS_OFFSET / 4); index++) {
171 pm8001_ha->forensic_info.data_buf.direct_data +=
172 sprintf(pm8001_ha->
173 forensic_info.data_buf.direct_data,
174 "%08x ", *(temp + index));
175 }
176
177 pm8001_ha->fatal_bar_loc = 0;
178 pm8001_ha->forensic_fatal_step = 1;
179 pm8001_ha->fatal_forensic_shift_offset = 0;
180 pm8001_ha->forensic_last_offset = 0;
181 status = 0;
182 return (char *)pm8001_ha->
183 forensic_info.data_buf.direct_data -
184 (char *)buf;
185 }
186 if (pm8001_ha->fatal_bar_loc < (64 * 1024)) {
187 pm8001_ha->forensic_info.data_buf.direct_data +=
188 sprintf(pm8001_ha->
189 forensic_info.data_buf.direct_data,
190 "%08x ", 2);
191 for (index = 0; index < (SYSFS_OFFSET / 4); index++) {
192 pm8001_ha->forensic_info.data_buf.direct_data +=
193 sprintf(pm8001_ha->
194 forensic_info.data_buf.direct_data,
195 "%08x ", *(temp + index));
196 }
197 status = 0;
198 return (char *)pm8001_ha->
199 forensic_info.data_buf.direct_data -
200 (char *)buf;
201 }
202
203 /* Increment the MEMBASE II Shifting Register value by 0x100.*/
204 pm8001_ha->forensic_info.data_buf.direct_data +=
205 sprintf(pm8001_ha->forensic_info.data_buf.direct_data,
206 "%08x ", 2);
207 for (index = 0; index < 256; index++) {
208 pm8001_ha->forensic_info.data_buf.direct_data +=
209 sprintf(pm8001_ha->
210 forensic_info.data_buf.direct_data,
211 "%08x ", *(temp + index));
212 }
213 pm8001_ha->fatal_forensic_shift_offset += 0x100;
214 pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
215 pm8001_ha->fatal_forensic_shift_offset);
216 pm8001_ha->fatal_bar_loc = 0;
217 status = 0;
218 return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
219 (char *)buf;
220 }
221 if (pm8001_ha->forensic_fatal_step == 1) {
222 pm8001_ha->fatal_forensic_shift_offset = 0;
223 /* Read 64K of the debug data. */
224 pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER,
225 pm8001_ha->fatal_forensic_shift_offset);
226 pm8001_mw32(fatal_table_address,
227 MPI_FATAL_EDUMP_TABLE_HANDSHAKE,
228 MPI_FATAL_EDUMP_HANDSHAKE_RDY);
229
230 /* Poll FDDHSHK until clear */
231 start = jiffies + (2 * HZ); /* 2 sec */
232
233 do {
234 reg_val = pm8001_mr32(fatal_table_address,
235 MPI_FATAL_EDUMP_TABLE_HANDSHAKE);
236 } while ((reg_val) && time_before(jiffies, start));
237
238 if (reg_val != 0) {
239 PM8001_FAIL_DBG(pm8001_ha,
240 pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER"
241 " = 0x%x\n", reg_val));
242 return -1;
243 }
244
245 /* Read the next 64K of the debug data. */
246 pm8001_ha->forensic_fatal_step = 0;
247 if (pm8001_mr32(fatal_table_address,
248 MPI_FATAL_EDUMP_TABLE_STATUS) !=
249 MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) {
250 pm8001_mw32(fatal_table_address,
251 MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 0);
252 goto moreData;
253 } else {
254 pm8001_ha->forensic_info.data_buf.direct_data +=
255 sprintf(pm8001_ha->
256 forensic_info.data_buf.direct_data,
257 "%08x ", 4);
258 pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF;
259 pm8001_ha->forensic_info.data_buf.direct_len = 0;
260 pm8001_ha->forensic_info.data_buf.direct_offset = 0;
261 pm8001_ha->forensic_info.data_buf.read_len = 0;
262 status = 0;
263 }
264 }
265
266 return (char *)pm8001_ha->forensic_info.data_buf.direct_data -
267 (char *)buf;
268}
269
48/** 270/**
49 * read_main_config_table - read the configure table and save it. 271 * read_main_config_table - read the configure table and save it.
50 * @pm8001_ha: our hba card information 272 * @pm8001_ha: our hba card information
@@ -583,6 +805,9 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha)
583 pm8001_ha->pspa_q_tbl_addr = 805 pm8001_ha->pspa_q_tbl_addr =
584 base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) & 806 base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0x90) &
585 0xFFFFFF); 807 0xFFFFFF);
808 pm8001_ha->fatal_tbl_addr =
809 base_addr + (pm8001_cr32(pm8001_ha, pcibar, offset + 0xA0) &
810 0xFFFFFF);
586 811
587 PM8001_INIT_DBG(pm8001_ha, 812 PM8001_INIT_DBG(pm8001_ha,
588 pm8001_printk("GST OFFSET 0x%x\n", 813 pm8001_printk("GST OFFSET 0x%x\n",