blob: ee4b79eb59ce9196f0cd05dde23bda940dc51206 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Andrew Vasquezfa90c542005-10-27 11:10:08 -07002 * QLogic Fibre Channel HBA Driver
3 * Copyright (c) 2003-2005 QLogic Corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Andrew Vasquezfa90c542005-10-27 11:10:08 -07005 * See LICENSE.qla2xxx for copyright and licensing details.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 */
7#include "qla_def.h"
8
9#include <linux/delay.h>
Andrew Vasquez0107109e2005-07-06 10:31:37 -070010#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070011
12#include "qla_devtbl.h"
13
14/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
15#ifndef EXT_IS_LUN_BIT_SET
16#define EXT_IS_LUN_BIT_SET(P,L) \
17 (((P)->mask[L/8] & (0x80 >> (L%8)))?1:0)
18#define EXT_SET_LUN_BIT(P,L) \
19 ((P)->mask[L/8] |= (0x80 >> (L%8)))
20#endif
21
22/*
23* QLogic ISP2x00 Hardware Support Function Prototypes.
24*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070025static int qla2x00_isp_firmware(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070026static void qla2x00_resize_request_q(scsi_qla_host_t *);
27static int qla2x00_setup_chip(scsi_qla_host_t *);
28static void qla2x00_init_response_q_entries(scsi_qla_host_t *);
29static int qla2x00_init_rings(scsi_qla_host_t *);
30static int qla2x00_fw_ready(scsi_qla_host_t *);
31static int qla2x00_configure_hba(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032static int qla2x00_configure_loop(scsi_qla_host_t *);
33static int qla2x00_configure_local_loop(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070034static int qla2x00_configure_fabric(scsi_qla_host_t *);
35static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
36static int qla2x00_device_resync(scsi_qla_host_t *);
37static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
38 uint16_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40static int qla2x00_restart_isp(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Adrian Bunk413975a2006-06-30 02:33:06 -070042static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev);
43
Linus Torvalds1da177e2005-04-16 15:20:36 -070044/****************************************************************************/
45/* QLogic ISP2x00 Hardware Support Functions. */
46/****************************************************************************/
47
48/*
49* qla2x00_initialize_adapter
50* Initialize board.
51*
52* Input:
53* ha = adapter block pointer.
54*
55* Returns:
56* 0 = success
57*/
58int
59qla2x00_initialize_adapter(scsi_qla_host_t *ha)
60{
61 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
63 /* Clear adapter flags. */
64 ha->flags.online = 0;
65 ha->flags.reset_active = 0;
66 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
67 atomic_set(&ha->loop_state, LOOP_DOWN);
Andrew Vasquez26032212007-01-29 10:22:23 -080068 ha->device_flags = DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 ha->dpc_flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 ha->flags.management_server_logged_in = 0;
71 ha->marker_needed = 0;
72 ha->mbx_flags = 0;
73 ha->isp_abort_cnt = 0;
74 ha->beacon_blink_led = 0;
Andrew Vasquezcca53352005-08-26 19:08:30 -070075 set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Andrew Vasquez0107109e2005-07-06 10:31:37 -070077 qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
Andrew Vasquezabbd8872005-07-06 10:30:05 -070078 rval = ha->isp_ops.pci_config(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 if (rval) {
80 DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n",
81 ha->host_no));
82 return (rval);
83 }
84
Andrew Vasquezabbd8872005-07-06 10:30:05 -070085 ha->isp_ops.reset_chip(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070086
Andrew Vasquez30c47662007-01-29 10:22:21 -080087 ha->isp_ops.get_flash_version(ha, ha->request_ring);
88
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
Andrew Vasquez0107109e2005-07-06 10:31:37 -070090
Andrew Vasquezabbd8872005-07-06 10:30:05 -070091 ha->isp_ops.nvram_config(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Andrew Vasquezd4c760c2006-06-23 16:10:39 -070093 if (ha->flags.disable_serdes) {
94 /* Mask HBA via NVRAM settings? */
95 qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
96 "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
97 ha->port_name[0], ha->port_name[1],
98 ha->port_name[2], ha->port_name[3],
99 ha->port_name[4], ha->port_name[5],
100 ha->port_name[6], ha->port_name[7]);
101 return QLA_FUNCTION_FAILED;
102 }
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
105
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800106 if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
107 rval = ha->isp_ops.chip_diag(ha);
108 if (rval)
109 return (rval);
110 rval = qla2x00_setup_chip(ha);
111 if (rval)
112 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 }
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800114 rval = qla2x00_init_rings(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115
116 return (rval);
117}
118
119/**
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700120 * qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 * @ha: HA context
122 *
123 * Returns 0 on success.
124 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700125int
126qla2100_pci_config(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700128 uint16_t w, mwi;
Adam Kropelin27b2f672005-09-16 19:28:20 -0700129 uint32_t d;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700130 unsigned long flags;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700131 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 pci_set_master(ha->pdev);
134 mwi = 0;
135 if (pci_set_mwi(ha->pdev))
136 mwi = PCI_COMMAND_INVALIDATE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
139 w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
141
142 /* Reset expansion ROM address decode enable */
Adam Kropelin27b2f672005-09-16 19:28:20 -0700143 pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
144 d &= ~PCI_ROM_ADDRESS_ENABLE;
145 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700147 /* Get PCI bus information. */
148 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700149 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700150 spin_unlock_irqrestore(&ha->hardware_lock, flags);
151
152 return QLA_SUCCESS;
153}
154
155/**
156 * qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
157 * @ha: HA context
158 *
159 * Returns 0 on success.
160 */
161int
162qla2300_pci_config(scsi_qla_host_t *ha)
163{
164 uint16_t w, mwi;
Adam Kropelin27b2f672005-09-16 19:28:20 -0700165 uint32_t d;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700166 unsigned long flags = 0;
167 uint32_t cnt;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700168 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700169
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700170 pci_set_master(ha->pdev);
171 mwi = 0;
172 if (pci_set_mwi(ha->pdev))
173 mwi = PCI_COMMAND_INVALIDATE;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700174
175 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
176 w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
177
178 if (IS_QLA2322(ha) || IS_QLA6322(ha))
179 w &= ~PCI_COMMAND_INTX_DISABLE;
180
181 /*
182 * If this is a 2300 card and not 2312, reset the
183 * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
184 * the 2310 also reports itself as a 2300 so we need to get the
185 * fb revision level -- a 6 indicates it really is a 2300 and
186 * not a 2310.
187 */
188 if (IS_QLA2300(ha)) {
189 spin_lock_irqsave(&ha->hardware_lock, flags);
190
191 /* Pause RISC. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700192 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700193 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700194 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700195 break;
196
197 udelay(10);
198 }
199
200 /* Select FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700201 WRT_REG_WORD(&reg->ctrl_status, 0x20);
202 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700203
204 /* Get the fb rev level */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700205 ha->fb_rev = RD_FB_CMD_REG(ha, reg);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700206
207 if (ha->fb_rev == FPM_2300)
208 w &= ~PCI_COMMAND_INVALIDATE;
209
210 /* Deselect FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700211 WRT_REG_WORD(&reg->ctrl_status, 0x0);
212 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700213
214 /* Release RISC module. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700215 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700216 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700217 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700218 break;
219
220 udelay(10);
221 }
222
223 spin_unlock_irqrestore(&ha->hardware_lock, flags);
224 }
225 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
226
227 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
228
229 /* Reset expansion ROM address decode enable */
Adam Kropelin27b2f672005-09-16 19:28:20 -0700230 pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
231 d &= ~PCI_ROM_ADDRESS_ENABLE;
232 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700233
234 /* Get PCI bus information. */
235 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700236 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700237 spin_unlock_irqrestore(&ha->hardware_lock, flags);
238
239 return QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240}
241
242/**
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700243 * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
244 * @ha: HA context
245 *
246 * Returns 0 on success.
247 */
248int
249qla24xx_pci_config(scsi_qla_host_t *ha)
250{
251 uint16_t w, mwi;
Adam Kropelin27b2f672005-09-16 19:28:20 -0700252 uint32_t d;
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700253 unsigned long flags = 0;
254 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
255 int pcix_cmd_reg, pcie_dctl_reg;
256
257 pci_set_master(ha->pdev);
258 mwi = 0;
259 if (pci_set_mwi(ha->pdev))
260 mwi = PCI_COMMAND_INVALIDATE;
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700261
262 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
263 w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
264 w &= ~PCI_COMMAND_INTX_DISABLE;
265 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
266
267 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
268
269 /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
270 pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
271 if (pcix_cmd_reg) {
272 uint16_t pcix_cmd;
273
274 pcix_cmd_reg += PCI_X_CMD;
275 pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
276 pcix_cmd &= ~PCI_X_CMD_MAX_READ;
277 pcix_cmd |= 0x0008;
278 pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
279 }
280
281 /* PCIe -- adjust Maximum Read Request Size (2048). */
282 pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
283 if (pcie_dctl_reg) {
284 uint16_t pcie_dctl;
285
286 pcie_dctl_reg += PCI_EXP_DEVCTL;
287 pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
288 pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
289 pcie_dctl |= 0x4000;
290 pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
291 }
292
293 /* Reset expansion ROM address decode enable */
Adam Kropelin27b2f672005-09-16 19:28:20 -0700294 pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
295 d &= ~PCI_ROM_ADDRESS_ENABLE;
296 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700297
Andrew Vasqueza8488ab2007-01-29 10:22:19 -0800298 pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision);
299
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700300 /* Get PCI bus information. */
301 spin_lock_irqsave(&ha->hardware_lock, flags);
302 ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
303 spin_unlock_irqrestore(&ha->hardware_lock, flags);
304
305 return QLA_SUCCESS;
306}
307
308/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 * qla2x00_isp_firmware() - Choose firmware image.
310 * @ha: HA context
311 *
312 * Returns 0 on success.
313 */
314static int
315qla2x00_isp_firmware(scsi_qla_host_t *ha)
316{
317 int rval;
318
319 /* Assume loading risc code */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700320 rval = QLA_FUNCTION_FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321
322 if (ha->flags.disable_risc_code_load) {
323 DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
324 ha->host_no));
325 qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
326
327 /* Verify checksum of loaded RISC code. */
Andrew Vasquez441d1072006-05-17 15:09:34 -0700328 rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 }
330
331 if (rval) {
332 DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
333 ha->host_no));
334 }
335
336 return (rval);
337}
338
339/**
340 * qla2x00_reset_chip() - Reset ISP chip.
341 * @ha: HA context
342 *
343 * Returns 0 on success.
344 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700345void
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700346qla2x00_reset_chip(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 unsigned long flags = 0;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700349 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 uint32_t cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 uint16_t cmd;
352
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700353 ha->isp_ops.disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354
355 spin_lock_irqsave(&ha->hardware_lock, flags);
356
357 /* Turn off master enable */
358 cmd = 0;
359 pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
360 cmd &= ~PCI_COMMAND_MASTER;
361 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
362
363 if (!IS_QLA2100(ha)) {
364 /* Pause RISC. */
365 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
366 if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
367 for (cnt = 0; cnt < 30000; cnt++) {
368 if ((RD_REG_WORD(&reg->hccr) &
369 HCCR_RISC_PAUSE) != 0)
370 break;
371 udelay(100);
372 }
373 } else {
374 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
375 udelay(10);
376 }
377
378 /* Select FPM registers. */
379 WRT_REG_WORD(&reg->ctrl_status, 0x20);
380 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
381
382 /* FPM Soft Reset. */
383 WRT_REG_WORD(&reg->fpm_diag_config, 0x100);
384 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
385
386 /* Toggle Fpm Reset. */
387 if (!IS_QLA2200(ha)) {
388 WRT_REG_WORD(&reg->fpm_diag_config, 0x0);
389 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
390 }
391
392 /* Select frame buffer registers. */
393 WRT_REG_WORD(&reg->ctrl_status, 0x10);
394 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
395
396 /* Reset frame buffer FIFOs. */
397 if (IS_QLA2200(ha)) {
398 WRT_FB_CMD_REG(ha, reg, 0xa000);
399 RD_FB_CMD_REG(ha, reg); /* PCI Posting. */
400 } else {
401 WRT_FB_CMD_REG(ha, reg, 0x00fc);
402
403 /* Read back fb_cmd until zero or 3 seconds max */
404 for (cnt = 0; cnt < 3000; cnt++) {
405 if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
406 break;
407 udelay(100);
408 }
409 }
410
411 /* Select RISC module registers. */
412 WRT_REG_WORD(&reg->ctrl_status, 0);
413 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
414
415 /* Reset RISC processor. */
416 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
417 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
418
419 /* Release RISC processor. */
420 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
421 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
422 }
423
424 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
425 WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);
426
427 /* Reset ISP chip. */
428 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
429
430 /* Wait for RISC to recover from reset. */
431 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
432 /*
433 * It is necessary to for a delay here since the card doesn't
434 * respond to PCI reads during a reset. On some architectures
435 * this will result in an MCA.
436 */
437 udelay(20);
438 for (cnt = 30000; cnt; cnt--) {
439 if ((RD_REG_WORD(&reg->ctrl_status) &
440 CSR_ISP_SOFT_RESET) == 0)
441 break;
442 udelay(100);
443 }
444 } else
445 udelay(10);
446
447 /* Reset RISC processor. */
448 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
449
450 WRT_REG_WORD(&reg->semaphore, 0);
451
452 /* Release RISC processor. */
453 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
454 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
455
456 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
457 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquezffb39f02006-05-17 15:09:06 -0700458 if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 udelay(100);
462 }
463 } else
464 udelay(100);
465
466 /* Turn on master enable */
467 cmd |= PCI_COMMAND_MASTER;
468 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
469
470 /* Disable RISC pause on FPM parity error. */
471 if (!IS_QLA2100(ha)) {
472 WRT_REG_WORD(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
473 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
474 }
475
476 spin_unlock_irqrestore(&ha->hardware_lock, flags);
477}
478
479/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700480 * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700481 * @ha: HA context
482 *
483 * Returns 0 on success.
484 */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700485static inline void
486qla24xx_reset_risc(scsi_qla_host_t *ha)
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700487{
488 unsigned long flags = 0;
489 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
490 uint32_t cnt, d2;
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800491 uint16_t wd;
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700492
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700493 spin_lock_irqsave(&ha->hardware_lock, flags);
494
495 /* Reset RISC. */
496 WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
497 for (cnt = 0; cnt < 30000; cnt++) {
498 if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
499 break;
500
501 udelay(10);
502 }
503
504 WRT_REG_DWORD(&reg->ctrl_status,
505 CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800506 pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700507
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800508 udelay(100);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700509 /* Wait for firmware to complete NVRAM accesses. */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700510 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
511 for (cnt = 10000 ; cnt && d2; cnt--) {
512 udelay(5);
513 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
514 barrier();
515 }
516
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800517 /* Wait for soft-reset to complete. */
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700518 d2 = RD_REG_DWORD(&reg->ctrl_status);
519 for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
520 udelay(5);
521 d2 = RD_REG_DWORD(&reg->ctrl_status);
522 barrier();
523 }
524
525 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
526 RD_REG_DWORD(&reg->hccr);
527
528 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
529 RD_REG_DWORD(&reg->hccr);
530
531 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
532 RD_REG_DWORD(&reg->hccr);
533
534 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
535 for (cnt = 6000000 ; cnt && d2; cnt--) {
536 udelay(5);
537 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
538 barrier();
539 }
540
541 spin_unlock_irqrestore(&ha->hardware_lock, flags);
542}
543
544/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700545 * qla24xx_reset_chip() - Reset ISP24xx chip.
546 * @ha: HA context
547 *
548 * Returns 0 on success.
549 */
550void
551qla24xx_reset_chip(scsi_qla_host_t *ha)
552{
553 ha->isp_ops.disable_intrs(ha);
554
555 /* Perform RISC reset. */
556 qla24xx_reset_risc(ha);
557}
558
559/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 * qla2x00_chip_diag() - Test chip for proper operation.
561 * @ha: HA context
562 *
563 * Returns 0 on success.
564 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700565int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566qla2x00_chip_diag(scsi_qla_host_t *ha)
567{
568 int rval;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700569 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 unsigned long flags = 0;
571 uint16_t data;
572 uint32_t cnt;
573 uint16_t mb[5];
574
575 /* Assume a failed state */
576 rval = QLA_FUNCTION_FAILED;
577
578 DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
579 ha->host_no, (u_long)&reg->flash_address));
580
581 spin_lock_irqsave(&ha->hardware_lock, flags);
582
583 /* Reset ISP chip. */
584 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
585
586 /*
587 * We need to have a delay here since the card will not respond while
588 * in reset causing an MCA on some architectures.
589 */
590 udelay(20);
591 data = qla2x00_debounce_register(&reg->ctrl_status);
592 for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
593 udelay(5);
594 data = RD_REG_WORD(&reg->ctrl_status);
595 barrier();
596 }
597
598 if (!cnt)
599 goto chip_diag_failed;
600
601 DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
602 ha->host_no));
603
604 /* Reset RISC processor. */
605 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
606 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
607
608 /* Workaround for QLA2312 PCI parity error */
609 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
610 data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
611 for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
612 udelay(5);
613 data = RD_MAILBOX_REG(ha, reg, 0);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700614 barrier();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 }
616 } else
617 udelay(10);
618
619 if (!cnt)
620 goto chip_diag_failed;
621
622 /* Check product ID of chip */
623 DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no));
624
625 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
626 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
627 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
628 mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
629 if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
630 mb[3] != PROD_ID_3) {
631 qla_printk(KERN_WARNING, ha,
632 "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
633
634 goto chip_diag_failed;
635 }
636 ha->product_id[0] = mb[1];
637 ha->product_id[1] = mb[2];
638 ha->product_id[2] = mb[3];
639 ha->product_id[3] = mb[4];
640
641 /* Adjust fw RISC transfer size */
642 if (ha->request_q_length > 1024)
643 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
644 else
645 ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
646 ha->request_q_length;
647
648 if (IS_QLA2200(ha) &&
649 RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
650 /* Limit firmware transfer size with a 2200A */
651 DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
652 ha->host_no));
653
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -0800654 ha->device_type |= DT_ISP2200A;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 ha->fw_transfer_size = 128;
656 }
657
658 /* Wrap Incoming Mailboxes Test. */
659 spin_unlock_irqrestore(&ha->hardware_lock, flags);
660
661 DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", ha->host_no));
662 rval = qla2x00_mbx_reg_test(ha);
663 if (rval) {
664 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
665 ha->host_no));
666 qla_printk(KERN_WARNING, ha,
667 "Failed mailbox send register test\n");
668 }
669 else {
670 /* Flag a successful rval */
671 rval = QLA_SUCCESS;
672 }
673 spin_lock_irqsave(&ha->hardware_lock, flags);
674
675chip_diag_failed:
676 if (rval)
677 DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
678 "****\n", ha->host_no));
679
680 spin_unlock_irqrestore(&ha->hardware_lock, flags);
681
682 return (rval);
683}
684
685/**
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700686 * qla24xx_chip_diag() - Test ISP24xx for proper operation.
687 * @ha: HA context
688 *
689 * Returns 0 on success.
690 */
691int
692qla24xx_chip_diag(scsi_qla_host_t *ha)
693{
694 int rval;
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700695
Andrew Vasquez88c26662005-07-08 17:59:26 -0700696 /* Perform RISC reset. */
697 qla24xx_reset_risc(ha);
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700698
699 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
700
701 rval = qla2x00_mbx_reg_test(ha);
702 if (rval) {
703 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
704 ha->host_no));
705 qla_printk(KERN_WARNING, ha,
706 "Failed mailbox send register test\n");
707 } else {
708 /* Flag a successful rval */
709 rval = QLA_SUCCESS;
710 }
711
712 return rval;
713}
714
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700715void
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700716qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
717{
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700718 int rval;
719 uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
720 eft_size;
721 dma_addr_t eft_dma;
722 void *eft;
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700723
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700724 if (ha->fw_dump) {
725 qla_printk(KERN_WARNING, ha,
726 "Firmware dump previously allocated.\n");
727 return;
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700728 }
729
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700730 ha->fw_dumped = 0;
731 fixed_size = mem_size = eft_size = 0;
732 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
733 fixed_size = sizeof(struct qla2100_fw_dump);
734 } else if (IS_QLA23XX(ha)) {
735 fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
736 mem_size = (ha->fw_memory_size - 0x11000 + 1) *
737 sizeof(uint16_t);
738 } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
739 fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
740 mem_size = (ha->fw_memory_size - 0x100000 + 1) *
741 sizeof(uint32_t);
742
743 /* Allocate memory for Extended Trace Buffer. */
744 eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
745 GFP_KERNEL);
746 if (!eft) {
747 qla_printk(KERN_WARNING, ha, "Unable to allocate "
748 "(%d KB) for EFT.\n", EFT_SIZE / 1024);
749 goto cont_alloc;
750 }
751
752 rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
753 EFT_NUM_BUFFERS);
754 if (rval) {
755 qla_printk(KERN_WARNING, ha, "Unable to initialize "
756 "EFT (%d).\n", rval);
757 dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
758 eft_dma);
759 goto cont_alloc;
760 }
761
762 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
763 EFT_SIZE / 1024);
764
765 eft_size = EFT_SIZE;
766 memset(eft, 0, eft_size);
767 ha->eft_dma = eft_dma;
768 ha->eft = eft;
769 }
770cont_alloc:
771 req_q_size = ha->request_q_length * sizeof(request_t);
772 rsp_q_size = ha->response_q_length * sizeof(response_t);
773
774 dump_size = offsetof(struct qla2xxx_fw_dump, isp);
775 dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
776 eft_size;
777
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700778 ha->fw_dump = vmalloc(dump_size);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700779 if (!ha->fw_dump) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700780 qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700781 "firmware dump!!!\n", dump_size / 1024);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700782
783 if (ha->eft) {
784 dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
785 ha->eft_dma);
786 ha->eft = NULL;
787 ha->eft_dma = 0;
788 }
789 return;
790 }
791
792 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
793 dump_size / 1024);
794
795 ha->fw_dump_len = dump_size;
796 ha->fw_dump->signature[0] = 'Q';
797 ha->fw_dump->signature[1] = 'L';
798 ha->fw_dump->signature[2] = 'G';
799 ha->fw_dump->signature[3] = 'C';
800 ha->fw_dump->version = __constant_htonl(1);
801
802 ha->fw_dump->fixed_size = htonl(fixed_size);
803 ha->fw_dump->mem_size = htonl(mem_size);
804 ha->fw_dump->req_q_size = htonl(req_q_size);
805 ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
806
807 ha->fw_dump->eft_size = htonl(eft_size);
808 ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
809 ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
810
811 ha->fw_dump->header_size =
812 htonl(offsetof(struct qla2xxx_fw_dump, isp));
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700813}
814
815/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 * qla2x00_resize_request_q() - Resize request queue given available ISP memory.
817 * @ha: HA context
818 *
819 * Returns 0 on success.
820 */
821static void
822qla2x00_resize_request_q(scsi_qla_host_t *ha)
823{
824 int rval;
825 uint16_t fw_iocb_cnt = 0;
826 uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM;
827 dma_addr_t request_dma;
828 request_t *request_ring;
829
830 /* Valid only on recent ISPs. */
831 if (IS_QLA2100(ha) || IS_QLA2200(ha))
832 return;
833
834 /* Retrieve IOCB counts available to the firmware. */
835 rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt);
836 if (rval)
837 return;
838 /* No point in continuing if current settings are sufficient. */
839 if (fw_iocb_cnt < 1024)
840 return;
841 if (ha->request_q_length >= request_q_length)
842 return;
843
844 /* Attempt to claim larger area for request queue. */
845 request_ring = dma_alloc_coherent(&ha->pdev->dev,
846 (request_q_length + 1) * sizeof(request_t), &request_dma,
847 GFP_KERNEL);
848 if (request_ring == NULL)
849 return;
850
851 /* Resize successful, report extensions. */
852 qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n",
853 (ha->fw_memory_size + 1) / 1024);
854 qla_printk(KERN_INFO, ha, "Resizing request queue depth "
855 "(%d -> %d)...\n", ha->request_q_length, request_q_length);
856
857 /* Clear old allocations. */
858 dma_free_coherent(&ha->pdev->dev,
859 (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring,
860 ha->request_dma);
861
862 /* Begin using larger queue. */
863 ha->request_q_length = request_q_length;
864 ha->request_ring = request_ring;
865 ha->request_dma = request_dma;
866}
867
868/**
869 * qla2x00_setup_chip() - Load and start RISC firmware.
870 * @ha: HA context
871 *
872 * Returns 0 on success.
873 */
874static int
875qla2x00_setup_chip(scsi_qla_host_t *ha)
876{
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700877 int rval;
878 uint32_t srisc_address = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879
880 /* Load firmware sequences */
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700881 rval = ha->isp_ops.load_risc(ha, &srisc_address);
882 if (rval == QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
884 "code.\n", ha->host_no));
885
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700886 rval = qla2x00_verify_checksum(ha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 if (rval == QLA_SUCCESS) {
888 /* Start firmware execution. */
889 DEBUG(printk("scsi(%ld): Checksum OK, start "
890 "firmware.\n", ha->host_no));
891
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700892 rval = qla2x00_execute_fw(ha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 /* Retrieve firmware information. */
894 if (rval == QLA_SUCCESS && ha->fw_major_version == 0) {
895 qla2x00_get_fw_version(ha,
896 &ha->fw_major_version,
897 &ha->fw_minor_version,
898 &ha->fw_subminor_version,
899 &ha->fw_attributes, &ha->fw_memory_size);
900 qla2x00_resize_request_q(ha);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700901
902 if (ql2xallocfwdump)
903 qla2x00_alloc_fw_dump(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 }
905 } else {
906 DEBUG2(printk(KERN_INFO
907 "scsi(%ld): ISP Firmware failed checksum.\n",
908 ha->host_no));
909 }
910 }
911
912 if (rval) {
913 DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
914 ha->host_no));
915 }
916
917 return (rval);
918}
919
920/**
921 * qla2x00_init_response_q_entries() - Initializes response queue entries.
922 * @ha: HA context
923 *
924 * Beginning of request ring has initialization control block already built
925 * by nvram config routine.
926 *
927 * Returns 0 on success.
928 */
929static void
930qla2x00_init_response_q_entries(scsi_qla_host_t *ha)
931{
932 uint16_t cnt;
933 response_t *pkt;
934
935 pkt = ha->response_ring_ptr;
936 for (cnt = 0; cnt < ha->response_q_length; cnt++) {
937 pkt->signature = RESPONSE_PROCESSED;
938 pkt++;
939 }
940
941}
942
943/**
944 * qla2x00_update_fw_options() - Read and process firmware options.
945 * @ha: HA context
946 *
947 * Returns 0 on success.
948 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700949void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950qla2x00_update_fw_options(scsi_qla_host_t *ha)
951{
952 uint16_t swing, emphasis, tx_sens, rx_sens;
953
954 memset(ha->fw_options, 0, sizeof(ha->fw_options));
955 qla2x00_get_fw_options(ha, ha->fw_options);
956
957 if (IS_QLA2100(ha) || IS_QLA2200(ha))
958 return;
959
960 /* Serial Link options. */
961 DEBUG3(printk("scsi(%ld): Serial link options:\n",
962 ha->host_no));
963 DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
964 sizeof(ha->fw_seriallink_options)));
965
966 ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
967 if (ha->fw_seriallink_options[3] & BIT_2) {
968 ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
969
970 /* 1G settings */
971 swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
972 emphasis = (ha->fw_seriallink_options[2] &
973 (BIT_4 | BIT_3)) >> 3;
974 tx_sens = ha->fw_seriallink_options[0] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700975 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 rx_sens = (ha->fw_seriallink_options[0] &
977 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
978 ha->fw_options[10] = (emphasis << 14) | (swing << 8);
979 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
980 if (rx_sens == 0x0)
981 rx_sens = 0x3;
982 ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
983 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
984 ha->fw_options[10] |= BIT_5 |
985 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
986 (tx_sens & (BIT_1 | BIT_0));
987
988 /* 2G settings */
989 swing = (ha->fw_seriallink_options[2] &
990 (BIT_7 | BIT_6 | BIT_5)) >> 5;
991 emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
992 tx_sens = ha->fw_seriallink_options[1] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700993 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 rx_sens = (ha->fw_seriallink_options[1] &
995 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
996 ha->fw_options[11] = (emphasis << 14) | (swing << 8);
997 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
998 if (rx_sens == 0x0)
999 rx_sens = 0x3;
1000 ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
1001 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1002 ha->fw_options[11] |= BIT_5 |
1003 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1004 (tx_sens & (BIT_1 | BIT_0));
1005 }
1006
1007 /* FCP2 options. */
1008 /* Return command IOCBs without waiting for an ABTS to complete. */
1009 ha->fw_options[3] |= BIT_13;
1010
1011 /* LED scheme. */
1012 if (ha->flags.enable_led_scheme)
1013 ha->fw_options[2] |= BIT_12;
1014
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08001015 /* Detect ISP6312. */
1016 if (IS_QLA6312(ha))
1017 ha->fw_options[2] |= BIT_13;
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 /* Update firmware options. */
1020 qla2x00_set_fw_options(ha, ha->fw_options);
1021}
1022
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001023void
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001024qla24xx_update_fw_options(scsi_qla_host_t *ha)
1025{
1026 int rval;
1027
1028 /* Update Serial Link options. */
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001029 if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001030 return;
1031
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001032 rval = qla2x00_set_serdes_params(ha,
1033 le16_to_cpu(ha->fw_seriallink_options24[1]),
1034 le16_to_cpu(ha->fw_seriallink_options24[2]),
1035 le16_to_cpu(ha->fw_seriallink_options24[3]));
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001036 if (rval != QLA_SUCCESS) {
1037 qla_printk(KERN_WARNING, ha,
1038 "Unable to update Serial Link options (%x).\n", rval);
1039 }
1040}
1041
1042void
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001043qla2x00_config_rings(struct scsi_qla_host *ha)
1044{
Andrew Vasquez3d716442005-07-06 10:30:26 -07001045 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001046
1047 /* Setup ring parameters in initialization control block. */
1048 ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0);
1049 ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0);
1050 ha->init_cb->request_q_length = cpu_to_le16(ha->request_q_length);
1051 ha->init_cb->response_q_length = cpu_to_le16(ha->response_q_length);
1052 ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(ha->request_dma));
1053 ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(ha->request_dma));
1054 ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(ha->response_dma));
1055 ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(ha->response_dma));
1056
1057 WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
1058 WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
1059 WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0);
1060 WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0);
1061 RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */
1062}
1063
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001064void
1065qla24xx_config_rings(struct scsi_qla_host *ha)
1066{
1067 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1068 struct init_cb_24xx *icb;
1069
1070 /* Setup ring parameters in initialization control block. */
1071 icb = (struct init_cb_24xx *)ha->init_cb;
1072 icb->request_q_outpointer = __constant_cpu_to_le16(0);
1073 icb->response_q_inpointer = __constant_cpu_to_le16(0);
1074 icb->request_q_length = cpu_to_le16(ha->request_q_length);
1075 icb->response_q_length = cpu_to_le16(ha->response_q_length);
1076 icb->request_q_address[0] = cpu_to_le32(LSD(ha->request_dma));
1077 icb->request_q_address[1] = cpu_to_le32(MSD(ha->request_dma));
1078 icb->response_q_address[0] = cpu_to_le32(LSD(ha->response_dma));
1079 icb->response_q_address[1] = cpu_to_le32(MSD(ha->response_dma));
1080
1081 WRT_REG_DWORD(&reg->req_q_in, 0);
1082 WRT_REG_DWORD(&reg->req_q_out, 0);
1083 WRT_REG_DWORD(&reg->rsp_q_in, 0);
1084 WRT_REG_DWORD(&reg->rsp_q_out, 0);
1085 RD_REG_DWORD(&reg->rsp_q_out);
1086}
1087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088/**
1089 * qla2x00_init_rings() - Initializes firmware.
1090 * @ha: HA context
1091 *
1092 * Beginning of request ring has initialization control block already built
1093 * by nvram config routine.
1094 *
1095 * Returns 0 on success.
1096 */
1097static int
1098qla2x00_init_rings(scsi_qla_host_t *ha)
1099{
1100 int rval;
1101 unsigned long flags = 0;
1102 int cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 spin_lock_irqsave(&ha->hardware_lock, flags);
1105
1106 /* Clear outstanding commands array. */
1107 for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
1108 ha->outstanding_cmds[cnt] = NULL;
1109
1110 ha->current_outstanding_cmd = 0;
1111
1112 /* Clear RSCN queue. */
1113 ha->rscn_in_ptr = 0;
1114 ha->rscn_out_ptr = 0;
1115
1116 /* Initialize firmware. */
1117 ha->request_ring_ptr = ha->request_ring;
1118 ha->req_ring_index = 0;
1119 ha->req_q_cnt = ha->request_q_length;
1120 ha->response_ring_ptr = ha->response_ring;
1121 ha->rsp_ring_index = 0;
1122
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 /* Initialize response queue entries */
1124 qla2x00_init_response_q_entries(ha);
1125
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001126 ha->isp_ops.config_rings(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127
1128 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1129
1130 /* Update any ISP specific firmware options before initialization. */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001131 ha->isp_ops.update_fw_options(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001134 rval = qla2x00_init_firmware(ha, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 if (rval) {
1136 DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
1137 ha->host_no));
1138 } else {
1139 DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
1140 ha->host_no));
1141 }
1142
1143 return (rval);
1144}
1145
1146/**
1147 * qla2x00_fw_ready() - Waits for firmware ready.
1148 * @ha: HA context
1149 *
1150 * Returns 0 on success.
1151 */
1152static int
1153qla2x00_fw_ready(scsi_qla_host_t *ha)
1154{
1155 int rval;
1156 unsigned long wtime, mtime;
1157 uint16_t min_wait; /* Minimum wait time if loop is down */
1158 uint16_t wait_time; /* Wait time if loop is coming ready */
1159 uint16_t fw_state;
1160
1161 rval = QLA_SUCCESS;
1162
1163 /* 20 seconds for loop down. */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001164 min_wait = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 /*
1167 * Firmware should take at most one RATOV to login, plus 5 seconds for
1168 * our own processing.
1169 */
1170 if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
1171 wait_time = min_wait;
1172 }
1173
1174 /* Min wait time if loop down */
1175 mtime = jiffies + (min_wait * HZ);
1176
1177 /* wait time before firmware ready */
1178 wtime = jiffies + (wait_time * HZ);
1179
1180 /* Wait for ISP to finish LIP */
1181 if (!ha->flags.init_done)
1182 qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
1183
1184 DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
1185 ha->host_no));
1186
1187 do {
1188 rval = qla2x00_get_firmware_state(ha, &fw_state);
1189 if (rval == QLA_SUCCESS) {
1190 if (fw_state < FSTATE_LOSS_OF_SYNC) {
1191 ha->device_flags &= ~DFLG_NO_CABLE;
1192 }
1193 if (fw_state == FSTATE_READY) {
1194 DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
1195 ha->host_no));
1196
1197 qla2x00_get_retry_cnt(ha, &ha->retry_count,
1198 &ha->login_timeout, &ha->r_a_tov);
1199
1200 rval = QLA_SUCCESS;
1201 break;
1202 }
1203
1204 rval = QLA_FUNCTION_FAILED;
1205
1206 if (atomic_read(&ha->loop_down_timer) &&
Andrew Vasquez7d7abc72006-06-23 16:11:17 -07001207 fw_state != FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 /* Loop down. Timeout on min_wait for states
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001209 * other than Wait for Login.
1210 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 if (time_after_eq(jiffies, mtime)) {
1212 qla_printk(KERN_INFO, ha,
1213 "Cable is unplugged...\n");
1214
1215 ha->device_flags |= DFLG_NO_CABLE;
1216 break;
1217 }
1218 }
1219 } else {
1220 /* Mailbox cmd failed. Timeout on min_wait. */
1221 if (time_after_eq(jiffies, mtime))
1222 break;
1223 }
1224
1225 if (time_after_eq(jiffies, wtime))
1226 break;
1227
1228 /* Delay for a while */
1229 msleep(500);
1230
1231 DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
1232 ha->host_no, fw_state, jiffies));
1233 } while (1);
1234
1235 DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
1236 ha->host_no, fw_state, jiffies));
1237
1238 if (rval) {
1239 DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
1240 ha->host_no));
1241 }
1242
1243 return (rval);
1244}
1245
1246/*
1247* qla2x00_configure_hba
1248* Setup adapter context.
1249*
1250* Input:
1251* ha = adapter state pointer.
1252*
1253* Returns:
1254* 0 = success
1255*
1256* Context:
1257* Kernel context.
1258*/
1259static int
1260qla2x00_configure_hba(scsi_qla_host_t *ha)
1261{
1262 int rval;
1263 uint16_t loop_id;
1264 uint16_t topo;
1265 uint8_t al_pa;
1266 uint8_t area;
1267 uint8_t domain;
1268 char connect_type[22];
1269
1270 /* Get host addresses. */
1271 rval = qla2x00_get_adapter_id(ha,
1272 &loop_id, &al_pa, &area, &domain, &topo);
1273 if (rval != QLA_SUCCESS) {
Andrew Vasquez23443b12005-12-06 10:57:06 -08001274 if (LOOP_TRANSITION(ha) || atomic_read(&ha->loop_down_timer) ||
Ravi Anand33135aa2005-11-08 14:37:20 -08001275 (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
1276 DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
1277 __func__, ha->host_no));
1278 } else {
1279 qla_printk(KERN_WARNING, ha,
1280 "ERROR -- Unable to get host loop ID.\n");
1281 set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
1282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001283 return (rval);
1284 }
1285
1286 if (topo == 4) {
1287 qla_printk(KERN_INFO, ha,
1288 "Cannot get topology - retrying.\n");
1289 return (QLA_FUNCTION_FAILED);
1290 }
1291
1292 ha->loop_id = loop_id;
1293
1294 /* initialize */
1295 ha->min_external_loopid = SNS_FIRST_LOOP_ID;
1296 ha->operating_mode = LOOP;
1297
1298 switch (topo) {
1299 case 0:
1300 DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
1301 ha->host_no));
1302 ha->current_topology = ISP_CFG_NL;
1303 strcpy(connect_type, "(Loop)");
1304 break;
1305
1306 case 1:
1307 DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
1308 ha->host_no));
1309 ha->current_topology = ISP_CFG_FL;
1310 strcpy(connect_type, "(FL_Port)");
1311 break;
1312
1313 case 2:
1314 DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
1315 ha->host_no));
1316 ha->operating_mode = P2P;
1317 ha->current_topology = ISP_CFG_N;
1318 strcpy(connect_type, "(N_Port-to-N_Port)");
1319 break;
1320
1321 case 3:
1322 DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
1323 ha->host_no));
1324 ha->operating_mode = P2P;
1325 ha->current_topology = ISP_CFG_F;
1326 strcpy(connect_type, "(F_Port)");
1327 break;
1328
1329 default:
1330 DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
1331 "Using NL.\n",
1332 ha->host_no, topo));
1333 ha->current_topology = ISP_CFG_NL;
1334 strcpy(connect_type, "(Loop)");
1335 break;
1336 }
1337
1338 /* Save Host port and loop ID. */
1339 /* byte order - Big Endian */
1340 ha->d_id.b.domain = domain;
1341 ha->d_id.b.area = area;
1342 ha->d_id.b.al_pa = al_pa;
1343
1344 if (!ha->flags.init_done)
1345 qla_printk(KERN_INFO, ha,
1346 "Topology - %s, Host Loop address 0x%x\n",
1347 connect_type, ha->loop_id);
1348
1349 if (rval) {
1350 DEBUG2_3(printk("scsi(%ld): FAILED.\n", ha->host_no));
1351 } else {
1352 DEBUG3(printk("scsi(%ld): exiting normally.\n", ha->host_no));
1353 }
1354
1355 return(rval);
1356}
1357
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001358static inline void
1359qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *def)
1360{
1361 char *st, *en;
1362 uint16_t index;
1363
1364 if (memcmp(model, BINZERO, len) != 0) {
1365 strncpy(ha->model_number, model, len);
1366 st = en = ha->model_number;
1367 en += len - 1;
1368 while (en > st) {
1369 if (*en != 0x20 && *en != 0x00)
1370 break;
1371 *en-- = '\0';
1372 }
1373
1374 index = (ha->pdev->subsystem_device & 0xff);
1375 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1376 index < QLA_MODEL_NAMES)
1377 ha->model_desc = qla2x00_model_name[index * 2 + 1];
1378 } else {
1379 index = (ha->pdev->subsystem_device & 0xff);
1380 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1381 index < QLA_MODEL_NAMES) {
1382 strcpy(ha->model_number,
1383 qla2x00_model_name[index * 2]);
1384 ha->model_desc = qla2x00_model_name[index * 2 + 1];
1385 } else {
1386 strcpy(ha->model_number, def);
1387 }
1388 }
1389}
1390
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391/*
1392* NVRAM configuration for ISP 2xxx
1393*
1394* Input:
1395* ha = adapter block pointer.
1396*
1397* Output:
1398* initialization control block in response_ring
1399* host adapters parameters in host adapter block
1400*
1401* Returns:
1402* 0 = success.
1403*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001404int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405qla2x00_nvram_config(scsi_qla_host_t *ha)
1406{
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001407 int rval;
1408 uint8_t chksum = 0;
1409 uint16_t cnt;
1410 uint8_t *dptr1, *dptr2;
1411 init_cb_t *icb = ha->init_cb;
1412 nvram_t *nv = (nvram_t *)ha->request_ring;
1413 uint8_t *ptr = (uint8_t *)ha->request_ring;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001414 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415
1416 rval = QLA_SUCCESS;
1417
1418 /* Determine NVRAM starting address. */
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001419 ha->nvram_size = sizeof(nvram_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 ha->nvram_base = 0;
1421 if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
1422 if ((RD_REG_WORD(&reg->ctrl_status) >> 14) == 1)
1423 ha->nvram_base = 0x80;
1424
1425 /* Get NVRAM data and calculate checksum. */
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001426 ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
1427 for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
1428 chksum += *ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
1430 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
1431 DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001432 ha->nvram_size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001433
1434 /* Bad NVRAM data, set defaults parameters. */
1435 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
1436 nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
1437 /* Reset NVRAM data. */
1438 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
1439 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
1440 nv->nvram_version);
1441 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
1442 "invalid -- WWPN) defaults.\n");
1443
1444 /*
1445 * Set default initialization control block.
1446 */
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001447 memset(nv, 0, ha->nvram_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 nv->parameter_block_version = ICB_VERSION;
1449
1450 if (IS_QLA23XX(ha)) {
1451 nv->firmware_options[0] = BIT_2 | BIT_1;
1452 nv->firmware_options[1] = BIT_7 | BIT_5;
1453 nv->add_firmware_options[0] = BIT_5;
1454 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1455 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1456 nv->special_options[1] = BIT_7;
1457 } else if (IS_QLA2200(ha)) {
1458 nv->firmware_options[0] = BIT_2 | BIT_1;
1459 nv->firmware_options[1] = BIT_7 | BIT_5;
1460 nv->add_firmware_options[0] = BIT_5;
1461 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1462 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1463 } else if (IS_QLA2100(ha)) {
1464 nv->firmware_options[0] = BIT_3 | BIT_1;
1465 nv->firmware_options[1] = BIT_5;
1466 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1467 }
1468
1469 nv->max_iocb_allocation = __constant_cpu_to_le16(256);
1470 nv->execution_throttle = __constant_cpu_to_le16(16);
1471 nv->retry_count = 8;
1472 nv->retry_delay = 1;
1473
1474 nv->port_name[0] = 33;
1475 nv->port_name[3] = 224;
1476 nv->port_name[4] = 139;
1477
1478 nv->login_timeout = 4;
1479
1480 /*
1481 * Set default host adapter parameters
1482 */
1483 nv->host_p[1] = BIT_2;
1484 nv->reset_delay = 5;
1485 nv->port_down_retry_count = 8;
1486 nv->max_luns_per_target = __constant_cpu_to_le16(8);
1487 nv->link_down_timeout = 60;
1488
1489 rval = 1;
1490 }
1491
1492#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
1493 /*
1494 * The SN2 does not provide BIOS emulation which means you can't change
1495 * potentially bogus BIOS settings. Force the use of default settings
1496 * for link rate and frame size. Hope that the rest of the settings
1497 * are valid.
1498 */
1499 if (ia64_platform_is("sn2")) {
1500 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1501 if (IS_QLA23XX(ha))
1502 nv->special_options[1] = BIT_7;
1503 }
1504#endif
1505
1506 /* Reset Initialization control block */
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001507 memset(icb, 0, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508
1509 /*
1510 * Setup driver NVRAM options.
1511 */
1512 nv->firmware_options[0] |= (BIT_6 | BIT_1);
1513 nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
1514 nv->firmware_options[1] |= (BIT_5 | BIT_0);
1515 nv->firmware_options[1] &= ~BIT_4;
1516
1517 if (IS_QLA23XX(ha)) {
1518 nv->firmware_options[0] |= BIT_2;
1519 nv->firmware_options[0] &= ~BIT_3;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001520 nv->add_firmware_options[1] |= BIT_5 | BIT_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
1522 if (IS_QLA2300(ha)) {
1523 if (ha->fb_rev == FPM_2310) {
1524 strcpy(ha->model_number, "QLA2310");
1525 } else {
1526 strcpy(ha->model_number, "QLA2300");
1527 }
1528 } else {
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001529 qla2x00_set_model_info(ha, nv->model_number,
1530 sizeof(nv->model_number), "QLA23xx");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531 }
1532 } else if (IS_QLA2200(ha)) {
1533 nv->firmware_options[0] |= BIT_2;
1534 /*
1535 * 'Point-to-point preferred, else loop' is not a safe
1536 * connection mode setting.
1537 */
1538 if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
1539 (BIT_5 | BIT_4)) {
1540 /* Force 'loop preferred, else point-to-point'. */
1541 nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
1542 nv->add_firmware_options[0] |= BIT_5;
1543 }
1544 strcpy(ha->model_number, "QLA22xx");
1545 } else /*if (IS_QLA2100(ha))*/ {
1546 strcpy(ha->model_number, "QLA2100");
1547 }
1548
1549 /*
1550 * Copy over NVRAM RISC parameter block to initialization control block.
1551 */
1552 dptr1 = (uint8_t *)icb;
1553 dptr2 = (uint8_t *)&nv->parameter_block_version;
1554 cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
1555 while (cnt--)
1556 *dptr1++ = *dptr2++;
1557
1558 /* Copy 2nd half. */
1559 dptr1 = (uint8_t *)icb->add_firmware_options;
1560 cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
1561 while (cnt--)
1562 *dptr1++ = *dptr2++;
1563
Andrew Vasquez5341e862006-05-17 15:09:16 -07001564 /* Use alternate WWN? */
1565 if (nv->host_p[1] & BIT_7) {
1566 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
1567 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
1568 }
1569
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 /* Prepare nodename */
1571 if ((icb->firmware_options[1] & BIT_6) == 0) {
1572 /*
1573 * Firmware will apply the following mask if the nodename was
1574 * not provided.
1575 */
1576 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
1577 icb->node_name[0] &= 0xF0;
1578 }
1579
1580 /*
1581 * Set host adapter parameters.
1582 */
Andrew Vasquez01819442006-06-23 16:11:10 -07001583 if (nv->host_p[0] & BIT_7)
Andrew Vasquez11010fe2006-10-06 09:54:59 -07001584 ql2xextended_error_logging = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
1586 /* Always load RISC code on non ISP2[12]00 chips. */
1587 if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
1588 ha->flags.disable_risc_code_load = 0;
1589 ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
1590 ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
1591 ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
Andrew Vasquez06c22bd2005-08-26 19:09:00 -07001592 ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07001593 ha->flags.disable_serdes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
1595 ha->operating_mode =
1596 (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
1597
1598 memcpy(ha->fw_seriallink_options, nv->seriallink_options,
1599 sizeof(ha->fw_seriallink_options));
1600
1601 /* save HBA serial number */
1602 ha->serial0 = icb->port_name[5];
1603 ha->serial1 = icb->port_name[6];
1604 ha->serial2 = icb->port_name[7];
Andrew Vasquez3d716442005-07-06 10:30:26 -07001605 ha->node_name = icb->node_name;
1606 ha->port_name = icb->port_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
1609
1610 ha->retry_count = nv->retry_count;
1611
1612 /* Set minimum login_timeout to 4 seconds. */
1613 if (nv->login_timeout < ql2xlogintimeout)
1614 nv->login_timeout = ql2xlogintimeout;
1615 if (nv->login_timeout < 4)
1616 nv->login_timeout = 4;
1617 ha->login_timeout = nv->login_timeout;
1618 icb->login_timeout = nv->login_timeout;
1619
1620 /* Set minimum RATOV to 200 tenths of a second. */
1621 ha->r_a_tov = 200;
1622
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 ha->loop_reset_delay = nv->reset_delay;
1624
Linus Torvalds1da177e2005-04-16 15:20:36 -07001625 /* Link Down Timeout = 0:
1626 *
1627 * When Port Down timer expires we will start returning
1628 * I/O's to OS with "DID_NO_CONNECT".
1629 *
1630 * Link Down Timeout != 0:
1631 *
1632 * The driver waits for the link to come up after link down
1633 * before returning I/Os to OS with "DID_NO_CONNECT".
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001634 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001635 if (nv->link_down_timeout == 0) {
1636 ha->loop_down_abort_time =
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001637 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 } else {
1639 ha->link_down_timeout = nv->link_down_timeout;
1640 ha->loop_down_abort_time =
1641 (LOOP_DOWN_TIME - ha->link_down_timeout);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001642 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 /*
1645 * Need enough time to try and get the port back.
1646 */
1647 ha->port_down_retry_count = nv->port_down_retry_count;
1648 if (qlport_down_retry)
1649 ha->port_down_retry_count = qlport_down_retry;
1650 /* Set login_retry_count */
1651 ha->login_retry_count = nv->retry_count;
1652 if (ha->port_down_retry_count == nv->port_down_retry_count &&
1653 ha->port_down_retry_count > 3)
1654 ha->login_retry_count = ha->port_down_retry_count;
1655 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
1656 ha->login_retry_count = ha->port_down_retry_count;
1657 if (ql2xloginretrycount)
1658 ha->login_retry_count = ql2xloginretrycount;
1659
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 icb->lun_enables = __constant_cpu_to_le16(0);
1661 icb->command_resource_count = 0;
1662 icb->immediate_notify_resource_count = 0;
1663 icb->timeout = __constant_cpu_to_le16(0);
1664
1665 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
1666 /* Enable RIO */
1667 icb->firmware_options[0] &= ~BIT_3;
1668 icb->add_firmware_options[0] &=
1669 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
1670 icb->add_firmware_options[0] |= BIT_2;
1671 icb->response_accumulation_timer = 3;
1672 icb->interrupt_delay_timer = 5;
1673
1674 ha->flags.process_response_queue = 1;
1675 } else {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001676 /* Enable ZIO. */
1677 if (!ha->flags.init_done) {
1678 ha->zio_mode = icb->add_firmware_options[0] &
1679 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
1680 ha->zio_timer = icb->interrupt_delay_timer ?
1681 icb->interrupt_delay_timer: 2;
1682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683 icb->add_firmware_options[0] &=
1684 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001685 ha->flags.process_response_queue = 0;
1686 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001687 ha->zio_mode = QLA_ZIO_MODE_6;
1688
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001689 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
1690 "delay (%d us).\n", ha->host_no, ha->zio_mode,
1691 ha->zio_timer * 100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692 qla_printk(KERN_INFO, ha,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001693 "ZIO mode %d enabled; timer delay (%d us).\n",
1694 ha->zio_mode, ha->zio_timer * 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001696 icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
1697 icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 ha->flags.process_response_queue = 1;
1699 }
1700 }
1701
1702 if (rval) {
1703 DEBUG2_3(printk(KERN_WARNING
1704 "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
1705 }
1706 return (rval);
1707}
1708
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001709static void
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001710qla2x00_rport_del(void *data)
1711{
1712 fc_port_t *fcport = data;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001713 struct fc_rport *rport;
1714 unsigned long flags;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001715
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001716 spin_lock_irqsave(&fcport->rport_lock, flags);
1717 rport = fcport->drport;
1718 fcport->drport = NULL;
1719 spin_unlock_irqrestore(&fcport->rport_lock, flags);
1720 if (rport)
1721 fc_remote_port_delete(rport);
1722
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001723}
1724
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725/**
1726 * qla2x00_alloc_fcport() - Allocate a generic fcport.
1727 * @ha: HA context
1728 * @flags: allocation flags
1729 *
1730 * Returns a pointer to the allocated fcport, or NULL, if none available.
1731 */
Adrian Bunk413975a2006-06-30 02:33:06 -07001732static fc_port_t *
Al Viroc53033f2005-10-21 03:22:08 -04001733qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734{
1735 fc_port_t *fcport;
1736
1737 fcport = kmalloc(sizeof(fc_port_t), flags);
1738 if (fcport == NULL)
1739 return (fcport);
1740
1741 /* Setup fcport template structure. */
1742 memset(fcport, 0, sizeof (fc_port_t));
1743 fcport->ha = ha;
1744 fcport->port_type = FCT_UNKNOWN;
1745 fcport->loop_id = FC_NO_LOOP_ID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746 atomic_set(&fcport->state, FCS_UNCONFIGURED);
1747 fcport->flags = FCF_RLC_SUPPORT;
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07001748 fcport->supported_classes = FC_COS_UNSPECIFIED;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001749 spin_lock_init(&fcport->rport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
1751 return (fcport);
1752}
1753
1754/*
1755 * qla2x00_configure_loop
1756 * Updates Fibre Channel Device Database with what is actually on loop.
1757 *
1758 * Input:
1759 * ha = adapter block pointer.
1760 *
1761 * Returns:
1762 * 0 = success.
1763 * 1 = error.
1764 * 2 = database was full and device was not configured.
1765 */
1766static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001767qla2x00_configure_loop(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768{
1769 int rval;
1770 unsigned long flags, save_flags;
1771
1772 rval = QLA_SUCCESS;
1773
1774 /* Get Initiator ID */
1775 if (test_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags)) {
1776 rval = qla2x00_configure_hba(ha);
1777 if (rval != QLA_SUCCESS) {
1778 DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
1779 ha->host_no));
1780 return (rval);
1781 }
1782 }
1783
1784 save_flags = flags = ha->dpc_flags;
1785 DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
1786 ha->host_no, flags));
1787
1788 /*
1789 * If we have both an RSCN and PORT UPDATE pending then handle them
1790 * both at the same time.
1791 */
1792 clear_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
1793 clear_bit(RSCN_UPDATE, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794
1795 /* Determine what we need to do */
1796 if (ha->current_topology == ISP_CFG_FL &&
1797 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
1798
1799 ha->flags.rscn_queue_overflow = 1;
1800 set_bit(RSCN_UPDATE, &flags);
1801
1802 } else if (ha->current_topology == ISP_CFG_F &&
1803 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
1804
1805 ha->flags.rscn_queue_overflow = 1;
1806 set_bit(RSCN_UPDATE, &flags);
1807 clear_bit(LOCAL_LOOP_UPDATE, &flags);
1808
Andrew Vasquez21333b42006-05-17 15:09:56 -07001809 } else if (ha->current_topology == ISP_CFG_N) {
1810 clear_bit(RSCN_UPDATE, &flags);
1811
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 } else if (!ha->flags.online ||
1813 (test_bit(ABORT_ISP_ACTIVE, &flags))) {
1814
1815 ha->flags.rscn_queue_overflow = 1;
1816 set_bit(RSCN_UPDATE, &flags);
1817 set_bit(LOCAL_LOOP_UPDATE, &flags);
1818 }
1819
1820 if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
1821 if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
1822 rval = QLA_FUNCTION_FAILED;
1823 } else {
1824 rval = qla2x00_configure_local_loop(ha);
1825 }
1826 }
1827
1828 if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
Andrew Vasquez23443b12005-12-06 10:57:06 -08001829 if (LOOP_TRANSITION(ha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 rval = QLA_FUNCTION_FAILED;
1831 } else {
1832 rval = qla2x00_configure_fabric(ha);
1833 }
1834 }
1835
1836 if (rval == QLA_SUCCESS) {
1837 if (atomic_read(&ha->loop_down_timer) ||
1838 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
1839 rval = QLA_FUNCTION_FAILED;
1840 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 atomic_set(&ha->loop_state, LOOP_READY);
1842
1843 DEBUG(printk("scsi(%ld): LOOP READY\n", ha->host_no));
1844 }
1845 }
1846
1847 if (rval) {
1848 DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
1849 __func__, ha->host_no));
1850 } else {
1851 DEBUG3(printk("%s: exiting normally\n", __func__));
1852 }
1853
1854 /* Restore state if a resync event occured during processing */
1855 if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
1856 if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
1857 set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
1858 if (test_bit(RSCN_UPDATE, &save_flags))
1859 set_bit(RSCN_UPDATE, &ha->dpc_flags);
1860 }
1861
1862 return (rval);
1863}
1864
1865
1866
1867/*
1868 * qla2x00_configure_local_loop
1869 * Updates Fibre Channel Device Database with local loop devices.
1870 *
1871 * Input:
1872 * ha = adapter block pointer.
1873 *
1874 * Returns:
1875 * 0 = success.
1876 */
1877static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001878qla2x00_configure_local_loop(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879{
1880 int rval, rval2;
1881 int found_devs;
1882 int found;
1883 fc_port_t *fcport, *new_fcport;
1884
1885 uint16_t index;
1886 uint16_t entries;
1887 char *id_iter;
1888 uint16_t loop_id;
1889 uint8_t domain, area, al_pa;
1890
1891 found_devs = 0;
1892 new_fcport = NULL;
1893 entries = MAX_FIBRE_DEVICES;
1894
1895 DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", ha->host_no));
1896 DEBUG3(qla2x00_get_fcal_position_map(ha, NULL));
1897
1898 /* Get list of logged in devices. */
1899 memset(ha->gid_list, 0, GID_LIST_SIZE);
1900 rval = qla2x00_get_id_list(ha, ha->gid_list, ha->gid_list_dma,
1901 &entries);
1902 if (rval != QLA_SUCCESS)
1903 goto cleanup_allocation;
1904
1905 DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
1906 ha->host_no, entries));
1907 DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
1908 entries * sizeof(struct gid_list_info)));
1909
1910 /* Allocate temporary fcport for any new fcports discovered. */
1911 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
1912 if (new_fcport == NULL) {
1913 rval = QLA_MEMORY_ALLOC_FAILED;
1914 goto cleanup_allocation;
1915 }
1916 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
1917
1918 /*
1919 * Mark local devices that were present with FCF_DEVICE_LOST for now.
1920 */
1921 list_for_each_entry(fcport, &ha->fcports, list) {
1922 if (atomic_read(&fcport->state) == FCS_ONLINE &&
1923 fcport->port_type != FCT_BROADCAST &&
1924 (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
1925
1926 DEBUG(printk("scsi(%ld): Marking port lost, "
1927 "loop_id=0x%04x\n",
1928 ha->host_no, fcport->loop_id));
1929
1930 atomic_set(&fcport->state, FCS_DEVICE_LOST);
1931 fcport->flags &= ~FCF_FARP_DONE;
1932 }
1933 }
1934
1935 /* Add devices to port list. */
1936 id_iter = (char *)ha->gid_list;
1937 for (index = 0; index < entries; index++) {
1938 domain = ((struct gid_list_info *)id_iter)->domain;
1939 area = ((struct gid_list_info *)id_iter)->area;
1940 al_pa = ((struct gid_list_info *)id_iter)->al_pa;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001941 if (IS_QLA2100(ha) || IS_QLA2200(ha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 loop_id = (uint16_t)
1943 ((struct gid_list_info *)id_iter)->loop_id_2100;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001944 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 loop_id = le16_to_cpu(
1946 ((struct gid_list_info *)id_iter)->loop_id);
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001947 id_iter += ha->gid_list_info_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948
1949 /* Bypass reserved domain fields. */
1950 if ((domain & 0xf0) == 0xf0)
1951 continue;
1952
1953 /* Bypass if not same domain and area of adapter. */
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07001954 if (area && domain &&
1955 (area != ha->d_id.b.area || domain != ha->d_id.b.domain))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956 continue;
1957
1958 /* Bypass invalid local loop ID. */
1959 if (loop_id > LAST_LOCAL_LOOP_ID)
1960 continue;
1961
1962 /* Fill in member data. */
1963 new_fcport->d_id.b.domain = domain;
1964 new_fcport->d_id.b.area = area;
1965 new_fcport->d_id.b.al_pa = al_pa;
1966 new_fcport->loop_id = loop_id;
1967 rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
1968 if (rval2 != QLA_SUCCESS) {
1969 DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
1970 "information -- get_port_database=%x, "
1971 "loop_id=0x%04x\n",
1972 ha->host_no, rval2, new_fcport->loop_id));
andrew.vasquez@qlogic.comc9d02ac2006-01-13 17:05:26 -08001973 DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
1974 ha->host_no));
1975 set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 continue;
1977 }
1978
1979 /* Check for matching device in port list. */
1980 found = 0;
1981 fcport = NULL;
1982 list_for_each_entry(fcport, &ha->fcports, list) {
1983 if (memcmp(new_fcport->port_name, fcport->port_name,
1984 WWN_SIZE))
1985 continue;
1986
1987 fcport->flags &= ~(FCF_FABRIC_DEVICE |
1988 FCF_PERSISTENT_BOUND);
1989 fcport->loop_id = new_fcport->loop_id;
1990 fcport->port_type = new_fcport->port_type;
1991 fcport->d_id.b24 = new_fcport->d_id.b24;
1992 memcpy(fcport->node_name, new_fcport->node_name,
1993 WWN_SIZE);
1994
1995 found++;
1996 break;
1997 }
1998
1999 if (!found) {
2000 /* New device, add to fcports list. */
2001 new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
2002 list_add_tail(&new_fcport->list, &ha->fcports);
2003
2004 /* Allocate a new replacement fcport. */
2005 fcport = new_fcport;
2006 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
2007 if (new_fcport == NULL) {
2008 rval = QLA_MEMORY_ALLOC_FAILED;
2009 goto cleanup_allocation;
2010 }
2011 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2012 }
2013
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002014 /* Base iIDMA settings on HBA port speed. */
2015 switch (ha->link_data_rate) {
2016 case PORT_SPEED_1GB:
2017 fcport->fp_speed = cpu_to_be16(BIT_15);
2018 break;
2019 case PORT_SPEED_2GB:
2020 fcport->fp_speed = cpu_to_be16(BIT_14);
2021 break;
2022 case PORT_SPEED_4GB:
2023 fcport->fp_speed = cpu_to_be16(BIT_13);
2024 break;
2025 }
2026
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 qla2x00_update_fcport(ha, fcport);
2028
2029 found_devs++;
2030 }
2031
2032cleanup_allocation:
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002033 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034
2035 if (rval != QLA_SUCCESS) {
2036 DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
2037 "rval=%x\n", ha->host_no, rval));
2038 }
2039
2040 if (found_devs) {
2041 ha->device_flags |= DFLG_LOCAL_DEVICES;
2042 ha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES;
2043 }
2044
2045 return (rval);
2046}
2047
2048static void
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002049qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002050{
2051 fc_port_t *fcport;
2052
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002053 qla2x00_mark_all_devices_lost(ha, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002054 list_for_each_entry(fcport, &ha->fcports, list) {
2055 if (fcport->port_type != FCT_TARGET)
2056 continue;
2057
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002058 qla2x00_update_fcport(ha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 }
2060}
2061
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002062static void
2063qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
2064{
2065#define LS_UNKNOWN 2
2066 static char *link_speeds[5] = { "1", "2", "?", "4" };
2067 int rval;
2068 uint16_t port_speed, mb[6];
2069
2070 if (!IS_QLA24XX(ha))
2071 return;
2072
2073 switch (be16_to_cpu(fcport->fp_speed)) {
2074 case BIT_15:
2075 port_speed = PORT_SPEED_1GB;
2076 break;
2077 case BIT_14:
2078 port_speed = PORT_SPEED_2GB;
2079 break;
2080 case BIT_13:
2081 port_speed = PORT_SPEED_4GB;
2082 break;
2083 default:
2084 DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
2085 "unsupported FM port operating speed (%04x).\n",
2086 ha->host_no, fcport->port_name[0], fcport->port_name[1],
2087 fcport->port_name[2], fcport->port_name[3],
2088 fcport->port_name[4], fcport->port_name[5],
2089 fcport->port_name[6], fcport->port_name[7],
2090 be16_to_cpu(fcport->fp_speed)));
2091 port_speed = PORT_SPEED_UNKNOWN;
2092 break;
2093 }
2094 if (port_speed == PORT_SPEED_UNKNOWN)
2095 return;
2096
2097 rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
2098 if (rval != QLA_SUCCESS) {
2099 DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
2100 "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
2101 ha->host_no, fcport->port_name[0], fcport->port_name[1],
2102 fcport->port_name[2], fcport->port_name[3],
2103 fcport->port_name[4], fcport->port_name[5],
2104 fcport->port_name[6], fcport->port_name[7], rval,
2105 port_speed, mb[0], mb[1]));
2106 } else {
2107 DEBUG2(qla_printk(KERN_INFO, ha,
2108 "iIDMA adjusted to %s GB/s on "
2109 "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
2110 link_speeds[port_speed], fcport->port_name[0],
2111 fcport->port_name[1], fcport->port_name[2],
2112 fcport->port_name[3], fcport->port_name[4],
2113 fcport->port_name[5], fcport->port_name[6],
2114 fcport->port_name[7]));
2115 }
2116}
2117
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118/*
2119 * qla2x00_update_fcport
2120 * Updates device on list.
2121 *
2122 * Input:
2123 * ha = adapter block pointer.
2124 * fcport = port structure pointer.
2125 *
2126 * Return:
2127 * 0 - Success
2128 * BIT_0 - error
2129 *
2130 * Context:
2131 * Kernel context.
2132 */
andrew.vasquez@qlogic.com052c40c2006-01-20 14:53:19 -08002133void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
2135{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136 fcport->ha = ha;
2137 fcport->login_retry = 0;
2138 fcport->port_login_retry_count = ha->port_down_retry_count *
2139 PORT_RETRY_TIME;
2140 atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
2141 PORT_RETRY_TIME);
2142 fcport->flags &= ~FCF_LOGIN_NEEDED;
2143
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002144 qla2x00_iidma_fcport(ha, fcport);
2145
Linus Torvalds1da177e2005-04-16 15:20:36 -07002146 atomic_set(&fcport->state, FCS_ONLINE);
bdf79622005-04-17 15:06:53 -05002147
Andrew Vasquezd19044c2006-11-22 08:22:19 -08002148 qla2x00_reg_remote_port(ha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149}
2150
8482e1182005-04-17 15:04:54 -05002151void
2152qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
2153{
2154 struct fc_rport_identifiers rport_ids;
bdf79622005-04-17 15:06:53 -05002155 struct fc_rport *rport;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002156 unsigned long flags;
8482e1182005-04-17 15:04:54 -05002157
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002158 if (fcport->drport)
2159 qla2x00_rport_del(fcport);
2160 if (fcport->rport)
2161 return;
8482e1182005-04-17 15:04:54 -05002162
Andrew Vasquezf8b02a82005-08-31 15:21:20 -07002163 rport_ids.node_name = wwn_to_u64(fcport->node_name);
2164 rport_ids.port_name = wwn_to_u64(fcport->port_name);
8482e1182005-04-17 15:04:54 -05002165 rport_ids.port_id = fcport->d_id.b.domain << 16 |
2166 fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
2167 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002168 rport = fc_remote_port_add(ha->host, 0, &rport_ids);
Andrew Vasquez77d74142005-07-08 18:00:36 -07002169 if (!rport) {
2170 qla_printk(KERN_WARNING, ha,
2171 "Unable to allocate fc remote port!\n");
2172 return;
2173 }
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002174 spin_lock_irqsave(&fcport->rport_lock, flags);
2175 fcport->rport = rport;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002176 *((fc_port_t **)rport->dd_data) = fcport;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002177 spin_unlock_irqrestore(&fcport->rport_lock, flags);
2178
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002179 rport->supported_classes = fcport->supported_classes;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002180
2181 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
8482e1182005-04-17 15:04:54 -05002182 if (fcport->port_type == FCT_INITIATOR)
2183 rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
2184 if (fcport->port_type == FCT_TARGET)
2185 rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002186 fc_remote_port_rolechg(rport, rport_ids.roles);
bdf79622005-04-17 15:06:53 -05002187
Andrew Vasquezcc4731f2005-07-06 10:32:37 -07002188 if (rport->scsi_target_id != -1 &&
2189 rport->scsi_target_id < ha->host->max_id)
bdf79622005-04-17 15:06:53 -05002190 fcport->os_target_id = rport->scsi_target_id;
8482e1182005-04-17 15:04:54 -05002191}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192
2193/*
2194 * qla2x00_configure_fabric
2195 * Setup SNS devices with loop ID's.
2196 *
2197 * Input:
2198 * ha = adapter block pointer.
2199 *
2200 * Returns:
2201 * 0 = success.
2202 * BIT_0 = error
2203 */
2204static int
2205qla2x00_configure_fabric(scsi_qla_host_t *ha)
2206{
2207 int rval, rval2;
2208 fc_port_t *fcport, *fcptemp;
2209 uint16_t next_loopid;
2210 uint16_t mb[MAILBOX_REGISTER_COUNT];
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002211 uint16_t loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212 LIST_HEAD(new_fcports);
2213
2214 /* If FL port exists, then SNS is present */
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08002215 if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002216 loop_id = NPH_F_PORT;
2217 else
2218 loop_id = SNS_FL_PORT;
Andrew Vasquez90991c82006-10-02 12:00:46 -07002219 rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 if (rval != QLA_SUCCESS) {
2221 DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
2222 "Port\n", ha->host_no));
2223
2224 ha->device_flags &= ~SWITCH_FOUND;
2225 return (QLA_SUCCESS);
2226 }
Andrew Vasquez90991c82006-10-02 12:00:46 -07002227 ha->device_flags |= SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228
2229 /* Mark devices that need re-synchronization. */
2230 rval2 = qla2x00_device_resync(ha);
2231 if (rval2 == QLA_RSCNS_HANDLED) {
2232 /* No point doing the scan, just continue. */
2233 return (QLA_SUCCESS);
2234 }
2235 do {
Andrew Vasquezcca53352005-08-26 19:08:30 -07002236 /* FDMI support. */
2237 if (ql2xfdmienable &&
2238 test_and_clear_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags))
2239 qla2x00_fdmi_register(ha);
2240
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 /* Ensure we are logged into the SNS. */
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08002242 if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002243 loop_id = NPH_SNS;
2244 else
2245 loop_id = SIMPLE_NAME_SERVER;
2246 ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff,
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002247 0xfc, mb, BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 if (mb[0] != MBS_COMMAND_COMPLETE) {
2249 DEBUG2(qla_printk(KERN_INFO, ha,
2250 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002251 "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252 mb[0], mb[1], mb[2], mb[6], mb[7]));
2253 return (QLA_SUCCESS);
2254 }
2255
2256 if (test_and_clear_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags)) {
2257 if (qla2x00_rft_id(ha)) {
2258 /* EMPTY */
2259 DEBUG2(printk("scsi(%ld): Register FC-4 "
2260 "TYPE failed.\n", ha->host_no));
2261 }
2262 if (qla2x00_rff_id(ha)) {
2263 /* EMPTY */
2264 DEBUG2(printk("scsi(%ld): Register FC-4 "
2265 "Features failed.\n", ha->host_no));
2266 }
2267 if (qla2x00_rnn_id(ha)) {
2268 /* EMPTY */
2269 DEBUG2(printk("scsi(%ld): Register Node Name "
2270 "failed.\n", ha->host_no));
2271 } else if (qla2x00_rsnn_nn(ha)) {
2272 /* EMPTY */
2273 DEBUG2(printk("scsi(%ld): Register Symbolic "
2274 "Node Name failed.\n", ha->host_no));
2275 }
2276 }
2277
2278 rval = qla2x00_find_all_fabric_devs(ha, &new_fcports);
2279 if (rval != QLA_SUCCESS)
2280 break;
2281
2282 /*
2283 * Logout all previous fabric devices marked lost, except
2284 * tape devices.
2285 */
2286 list_for_each_entry(fcport, &ha->fcports, list) {
2287 if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
2288 break;
2289
2290 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
2291 continue;
2292
2293 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
2294 qla2x00_mark_device_lost(ha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002295 ql2xplogiabsentdevice, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 if (fcport->loop_id != FC_NO_LOOP_ID &&
2297 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2298 fcport->port_type != FCT_INITIATOR &&
2299 fcport->port_type != FCT_BROADCAST) {
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002300 ha->isp_ops.fabric_logout(ha,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002301 fcport->loop_id,
2302 fcport->d_id.b.domain,
2303 fcport->d_id.b.area,
2304 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 fcport->loop_id = FC_NO_LOOP_ID;
2306 }
2307 }
2308 }
2309
2310 /* Starting free loop ID. */
2311 next_loopid = ha->min_external_loopid;
2312
2313 /*
2314 * Scan through our port list and login entries that need to be
2315 * logged in.
2316 */
2317 list_for_each_entry(fcport, &ha->fcports, list) {
2318 if (atomic_read(&ha->loop_down_timer) ||
2319 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
2320 break;
2321
2322 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2323 (fcport->flags & FCF_LOGIN_NEEDED) == 0)
2324 continue;
2325
2326 if (fcport->loop_id == FC_NO_LOOP_ID) {
2327 fcport->loop_id = next_loopid;
2328 rval = qla2x00_find_new_loop_id(ha, fcport);
2329 if (rval != QLA_SUCCESS) {
2330 /* Ran out of IDs to use */
2331 break;
2332 }
2333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 /* Login and update database */
2335 qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
2336 }
2337
2338 /* Exit if out of loop IDs. */
2339 if (rval != QLA_SUCCESS) {
2340 break;
2341 }
2342
2343 /*
2344 * Login and add the new devices to our port list.
2345 */
2346 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
2347 if (atomic_read(&ha->loop_down_timer) ||
2348 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
2349 break;
2350
2351 /* Find a new loop ID to use. */
2352 fcport->loop_id = next_loopid;
2353 rval = qla2x00_find_new_loop_id(ha, fcport);
2354 if (rval != QLA_SUCCESS) {
2355 /* Ran out of IDs to use */
2356 break;
2357 }
2358
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359 /* Remove device from the new list and add it to DB */
Akinobu Mita179e0912006-06-26 00:24:41 -07002360 list_move_tail(&fcport->list, &ha->fcports);
bdf79622005-04-17 15:06:53 -05002361
2362 /* Login and update database */
2363 qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 }
2365 } while (0);
2366
2367 /* Free all new device structures not processed. */
2368 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
2369 list_del(&fcport->list);
2370 kfree(fcport);
2371 }
2372
2373 if (rval) {
2374 DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
2375 "rval=%d\n", ha->host_no, rval));
2376 }
2377
2378 return (rval);
2379}
2380
2381
2382/*
2383 * qla2x00_find_all_fabric_devs
2384 *
2385 * Input:
2386 * ha = adapter block pointer.
2387 * dev = database device entry pointer.
2388 *
2389 * Returns:
2390 * 0 = success.
2391 *
2392 * Context:
2393 * Kernel context.
2394 */
2395static int
2396qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
2397{
2398 int rval;
2399 uint16_t loop_id;
2400 fc_port_t *fcport, *new_fcport, *fcptemp;
2401 int found;
2402
2403 sw_info_t *swl;
2404 int swl_idx;
2405 int first_dev, last_dev;
2406 port_id_t wrap, nxt_d_id;
2407
2408 rval = QLA_SUCCESS;
2409
2410 /* Try GID_PT to get device list, else GAN. */
2411 swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC);
2412 if (swl == NULL) {
2413 /*EMPTY*/
2414 DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
2415 "on GA_NXT\n", ha->host_no));
2416 } else {
2417 memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES);
2418 if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) {
2419 kfree(swl);
2420 swl = NULL;
2421 } else if (qla2x00_gpn_id(ha, swl) != QLA_SUCCESS) {
2422 kfree(swl);
2423 swl = NULL;
2424 } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
2425 kfree(swl);
2426 swl = NULL;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002427 } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
2428 qla2x00_gpsc(ha, swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429 }
2430 }
2431 swl_idx = 0;
2432
2433 /* Allocate temporary fcport for any new fcports discovered. */
2434 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
2435 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002436 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 return (QLA_MEMORY_ALLOC_FAILED);
2438 }
2439 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
2440
2441 /* Set start port ID scan at adapter ID. */
2442 first_dev = 1;
2443 last_dev = 0;
2444
2445 /* Starting free loop ID. */
2446 loop_id = ha->min_external_loopid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 for (; loop_id <= ha->last_loop_id; loop_id++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -07002448 if (qla2x00_is_reserved_id(ha, loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 continue;
2450
Andrew Vasquez23443b12005-12-06 10:57:06 -08002451 if (atomic_read(&ha->loop_down_timer) || LOOP_TRANSITION(ha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 break;
2453
2454 if (swl != NULL) {
2455 if (last_dev) {
2456 wrap.b24 = new_fcport->d_id.b24;
2457 } else {
2458 new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
2459 memcpy(new_fcport->node_name,
2460 swl[swl_idx].node_name, WWN_SIZE);
2461 memcpy(new_fcport->port_name,
2462 swl[swl_idx].port_name, WWN_SIZE);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002463 memcpy(new_fcport->fabric_port_name,
2464 swl[swl_idx].fabric_port_name, WWN_SIZE);
2465 new_fcport->fp_speed = swl[swl_idx].fp_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466
2467 if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
2468 last_dev = 1;
2469 }
2470 swl_idx++;
2471 }
2472 } else {
2473 /* Send GA_NXT to the switch */
2474 rval = qla2x00_ga_nxt(ha, new_fcport);
2475 if (rval != QLA_SUCCESS) {
2476 qla_printk(KERN_WARNING, ha,
2477 "SNS scan failed -- assuming zero-entry "
2478 "result...\n");
2479 list_for_each_entry_safe(fcport, fcptemp,
2480 new_fcports, list) {
2481 list_del(&fcport->list);
2482 kfree(fcport);
2483 }
2484 rval = QLA_SUCCESS;
2485 break;
2486 }
2487 }
2488
2489 /* If wrap on switch device list, exit. */
2490 if (first_dev) {
2491 wrap.b24 = new_fcport->d_id.b24;
2492 first_dev = 0;
2493 } else if (new_fcport->d_id.b24 == wrap.b24) {
2494 DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
2495 ha->host_no, new_fcport->d_id.b.domain,
2496 new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
2497 break;
2498 }
2499
2500 /* Bypass if host adapter. */
2501 if (new_fcport->d_id.b24 == ha->d_id.b24)
2502 continue;
2503
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002504 /* Bypass if same domain and area of adapter. */
2505 if (((new_fcport->d_id.b24 & 0xffff00) ==
2506 (ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
2507 ISP_CFG_FL)
2508 continue;
2509
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 /* Bypass reserved domain fields. */
2511 if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
2512 continue;
2513
2514 /* Locate matching device in database. */
2515 found = 0;
2516 list_for_each_entry(fcport, &ha->fcports, list) {
2517 if (memcmp(new_fcport->port_name, fcport->port_name,
2518 WWN_SIZE))
2519 continue;
2520
2521 found++;
2522
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002523 /* Update port state. */
2524 memcpy(fcport->fabric_port_name,
2525 new_fcport->fabric_port_name, WWN_SIZE);
2526 fcport->fp_speed = new_fcport->fp_speed;
2527
Linus Torvalds1da177e2005-04-16 15:20:36 -07002528 /*
2529 * If address the same and state FCS_ONLINE, nothing
2530 * changed.
2531 */
2532 if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
2533 atomic_read(&fcport->state) == FCS_ONLINE) {
2534 break;
2535 }
2536
2537 /*
2538 * If device was not a fabric device before.
2539 */
2540 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
2541 fcport->d_id.b24 = new_fcport->d_id.b24;
2542 fcport->loop_id = FC_NO_LOOP_ID;
2543 fcport->flags |= (FCF_FABRIC_DEVICE |
2544 FCF_LOGIN_NEEDED);
2545 fcport->flags &= ~FCF_PERSISTENT_BOUND;
2546 break;
2547 }
2548
2549 /*
2550 * Port ID changed or device was marked to be updated;
2551 * Log it out if still logged in and mark it for
2552 * relogin later.
2553 */
2554 fcport->d_id.b24 = new_fcport->d_id.b24;
2555 fcport->flags |= FCF_LOGIN_NEEDED;
2556 if (fcport->loop_id != FC_NO_LOOP_ID &&
2557 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2558 fcport->port_type != FCT_INITIATOR &&
2559 fcport->port_type != FCT_BROADCAST) {
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002560 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2561 fcport->d_id.b.domain, fcport->d_id.b.area,
2562 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002563 fcport->loop_id = FC_NO_LOOP_ID;
2564 }
2565
2566 break;
2567 }
2568
2569 if (found)
2570 continue;
2571
2572 /* If device was not in our fcports list, then add it. */
2573 list_add_tail(&new_fcport->list, new_fcports);
2574
2575 /* Allocate a new replacement fcport. */
2576 nxt_d_id.b24 = new_fcport->d_id.b24;
2577 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
2578 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002579 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 return (QLA_MEMORY_ALLOC_FAILED);
2581 }
2582 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
2583 new_fcport->d_id.b24 = nxt_d_id.b24;
2584 }
2585
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002586 kfree(swl);
2587 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588
2589 if (!list_empty(new_fcports))
2590 ha->device_flags |= DFLG_FABRIC_DEVICES;
2591
2592 return (rval);
2593}
2594
2595/*
2596 * qla2x00_find_new_loop_id
2597 * Scan through our port list and find a new usable loop ID.
2598 *
2599 * Input:
2600 * ha: adapter state pointer.
2601 * dev: port structure pointer.
2602 *
2603 * Returns:
2604 * qla2x00 local function return status code.
2605 *
2606 * Context:
2607 * Kernel context.
2608 */
Adrian Bunk413975a2006-06-30 02:33:06 -07002609static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002610qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
2611{
2612 int rval;
2613 int found;
2614 fc_port_t *fcport;
2615 uint16_t first_loop_id;
2616
2617 rval = QLA_SUCCESS;
2618
2619 /* Save starting loop ID. */
2620 first_loop_id = dev->loop_id;
2621
2622 for (;;) {
2623 /* Skip loop ID if already used by adapter. */
2624 if (dev->loop_id == ha->loop_id) {
2625 dev->loop_id++;
2626 }
2627
2628 /* Skip reserved loop IDs. */
Andrew Vasquez3d716442005-07-06 10:30:26 -07002629 while (qla2x00_is_reserved_id(ha, dev->loop_id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 dev->loop_id++;
2631 }
2632
2633 /* Reset loop ID if passed the end. */
2634 if (dev->loop_id > ha->last_loop_id) {
2635 /* first loop ID. */
2636 dev->loop_id = ha->min_external_loopid;
2637 }
2638
2639 /* Check for loop ID being already in use. */
2640 found = 0;
2641 fcport = NULL;
2642 list_for_each_entry(fcport, &ha->fcports, list) {
2643 if (fcport->loop_id == dev->loop_id && fcport != dev) {
2644 /* ID possibly in use */
2645 found++;
2646 break;
2647 }
2648 }
2649
2650 /* If not in use then it is free to use. */
2651 if (!found) {
2652 break;
2653 }
2654
2655 /* ID in use. Try next value. */
2656 dev->loop_id++;
2657
2658 /* If wrap around. No free ID to use. */
2659 if (dev->loop_id == first_loop_id) {
2660 dev->loop_id = FC_NO_LOOP_ID;
2661 rval = QLA_FUNCTION_FAILED;
2662 break;
2663 }
2664 }
2665
2666 return (rval);
2667}
2668
2669/*
2670 * qla2x00_device_resync
2671 * Marks devices in the database that needs resynchronization.
2672 *
2673 * Input:
2674 * ha = adapter block pointer.
2675 *
2676 * Context:
2677 * Kernel context.
2678 */
2679static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002680qla2x00_device_resync(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681{
2682 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 uint32_t mask;
2684 fc_port_t *fcport;
2685 uint32_t rscn_entry;
2686 uint8_t rscn_out_iter;
2687 uint8_t format;
2688 port_id_t d_id;
2689
2690 rval = QLA_RSCNS_HANDLED;
2691
2692 while (ha->rscn_out_ptr != ha->rscn_in_ptr ||
2693 ha->flags.rscn_queue_overflow) {
2694
2695 rscn_entry = ha->rscn_queue[ha->rscn_out_ptr];
2696 format = MSB(MSW(rscn_entry));
2697 d_id.b.domain = LSB(MSW(rscn_entry));
2698 d_id.b.area = MSB(LSW(rscn_entry));
2699 d_id.b.al_pa = LSB(LSW(rscn_entry));
2700
2701 DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
2702 "[%02x/%02x%02x%02x].\n",
2703 ha->host_no, ha->rscn_out_ptr, format, d_id.b.domain,
2704 d_id.b.area, d_id.b.al_pa));
2705
2706 ha->rscn_out_ptr++;
2707 if (ha->rscn_out_ptr == MAX_RSCN_COUNT)
2708 ha->rscn_out_ptr = 0;
2709
2710 /* Skip duplicate entries. */
2711 for (rscn_out_iter = ha->rscn_out_ptr;
2712 !ha->flags.rscn_queue_overflow &&
2713 rscn_out_iter != ha->rscn_in_ptr;
2714 rscn_out_iter = (rscn_out_iter ==
2715 (MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
2716
2717 if (rscn_entry != ha->rscn_queue[rscn_out_iter])
2718 break;
2719
2720 DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
2721 "entry found at [%d].\n", ha->host_no,
2722 rscn_out_iter));
2723
2724 ha->rscn_out_ptr = rscn_out_iter;
2725 }
2726
2727 /* Queue overflow, set switch default case. */
2728 if (ha->flags.rscn_queue_overflow) {
2729 DEBUG(printk("scsi(%ld): device_resync: rscn "
2730 "overflow.\n", ha->host_no));
2731
2732 format = 3;
2733 ha->flags.rscn_queue_overflow = 0;
2734 }
2735
2736 switch (format) {
2737 case 0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002738 mask = 0xffffff;
2739 break;
2740 case 1:
2741 mask = 0xffff00;
2742 break;
2743 case 2:
2744 mask = 0xff0000;
2745 break;
2746 default:
2747 mask = 0x0;
2748 d_id.b24 = 0;
2749 ha->rscn_out_ptr = ha->rscn_in_ptr;
2750 break;
2751 }
2752
2753 rval = QLA_SUCCESS;
2754
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 list_for_each_entry(fcport, &ha->fcports, list) {
2756 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2757 (fcport->d_id.b24 & mask) != d_id.b24 ||
2758 fcport->port_type == FCT_BROADCAST)
2759 continue;
2760
2761 if (atomic_read(&fcport->state) == FCS_ONLINE) {
2762 if (format != 3 ||
2763 fcport->port_type != FCT_INITIATOR) {
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002764 qla2x00_mark_device_lost(ha, fcport,
2765 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 }
2767 }
2768 fcport->flags &= ~FCF_FARP_DONE;
2769 }
2770 }
2771 return (rval);
2772}
2773
2774/*
2775 * qla2x00_fabric_dev_login
2776 * Login fabric target device and update FC port database.
2777 *
2778 * Input:
2779 * ha: adapter state pointer.
2780 * fcport: port structure list pointer.
2781 * next_loopid: contains value of a new loop ID that can be used
2782 * by the next login attempt.
2783 *
2784 * Returns:
2785 * qla2x00 local function return status code.
2786 *
2787 * Context:
2788 * Kernel context.
2789 */
2790static int
2791qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
2792 uint16_t *next_loopid)
2793{
2794 int rval;
2795 int retry;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002796 uint8_t opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
2798 rval = QLA_SUCCESS;
2799 retry = 0;
2800
2801 rval = qla2x00_fabric_login(ha, fcport, next_loopid);
2802 if (rval == QLA_SUCCESS) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002803 /* Send an ADISC to tape devices.*/
2804 opts = 0;
2805 if (fcport->flags & FCF_TAPE_PRESENT)
2806 opts |= BIT_1;
2807 rval = qla2x00_get_port_database(ha, fcport, opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 if (rval != QLA_SUCCESS) {
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002809 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2810 fcport->d_id.b.domain, fcport->d_id.b.area,
2811 fcport->d_id.b.al_pa);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002812 qla2x00_mark_device_lost(ha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002813 } else {
2814 qla2x00_update_fcport(ha, fcport);
2815 }
2816 }
2817
2818 return (rval);
2819}
2820
2821/*
2822 * qla2x00_fabric_login
2823 * Issue fabric login command.
2824 *
2825 * Input:
2826 * ha = adapter block pointer.
2827 * device = pointer to FC device type structure.
2828 *
2829 * Returns:
2830 * 0 - Login successfully
2831 * 1 - Login failed
2832 * 2 - Initiator device
2833 * 3 - Fatal error
2834 */
2835int
2836qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
2837 uint16_t *next_loopid)
2838{
2839 int rval;
2840 int retry;
2841 uint16_t tmp_loopid;
2842 uint16_t mb[MAILBOX_REGISTER_COUNT];
2843
2844 retry = 0;
2845 tmp_loopid = 0;
2846
2847 for (;;) {
2848 DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
2849 "for port %02x%02x%02x.\n",
2850 ha->host_no, fcport->loop_id, fcport->d_id.b.domain,
2851 fcport->d_id.b.area, fcport->d_id.b.al_pa));
2852
2853 /* Login fcport on switch. */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002854 ha->isp_ops.fabric_login(ha, fcport->loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 fcport->d_id.b.domain, fcport->d_id.b.area,
2856 fcport->d_id.b.al_pa, mb, BIT_0);
2857 if (mb[0] == MBS_PORT_ID_USED) {
2858 /*
2859 * Device has another loop ID. The firmware team
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002860 * recommends the driver perform an implicit login with
2861 * the specified ID again. The ID we just used is save
2862 * here so we return with an ID that can be tried by
2863 * the next login.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864 */
2865 retry++;
2866 tmp_loopid = fcport->loop_id;
2867 fcport->loop_id = mb[1];
2868
2869 DEBUG(printk("Fabric Login: port in use - next "
2870 "loop id=0x%04x, port Id=%02x%02x%02x.\n",
2871 fcport->loop_id, fcport->d_id.b.domain,
2872 fcport->d_id.b.area, fcport->d_id.b.al_pa));
2873
2874 } else if (mb[0] == MBS_COMMAND_COMPLETE) {
2875 /*
2876 * Login succeeded.
2877 */
2878 if (retry) {
2879 /* A retry occurred before. */
2880 *next_loopid = tmp_loopid;
2881 } else {
2882 /*
2883 * No retry occurred before. Just increment the
2884 * ID value for next login.
2885 */
2886 *next_loopid = (fcport->loop_id + 1);
2887 }
2888
2889 if (mb[1] & BIT_0) {
2890 fcport->port_type = FCT_INITIATOR;
2891 } else {
2892 fcport->port_type = FCT_TARGET;
2893 if (mb[1] & BIT_1) {
2894 fcport->flags |= FCF_TAPE_PRESENT;
2895 }
2896 }
2897
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002898 if (mb[10] & BIT_0)
2899 fcport->supported_classes |= FC_COS_CLASS2;
2900 if (mb[10] & BIT_1)
2901 fcport->supported_classes |= FC_COS_CLASS3;
2902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 rval = QLA_SUCCESS;
2904 break;
2905 } else if (mb[0] == MBS_LOOP_ID_USED) {
2906 /*
2907 * Loop ID already used, try next loop ID.
2908 */
2909 fcport->loop_id++;
2910 rval = qla2x00_find_new_loop_id(ha, fcport);
2911 if (rval != QLA_SUCCESS) {
2912 /* Ran out of loop IDs to use */
2913 break;
2914 }
2915 } else if (mb[0] == MBS_COMMAND_ERROR) {
2916 /*
2917 * Firmware possibly timed out during login. If NO
2918 * retries are left to do then the device is declared
2919 * dead.
2920 */
2921 *next_loopid = fcport->loop_id;
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002922 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2923 fcport->d_id.b.domain, fcport->d_id.b.area,
2924 fcport->d_id.b.al_pa);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002925 qla2x00_mark_device_lost(ha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926
2927 rval = 1;
2928 break;
2929 } else {
2930 /*
2931 * unrecoverable / not handled error
2932 */
2933 DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002934 "loop_id=%x jiffies=%lx.\n",
2935 __func__, ha->host_no, mb[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936 fcport->d_id.b.domain, fcport->d_id.b.area,
2937 fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
2938
2939 *next_loopid = fcport->loop_id;
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002940 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2941 fcport->d_id.b.domain, fcport->d_id.b.area,
2942 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002943 fcport->loop_id = FC_NO_LOOP_ID;
Andrew Vasquez0eedfcf2005-10-27 11:09:38 -07002944 fcport->login_retry = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002945
2946 rval = 3;
2947 break;
2948 }
2949 }
2950
2951 return (rval);
2952}
2953
2954/*
2955 * qla2x00_local_device_login
2956 * Issue local device login command.
2957 *
2958 * Input:
2959 * ha = adapter block pointer.
2960 * loop_id = loop id of device to login to.
2961 *
2962 * Returns (Where's the #define!!!!):
2963 * 0 - Login successfully
2964 * 1 - Login failed
2965 * 3 - Fatal error
2966 */
2967int
andrew.vasquez@qlogic.com9a52a57c2006-03-09 14:27:44 -08002968qla2x00_local_device_login(scsi_qla_host_t *ha, fc_port_t *fcport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969{
2970 int rval;
2971 uint16_t mb[MAILBOX_REGISTER_COUNT];
2972
2973 memset(mb, 0, sizeof(mb));
andrew.vasquez@qlogic.com9a52a57c2006-03-09 14:27:44 -08002974 rval = qla2x00_login_local_device(ha, fcport, mb, BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 if (rval == QLA_SUCCESS) {
2976 /* Interrogate mailbox registers for any errors */
2977 if (mb[0] == MBS_COMMAND_ERROR)
2978 rval = 1;
2979 else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
2980 /* device not in PCB table */
2981 rval = 3;
2982 }
2983
2984 return (rval);
2985}
2986
2987/*
2988 * qla2x00_loop_resync
2989 * Resync with fibre channel devices.
2990 *
2991 * Input:
2992 * ha = adapter block pointer.
2993 *
2994 * Returns:
2995 * 0 = success
2996 */
2997int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002998qla2x00_loop_resync(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999{
3000 int rval;
3001 uint32_t wait_time;
3002
3003 rval = QLA_SUCCESS;
3004
3005 atomic_set(&ha->loop_state, LOOP_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
3007 if (ha->flags.online) {
3008 if (!(rval = qla2x00_fw_ready(ha))) {
3009 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3010 wait_time = 256;
3011 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003012 atomic_set(&ha->loop_state, LOOP_UPDATE);
3013
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003014 /* Issue a marker after FW becomes ready. */
3015 qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
3016 ha->marker_needed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017
3018 /* Remap devices on Loop. */
3019 clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
3020
3021 qla2x00_configure_loop(ha);
3022 wait_time--;
3023 } while (!atomic_read(&ha->loop_down_timer) &&
3024 !(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) &&
3025 wait_time &&
3026 (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)));
3027 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 }
3029
3030 if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
3031 return (QLA_FUNCTION_FAILED);
3032 }
3033
3034 if (rval) {
3035 DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
3036 }
3037
3038 return (rval);
3039}
3040
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041void
3042qla2x00_rescan_fcports(scsi_qla_host_t *ha)
3043{
3044 int rescan_done;
3045 fc_port_t *fcport;
3046
3047 rescan_done = 0;
3048 list_for_each_entry(fcport, &ha->fcports, list) {
3049 if ((fcport->flags & FCF_RESCAN_NEEDED) == 0)
3050 continue;
3051
3052 qla2x00_update_fcport(ha, fcport);
3053 fcport->flags &= ~FCF_RESCAN_NEEDED;
3054
3055 rescan_done = 1;
3056 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003057 qla2x00_probe_for_all_luns(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058}
3059
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003060void
3061qla2x00_update_fcports(scsi_qla_host_t *ha)
3062{
3063 fc_port_t *fcport;
3064
3065 /* Go with deferred removal of rport references. */
3066 list_for_each_entry(fcport, &ha->fcports, list)
3067 if (fcport->drport)
3068 qla2x00_rport_del(fcport);
3069}
3070
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071/*
3072* qla2x00_abort_isp
3073* Resets ISP and aborts all outstanding commands.
3074*
3075* Input:
3076* ha = adapter block pointer.
3077*
3078* Returns:
3079* 0 = success
3080*/
3081int
3082qla2x00_abort_isp(scsi_qla_host_t *ha)
3083{
Andrew Vasquez476e8972006-08-23 14:54:55 -07003084 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 unsigned long flags = 0;
3086 uint16_t cnt;
3087 srb_t *sp;
3088 uint8_t status = 0;
3089
3090 if (ha->flags.online) {
3091 ha->flags.online = 0;
3092 clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093
3094 qla_printk(KERN_INFO, ha,
3095 "Performing ISP error recovery - ha= %p.\n", ha);
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003096 ha->isp_ops.reset_chip(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097
3098 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
3099 if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
3100 atomic_set(&ha->loop_state, LOOP_DOWN);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003101 qla2x00_mark_all_devices_lost(ha, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003102 } else {
3103 if (!atomic_read(&ha->loop_down_timer))
3104 atomic_set(&ha->loop_down_timer,
3105 LOOP_DOWN_TIME);
3106 }
3107
3108 spin_lock_irqsave(&ha->hardware_lock, flags);
3109 /* Requeue all commands in outstanding command list. */
3110 for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
3111 sp = ha->outstanding_cmds[cnt];
3112 if (sp) {
3113 ha->outstanding_cmds[cnt] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 sp->flags = 0;
f4f051e2005-04-17 15:02:26 -05003115 sp->cmd->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 sp->cmd->host_scribble = (unsigned char *)NULL;
f4f051e2005-04-17 15:02:26 -05003117 qla2x00_sp_compl(ha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 }
3119 }
3120 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3121
Andrew Vasquez30c47662007-01-29 10:22:21 -08003122 ha->isp_ops.get_flash_version(ha, ha->request_ring);
3123
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003124 ha->isp_ops.nvram_config(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003125
3126 if (!qla2x00_restart_isp(ha)) {
3127 clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
3128
3129 if (!atomic_read(&ha->loop_down_timer)) {
3130 /*
3131 * Issue marker command only when we are going
3132 * to start the I/O .
3133 */
3134 ha->marker_needed = 1;
3135 }
3136
3137 ha->flags.online = 1;
3138
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003139 ha->isp_ops.enable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003141 ha->isp_abort_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
Andrew Vasquez476e8972006-08-23 14:54:55 -07003143
3144 if (ha->eft) {
3145 rval = qla2x00_trace_control(ha, TC_ENABLE,
3146 ha->eft_dma, EFT_NUM_BUFFERS);
3147 if (rval) {
3148 qla_printk(KERN_WARNING, ha,
3149 "Unable to reinitialize EFT "
3150 "(%d).\n", rval);
3151 }
3152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003153 } else { /* failed the ISP abort */
3154 ha->flags.online = 1;
3155 if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
3156 if (ha->isp_abort_cnt == 0) {
3157 qla_printk(KERN_WARNING, ha,
3158 "ISP error recovery failed - "
3159 "board disabled\n");
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003160 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003161 * The next call disables the board
3162 * completely.
3163 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003164 ha->isp_ops.reset_adapter(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003165 ha->flags.online = 0;
3166 clear_bit(ISP_ABORT_RETRY,
3167 &ha->dpc_flags);
3168 status = 0;
3169 } else { /* schedule another ISP abort */
3170 ha->isp_abort_cnt--;
3171 DEBUG(printk("qla%ld: ISP abort - "
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003172 "retry remaining %d\n",
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003173 ha->host_no, ha->isp_abort_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003174 status = 1;
3175 }
3176 } else {
3177 ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
3178 DEBUG(printk("qla2x00(%ld): ISP error recovery "
3179 "- retrying (%d) more times\n",
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003180 ha->host_no, ha->isp_abort_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003181 set_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
3182 status = 1;
3183 }
3184 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003185
Linus Torvalds1da177e2005-04-16 15:20:36 -07003186 }
3187
3188 if (status) {
3189 qla_printk(KERN_INFO, ha,
3190 "qla2x00_abort_isp: **** FAILED ****\n");
3191 } else {
3192 DEBUG(printk(KERN_INFO
3193 "qla2x00_abort_isp(%ld): exiting.\n",
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003194 ha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 }
3196
3197 return(status);
3198}
3199
3200/*
3201* qla2x00_restart_isp
3202* restarts the ISP after a reset
3203*
3204* Input:
3205* ha = adapter block pointer.
3206*
3207* Returns:
3208* 0 = success
3209*/
3210static int
3211qla2x00_restart_isp(scsi_qla_host_t *ha)
3212{
3213 uint8_t status = 0;
Andrew Vasquez3d716442005-07-06 10:30:26 -07003214 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003215 unsigned long flags = 0;
3216 uint32_t wait_time;
3217
3218 /* If firmware needs to be loaded */
3219 if (qla2x00_isp_firmware(ha)) {
3220 ha->flags.online = 0;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003221 if (!(status = ha->isp_ops.chip_diag(ha))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
3223 status = qla2x00_setup_chip(ha);
3224 goto done;
3225 }
3226
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 spin_lock_irqsave(&ha->hardware_lock, flags);
3228
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08003229 if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003230 /*
3231 * Disable SRAM, Instruction RAM and GP RAM
3232 * parity.
3233 */
3234 WRT_REG_WORD(&reg->hccr,
3235 (HCCR_ENABLE_PARITY + 0x0));
3236 RD_REG_WORD(&reg->hccr);
3237 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238
3239 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003240
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 status = qla2x00_setup_chip(ha);
3242
3243 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003244
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08003245 if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003246 /* Enable proper parity */
3247 if (IS_QLA2300(ha))
3248 /* SRAM parity */
3249 WRT_REG_WORD(&reg->hccr,
3250 (HCCR_ENABLE_PARITY + 0x1));
3251 else
3252 /*
3253 * SRAM, Instruction RAM and GP RAM
3254 * parity.
3255 */
3256 WRT_REG_WORD(&reg->hccr,
3257 (HCCR_ENABLE_PARITY + 0x7));
3258 RD_REG_WORD(&reg->hccr);
3259 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260
3261 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3262 }
3263 }
3264
3265 done:
3266 if (!status && !(status = qla2x00_init_rings(ha))) {
3267 clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
3268 if (!(status = qla2x00_fw_ready(ha))) {
3269 DEBUG(printk("%s(): Start configure loop, "
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003270 "status = %d\n", __func__, status));
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003271
3272 /* Issue a marker after FW becomes ready. */
3273 qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
3274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 ha->flags.online = 1;
3276 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3277 wait_time = 256;
3278 do {
3279 clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
3280 qla2x00_configure_loop(ha);
3281 wait_time--;
3282 } while (!atomic_read(&ha->loop_down_timer) &&
3283 !(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) &&
3284 wait_time &&
3285 (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)));
3286 }
3287
3288 /* if no cable then assume it's good */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003289 if ((ha->device_flags & DFLG_NO_CABLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003290 status = 0;
3291
3292 DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
3293 __func__,
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003294 status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003295 }
3296 return (status);
3297}
3298
3299/*
3300* qla2x00_reset_adapter
3301* Reset adapter.
3302*
3303* Input:
3304* ha = adapter block pointer.
3305*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003306void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307qla2x00_reset_adapter(scsi_qla_host_t *ha)
3308{
3309 unsigned long flags = 0;
Andrew Vasquez3d716442005-07-06 10:30:26 -07003310 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003311
3312 ha->flags.online = 0;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003313 ha->isp_ops.disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003314
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315 spin_lock_irqsave(&ha->hardware_lock, flags);
3316 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
3317 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3318 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
3319 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3320 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3321}
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003322
3323void
3324qla24xx_reset_adapter(scsi_qla_host_t *ha)
3325{
3326 unsigned long flags = 0;
3327 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
3328
3329 ha->flags.online = 0;
3330 ha->isp_ops.disable_intrs(ha);
3331
3332 spin_lock_irqsave(&ha->hardware_lock, flags);
3333 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
3334 RD_REG_DWORD(&reg->hccr);
3335 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
3336 RD_REG_DWORD(&reg->hccr);
3337 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3338}
3339
3340int
3341qla24xx_nvram_config(scsi_qla_host_t *ha)
3342{
3343 int rval;
3344 struct init_cb_24xx *icb;
3345 struct nvram_24xx *nv;
3346 uint32_t *dptr;
3347 uint8_t *dptr1, *dptr2;
3348 uint32_t chksum;
3349 uint16_t cnt;
3350
3351 rval = QLA_SUCCESS;
3352 icb = (struct init_cb_24xx *)ha->init_cb;
3353 nv = (struct nvram_24xx *)ha->request_ring;
3354
3355 /* Determine NVRAM starting address. */
3356 ha->nvram_size = sizeof(struct nvram_24xx);
3357 ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003358 ha->vpd_size = FA_NVRAM_VPD_SIZE;
3359 ha->vpd_base = FA_NVRAM_VPD0_ADDR;
3360 if (PCI_FUNC(ha->pdev->devfn)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003361 ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003362 ha->vpd_base = FA_NVRAM_VPD1_ADDR;
3363 }
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003364
3365 /* Get NVRAM data and calculate checksum. */
3366 dptr = (uint32_t *)nv;
3367 ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
3368 ha->nvram_size);
3369 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
3370 chksum += le32_to_cpu(*dptr++);
3371
3372 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
3373 DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
3374 ha->nvram_size));
3375
3376 /* Bad NVRAM data, set defaults parameters. */
3377 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
3378 || nv->id[3] != ' ' ||
3379 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
3380 /* Reset NVRAM data. */
3381 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
3382 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
3383 le16_to_cpu(nv->nvram_version));
3384 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
3385 "invalid -- WWPN) defaults.\n");
3386
3387 /*
3388 * Set default initialization control block.
3389 */
3390 memset(nv, 0, ha->nvram_size);
3391 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
3392 nv->version = __constant_cpu_to_le16(ICB_VERSION);
3393 nv->frame_payload_size = __constant_cpu_to_le16(2048);
3394 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3395 nv->exchange_count = __constant_cpu_to_le16(0);
3396 nv->hard_address = __constant_cpu_to_le16(124);
3397 nv->port_name[0] = 0x21;
3398 nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
3399 nv->port_name[2] = 0x00;
3400 nv->port_name[3] = 0xe0;
3401 nv->port_name[4] = 0x8b;
3402 nv->port_name[5] = 0x1c;
3403 nv->port_name[6] = 0x55;
3404 nv->port_name[7] = 0x86;
3405 nv->node_name[0] = 0x20;
3406 nv->node_name[1] = 0x00;
3407 nv->node_name[2] = 0x00;
3408 nv->node_name[3] = 0xe0;
3409 nv->node_name[4] = 0x8b;
3410 nv->node_name[5] = 0x1c;
3411 nv->node_name[6] = 0x55;
3412 nv->node_name[7] = 0x86;
3413 nv->login_retry_count = __constant_cpu_to_le16(8);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003414 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
3415 nv->login_timeout = __constant_cpu_to_le16(0);
3416 nv->firmware_options_1 =
3417 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
3418 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
3419 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
3420 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
3421 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
3422 nv->efi_parameters = __constant_cpu_to_le32(0);
3423 nv->reset_delay = 5;
3424 nv->max_luns_per_target = __constant_cpu_to_le16(128);
3425 nv->port_down_retry_count = __constant_cpu_to_le16(30);
3426 nv->link_down_timeout = __constant_cpu_to_le16(30);
3427
3428 rval = 1;
3429 }
3430
3431 /* Reset Initialization control block */
3432 memset(icb, 0, sizeof(struct init_cb_24xx));
3433
3434 /* Copy 1st segment. */
3435 dptr1 = (uint8_t *)icb;
3436 dptr2 = (uint8_t *)&nv->version;
3437 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
3438 while (cnt--)
3439 *dptr1++ = *dptr2++;
3440
3441 icb->login_retry_count = nv->login_retry_count;
Andrew Vasquez3ea66e22006-06-23 16:11:27 -07003442 icb->link_down_on_nos = nv->link_down_on_nos;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003443
3444 /* Copy 2nd segment. */
3445 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
3446 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
3447 cnt = (uint8_t *)&icb->reserved_3 -
3448 (uint8_t *)&icb->interrupt_delay_timer;
3449 while (cnt--)
3450 *dptr1++ = *dptr2++;
3451
3452 /*
3453 * Setup driver NVRAM options.
3454 */
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08003455 qla2x00_set_model_info(ha, nv->model_name, sizeof(nv->model_name),
3456 "QLA2462");
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003457
Andrew Vasquez5341e862006-05-17 15:09:16 -07003458 /* Use alternate WWN? */
3459 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
3460 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
3461 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
3462 }
3463
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003464 /* Prepare nodename */
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003465 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003466 /*
3467 * Firmware will apply the following mask if the nodename was
3468 * not provided.
3469 */
3470 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
3471 icb->node_name[0] &= 0xF0;
3472 }
3473
3474 /* Set host adapter parameters. */
3475 ha->flags.disable_risc_code_load = 0;
3476 ha->flags.enable_lip_reset = 1;
3477 ha->flags.enable_lip_full_login = 1;
3478 ha->flags.enable_target_reset = 1;
3479 ha->flags.enable_led_scheme = 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07003480 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003481
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003482 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
3483 (BIT_6 | BIT_5 | BIT_4)) >> 4;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003484
3485 memcpy(ha->fw_seriallink_options24, nv->seriallink_options,
3486 sizeof(ha->fw_seriallink_options24));
3487
3488 /* save HBA serial number */
3489 ha->serial0 = icb->port_name[5];
3490 ha->serial1 = icb->port_name[6];
3491 ha->serial2 = icb->port_name[7];
3492 ha->node_name = icb->node_name;
3493 ha->port_name = icb->port_name;
3494
andrew.vasquez@qlogic.combc8fb3c2006-01-13 17:05:42 -08003495 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3496
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003497 ha->retry_count = le16_to_cpu(nv->login_retry_count);
3498
3499 /* Set minimum login_timeout to 4 seconds. */
3500 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
3501 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
3502 if (le16_to_cpu(nv->login_timeout) < 4)
3503 nv->login_timeout = __constant_cpu_to_le16(4);
3504 ha->login_timeout = le16_to_cpu(nv->login_timeout);
3505 icb->login_timeout = cpu_to_le16(nv->login_timeout);
3506
3507 /* Set minimum RATOV to 200 tenths of a second. */
3508 ha->r_a_tov = 200;
3509
3510 ha->loop_reset_delay = nv->reset_delay;
3511
3512 /* Link Down Timeout = 0:
3513 *
3514 * When Port Down timer expires we will start returning
3515 * I/O's to OS with "DID_NO_CONNECT".
3516 *
3517 * Link Down Timeout != 0:
3518 *
3519 * The driver waits for the link to come up after link down
3520 * before returning I/Os to OS with "DID_NO_CONNECT".
3521 */
3522 if (le16_to_cpu(nv->link_down_timeout) == 0) {
3523 ha->loop_down_abort_time =
3524 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
3525 } else {
3526 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
3527 ha->loop_down_abort_time =
3528 (LOOP_DOWN_TIME - ha->link_down_timeout);
3529 }
3530
3531 /* Need enough time to try and get the port back. */
3532 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
3533 if (qlport_down_retry)
3534 ha->port_down_retry_count = qlport_down_retry;
3535
3536 /* Set login_retry_count */
3537 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
3538 if (ha->port_down_retry_count ==
3539 le16_to_cpu(nv->port_down_retry_count) &&
3540 ha->port_down_retry_count > 3)
3541 ha->login_retry_count = ha->port_down_retry_count;
3542 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
3543 ha->login_retry_count = ha->port_down_retry_count;
3544 if (ql2xloginretrycount)
3545 ha->login_retry_count = ql2xloginretrycount;
3546
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003547 /* Enable ZIO. */
3548 if (!ha->flags.init_done) {
3549 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
3550 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
3551 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
3552 le16_to_cpu(icb->interrupt_delay_timer): 2;
3553 }
3554 icb->firmware_options_2 &= __constant_cpu_to_le32(
3555 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
3556 ha->flags.process_response_queue = 0;
3557 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08003558 ha->zio_mode = QLA_ZIO_MODE_6;
3559
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003560 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
3561 "(%d us).\n", ha->host_no, ha->zio_mode,
3562 ha->zio_timer * 100));
3563 qla_printk(KERN_INFO, ha,
3564 "ZIO mode %d enabled; timer delay (%d us).\n",
3565 ha->zio_mode, ha->zio_timer * 100);
3566
3567 icb->firmware_options_2 |= cpu_to_le32(
3568 (uint32_t)ha->zio_mode);
3569 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
3570 ha->flags.process_response_queue = 1;
3571 }
3572
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003573 if (rval) {
3574 DEBUG2_3(printk(KERN_WARNING
3575 "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
3576 }
3577 return (rval);
3578}
3579
Adrian Bunk413975a2006-06-30 02:33:06 -07003580static int
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003581qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
3582{
3583 int rval;
3584 int segments, fragment;
3585 uint32_t faddr;
3586 uint32_t *dcode, dlen;
3587 uint32_t risc_addr;
3588 uint32_t risc_size;
3589 uint32_t i;
3590
3591 rval = QLA_SUCCESS;
3592
3593 segments = FA_RISC_CODE_SEGMENTS;
3594 faddr = FA_RISC_CODE_ADDR;
3595 dcode = (uint32_t *)ha->request_ring;
3596 *srisc_addr = 0;
3597
3598 /* Validate firmware image by checking version. */
3599 qla24xx_read_flash_data(ha, dcode, faddr + 4, 4);
3600 for (i = 0; i < 4; i++)
3601 dcode[i] = be32_to_cpu(dcode[i]);
3602 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
3603 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
3604 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
3605 dcode[3] == 0)) {
3606 qla_printk(KERN_WARNING, ha,
3607 "Unable to verify integrity of flash firmware image!\n");
3608 qla_printk(KERN_WARNING, ha,
3609 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
3610 dcode[1], dcode[2], dcode[3]);
3611
3612 return QLA_FUNCTION_FAILED;
3613 }
3614
3615 while (segments && rval == QLA_SUCCESS) {
3616 /* Read segment's load information. */
3617 qla24xx_read_flash_data(ha, dcode, faddr, 4);
3618
3619 risc_addr = be32_to_cpu(dcode[2]);
3620 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
3621 risc_size = be32_to_cpu(dcode[3]);
3622
3623 fragment = 0;
3624 while (risc_size > 0 && rval == QLA_SUCCESS) {
3625 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
3626 if (dlen > risc_size)
3627 dlen = risc_size;
3628
3629 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3630 "addr %x, number of dwords 0x%x, offset 0x%x.\n",
3631 ha->host_no, risc_addr, dlen, faddr));
3632
3633 qla24xx_read_flash_data(ha, dcode, faddr, dlen);
3634 for (i = 0; i < dlen; i++)
3635 dcode[i] = swab32(dcode[i]);
3636
3637 rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
3638 dlen);
3639 if (rval) {
3640 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
3641 "segment %d of firmware\n", ha->host_no,
3642 fragment));
3643 qla_printk(KERN_WARNING, ha,
3644 "[ERROR] Failed to load segment %d of "
3645 "firmware\n", fragment);
3646 break;
3647 }
3648
3649 faddr += dlen;
3650 risc_addr += dlen;
3651 risc_size -= dlen;
3652 fragment++;
3653 }
3654
3655 /* Next segment. */
3656 segments--;
3657 }
3658
3659 return rval;
3660}
3661
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003662#define QLA_FW_URL "ftp://ftp.qlogic.com/outgoing/linux/firmware/"
3663
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003664int
Andrew Vasquez54333832005-11-09 15:49:04 -08003665qla2x00_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
3666{
3667 int rval;
3668 int i, fragment;
3669 uint16_t *wcode, *fwcode;
3670 uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
3671 struct fw_blob *blob;
3672
3673 /* Load firmware blob. */
3674 blob = qla2x00_request_firmware(ha);
3675 if (!blob) {
3676 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003677 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
3678 "from: " QLA_FW_URL ".\n");
Andrew Vasquez54333832005-11-09 15:49:04 -08003679 return QLA_FUNCTION_FAILED;
3680 }
3681
3682 rval = QLA_SUCCESS;
3683
3684 wcode = (uint16_t *)ha->request_ring;
3685 *srisc_addr = 0;
3686 fwcode = (uint16_t *)blob->fw->data;
3687 fwclen = 0;
3688
3689 /* Validate firmware image by checking version. */
3690 if (blob->fw->size < 8 * sizeof(uint16_t)) {
3691 qla_printk(KERN_WARNING, ha,
3692 "Unable to verify integrity of firmware image (%Zd)!\n",
3693 blob->fw->size);
3694 goto fail_fw_integrity;
3695 }
3696 for (i = 0; i < 4; i++)
3697 wcode[i] = be16_to_cpu(fwcode[i + 4]);
3698 if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
3699 wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
3700 wcode[2] == 0 && wcode[3] == 0)) {
3701 qla_printk(KERN_WARNING, ha,
3702 "Unable to verify integrity of firmware image!\n");
3703 qla_printk(KERN_WARNING, ha,
3704 "Firmware data: %04x %04x %04x %04x!\n", wcode[0],
3705 wcode[1], wcode[2], wcode[3]);
3706 goto fail_fw_integrity;
3707 }
3708
3709 seg = blob->segs;
3710 while (*seg && rval == QLA_SUCCESS) {
3711 risc_addr = *seg;
3712 *srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
3713 risc_size = be16_to_cpu(fwcode[3]);
3714
3715 /* Validate firmware image size. */
3716 fwclen += risc_size * sizeof(uint16_t);
3717 if (blob->fw->size < fwclen) {
3718 qla_printk(KERN_WARNING, ha,
3719 "Unable to verify integrity of firmware image "
3720 "(%Zd)!\n", blob->fw->size);
3721 goto fail_fw_integrity;
3722 }
3723
3724 fragment = 0;
3725 while (risc_size > 0 && rval == QLA_SUCCESS) {
3726 wlen = (uint16_t)(ha->fw_transfer_size >> 1);
3727 if (wlen > risc_size)
3728 wlen = risc_size;
3729
3730 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3731 "addr %x, number of words 0x%x.\n", ha->host_no,
3732 risc_addr, wlen));
3733
3734 for (i = 0; i < wlen; i++)
3735 wcode[i] = swab16(fwcode[i]);
3736
3737 rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
3738 wlen);
3739 if (rval) {
3740 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
3741 "segment %d of firmware\n", ha->host_no,
3742 fragment));
3743 qla_printk(KERN_WARNING, ha,
3744 "[ERROR] Failed to load segment %d of "
3745 "firmware\n", fragment);
3746 break;
3747 }
3748
3749 fwcode += wlen;
3750 risc_addr += wlen;
3751 risc_size -= wlen;
3752 fragment++;
3753 }
3754
3755 /* Next segment. */
3756 seg++;
3757 }
3758 return rval;
3759
3760fail_fw_integrity:
3761 return QLA_FUNCTION_FAILED;
3762}
3763
3764int
3765qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003766{
3767 int rval;
3768 int segments, fragment;
3769 uint32_t *dcode, dlen;
3770 uint32_t risc_addr;
3771 uint32_t risc_size;
3772 uint32_t i;
Andrew Vasquez54333832005-11-09 15:49:04 -08003773 struct fw_blob *blob;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003774 uint32_t *fwcode, fwclen;
3775
Andrew Vasquez54333832005-11-09 15:49:04 -08003776 /* Load firmware blob. */
3777 blob = qla2x00_request_firmware(ha);
3778 if (!blob) {
3779 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003780 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
3781 "from: " QLA_FW_URL ".\n");
3782
3783 /* Try to load RISC code from flash. */
3784 qla_printk(KERN_ERR, ha, "Attempting to load (potentially "
3785 "outdated) firmware from flash.\n");
3786 return qla24xx_load_risc_flash(ha, srisc_addr);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003787 }
3788
3789 rval = QLA_SUCCESS;
3790
3791 segments = FA_RISC_CODE_SEGMENTS;
3792 dcode = (uint32_t *)ha->request_ring;
3793 *srisc_addr = 0;
Andrew Vasquez54333832005-11-09 15:49:04 -08003794 fwcode = (uint32_t *)blob->fw->data;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003795 fwclen = 0;
3796
3797 /* Validate firmware image by checking version. */
Andrew Vasquez54333832005-11-09 15:49:04 -08003798 if (blob->fw->size < 8 * sizeof(uint32_t)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003799 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08003800 "Unable to verify integrity of firmware image (%Zd)!\n",
3801 blob->fw->size);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003802 goto fail_fw_integrity;
3803 }
3804 for (i = 0; i < 4; i++)
3805 dcode[i] = be32_to_cpu(fwcode[i + 4]);
3806 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
3807 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
3808 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
3809 dcode[3] == 0)) {
3810 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08003811 "Unable to verify integrity of firmware image!\n");
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003812 qla_printk(KERN_WARNING, ha,
3813 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
3814 dcode[1], dcode[2], dcode[3]);
3815 goto fail_fw_integrity;
3816 }
3817
3818 while (segments && rval == QLA_SUCCESS) {
3819 risc_addr = be32_to_cpu(fwcode[2]);
3820 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
3821 risc_size = be32_to_cpu(fwcode[3]);
3822
3823 /* Validate firmware image size. */
3824 fwclen += risc_size * sizeof(uint32_t);
Andrew Vasquez54333832005-11-09 15:49:04 -08003825 if (blob->fw->size < fwclen) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003826 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08003827 "Unable to verify integrity of firmware image "
3828 "(%Zd)!\n", blob->fw->size);
3829
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003830 goto fail_fw_integrity;
3831 }
3832
3833 fragment = 0;
3834 while (risc_size > 0 && rval == QLA_SUCCESS) {
3835 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
3836 if (dlen > risc_size)
3837 dlen = risc_size;
3838
3839 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3840 "addr %x, number of dwords 0x%x.\n", ha->host_no,
3841 risc_addr, dlen));
3842
3843 for (i = 0; i < dlen; i++)
3844 dcode[i] = swab32(fwcode[i]);
3845
andrew.vasquez@qlogic.com590f98e2006-01-13 17:05:37 -08003846 rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
3847 dlen);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003848 if (rval) {
3849 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
3850 "segment %d of firmware\n", ha->host_no,
3851 fragment));
3852 qla_printk(KERN_WARNING, ha,
3853 "[ERROR] Failed to load segment %d of "
3854 "firmware\n", fragment);
3855 break;
3856 }
3857
3858 fwcode += dlen;
3859 risc_addr += dlen;
3860 risc_size -= dlen;
3861 fragment++;
3862 }
3863
3864 /* Next segment. */
3865 segments--;
3866 }
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003867 return rval;
3868
3869fail_fw_integrity:
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003870 return QLA_FUNCTION_FAILED;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003871}
Andrew Vasquez18c6c122006-10-13 09:33:38 -07003872
3873void
3874qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
3875{
3876 int ret, retries;
3877
3878 if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
3879 return;
3880
3881 ret = qla2x00_stop_firmware(ha);
3882 for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
3883 qla2x00_reset_chip(ha);
3884 if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
3885 continue;
3886 if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
3887 continue;
3888 qla_printk(KERN_INFO, ha,
3889 "Attempting retry of stop-firmware command...\n");
3890 ret = qla2x00_stop_firmware(ha);
3891 }
3892}