aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_sup.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_sup.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_sup.c296
1 files changed, 296 insertions, 0 deletions
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
new file mode 100644
index 000000000000..0e75fbb77b6b
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -0,0 +1,296 @@
1/******************************************************************************
2 * QLOGIC LINUX SOFTWARE
3 *
4 * QLogic ISP2x00 device driver for Linux 2.6.x
5 * Copyright (C) 2003-2004 QLogic Corporation
6 * (www.qlogic.com)
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 ******************************************************************************/
19
20#include "qla_def.h"
21
22#include <linux/delay.h>
23#include <asm/uaccess.h>
24
25static uint16_t qla2x00_nvram_request(scsi_qla_host_t *, uint32_t);
26static void qla2x00_nv_deselect(scsi_qla_host_t *);
27static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);
28
29/*
30 * NVRAM support routines
31 */
32
33/**
34 * qla2x00_lock_nvram_access() -
35 * @ha: HA context
36 */
37void
38qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
39{
40 uint16_t data;
41 device_reg_t __iomem *reg = ha->iobase;
42
43 if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) {
44 data = RD_REG_WORD(&reg->nvram);
45 while (data & NVR_BUSY) {
46 udelay(100);
47 data = RD_REG_WORD(&reg->nvram);
48 }
49
50 /* Lock resource */
51 WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0x1);
52 RD_REG_WORD(&reg->u.isp2300.host_semaphore);
53 udelay(5);
54 data = RD_REG_WORD(&reg->u.isp2300.host_semaphore);
55 while ((data & BIT_0) == 0) {
56 /* Lock failed */
57 udelay(100);
58 WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0x1);
59 RD_REG_WORD(&reg->u.isp2300.host_semaphore);
60 udelay(5);
61 data = RD_REG_WORD(&reg->u.isp2300.host_semaphore);
62 }
63 }
64}
65
66/**
67 * qla2x00_unlock_nvram_access() -
68 * @ha: HA context
69 */
70void
71qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
72{
73 device_reg_t __iomem *reg = ha->iobase;
74
75 if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) {
76 WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0);
77 RD_REG_WORD(&reg->u.isp2300.host_semaphore);
78 }
79}
80
81/**
82 * qla2x00_release_nvram_protection() -
83 * @ha: HA context
84 */
85void
86qla2x00_release_nvram_protection(scsi_qla_host_t *ha)
87{
88 device_reg_t *reg;
89 uint32_t word;
90
91 reg = ha->iobase;
92
93 /* Release NVRAM write protection. */
94 if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
95 /* Write enable. */
96 qla2x00_nv_write(ha, NVR_DATA_OUT);
97 qla2x00_nv_write(ha, 0);
98 qla2x00_nv_write(ha, 0);
99 for (word = 0; word < 8; word++)
100 qla2x00_nv_write(ha, NVR_DATA_OUT);
101
102 qla2x00_nv_deselect(ha);
103
104 /* Enable protection register. */
105 qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
106 qla2x00_nv_write(ha, NVR_PR_ENABLE);
107 qla2x00_nv_write(ha, NVR_PR_ENABLE);
108 for (word = 0; word < 8; word++)
109 qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
110
111 qla2x00_nv_deselect(ha);
112
113 /* Clear protection register (ffff is cleared). */
114 qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
115 qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
116 qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
117 for (word = 0; word < 8; word++)
118 qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
119
120 qla2x00_nv_deselect(ha);
121
122 /* Wait for NVRAM to become ready. */
123 WRT_REG_WORD(&reg->nvram, NVR_SELECT);
124 do {
125 NVRAM_DELAY();
126 word = RD_REG_WORD(&reg->nvram);
127 } while ((word & NVR_DATA_IN) == 0);
128 }
129}
130
131/**
132 * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the
133 * request routine to get the word from NVRAM.
134 * @ha: HA context
135 * @addr: Address in NVRAM to read
136 *
137 * Returns the word read from nvram @addr.
138 */
139uint16_t
140qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
141{
142 uint16_t data;
143 uint32_t nv_cmd;
144
145 nv_cmd = addr << 16;
146 nv_cmd |= NV_READ_OP;
147 data = qla2x00_nvram_request(ha, nv_cmd);
148
149 return (data);
150}
151
152/**
153 * qla2x00_write_nvram_word() - Write NVRAM data.
154 * @ha: HA context
155 * @addr: Address in NVRAM to write
156 * @data: word to program
157 */
158void
159qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
160{
161 int count;
162 uint16_t word;
163 uint32_t nv_cmd;
164 device_reg_t __iomem *reg = ha->iobase;
165
166 qla2x00_nv_write(ha, NVR_DATA_OUT);
167 qla2x00_nv_write(ha, 0);
168 qla2x00_nv_write(ha, 0);
169
170 for (word = 0; word < 8; word++)
171 qla2x00_nv_write(ha, NVR_DATA_OUT);
172
173 qla2x00_nv_deselect(ha);
174
175 /* Write data */
176 nv_cmd = (addr << 16) | NV_WRITE_OP;
177 nv_cmd |= data;
178 nv_cmd <<= 5;
179 for (count = 0; count < 27; count++) {
180 if (nv_cmd & BIT_31)
181 qla2x00_nv_write(ha, NVR_DATA_OUT);
182 else
183 qla2x00_nv_write(ha, 0);
184
185 nv_cmd <<= 1;
186 }
187
188 qla2x00_nv_deselect(ha);
189
190 /* Wait for NVRAM to become ready */
191 WRT_REG_WORD(&reg->nvram, NVR_SELECT);
192 do {
193 NVRAM_DELAY();
194 word = RD_REG_WORD(&reg->nvram);
195 } while ((word & NVR_DATA_IN) == 0);
196
197 qla2x00_nv_deselect(ha);
198
199 /* Disable writes */
200 qla2x00_nv_write(ha, NVR_DATA_OUT);
201 for (count = 0; count < 10; count++)
202 qla2x00_nv_write(ha, 0);
203
204 qla2x00_nv_deselect(ha);
205}
206
207/**
208 * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from
209 * NVRAM.
210 * @ha: HA context
211 * @nv_cmd: NVRAM command
212 *
213 * Bit definitions for NVRAM command:
214 *
215 * Bit 26 = start bit
216 * Bit 25, 24 = opcode
217 * Bit 23-16 = address
218 * Bit 15-0 = write data
219 *
220 * Returns the word read from nvram @addr.
221 */
222static uint16_t
223qla2x00_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd)
224{
225 uint8_t cnt;
226 device_reg_t __iomem *reg = ha->iobase;
227 uint16_t data = 0;
228 uint16_t reg_data;
229
230 /* Send command to NVRAM. */
231 nv_cmd <<= 5;
232 for (cnt = 0; cnt < 11; cnt++) {
233 if (nv_cmd & BIT_31)
234 qla2x00_nv_write(ha, NVR_DATA_OUT);
235 else
236 qla2x00_nv_write(ha, 0);
237 nv_cmd <<= 1;
238 }
239
240 /* Read data from NVRAM. */
241 for (cnt = 0; cnt < 16; cnt++) {
242 WRT_REG_WORD(&reg->nvram, NVR_SELECT | NVR_CLOCK);
243 NVRAM_DELAY();
244 data <<= 1;
245 reg_data = RD_REG_WORD(&reg->nvram);
246 if (reg_data & NVR_DATA_IN)
247 data |= BIT_0;
248 WRT_REG_WORD(&reg->nvram, NVR_SELECT);
249 RD_REG_WORD(&reg->nvram); /* PCI Posting. */
250 NVRAM_DELAY();
251 }
252
253 /* Deselect chip. */
254 WRT_REG_WORD(&reg->nvram, NVR_DESELECT);
255 RD_REG_WORD(&reg->nvram); /* PCI Posting. */
256 NVRAM_DELAY();
257
258 return (data);
259}
260
261/**
262 * qla2x00_nv_write() - Clean NVRAM operations.
263 * @ha: HA context
264 */
265static void
266qla2x00_nv_deselect(scsi_qla_host_t *ha)
267{
268 device_reg_t __iomem *reg = ha->iobase;
269
270 WRT_REG_WORD(&reg->nvram, NVR_DESELECT);
271 RD_REG_WORD(&reg->nvram); /* PCI Posting. */
272 NVRAM_DELAY();
273}
274
275/**
276 * qla2x00_nv_write() - Prepare for NVRAM read/write operation.
277 * @ha: HA context
278 * @data: Serial interface selector
279 */
280static void
281qla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data)
282{
283 device_reg_t __iomem *reg = ha->iobase;
284
285 WRT_REG_WORD(&reg->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
286 RD_REG_WORD(&reg->nvram); /* PCI Posting. */
287 NVRAM_DELAY();
288 WRT_REG_WORD(&reg->nvram, data | NVR_SELECT| NVR_CLOCK |
289 NVR_WRT_ENABLE);
290 RD_REG_WORD(&reg->nvram); /* PCI Posting. */
291 NVRAM_DELAY();
292 WRT_REG_WORD(&reg->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
293 RD_REG_WORD(&reg->nvram); /* PCI Posting. */
294 NVRAM_DELAY();
295}
296