diff options
author | Andrew Vasquez <andrew.vasquez@qlogic.com> | 2005-07-06 13:31:07 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-07-14 10:56:54 -0400 |
commit | 459c537807bd72cce7b007fb218bb5a658a6c3c1 (patch) | |
tree | 18a05e5f8fb73651219860f7056c6f73a885d623 /drivers/scsi | |
parent | 1c7c63574ff3e568ca374e9f05e30b8d7d64273e (diff) |
[SCSI] qla2xxx: Add ISP24xx flash-manipulation routines.
Add ISP24xx flash-manipulation routines.
Add read/write flash manipulation routines for the ISP24xx.
Update sysfs NVRAM objects to use generalized accessor
functions.
Signed-off-by: Andrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_attr.c | 59 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_gbl.h | 11 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_os.c | 2 | ||||
-rw-r--r-- | drivers/scsi/qla2xxx/qla_sup.c | 538 |
4 files changed, 531 insertions, 79 deletions
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 30c381c3abcc..9361f4255e62 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c | |||
@@ -118,23 +118,15 @@ qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf, loff_t off, | |||
118 | { | 118 | { |
119 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | 119 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, |
120 | struct device, kobj))); | 120 | struct device, kobj))); |
121 | uint16_t *witer; | ||
122 | unsigned long flags; | 121 | unsigned long flags; |
123 | uint16_t cnt; | ||
124 | 122 | ||
125 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t)) | 123 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size) |
126 | return 0; | 124 | return 0; |
127 | 125 | ||
128 | /* Read NVRAM. */ | 126 | /* Read NVRAM. */ |
129 | spin_lock_irqsave(&ha->hardware_lock, flags); | 127 | spin_lock_irqsave(&ha->hardware_lock, flags); |
130 | qla2x00_lock_nvram_access(ha); | 128 | ha->isp_ops.read_nvram(ha, (uint8_t *)buf, ha->nvram_base, |
131 | witer = (uint16_t *)buf; | 129 | ha->nvram_size); |
132 | for (cnt = 0; cnt < count / 2; cnt++) { | ||
133 | *witer = cpu_to_le16(qla2x00_get_nvram_word(ha, | ||
134 | cnt+ha->nvram_base)); | ||
135 | witer++; | ||
136 | } | ||
137 | qla2x00_unlock_nvram_access(ha); | ||
138 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 130 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
139 | 131 | ||
140 | return (count); | 132 | return (count); |
@@ -146,34 +138,38 @@ qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf, loff_t off, | |||
146 | { | 138 | { |
147 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, | 139 | struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj, |
148 | struct device, kobj))); | 140 | struct device, kobj))); |
149 | uint8_t *iter; | ||
150 | uint16_t *witer; | ||
151 | unsigned long flags; | 141 | unsigned long flags; |
152 | uint16_t cnt; | 142 | uint16_t cnt; |
153 | uint8_t chksum; | ||
154 | 143 | ||
155 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t)) | 144 | if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size) |
156 | return 0; | 145 | return 0; |
157 | 146 | ||
158 | /* Checksum NVRAM. */ | 147 | /* Checksum NVRAM. */ |
159 | iter = (uint8_t *)buf; | 148 | if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) { |
160 | chksum = 0; | 149 | uint32_t *iter; |
161 | for (cnt = 0; cnt < count - 1; cnt++) | 150 | uint32_t chksum; |
162 | chksum += *iter++; | 151 | |
163 | chksum = ~chksum + 1; | 152 | iter = (uint32_t *)buf; |
164 | *iter = chksum; | 153 | chksum = 0; |
154 | for (cnt = 0; cnt < ((count >> 2) - 1); cnt++) | ||
155 | chksum += le32_to_cpu(*iter++); | ||
156 | chksum = ~chksum + 1; | ||
157 | *iter = cpu_to_le32(chksum); | ||
158 | } else { | ||
159 | uint8_t *iter; | ||
160 | uint8_t chksum; | ||
161 | |||
162 | iter = (uint8_t *)buf; | ||
163 | chksum = 0; | ||
164 | for (cnt = 0; cnt < count - 1; cnt++) | ||
165 | chksum += *iter++; | ||
166 | chksum = ~chksum + 1; | ||
167 | *iter = chksum; | ||
168 | } | ||
165 | 169 | ||
166 | /* Write NVRAM. */ | 170 | /* Write NVRAM. */ |
167 | spin_lock_irqsave(&ha->hardware_lock, flags); | 171 | spin_lock_irqsave(&ha->hardware_lock, flags); |
168 | qla2x00_lock_nvram_access(ha); | 172 | ha->isp_ops.write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count); |
169 | qla2x00_release_nvram_protection(ha); | ||
170 | witer = (uint16_t *)buf; | ||
171 | for (cnt = 0; cnt < count / 2; cnt++) { | ||
172 | qla2x00_write_nvram_word(ha, cnt+ha->nvram_base, | ||
173 | cpu_to_le16(*witer)); | ||
174 | witer++; | ||
175 | } | ||
176 | qla2x00_unlock_nvram_access(ha); | ||
177 | spin_unlock_irqrestore(&ha->hardware_lock, flags); | 173 | spin_unlock_irqrestore(&ha->hardware_lock, flags); |
178 | 174 | ||
179 | return (count); | 175 | return (count); |
@@ -185,7 +181,7 @@ static struct bin_attribute sysfs_nvram_attr = { | |||
185 | .mode = S_IRUSR | S_IWUSR, | 181 | .mode = S_IRUSR | S_IWUSR, |
186 | .owner = THIS_MODULE, | 182 | .owner = THIS_MODULE, |
187 | }, | 183 | }, |
188 | .size = sizeof(nvram_t), | 184 | .size = 0, |
189 | .read = qla2x00_sysfs_read_nvram, | 185 | .read = qla2x00_sysfs_read_nvram, |
190 | .write = qla2x00_sysfs_write_nvram, | 186 | .write = qla2x00_sysfs_write_nvram, |
191 | }; | 187 | }; |
@@ -196,6 +192,7 @@ qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha) | |||
196 | struct Scsi_Host *host = ha->host; | 192 | struct Scsi_Host *host = ha->host; |
197 | 193 | ||
198 | sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); | 194 | sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr); |
195 | sysfs_nvram_attr.size = ha->nvram_size; | ||
199 | sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); | 196 | sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); |
200 | } | 197 | } |
201 | 198 | ||
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 574446c0892a..0dd732486e24 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h | |||
@@ -220,6 +220,17 @@ extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *); | |||
220 | extern void qla2x00_release_nvram_protection(scsi_qla_host_t *); | 220 | extern void qla2x00_release_nvram_protection(scsi_qla_host_t *); |
221 | extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t); | 221 | extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t); |
222 | extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t); | 222 | extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t); |
223 | extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *, | ||
224 | uint32_t, uint32_t); | ||
225 | extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, | ||
226 | uint32_t); | ||
227 | extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, | ||
228 | uint32_t); | ||
229 | extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, | ||
230 | uint32_t); | ||
231 | extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, | ||
232 | uint32_t); | ||
233 | |||
223 | /* | 234 | /* |
224 | * Global Function Prototypes in qla_dbg.c source file. | 235 | * Global Function Prototypes in qla_dbg.c source file. |
225 | */ | 236 | */ |
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index a325b66ea41c..9e6d05119253 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c | |||
@@ -1187,6 +1187,8 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) | |||
1187 | ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32; | 1187 | ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32; |
1188 | ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32; | 1188 | ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32; |
1189 | ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb; | 1189 | ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb; |
1190 | ha->isp_ops.read_nvram = qla2x00_read_nvram_data; | ||
1191 | ha->isp_ops.write_nvram = qla2x00_write_nvram_data; | ||
1190 | ha->isp_ops.fw_dump = qla2100_fw_dump; | 1192 | ha->isp_ops.fw_dump = qla2100_fw_dump; |
1191 | ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump; | 1193 | ha->isp_ops.ascii_fw_dump = qla2100_ascii_fw_dump; |
1192 | if (IS_QLA2100(ha)) { | 1194 | if (IS_QLA2100(ha)) { |
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index cf2a6bc444d2..c95ef2bb089a 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c | |||
@@ -79,54 +79,6 @@ qla2x00_unlock_nvram_access(scsi_qla_host_t *ha) | |||
79 | } | 79 | } |
80 | 80 | ||
81 | /** | 81 | /** |
82 | * qla2x00_release_nvram_protection() - | ||
83 | * @ha: HA context | ||
84 | */ | ||
85 | void | ||
86 | qla2x00_release_nvram_protection(scsi_qla_host_t *ha) | ||
87 | { | ||
88 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | ||
89 | uint32_t word; | ||
90 | |||
91 | /* Release NVRAM write protection. */ | ||
92 | if (IS_QLA2322(ha) || IS_QLA6322(ha)) { | ||
93 | /* Write enable. */ | ||
94 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
95 | qla2x00_nv_write(ha, 0); | ||
96 | qla2x00_nv_write(ha, 0); | ||
97 | for (word = 0; word < 8; word++) | ||
98 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
99 | |||
100 | qla2x00_nv_deselect(ha); | ||
101 | |||
102 | /* Enable protection register. */ | ||
103 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
104 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
105 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
106 | for (word = 0; word < 8; word++) | ||
107 | qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); | ||
108 | |||
109 | qla2x00_nv_deselect(ha); | ||
110 | |||
111 | /* Clear protection register (ffff is cleared). */ | ||
112 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
113 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
114 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
115 | for (word = 0; word < 8; word++) | ||
116 | qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); | ||
117 | |||
118 | qla2x00_nv_deselect(ha); | ||
119 | |||
120 | /* Wait for NVRAM to become ready. */ | ||
121 | WRT_REG_WORD(®->nvram, NVR_SELECT); | ||
122 | do { | ||
123 | NVRAM_DELAY(); | ||
124 | word = RD_REG_WORD(®->nvram); | ||
125 | } while ((word & NVR_DATA_IN) == 0); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the | 82 | * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the |
131 | * request routine to get the word from NVRAM. | 83 | * request routine to get the word from NVRAM. |
132 | * @ha: HA context | 84 | * @ha: HA context |
@@ -202,6 +154,64 @@ qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data) | |||
202 | qla2x00_nv_deselect(ha); | 154 | qla2x00_nv_deselect(ha); |
203 | } | 155 | } |
204 | 156 | ||
157 | static int | ||
158 | qla2x00_write_nvram_word_tmo(scsi_qla_host_t *ha, uint32_t addr, uint16_t data, | ||
159 | uint32_t tmo) | ||
160 | { | ||
161 | int ret, count; | ||
162 | uint16_t word; | ||
163 | uint32_t nv_cmd; | ||
164 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | ||
165 | |||
166 | ret = QLA_SUCCESS; | ||
167 | |||
168 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
169 | qla2x00_nv_write(ha, 0); | ||
170 | qla2x00_nv_write(ha, 0); | ||
171 | |||
172 | for (word = 0; word < 8; word++) | ||
173 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
174 | |||
175 | qla2x00_nv_deselect(ha); | ||
176 | |||
177 | /* Write data */ | ||
178 | nv_cmd = (addr << 16) | NV_WRITE_OP; | ||
179 | nv_cmd |= data; | ||
180 | nv_cmd <<= 5; | ||
181 | for (count = 0; count < 27; count++) { | ||
182 | if (nv_cmd & BIT_31) | ||
183 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
184 | else | ||
185 | qla2x00_nv_write(ha, 0); | ||
186 | |||
187 | nv_cmd <<= 1; | ||
188 | } | ||
189 | |||
190 | qla2x00_nv_deselect(ha); | ||
191 | |||
192 | /* Wait for NVRAM to become ready */ | ||
193 | WRT_REG_WORD(®->nvram, NVR_SELECT); | ||
194 | do { | ||
195 | NVRAM_DELAY(); | ||
196 | word = RD_REG_WORD(®->nvram); | ||
197 | if (!--tmo) { | ||
198 | ret = QLA_FUNCTION_FAILED; | ||
199 | break; | ||
200 | } | ||
201 | } while ((word & NVR_DATA_IN) == 0); | ||
202 | |||
203 | qla2x00_nv_deselect(ha); | ||
204 | |||
205 | /* Disable writes */ | ||
206 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
207 | for (count = 0; count < 10; count++) | ||
208 | qla2x00_nv_write(ha, 0); | ||
209 | |||
210 | qla2x00_nv_deselect(ha); | ||
211 | |||
212 | return ret; | ||
213 | } | ||
214 | |||
205 | /** | 215 | /** |
206 | * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from | 216 | * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from |
207 | * NVRAM. | 217 | * NVRAM. |
@@ -292,3 +302,435 @@ qla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data) | |||
292 | NVRAM_DELAY(); | 302 | NVRAM_DELAY(); |
293 | } | 303 | } |
294 | 304 | ||
305 | /** | ||
306 | * qla2x00_clear_nvram_protection() - | ||
307 | * @ha: HA context | ||
308 | */ | ||
309 | static int | ||
310 | qla2x00_clear_nvram_protection(scsi_qla_host_t *ha) | ||
311 | { | ||
312 | int ret, stat; | ||
313 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | ||
314 | uint32_t word; | ||
315 | uint16_t wprot, wprot_old; | ||
316 | |||
317 | /* Clear NVRAM write protection. */ | ||
318 | ret = QLA_FUNCTION_FAILED; | ||
319 | wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, 0)); | ||
320 | stat = qla2x00_write_nvram_word_tmo(ha, 0, | ||
321 | __constant_cpu_to_le16(0x1234), 100000); | ||
322 | wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, 0)); | ||
323 | if (stat != QLA_SUCCESS || wprot != __constant_cpu_to_le16(0x1234)) { | ||
324 | /* Write enable. */ | ||
325 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
326 | qla2x00_nv_write(ha, 0); | ||
327 | qla2x00_nv_write(ha, 0); | ||
328 | for (word = 0; word < 8; word++) | ||
329 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
330 | |||
331 | qla2x00_nv_deselect(ha); | ||
332 | |||
333 | /* Enable protection register. */ | ||
334 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
335 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
336 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
337 | for (word = 0; word < 8; word++) | ||
338 | qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); | ||
339 | |||
340 | qla2x00_nv_deselect(ha); | ||
341 | |||
342 | /* Clear protection register (ffff is cleared). */ | ||
343 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
344 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
345 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
346 | for (word = 0; word < 8; word++) | ||
347 | qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); | ||
348 | |||
349 | qla2x00_nv_deselect(ha); | ||
350 | |||
351 | /* Wait for NVRAM to become ready. */ | ||
352 | WRT_REG_WORD(®->nvram, NVR_SELECT); | ||
353 | do { | ||
354 | NVRAM_DELAY(); | ||
355 | word = RD_REG_WORD(®->nvram); | ||
356 | } while ((word & NVR_DATA_IN) == 0); | ||
357 | |||
358 | ret = QLA_SUCCESS; | ||
359 | } else | ||
360 | qla2x00_write_nvram_word(ha, 0, wprot_old); | ||
361 | |||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | static void | ||
366 | qla2x00_set_nvram_protection(scsi_qla_host_t *ha, int stat) | ||
367 | { | ||
368 | struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; | ||
369 | uint32_t word; | ||
370 | |||
371 | if (stat != QLA_SUCCESS) | ||
372 | return; | ||
373 | |||
374 | /* Set NVRAM write protection. */ | ||
375 | /* Write enable. */ | ||
376 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
377 | qla2x00_nv_write(ha, 0); | ||
378 | qla2x00_nv_write(ha, 0); | ||
379 | for (word = 0; word < 8; word++) | ||
380 | qla2x00_nv_write(ha, NVR_DATA_OUT); | ||
381 | |||
382 | qla2x00_nv_deselect(ha); | ||
383 | |||
384 | /* Enable protection register. */ | ||
385 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
386 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
387 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
388 | for (word = 0; word < 8; word++) | ||
389 | qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); | ||
390 | |||
391 | qla2x00_nv_deselect(ha); | ||
392 | |||
393 | /* Enable protection register. */ | ||
394 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
395 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
396 | qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); | ||
397 | for (word = 0; word < 8; word++) | ||
398 | qla2x00_nv_write(ha, NVR_PR_ENABLE); | ||
399 | |||
400 | qla2x00_nv_deselect(ha); | ||
401 | |||
402 | /* Wait for NVRAM to become ready. */ | ||
403 | WRT_REG_WORD(®->nvram, NVR_SELECT); | ||
404 | do { | ||
405 | NVRAM_DELAY(); | ||
406 | word = RD_REG_WORD(®->nvram); | ||
407 | } while ((word & NVR_DATA_IN) == 0); | ||
408 | } | ||
409 | |||
410 | |||
411 | /*****************************************************************************/ | ||
412 | /* Flash Manipulation Routines */ | ||
413 | /*****************************************************************************/ | ||
414 | |||
415 | static inline uint32_t | ||
416 | flash_conf_to_access_addr(uint32_t faddr) | ||
417 | { | ||
418 | return FARX_ACCESS_FLASH_CONF | faddr; | ||
419 | } | ||
420 | |||
421 | static inline uint32_t | ||
422 | flash_data_to_access_addr(uint32_t faddr) | ||
423 | { | ||
424 | return FARX_ACCESS_FLASH_DATA | faddr; | ||
425 | } | ||
426 | |||
427 | static inline uint32_t | ||
428 | nvram_conf_to_access_addr(uint32_t naddr) | ||
429 | { | ||
430 | return FARX_ACCESS_NVRAM_CONF | naddr; | ||
431 | } | ||
432 | |||
433 | static inline uint32_t | ||
434 | nvram_data_to_access_addr(uint32_t naddr) | ||
435 | { | ||
436 | return FARX_ACCESS_NVRAM_DATA | naddr; | ||
437 | } | ||
438 | |||
439 | uint32_t | ||
440 | qla24xx_read_flash_dword(scsi_qla_host_t *ha, uint32_t addr) | ||
441 | { | ||
442 | int rval; | ||
443 | uint32_t cnt, data; | ||
444 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
445 | |||
446 | WRT_REG_DWORD(®->flash_addr, addr & ~FARX_DATA_FLAG); | ||
447 | /* Wait for READ cycle to complete. */ | ||
448 | rval = QLA_SUCCESS; | ||
449 | for (cnt = 3000; | ||
450 | (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) == 0 && | ||
451 | rval == QLA_SUCCESS; cnt--) { | ||
452 | if (cnt) | ||
453 | udelay(10); | ||
454 | else | ||
455 | rval = QLA_FUNCTION_TIMEOUT; | ||
456 | } | ||
457 | |||
458 | /* TODO: What happens if we time out? */ | ||
459 | data = 0xDEADDEAD; | ||
460 | if (rval == QLA_SUCCESS) | ||
461 | data = RD_REG_DWORD(®->flash_data); | ||
462 | |||
463 | return data; | ||
464 | } | ||
465 | |||
466 | uint32_t * | ||
467 | qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | ||
468 | uint32_t dwords) | ||
469 | { | ||
470 | uint32_t i; | ||
471 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
472 | |||
473 | /* Pause RISC. */ | ||
474 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); | ||
475 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
476 | |||
477 | /* Dword reads to flash. */ | ||
478 | for (i = 0; i < dwords; i++, faddr++) | ||
479 | dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, | ||
480 | flash_data_to_access_addr(faddr))); | ||
481 | |||
482 | /* Release RISC pause. */ | ||
483 | WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); | ||
484 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
485 | |||
486 | return dwptr; | ||
487 | } | ||
488 | |||
489 | int | ||
490 | qla24xx_write_flash_dword(scsi_qla_host_t *ha, uint32_t addr, uint32_t data) | ||
491 | { | ||
492 | int rval; | ||
493 | uint32_t cnt; | ||
494 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
495 | |||
496 | WRT_REG_DWORD(®->flash_data, data); | ||
497 | RD_REG_DWORD(®->flash_data); /* PCI Posting. */ | ||
498 | WRT_REG_DWORD(®->flash_addr, addr | FARX_DATA_FLAG); | ||
499 | /* Wait for Write cycle to complete. */ | ||
500 | rval = QLA_SUCCESS; | ||
501 | for (cnt = 500000; (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) && | ||
502 | rval == QLA_SUCCESS; cnt--) { | ||
503 | if (cnt) | ||
504 | udelay(10); | ||
505 | else | ||
506 | rval = QLA_FUNCTION_TIMEOUT; | ||
507 | } | ||
508 | return rval; | ||
509 | } | ||
510 | |||
511 | void | ||
512 | qla24xx_get_flash_manufacturer(scsi_qla_host_t *ha, uint8_t *man_id, | ||
513 | uint8_t *flash_id) | ||
514 | { | ||
515 | uint32_t ids; | ||
516 | |||
517 | ids = qla24xx_read_flash_dword(ha, flash_data_to_access_addr(0xd03ab)); | ||
518 | *man_id = LSB(ids); | ||
519 | *flash_id = MSB(ids); | ||
520 | } | ||
521 | |||
522 | int | ||
523 | qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, | ||
524 | uint32_t dwords) | ||
525 | { | ||
526 | int ret; | ||
527 | uint32_t liter; | ||
528 | uint32_t sec_mask, rest_addr, conf_addr; | ||
529 | uint32_t fdata; | ||
530 | uint8_t man_id, flash_id; | ||
531 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
532 | |||
533 | ret = QLA_SUCCESS; | ||
534 | |||
535 | /* Pause RISC. */ | ||
536 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); | ||
537 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
538 | |||
539 | qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); | ||
540 | DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, | ||
541 | ha->host_no, man_id, flash_id)); | ||
542 | |||
543 | conf_addr = flash_conf_to_access_addr(0x03d8); | ||
544 | switch (man_id) { | ||
545 | case 0xbf: // STT flash | ||
546 | rest_addr = 0x1fff; | ||
547 | sec_mask = 0x3e000; | ||
548 | if (flash_id == 0x80) | ||
549 | conf_addr = flash_conf_to_access_addr(0x0352); | ||
550 | break; | ||
551 | case 0x13: // ST M25P80 | ||
552 | rest_addr = 0x3fff; | ||
553 | sec_mask = 0x3c000; | ||
554 | break; | ||
555 | default: | ||
556 | // Default to 64 kb sector size | ||
557 | rest_addr = 0x3fff; | ||
558 | sec_mask = 0x3c000; | ||
559 | break; | ||
560 | } | ||
561 | |||
562 | /* Enable flash write. */ | ||
563 | WRT_REG_DWORD(®->ctrl_status, | ||
564 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); | ||
565 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
566 | |||
567 | /* Disable flash write-protection. */ | ||
568 | qla24xx_write_flash_dword(ha, flash_conf_to_access_addr(0x101), 0); | ||
569 | |||
570 | do { /* Loop once to provide quick error exit. */ | ||
571 | for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { | ||
572 | /* Are we at the beginning of a sector? */ | ||
573 | if ((faddr & rest_addr) == 0) { | ||
574 | fdata = (faddr & sec_mask) << 2; | ||
575 | ret = qla24xx_write_flash_dword(ha, conf_addr, | ||
576 | (fdata & 0xff00) |((fdata << 16) & | ||
577 | 0xff0000) | ((fdata >> 16) & 0xff)); | ||
578 | if (ret != QLA_SUCCESS) { | ||
579 | DEBUG9(printk("%s(%ld) Unable to flash " | ||
580 | "sector: address=%x.\n", __func__, | ||
581 | ha->host_no, faddr)); | ||
582 | break; | ||
583 | } | ||
584 | } | ||
585 | ret = qla24xx_write_flash_dword(ha, | ||
586 | flash_data_to_access_addr(faddr), | ||
587 | cpu_to_le32(*dwptr)); | ||
588 | if (ret != QLA_SUCCESS) { | ||
589 | DEBUG9(printk("%s(%ld) Unable to program flash " | ||
590 | "address=%x data=%x.\n", __func__, | ||
591 | ha->host_no, faddr, *dwptr)); | ||
592 | break; | ||
593 | } | ||
594 | } | ||
595 | } while (0); | ||
596 | |||
597 | /* Disable flash write. */ | ||
598 | WRT_REG_DWORD(®->ctrl_status, | ||
599 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | ||
600 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
601 | |||
602 | /* Release RISC pause. */ | ||
603 | WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); | ||
604 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
605 | |||
606 | return ret; | ||
607 | } | ||
608 | |||
609 | uint8_t * | ||
610 | qla2x00_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, | ||
611 | uint32_t bytes) | ||
612 | { | ||
613 | uint32_t i; | ||
614 | uint16_t *wptr; | ||
615 | |||
616 | /* Word reads to NVRAM via registers. */ | ||
617 | wptr = (uint16_t *)buf; | ||
618 | qla2x00_lock_nvram_access(ha); | ||
619 | for (i = 0; i < bytes >> 1; i++, naddr++) | ||
620 | wptr[i] = cpu_to_le16(qla2x00_get_nvram_word(ha, | ||
621 | naddr)); | ||
622 | qla2x00_unlock_nvram_access(ha); | ||
623 | |||
624 | return buf; | ||
625 | } | ||
626 | |||
627 | uint8_t * | ||
628 | qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, | ||
629 | uint32_t bytes) | ||
630 | { | ||
631 | uint32_t i; | ||
632 | uint32_t *dwptr; | ||
633 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
634 | |||
635 | /* Pause RISC. */ | ||
636 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); | ||
637 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
638 | |||
639 | /* Dword reads to flash. */ | ||
640 | dwptr = (uint32_t *)buf; | ||
641 | for (i = 0; i < bytes >> 2; i++, naddr++) | ||
642 | dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, | ||
643 | nvram_data_to_access_addr(naddr))); | ||
644 | |||
645 | /* Release RISC pause. */ | ||
646 | WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); | ||
647 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
648 | |||
649 | return buf; | ||
650 | } | ||
651 | |||
652 | int | ||
653 | qla2x00_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, | ||
654 | uint32_t bytes) | ||
655 | { | ||
656 | int ret, stat; | ||
657 | uint32_t i; | ||
658 | uint16_t *wptr; | ||
659 | |||
660 | ret = QLA_SUCCESS; | ||
661 | |||
662 | qla2x00_lock_nvram_access(ha); | ||
663 | |||
664 | /* Disable NVRAM write-protection. */ | ||
665 | stat = qla2x00_clear_nvram_protection(ha); | ||
666 | |||
667 | wptr = (uint16_t *)buf; | ||
668 | for (i = 0; i < bytes >> 1; i++, naddr++) { | ||
669 | qla2x00_write_nvram_word(ha, naddr, | ||
670 | cpu_to_le16(*wptr)); | ||
671 | wptr++; | ||
672 | } | ||
673 | |||
674 | /* Enable NVRAM write-protection. */ | ||
675 | qla2x00_set_nvram_protection(ha, stat); | ||
676 | |||
677 | qla2x00_unlock_nvram_access(ha); | ||
678 | |||
679 | return ret; | ||
680 | } | ||
681 | |||
682 | int | ||
683 | qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, | ||
684 | uint32_t bytes) | ||
685 | { | ||
686 | int ret; | ||
687 | uint32_t i; | ||
688 | uint32_t *dwptr; | ||
689 | struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; | ||
690 | |||
691 | ret = QLA_SUCCESS; | ||
692 | |||
693 | /* Pause RISC. */ | ||
694 | WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); | ||
695 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
696 | |||
697 | /* Enable flash write. */ | ||
698 | WRT_REG_DWORD(®->ctrl_status, | ||
699 | RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); | ||
700 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
701 | |||
702 | /* Disable NVRAM write-protection. */ | ||
703 | qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101), | ||
704 | 0); | ||
705 | qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101), | ||
706 | 0); | ||
707 | |||
708 | /* Dword writes to flash. */ | ||
709 | dwptr = (uint32_t *)buf; | ||
710 | for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) { | ||
711 | ret = qla24xx_write_flash_dword(ha, | ||
712 | nvram_data_to_access_addr(naddr), | ||
713 | cpu_to_le32(*dwptr)); | ||
714 | if (ret != QLA_SUCCESS) { | ||
715 | DEBUG9(printk("%s(%ld) Unable to program " | ||
716 | "nvram address=%x data=%x.\n", __func__, | ||
717 | ha->host_no, naddr, *dwptr)); | ||
718 | break; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | /* Enable NVRAM write-protection. */ | ||
723 | qla24xx_write_flash_dword(ha, nvram_conf_to_access_addr(0x101), | ||
724 | 0x8c); | ||
725 | |||
726 | /* Disable flash write. */ | ||
727 | WRT_REG_DWORD(®->ctrl_status, | ||
728 | RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); | ||
729 | RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ | ||
730 | |||
731 | /* Release RISC pause. */ | ||
732 | WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); | ||
733 | RD_REG_DWORD(®->hccr); /* PCI Posting. */ | ||
734 | |||
735 | return ret; | ||
736 | } | ||