patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / scsi / qla2xxx / qla_sup.c
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_os.h"
21 #include "qla_def.h"
22
23 static uint16_t qla2x00_nvram_request(scsi_qla_host_t *, uint32_t);
24 static void qla2x00_nv_deselect(scsi_qla_host_t *);
25 static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);
26
27
28 /*
29  * NVRAM support routines
30  */
31
32 /**
33  * qla2x00_lock_nvram_access() - 
34  * @ha: HA context
35  */
36 void
37 qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
38 {
39         uint16_t data;
40         device_reg_t *reg;
41
42         reg = ha->iobase;
43
44         if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) {
45                 data = RD_REG_WORD(&reg->nvram);
46                 while (data & NVR_BUSY) {
47                         udelay(100);
48                         data = RD_REG_WORD(&reg->nvram);
49                 }
50
51                 /* Lock resource */
52                 WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0x1);
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                         udelay(5);
60                         data = RD_REG_WORD(&reg->u.isp2300.host_semaphore);
61                 }
62         }
63 }
64
65 /**
66  * qla2x00_unlock_nvram_access() - 
67  * @ha: HA context
68  */
69 void
70 qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
71 {
72         device_reg_t *reg;
73
74         reg = ha->iobase;
75
76         if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
77                 WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0);
78 }
79
80 /**
81  * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the
82  *      request routine to get the word from NVRAM.
83  * @ha: HA context
84  * @addr: Address in NVRAM to read
85  *
86  * Returns the word read from nvram @addr.
87  */
88 uint16_t
89 qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
90 {
91         uint16_t        data;
92         uint32_t        nv_cmd;
93
94         nv_cmd = addr << 16;
95         nv_cmd |= NV_READ_OP;
96         data = qla2x00_nvram_request(ha, nv_cmd);
97
98         return (data);
99 }
100
101 /**
102  * qla2x00_write_nvram_word() - Write NVRAM data.
103  * @ha: HA context
104  * @addr: Address in NVRAM to write
105  * @data: word to program
106  */
107 void
108 qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
109 {
110         int count;
111         uint16_t word;
112         uint32_t nv_cmd;
113         device_reg_t *reg = ha->iobase;
114
115         qla2x00_nv_write(ha, NVR_DATA_OUT);
116         qla2x00_nv_write(ha, 0);
117         qla2x00_nv_write(ha, 0);
118
119         for (word = 0; word < 8; word++)
120                 qla2x00_nv_write(ha, NVR_DATA_OUT);
121
122         qla2x00_nv_deselect(ha);
123
124         /* Erase Location */
125         nv_cmd = (addr << 16) | NV_ERASE_OP;
126         nv_cmd <<= 5;
127         for (count = 0; count < 11; count++) {
128                 if (nv_cmd & BIT_31)
129                         qla2x00_nv_write(ha, NVR_DATA_OUT);
130                 else
131                         qla2x00_nv_write(ha, 0);
132
133                 nv_cmd <<= 1;
134         }
135
136         qla2x00_nv_deselect(ha);
137
138         /* Wait for Erase to Finish */
139         WRT_REG_WORD(&reg->nvram, NVR_SELECT);
140         do {
141                 NVRAM_DELAY();
142                 word = RD_REG_WORD(&reg->nvram);
143         } while ((word & NVR_DATA_IN) == 0);
144
145         qla2x00_nv_deselect(ha);
146
147         /* Write data */
148         nv_cmd = (addr << 16) | NV_WRITE_OP;
149         nv_cmd |= data;
150         nv_cmd <<= 5;
151         for (count = 0; count < 27; count++) {
152                 if (nv_cmd & BIT_31)
153                         qla2x00_nv_write(ha, NVR_DATA_OUT);
154                 else
155                         qla2x00_nv_write(ha, 0);
156
157                 nv_cmd <<= 1;
158         }
159
160         qla2x00_nv_deselect(ha);
161
162         /* Wait for NVRAM to become ready */
163         WRT_REG_WORD(&reg->nvram, NVR_SELECT);
164         do {
165                 NVRAM_DELAY();
166                 word = RD_REG_WORD(&reg->nvram);
167         } while ((word & NVR_DATA_IN) == 0);
168
169         qla2x00_nv_deselect(ha);
170
171         /* Disable writes */
172         qla2x00_nv_write(ha, NVR_DATA_OUT);
173         for (count = 0; count < 10; count++)
174                 qla2x00_nv_write(ha, 0);
175
176         qla2x00_nv_deselect(ha);
177 }
178
179 /**
180  * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from
181  *      NVRAM.
182  * @ha: HA context
183  * @nv_cmd: NVRAM command
184  *
185  * Bit definitions for NVRAM command:
186  *
187  *      Bit 26     = start bit
188  *      Bit 25, 24 = opcode
189  *      Bit 23-16  = address
190  *      Bit 15-0   = write data
191  *
192  * Returns the word read from nvram @addr.
193  */
194 static uint16_t
195 qla2x00_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd)
196 {
197         uint8_t         cnt;
198         device_reg_t    *reg = ha->iobase;
199         uint16_t        data = 0;
200         uint16_t        reg_data;
201
202         /* Send command to NVRAM. */
203         nv_cmd <<= 5;
204         for (cnt = 0; cnt < 11; cnt++) {
205                 if (nv_cmd & BIT_31)
206                         qla2x00_nv_write(ha, NVR_DATA_OUT);
207                 else
208                         qla2x00_nv_write(ha, 0);
209                 nv_cmd <<= 1;
210         }
211
212         /* Read data from NVRAM. */
213         for (cnt = 0; cnt < 16; cnt++) {
214                 WRT_REG_WORD(&reg->nvram, NVR_SELECT | NVR_CLOCK);
215                 NVRAM_DELAY();
216                 data <<= 1;
217                 reg_data = RD_REG_WORD(&reg->nvram);
218                 if (reg_data & NVR_DATA_IN)
219                         data |= BIT_0;
220                 WRT_REG_WORD(&reg->nvram, NVR_SELECT);
221                 NVRAM_DELAY();
222                 RD_REG_WORD(&reg->nvram);       /* PCI Posting. */
223         }
224
225         /* Deselect chip. */
226         WRT_REG_WORD(&reg->nvram, NVR_DESELECT);
227         NVRAM_DELAY();
228         RD_REG_WORD(&reg->nvram);               /* PCI Posting. */
229
230         return (data);
231 }
232
233 /**
234  * qla2x00_nv_write() - Clean NVRAM operations.
235  * @ha: HA context
236  */
237 void
238 qla2x00_nv_deselect(scsi_qla_host_t *ha)
239 {
240         device_reg_t *reg = ha->iobase;
241
242         WRT_REG_WORD(&reg->nvram, NVR_DESELECT);
243         NVRAM_DELAY();
244         RD_REG_WORD(&reg->nvram);               /* PCI Posting. */
245 }
246
247 /**
248  * qla2x00_nv_write() - Prepare for NVRAM read/write operation.
249  * @ha: HA context
250  * @data: Serial interface selector
251  */
252 void
253 qla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data)
254 {
255         device_reg_t *reg = ha->iobase;
256
257         WRT_REG_WORD(&reg->nvram, data | NVR_SELECT);
258         NVRAM_DELAY();
259         RD_REG_WORD(&reg->nvram);               /* PCI Posting. */
260         WRT_REG_WORD(&reg->nvram, data | NVR_SELECT | NVR_CLOCK);
261         NVRAM_DELAY();
262         RD_REG_WORD(&reg->nvram);               /* PCI Posting. */
263         WRT_REG_WORD(&reg->nvram, data | NVR_SELECT);
264         NVRAM_DELAY();
265         RD_REG_WORD(&reg->nvram);               /* PCI Posting. */
266 }
267