1 /******************************************************************************
2 * QLOGIC LINUX SOFTWARE
4 * QLogic ISP2x00 device driver for Linux 2.6.x
5 * Copyright (C) 2003-2004 QLogic Corporation
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
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.
18 ******************************************************************************/
22 #include <linux/delay.h>
23 #include <asm/uaccess.h>
25 static uint16_t qla2x00_nvram_request(scsi_qla_host_t
*, uint32_t);
26 static void qla2x00_nv_deselect(scsi_qla_host_t
*);
27 static void qla2x00_nv_write(scsi_qla_host_t
*, uint16_t);
30 * NVRAM support routines
34 * qla2x00_lock_nvram_access() -
38 qla2x00_lock_nvram_access(scsi_qla_host_t
*ha
)
41 device_reg_t __iomem
*reg
= ha
->iobase
;
43 if (!IS_QLA2100(ha
) && !IS_QLA2200(ha
) && !IS_QLA2300(ha
)) {
44 data
= RD_REG_WORD(®
->nvram
);
45 while (data
& NVR_BUSY
) {
47 data
= RD_REG_WORD(®
->nvram
);
51 WRT_REG_WORD(®
->u
.isp2300
.host_semaphore
, 0x1);
52 RD_REG_WORD(®
->u
.isp2300
.host_semaphore
);
54 data
= RD_REG_WORD(®
->u
.isp2300
.host_semaphore
);
55 while ((data
& BIT_0
) == 0) {
58 WRT_REG_WORD(®
->u
.isp2300
.host_semaphore
, 0x1);
59 RD_REG_WORD(®
->u
.isp2300
.host_semaphore
);
61 data
= RD_REG_WORD(®
->u
.isp2300
.host_semaphore
);
67 * qla2x00_unlock_nvram_access() -
71 qla2x00_unlock_nvram_access(scsi_qla_host_t
*ha
)
73 device_reg_t __iomem
*reg
= ha
->iobase
;
75 if (!IS_QLA2100(ha
) && !IS_QLA2200(ha
) && !IS_QLA2300(ha
)) {
76 WRT_REG_WORD(®
->u
.isp2300
.host_semaphore
, 0);
77 RD_REG_WORD(®
->u
.isp2300
.host_semaphore
);
82 * qla2x00_release_nvram_protection() -
86 qla2x00_release_nvram_protection(scsi_qla_host_t
*ha
)
88 device_reg_t __iomem
*reg
;
93 /* Release NVRAM write protection. */
94 if (IS_QLA2322(ha
) || IS_QLA6322(ha
)) {
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
);
102 qla2x00_nv_deselect(ha
);
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
);
111 qla2x00_nv_deselect(ha
);
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
);
120 qla2x00_nv_deselect(ha
);
122 /* Wait for NVRAM to become ready. */
123 WRT_REG_WORD(®
->nvram
, NVR_SELECT
);
126 word
= RD_REG_WORD(®
->nvram
);
127 } while ((word
& NVR_DATA_IN
) == 0);
132 * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the
133 * request routine to get the word from NVRAM.
135 * @addr: Address in NVRAM to read
137 * Returns the word read from nvram @addr.
140 qla2x00_get_nvram_word(scsi_qla_host_t
*ha
, uint32_t addr
)
146 nv_cmd
|= NV_READ_OP
;
147 data
= qla2x00_nvram_request(ha
, nv_cmd
);
153 * qla2x00_write_nvram_word() - Write NVRAM data.
155 * @addr: Address in NVRAM to write
156 * @data: word to program
159 qla2x00_write_nvram_word(scsi_qla_host_t
*ha
, uint32_t addr
, uint16_t data
)
164 device_reg_t __iomem
*reg
= ha
->iobase
;
166 qla2x00_nv_write(ha
, NVR_DATA_OUT
);
167 qla2x00_nv_write(ha
, 0);
168 qla2x00_nv_write(ha
, 0);
170 for (word
= 0; word
< 8; word
++)
171 qla2x00_nv_write(ha
, NVR_DATA_OUT
);
173 qla2x00_nv_deselect(ha
);
176 nv_cmd
= (addr
<< 16) | NV_WRITE_OP
;
179 for (count
= 0; count
< 27; count
++) {
181 qla2x00_nv_write(ha
, NVR_DATA_OUT
);
183 qla2x00_nv_write(ha
, 0);
188 qla2x00_nv_deselect(ha
);
190 /* Wait for NVRAM to become ready */
191 WRT_REG_WORD(®
->nvram
, NVR_SELECT
);
194 word
= RD_REG_WORD(®
->nvram
);
195 } while ((word
& NVR_DATA_IN
) == 0);
197 qla2x00_nv_deselect(ha
);
200 qla2x00_nv_write(ha
, NVR_DATA_OUT
);
201 for (count
= 0; count
< 10; count
++)
202 qla2x00_nv_write(ha
, 0);
204 qla2x00_nv_deselect(ha
);
208 * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from
211 * @nv_cmd: NVRAM command
213 * Bit definitions for NVRAM command:
216 * Bit 25, 24 = opcode
217 * Bit 23-16 = address
218 * Bit 15-0 = write data
220 * Returns the word read from nvram @addr.
223 qla2x00_nvram_request(scsi_qla_host_t
*ha
, uint32_t nv_cmd
)
226 device_reg_t __iomem
*reg
= ha
->iobase
;
230 /* Send command to NVRAM. */
232 for (cnt
= 0; cnt
< 11; cnt
++) {
234 qla2x00_nv_write(ha
, NVR_DATA_OUT
);
236 qla2x00_nv_write(ha
, 0);
240 /* Read data from NVRAM. */
241 for (cnt
= 0; cnt
< 16; cnt
++) {
242 WRT_REG_WORD(®
->nvram
, NVR_SELECT
| NVR_CLOCK
);
245 reg_data
= RD_REG_WORD(®
->nvram
);
246 if (reg_data
& NVR_DATA_IN
)
248 WRT_REG_WORD(®
->nvram
, NVR_SELECT
);
249 RD_REG_WORD(®
->nvram
); /* PCI Posting. */
254 WRT_REG_WORD(®
->nvram
, NVR_DESELECT
);
255 RD_REG_WORD(®
->nvram
); /* PCI Posting. */
262 * qla2x00_nv_write() - Clean NVRAM operations.
266 qla2x00_nv_deselect(scsi_qla_host_t
*ha
)
268 device_reg_t __iomem
*reg
= ha
->iobase
;
270 WRT_REG_WORD(®
->nvram
, NVR_DESELECT
);
271 RD_REG_WORD(®
->nvram
); /* PCI Posting. */
276 * qla2x00_nv_write() - Prepare for NVRAM read/write operation.
278 * @data: Serial interface selector
281 qla2x00_nv_write(scsi_qla_host_t
*ha
, uint16_t data
)
283 device_reg_t __iomem
*reg
= ha
->iobase
;
285 WRT_REG_WORD(®
->nvram
, data
| NVR_SELECT
| NVR_WRT_ENABLE
);
286 RD_REG_WORD(®
->nvram
); /* PCI Posting. */
288 WRT_REG_WORD(®
->nvram
, data
| NVR_SELECT
| NVR_CLOCK
|
290 RD_REG_WORD(®
->nvram
); /* PCI Posting. */
292 WRT_REG_WORD(®
->nvram
, data
| NVR_SELECT
| NVR_WRT_ENABLE
);
293 RD_REG_WORD(®
->nvram
); /* PCI Posting. */