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