blob: db998d84cd402e379a1c611ecbacf01e10a64361 [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
David Miller4e08df32007-04-16 12:37:43 -070014#ifdef CONFIG_SPARC
15#include <asm/prom.h>
16#include <asm/pbm.h>
17#endif
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
20#ifndef EXT_IS_LUN_BIT_SET
21#define EXT_IS_LUN_BIT_SET(P,L) \
22 (((P)->mask[L/8] & (0x80 >> (L%8)))?1:0)
23#define EXT_SET_LUN_BIT(P,L) \
24 ((P)->mask[L/8] |= (0x80 >> (L%8)))
25#endif
26
27/*
28* QLogic ISP2x00 Hardware Support Function Prototypes.
29*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070030static int qla2x00_isp_firmware(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031static void qla2x00_resize_request_q(scsi_qla_host_t *);
32static int qla2x00_setup_chip(scsi_qla_host_t *);
33static void qla2x00_init_response_q_entries(scsi_qla_host_t *);
34static int qla2x00_init_rings(scsi_qla_host_t *);
35static int qla2x00_fw_ready(scsi_qla_host_t *);
36static int qla2x00_configure_hba(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070037static int qla2x00_configure_loop(scsi_qla_host_t *);
38static int qla2x00_configure_local_loop(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039static int qla2x00_configure_fabric(scsi_qla_host_t *);
40static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
41static int qla2x00_device_resync(scsi_qla_host_t *);
42static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
43 uint16_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45static int qla2x00_restart_isp(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Adrian Bunk413975a2006-06-30 02:33:06 -070047static int qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev);
48
Linus Torvalds1da177e2005-04-16 15:20:36 -070049/****************************************************************************/
50/* QLogic ISP2x00 Hardware Support Functions. */
51/****************************************************************************/
52
53/*
54* qla2x00_initialize_adapter
55* Initialize board.
56*
57* Input:
58* ha = adapter block pointer.
59*
60* Returns:
61* 0 = success
62*/
63int
64qla2x00_initialize_adapter(scsi_qla_host_t *ha)
65{
66 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
68 /* Clear adapter flags. */
69 ha->flags.online = 0;
70 ha->flags.reset_active = 0;
71 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
72 atomic_set(&ha->loop_state, LOOP_DOWN);
Andrew Vasquez26032212007-01-29 10:22:23 -080073 ha->device_flags = DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 ha->dpc_flags = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 ha->flags.management_server_logged_in = 0;
76 ha->marker_needed = 0;
77 ha->mbx_flags = 0;
78 ha->isp_abort_cnt = 0;
79 ha->beacon_blink_led = 0;
Andrew Vasquezcca53352005-08-26 19:08:30 -070080 set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Andrew Vasquez0107109e2005-07-06 10:31:37 -070082 qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
Andrew Vasquezabbd8872005-07-06 10:30:05 -070083 rval = ha->isp_ops.pci_config(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 if (rval) {
Andrew Vasquez7c98a042007-01-29 10:22:29 -080085 DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 ha->host_no));
87 return (rval);
88 }
89
Andrew Vasquezabbd8872005-07-06 10:30:05 -070090 ha->isp_ops.reset_chip(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Andrew Vasquez30c47662007-01-29 10:22:21 -080092 ha->isp_ops.get_flash_version(ha, ha->request_ring);
93
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
Andrew Vasquez0107109e2005-07-06 10:31:37 -070095
David Miller4e08df32007-04-16 12:37:43 -070096 ha->isp_ops.nvram_config(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Andrew Vasquezd4c760c2006-06-23 16:10:39 -070098 if (ha->flags.disable_serdes) {
99 /* Mask HBA via NVRAM settings? */
100 qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
101 "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
102 ha->port_name[0], ha->port_name[1],
103 ha->port_name[2], ha->port_name[3],
104 ha->port_name[4], ha->port_name[5],
105 ha->port_name[6], ha->port_name[7]);
106 return QLA_FUNCTION_FAILED;
107 }
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
110
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800111 if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
112 rval = ha->isp_ops.chip_diag(ha);
113 if (rval)
114 return (rval);
115 rval = qla2x00_setup_chip(ha);
116 if (rval)
117 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 }
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800119 rval = qla2x00_init_rings(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
121 return (rval);
122}
123
124/**
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700125 * qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 * @ha: HA context
127 *
128 * Returns 0 on success.
129 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700130int
131qla2100_pci_config(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700133 int ret;
134 uint16_t w;
Adam Kropelin27b2f672005-09-16 19:28:20 -0700135 uint32_t d;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700136 unsigned long flags;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700137 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 pci_set_master(ha->pdev);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700140 ret = pci_set_mwi(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700143 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
145
146 /* Reset expansion ROM address decode enable */
Adam Kropelin27b2f672005-09-16 19:28:20 -0700147 pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
148 d &= ~PCI_ROM_ADDRESS_ENABLE;
149 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700151 /* Get PCI bus information. */
152 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700153 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700154 spin_unlock_irqrestore(&ha->hardware_lock, flags);
155
156 return QLA_SUCCESS;
157}
158
159/**
160 * qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
161 * @ha: HA context
162 *
163 * Returns 0 on success.
164 */
165int
166qla2300_pci_config(scsi_qla_host_t *ha)
167{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700168 int ret;
169 uint16_t w;
Adam Kropelin27b2f672005-09-16 19:28:20 -0700170 uint32_t d;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700171 unsigned long flags = 0;
172 uint32_t cnt;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700173 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700174
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700175 pci_set_master(ha->pdev);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700176 ret = pci_set_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700177
178 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700179 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700180
181 if (IS_QLA2322(ha) || IS_QLA6322(ha))
182 w &= ~PCI_COMMAND_INTX_DISABLE;
Andrew Vasqueza157b102007-05-07 07:43:01 -0700183 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700184
185 /*
186 * If this is a 2300 card and not 2312, reset the
187 * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
188 * the 2310 also reports itself as a 2300 so we need to get the
189 * fb revision level -- a 6 indicates it really is a 2300 and
190 * not a 2310.
191 */
192 if (IS_QLA2300(ha)) {
193 spin_lock_irqsave(&ha->hardware_lock, flags);
194
195 /* Pause RISC. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700196 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700197 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700198 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700199 break;
200
201 udelay(10);
202 }
203
204 /* Select FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700205 WRT_REG_WORD(&reg->ctrl_status, 0x20);
206 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700207
208 /* Get the fb rev level */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700209 ha->fb_rev = RD_FB_CMD_REG(ha, reg);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700210
211 if (ha->fb_rev == FPM_2300)
Andrew Vasqueza157b102007-05-07 07:43:01 -0700212 pci_clear_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700213
214 /* Deselect FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700215 WRT_REG_WORD(&reg->ctrl_status, 0x0);
216 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700217
218 /* Release RISC module. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700219 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700220 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700221 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700222 break;
223
224 udelay(10);
225 }
226
227 spin_unlock_irqrestore(&ha->hardware_lock, flags);
228 }
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700229
230 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
231
232 /* Reset expansion ROM address decode enable */
Adam Kropelin27b2f672005-09-16 19:28:20 -0700233 pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
234 d &= ~PCI_ROM_ADDRESS_ENABLE;
235 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700236
237 /* Get PCI bus information. */
238 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700239 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700240 spin_unlock_irqrestore(&ha->hardware_lock, flags);
241
242 return QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243}
244
245/**
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700246 * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
247 * @ha: HA context
248 *
249 * Returns 0 on success.
250 */
251int
252qla24xx_pci_config(scsi_qla_host_t *ha)
253{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700254 int ret;
255 uint16_t w;
Adam Kropelin27b2f672005-09-16 19:28:20 -0700256 uint32_t d;
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700257 unsigned long flags = 0;
258 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
259 int pcix_cmd_reg, pcie_dctl_reg;
260
261 pci_set_master(ha->pdev);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700262 ret = pci_set_mwi(ha->pdev);
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700263
264 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700265 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700266 w &= ~PCI_COMMAND_INTX_DISABLE;
267 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
268
269 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
270
271 /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
272 pcix_cmd_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX);
273 if (pcix_cmd_reg) {
274 uint16_t pcix_cmd;
275
276 pcix_cmd_reg += PCI_X_CMD;
277 pci_read_config_word(ha->pdev, pcix_cmd_reg, &pcix_cmd);
278 pcix_cmd &= ~PCI_X_CMD_MAX_READ;
279 pcix_cmd |= 0x0008;
280 pci_write_config_word(ha->pdev, pcix_cmd_reg, pcix_cmd);
281 }
282
283 /* PCIe -- adjust Maximum Read Request Size (2048). */
284 pcie_dctl_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
285 if (pcie_dctl_reg) {
286 uint16_t pcie_dctl;
287
288 pcie_dctl_reg += PCI_EXP_DEVCTL;
289 pci_read_config_word(ha->pdev, pcie_dctl_reg, &pcie_dctl);
290 pcie_dctl &= ~PCI_EXP_DEVCTL_READRQ;
291 pcie_dctl |= 0x4000;
292 pci_write_config_word(ha->pdev, pcie_dctl_reg, pcie_dctl);
293 }
294
295 /* Reset expansion ROM address decode enable */
Adam Kropelin27b2f672005-09-16 19:28:20 -0700296 pci_read_config_dword(ha->pdev, PCI_ROM_ADDRESS, &d);
297 d &= ~PCI_ROM_ADDRESS_ENABLE;
298 pci_write_config_dword(ha->pdev, PCI_ROM_ADDRESS, d);
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700299
Andrew Vasqueza8488ab2007-01-29 10:22:19 -0800300 pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->chip_revision);
301
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700302 /* Get PCI bus information. */
303 spin_lock_irqsave(&ha->hardware_lock, flags);
304 ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
305 spin_unlock_irqrestore(&ha->hardware_lock, flags);
306
307 return QLA_SUCCESS;
308}
309
310/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311 * qla2x00_isp_firmware() - Choose firmware image.
312 * @ha: HA context
313 *
314 * Returns 0 on success.
315 */
316static int
317qla2x00_isp_firmware(scsi_qla_host_t *ha)
318{
319 int rval;
320
321 /* Assume loading risc code */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700322 rval = QLA_FUNCTION_FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 if (ha->flags.disable_risc_code_load) {
325 DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
326 ha->host_no));
327 qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
328
329 /* Verify checksum of loaded RISC code. */
Andrew Vasquez441d1072006-05-17 15:09:34 -0700330 rval = qla2x00_verify_checksum(ha, ha->fw_srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 }
332
333 if (rval) {
334 DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
335 ha->host_no));
336 }
337
338 return (rval);
339}
340
341/**
342 * qla2x00_reset_chip() - Reset ISP chip.
343 * @ha: HA context
344 *
345 * Returns 0 on success.
346 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700347void
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700348qla2x00_reset_chip(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349{
350 unsigned long flags = 0;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700351 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 uint32_t cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353 uint16_t cmd;
354
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700355 ha->isp_ops.disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 spin_lock_irqsave(&ha->hardware_lock, flags);
358
359 /* Turn off master enable */
360 cmd = 0;
361 pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
362 cmd &= ~PCI_COMMAND_MASTER;
363 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
364
365 if (!IS_QLA2100(ha)) {
366 /* Pause RISC. */
367 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
368 if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
369 for (cnt = 0; cnt < 30000; cnt++) {
370 if ((RD_REG_WORD(&reg->hccr) &
371 HCCR_RISC_PAUSE) != 0)
372 break;
373 udelay(100);
374 }
375 } else {
376 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
377 udelay(10);
378 }
379
380 /* Select FPM registers. */
381 WRT_REG_WORD(&reg->ctrl_status, 0x20);
382 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
383
384 /* FPM Soft Reset. */
385 WRT_REG_WORD(&reg->fpm_diag_config, 0x100);
386 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
387
388 /* Toggle Fpm Reset. */
389 if (!IS_QLA2200(ha)) {
390 WRT_REG_WORD(&reg->fpm_diag_config, 0x0);
391 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
392 }
393
394 /* Select frame buffer registers. */
395 WRT_REG_WORD(&reg->ctrl_status, 0x10);
396 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
397
398 /* Reset frame buffer FIFOs. */
399 if (IS_QLA2200(ha)) {
400 WRT_FB_CMD_REG(ha, reg, 0xa000);
401 RD_FB_CMD_REG(ha, reg); /* PCI Posting. */
402 } else {
403 WRT_FB_CMD_REG(ha, reg, 0x00fc);
404
405 /* Read back fb_cmd until zero or 3 seconds max */
406 for (cnt = 0; cnt < 3000; cnt++) {
407 if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
408 break;
409 udelay(100);
410 }
411 }
412
413 /* Select RISC module registers. */
414 WRT_REG_WORD(&reg->ctrl_status, 0);
415 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
416
417 /* Reset RISC processor. */
418 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
419 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
420
421 /* Release RISC processor. */
422 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
423 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
424 }
425
426 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
427 WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);
428
429 /* Reset ISP chip. */
430 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
431
432 /* Wait for RISC to recover from reset. */
433 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
434 /*
435 * It is necessary to for a delay here since the card doesn't
436 * respond to PCI reads during a reset. On some architectures
437 * this will result in an MCA.
438 */
439 udelay(20);
440 for (cnt = 30000; cnt; cnt--) {
441 if ((RD_REG_WORD(&reg->ctrl_status) &
442 CSR_ISP_SOFT_RESET) == 0)
443 break;
444 udelay(100);
445 }
446 } else
447 udelay(10);
448
449 /* Reset RISC processor. */
450 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
451
452 WRT_REG_WORD(&reg->semaphore, 0);
453
454 /* Release RISC processor. */
455 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
456 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
457
458 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
459 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquezffb39f02006-05-17 15:09:06 -0700460 if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462
463 udelay(100);
464 }
465 } else
466 udelay(100);
467
468 /* Turn on master enable */
469 cmd |= PCI_COMMAND_MASTER;
470 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
471
472 /* Disable RISC pause on FPM parity error. */
473 if (!IS_QLA2100(ha)) {
474 WRT_REG_WORD(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
475 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
476 }
477
478 spin_unlock_irqrestore(&ha->hardware_lock, flags);
479}
480
481/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700482 * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700483 * @ha: HA context
484 *
485 * Returns 0 on success.
486 */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700487static inline void
488qla24xx_reset_risc(scsi_qla_host_t *ha)
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700489{
490 unsigned long flags = 0;
491 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
492 uint32_t cnt, d2;
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800493 uint16_t wd;
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700494
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700495 spin_lock_irqsave(&ha->hardware_lock, flags);
496
497 /* Reset RISC. */
498 WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
499 for (cnt = 0; cnt < 30000; cnt++) {
500 if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
501 break;
502
503 udelay(10);
504 }
505
506 WRT_REG_DWORD(&reg->ctrl_status,
507 CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800508 pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700509
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800510 udelay(100);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700511 /* Wait for firmware to complete NVRAM accesses. */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700512 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
513 for (cnt = 10000 ; cnt && d2; cnt--) {
514 udelay(5);
515 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
516 barrier();
517 }
518
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800519 /* Wait for soft-reset to complete. */
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700520 d2 = RD_REG_DWORD(&reg->ctrl_status);
521 for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
522 udelay(5);
523 d2 = RD_REG_DWORD(&reg->ctrl_status);
524 barrier();
525 }
526
527 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
528 RD_REG_DWORD(&reg->hccr);
529
530 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
531 RD_REG_DWORD(&reg->hccr);
532
533 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
534 RD_REG_DWORD(&reg->hccr);
535
536 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
537 for (cnt = 6000000 ; cnt && d2; cnt--) {
538 udelay(5);
539 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
540 barrier();
541 }
542
543 spin_unlock_irqrestore(&ha->hardware_lock, flags);
544}
545
546/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700547 * qla24xx_reset_chip() - Reset ISP24xx chip.
548 * @ha: HA context
549 *
550 * Returns 0 on success.
551 */
552void
553qla24xx_reset_chip(scsi_qla_host_t *ha)
554{
555 ha->isp_ops.disable_intrs(ha);
556
557 /* Perform RISC reset. */
558 qla24xx_reset_risc(ha);
559}
560
561/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 * qla2x00_chip_diag() - Test chip for proper operation.
563 * @ha: HA context
564 *
565 * Returns 0 on success.
566 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700567int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568qla2x00_chip_diag(scsi_qla_host_t *ha)
569{
570 int rval;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700571 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 unsigned long flags = 0;
573 uint16_t data;
574 uint32_t cnt;
575 uint16_t mb[5];
576
577 /* Assume a failed state */
578 rval = QLA_FUNCTION_FAILED;
579
580 DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
581 ha->host_no, (u_long)&reg->flash_address));
582
583 spin_lock_irqsave(&ha->hardware_lock, flags);
584
585 /* Reset ISP chip. */
586 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
587
588 /*
589 * We need to have a delay here since the card will not respond while
590 * in reset causing an MCA on some architectures.
591 */
592 udelay(20);
593 data = qla2x00_debounce_register(&reg->ctrl_status);
594 for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
595 udelay(5);
596 data = RD_REG_WORD(&reg->ctrl_status);
597 barrier();
598 }
599
600 if (!cnt)
601 goto chip_diag_failed;
602
603 DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
604 ha->host_no));
605
606 /* Reset RISC processor. */
607 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
608 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
609
610 /* Workaround for QLA2312 PCI parity error */
611 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
612 data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
613 for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
614 udelay(5);
615 data = RD_MAILBOX_REG(ha, reg, 0);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700616 barrier();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 }
618 } else
619 udelay(10);
620
621 if (!cnt)
622 goto chip_diag_failed;
623
624 /* Check product ID of chip */
625 DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no));
626
627 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
628 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
629 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
630 mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
631 if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
632 mb[3] != PROD_ID_3) {
633 qla_printk(KERN_WARNING, ha,
634 "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
635
636 goto chip_diag_failed;
637 }
638 ha->product_id[0] = mb[1];
639 ha->product_id[1] = mb[2];
640 ha->product_id[2] = mb[3];
641 ha->product_id[3] = mb[4];
642
643 /* Adjust fw RISC transfer size */
644 if (ha->request_q_length > 1024)
645 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
646 else
647 ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
648 ha->request_q_length;
649
650 if (IS_QLA2200(ha) &&
651 RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
652 /* Limit firmware transfer size with a 2200A */
653 DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
654 ha->host_no));
655
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -0800656 ha->device_type |= DT_ISP2200A;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 ha->fw_transfer_size = 128;
658 }
659
660 /* Wrap Incoming Mailboxes Test. */
661 spin_unlock_irqrestore(&ha->hardware_lock, flags);
662
663 DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", ha->host_no));
664 rval = qla2x00_mbx_reg_test(ha);
665 if (rval) {
666 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
667 ha->host_no));
668 qla_printk(KERN_WARNING, ha,
669 "Failed mailbox send register test\n");
670 }
671 else {
672 /* Flag a successful rval */
673 rval = QLA_SUCCESS;
674 }
675 spin_lock_irqsave(&ha->hardware_lock, flags);
676
677chip_diag_failed:
678 if (rval)
679 DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
680 "****\n", ha->host_no));
681
682 spin_unlock_irqrestore(&ha->hardware_lock, flags);
683
684 return (rval);
685}
686
687/**
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700688 * qla24xx_chip_diag() - Test ISP24xx for proper operation.
689 * @ha: HA context
690 *
691 * Returns 0 on success.
692 */
693int
694qla24xx_chip_diag(scsi_qla_host_t *ha)
695{
696 int rval;
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700697
Andrew Vasquez88c26662005-07-08 17:59:26 -0700698 /* Perform RISC reset. */
699 qla24xx_reset_risc(ha);
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700700
701 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
702
703 rval = qla2x00_mbx_reg_test(ha);
704 if (rval) {
705 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
706 ha->host_no));
707 qla_printk(KERN_WARNING, ha,
708 "Failed mailbox send register test\n");
709 } else {
710 /* Flag a successful rval */
711 rval = QLA_SUCCESS;
712 }
713
714 return rval;
715}
716
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700717void
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700718qla2x00_alloc_fw_dump(scsi_qla_host_t *ha)
719{
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700720 int rval;
721 uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
722 eft_size;
723 dma_addr_t eft_dma;
724 void *eft;
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700725
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700726 if (ha->fw_dump) {
727 qla_printk(KERN_WARNING, ha,
728 "Firmware dump previously allocated.\n");
729 return;
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700730 }
731
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700732 ha->fw_dumped = 0;
733 fixed_size = mem_size = eft_size = 0;
734 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
735 fixed_size = sizeof(struct qla2100_fw_dump);
736 } else if (IS_QLA23XX(ha)) {
737 fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
738 mem_size = (ha->fw_memory_size - 0x11000 + 1) *
739 sizeof(uint16_t);
740 } else if (IS_QLA24XX(ha) || IS_QLA54XX(ha)) {
741 fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
742 mem_size = (ha->fw_memory_size - 0x100000 + 1) *
743 sizeof(uint32_t);
744
745 /* Allocate memory for Extended Trace Buffer. */
746 eft = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &eft_dma,
747 GFP_KERNEL);
748 if (!eft) {
749 qla_printk(KERN_WARNING, ha, "Unable to allocate "
750 "(%d KB) for EFT.\n", EFT_SIZE / 1024);
751 goto cont_alloc;
752 }
753
754 rval = qla2x00_trace_control(ha, TC_ENABLE, eft_dma,
755 EFT_NUM_BUFFERS);
756 if (rval) {
757 qla_printk(KERN_WARNING, ha, "Unable to initialize "
758 "EFT (%d).\n", rval);
759 dma_free_coherent(&ha->pdev->dev, EFT_SIZE, eft,
760 eft_dma);
761 goto cont_alloc;
762 }
763
764 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
765 EFT_SIZE / 1024);
766
767 eft_size = EFT_SIZE;
768 memset(eft, 0, eft_size);
769 ha->eft_dma = eft_dma;
770 ha->eft = eft;
771 }
772cont_alloc:
773 req_q_size = ha->request_q_length * sizeof(request_t);
774 rsp_q_size = ha->response_q_length * sizeof(response_t);
775
776 dump_size = offsetof(struct qla2xxx_fw_dump, isp);
777 dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
778 eft_size;
779
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700780 ha->fw_dump = vmalloc(dump_size);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700781 if (!ha->fw_dump) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700782 qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700783 "firmware dump!!!\n", dump_size / 1024);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700784
785 if (ha->eft) {
786 dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
787 ha->eft_dma);
788 ha->eft = NULL;
789 ha->eft_dma = 0;
790 }
791 return;
792 }
793
794 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
795 dump_size / 1024);
796
797 ha->fw_dump_len = dump_size;
798 ha->fw_dump->signature[0] = 'Q';
799 ha->fw_dump->signature[1] = 'L';
800 ha->fw_dump->signature[2] = 'G';
801 ha->fw_dump->signature[3] = 'C';
802 ha->fw_dump->version = __constant_htonl(1);
803
804 ha->fw_dump->fixed_size = htonl(fixed_size);
805 ha->fw_dump->mem_size = htonl(mem_size);
806 ha->fw_dump->req_q_size = htonl(req_q_size);
807 ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
808
809 ha->fw_dump->eft_size = htonl(eft_size);
810 ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
811 ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
812
813 ha->fw_dump->header_size =
814 htonl(offsetof(struct qla2xxx_fw_dump, isp));
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700815}
816
817/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 * qla2x00_resize_request_q() - Resize request queue given available ISP memory.
819 * @ha: HA context
820 *
821 * Returns 0 on success.
822 */
823static void
824qla2x00_resize_request_q(scsi_qla_host_t *ha)
825{
826 int rval;
827 uint16_t fw_iocb_cnt = 0;
828 uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM;
829 dma_addr_t request_dma;
830 request_t *request_ring;
831
832 /* Valid only on recent ISPs. */
833 if (IS_QLA2100(ha) || IS_QLA2200(ha))
834 return;
835
836 /* Retrieve IOCB counts available to the firmware. */
837 rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt);
838 if (rval)
839 return;
840 /* No point in continuing if current settings are sufficient. */
841 if (fw_iocb_cnt < 1024)
842 return;
843 if (ha->request_q_length >= request_q_length)
844 return;
845
846 /* Attempt to claim larger area for request queue. */
847 request_ring = dma_alloc_coherent(&ha->pdev->dev,
848 (request_q_length + 1) * sizeof(request_t), &request_dma,
849 GFP_KERNEL);
850 if (request_ring == NULL)
851 return;
852
853 /* Resize successful, report extensions. */
854 qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n",
855 (ha->fw_memory_size + 1) / 1024);
856 qla_printk(KERN_INFO, ha, "Resizing request queue depth "
857 "(%d -> %d)...\n", ha->request_q_length, request_q_length);
858
859 /* Clear old allocations. */
860 dma_free_coherent(&ha->pdev->dev,
861 (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring,
862 ha->request_dma);
863
864 /* Begin using larger queue. */
865 ha->request_q_length = request_q_length;
866 ha->request_ring = request_ring;
867 ha->request_dma = request_dma;
868}
869
870/**
871 * qla2x00_setup_chip() - Load and start RISC firmware.
872 * @ha: HA context
873 *
874 * Returns 0 on success.
875 */
876static int
877qla2x00_setup_chip(scsi_qla_host_t *ha)
878{
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700879 int rval;
880 uint32_t srisc_address = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
882 /* Load firmware sequences */
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700883 rval = ha->isp_ops.load_risc(ha, &srisc_address);
884 if (rval == QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
886 "code.\n", ha->host_no));
887
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700888 rval = qla2x00_verify_checksum(ha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if (rval == QLA_SUCCESS) {
890 /* Start firmware execution. */
891 DEBUG(printk("scsi(%ld): Checksum OK, start "
892 "firmware.\n", ha->host_no));
893
Andrew Vasquez0107109e2005-07-06 10:31:37 -0700894 rval = qla2x00_execute_fw(ha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 /* Retrieve firmware information. */
896 if (rval == QLA_SUCCESS && ha->fw_major_version == 0) {
897 qla2x00_get_fw_version(ha,
898 &ha->fw_major_version,
899 &ha->fw_minor_version,
900 &ha->fw_subminor_version,
901 &ha->fw_attributes, &ha->fw_memory_size);
902 qla2x00_resize_request_q(ha);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700903
904 if (ql2xallocfwdump)
905 qla2x00_alloc_fw_dump(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 }
907 } else {
908 DEBUG2(printk(KERN_INFO
909 "scsi(%ld): ISP Firmware failed checksum.\n",
910 ha->host_no));
911 }
912 }
913
914 if (rval) {
915 DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
916 ha->host_no));
917 }
918
919 return (rval);
920}
921
922/**
923 * qla2x00_init_response_q_entries() - Initializes response queue entries.
924 * @ha: HA context
925 *
926 * Beginning of request ring has initialization control block already built
927 * by nvram config routine.
928 *
929 * Returns 0 on success.
930 */
931static void
932qla2x00_init_response_q_entries(scsi_qla_host_t *ha)
933{
934 uint16_t cnt;
935 response_t *pkt;
936
937 pkt = ha->response_ring_ptr;
938 for (cnt = 0; cnt < ha->response_q_length; cnt++) {
939 pkt->signature = RESPONSE_PROCESSED;
940 pkt++;
941 }
942
943}
944
945/**
946 * qla2x00_update_fw_options() - Read and process firmware options.
947 * @ha: HA context
948 *
949 * Returns 0 on success.
950 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700951void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952qla2x00_update_fw_options(scsi_qla_host_t *ha)
953{
954 uint16_t swing, emphasis, tx_sens, rx_sens;
955
956 memset(ha->fw_options, 0, sizeof(ha->fw_options));
957 qla2x00_get_fw_options(ha, ha->fw_options);
958
959 if (IS_QLA2100(ha) || IS_QLA2200(ha))
960 return;
961
962 /* Serial Link options. */
963 DEBUG3(printk("scsi(%ld): Serial link options:\n",
964 ha->host_no));
965 DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
966 sizeof(ha->fw_seriallink_options)));
967
968 ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
969 if (ha->fw_seriallink_options[3] & BIT_2) {
970 ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
971
972 /* 1G settings */
973 swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
974 emphasis = (ha->fw_seriallink_options[2] &
975 (BIT_4 | BIT_3)) >> 3;
976 tx_sens = ha->fw_seriallink_options[0] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700977 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 rx_sens = (ha->fw_seriallink_options[0] &
979 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
980 ha->fw_options[10] = (emphasis << 14) | (swing << 8);
981 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
982 if (rx_sens == 0x0)
983 rx_sens = 0x3;
984 ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
985 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
986 ha->fw_options[10] |= BIT_5 |
987 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
988 (tx_sens & (BIT_1 | BIT_0));
989
990 /* 2G settings */
991 swing = (ha->fw_seriallink_options[2] &
992 (BIT_7 | BIT_6 | BIT_5)) >> 5;
993 emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
994 tx_sens = ha->fw_seriallink_options[1] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700995 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 rx_sens = (ha->fw_seriallink_options[1] &
997 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
998 ha->fw_options[11] = (emphasis << 14) | (swing << 8);
999 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
1000 if (rx_sens == 0x0)
1001 rx_sens = 0x3;
1002 ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
1003 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1004 ha->fw_options[11] |= BIT_5 |
1005 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1006 (tx_sens & (BIT_1 | BIT_0));
1007 }
1008
1009 /* FCP2 options. */
1010 /* Return command IOCBs without waiting for an ABTS to complete. */
1011 ha->fw_options[3] |= BIT_13;
1012
1013 /* LED scheme. */
1014 if (ha->flags.enable_led_scheme)
1015 ha->fw_options[2] |= BIT_12;
1016
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08001017 /* Detect ISP6312. */
1018 if (IS_QLA6312(ha))
1019 ha->fw_options[2] |= BIT_13;
1020
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 /* Update firmware options. */
1022 qla2x00_set_fw_options(ha, ha->fw_options);
1023}
1024
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001025void
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001026qla24xx_update_fw_options(scsi_qla_host_t *ha)
1027{
1028 int rval;
1029
1030 /* Update Serial Link options. */
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001031 if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001032 return;
1033
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001034 rval = qla2x00_set_serdes_params(ha,
1035 le16_to_cpu(ha->fw_seriallink_options24[1]),
1036 le16_to_cpu(ha->fw_seriallink_options24[2]),
1037 le16_to_cpu(ha->fw_seriallink_options24[3]));
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001038 if (rval != QLA_SUCCESS) {
1039 qla_printk(KERN_WARNING, ha,
1040 "Unable to update Serial Link options (%x).\n", rval);
1041 }
1042}
1043
1044void
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001045qla2x00_config_rings(struct scsi_qla_host *ha)
1046{
Andrew Vasquez3d716442005-07-06 10:30:26 -07001047 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001048
1049 /* Setup ring parameters in initialization control block. */
1050 ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0);
1051 ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0);
1052 ha->init_cb->request_q_length = cpu_to_le16(ha->request_q_length);
1053 ha->init_cb->response_q_length = cpu_to_le16(ha->response_q_length);
1054 ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(ha->request_dma));
1055 ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(ha->request_dma));
1056 ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(ha->response_dma));
1057 ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(ha->response_dma));
1058
1059 WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
1060 WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
1061 WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0);
1062 WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0);
1063 RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */
1064}
1065
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001066void
1067qla24xx_config_rings(struct scsi_qla_host *ha)
1068{
1069 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1070 struct init_cb_24xx *icb;
1071
1072 /* Setup ring parameters in initialization control block. */
1073 icb = (struct init_cb_24xx *)ha->init_cb;
1074 icb->request_q_outpointer = __constant_cpu_to_le16(0);
1075 icb->response_q_inpointer = __constant_cpu_to_le16(0);
1076 icb->request_q_length = cpu_to_le16(ha->request_q_length);
1077 icb->response_q_length = cpu_to_le16(ha->response_q_length);
1078 icb->request_q_address[0] = cpu_to_le32(LSD(ha->request_dma));
1079 icb->request_q_address[1] = cpu_to_le32(MSD(ha->request_dma));
1080 icb->response_q_address[0] = cpu_to_le32(LSD(ha->response_dma));
1081 icb->response_q_address[1] = cpu_to_le32(MSD(ha->response_dma));
1082
1083 WRT_REG_DWORD(&reg->req_q_in, 0);
1084 WRT_REG_DWORD(&reg->req_q_out, 0);
1085 WRT_REG_DWORD(&reg->rsp_q_in, 0);
1086 WRT_REG_DWORD(&reg->rsp_q_out, 0);
1087 RD_REG_DWORD(&reg->rsp_q_out);
1088}
1089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090/**
1091 * qla2x00_init_rings() - Initializes firmware.
1092 * @ha: HA context
1093 *
1094 * Beginning of request ring has initialization control block already built
1095 * by nvram config routine.
1096 *
1097 * Returns 0 on success.
1098 */
1099static int
1100qla2x00_init_rings(scsi_qla_host_t *ha)
1101{
1102 int rval;
1103 unsigned long flags = 0;
1104 int cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
1106 spin_lock_irqsave(&ha->hardware_lock, flags);
1107
1108 /* Clear outstanding commands array. */
1109 for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
1110 ha->outstanding_cmds[cnt] = NULL;
1111
1112 ha->current_outstanding_cmd = 0;
1113
1114 /* Clear RSCN queue. */
1115 ha->rscn_in_ptr = 0;
1116 ha->rscn_out_ptr = 0;
1117
1118 /* Initialize firmware. */
1119 ha->request_ring_ptr = ha->request_ring;
1120 ha->req_ring_index = 0;
1121 ha->req_q_cnt = ha->request_q_length;
1122 ha->response_ring_ptr = ha->response_ring;
1123 ha->rsp_ring_index = 0;
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 /* Initialize response queue entries */
1126 qla2x00_init_response_q_entries(ha);
1127
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001128 ha->isp_ops.config_rings(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
1130 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1131
1132 /* Update any ISP specific firmware options before initialization. */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001133 ha->isp_ops.update_fw_options(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134
1135 DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001136 rval = qla2x00_init_firmware(ha, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if (rval) {
1138 DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
1139 ha->host_no));
1140 } else {
1141 DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
1142 ha->host_no));
1143 }
1144
1145 return (rval);
1146}
1147
1148/**
1149 * qla2x00_fw_ready() - Waits for firmware ready.
1150 * @ha: HA context
1151 *
1152 * Returns 0 on success.
1153 */
1154static int
1155qla2x00_fw_ready(scsi_qla_host_t *ha)
1156{
1157 int rval;
1158 unsigned long wtime, mtime;
1159 uint16_t min_wait; /* Minimum wait time if loop is down */
1160 uint16_t wait_time; /* Wait time if loop is coming ready */
1161 uint16_t fw_state;
1162
1163 rval = QLA_SUCCESS;
1164
1165 /* 20 seconds for loop down. */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001166 min_wait = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
1168 /*
1169 * Firmware should take at most one RATOV to login, plus 5 seconds for
1170 * our own processing.
1171 */
1172 if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
1173 wait_time = min_wait;
1174 }
1175
1176 /* Min wait time if loop down */
1177 mtime = jiffies + (min_wait * HZ);
1178
1179 /* wait time before firmware ready */
1180 wtime = jiffies + (wait_time * HZ);
1181
1182 /* Wait for ISP to finish LIP */
1183 if (!ha->flags.init_done)
1184 qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
1185
1186 DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
1187 ha->host_no));
1188
1189 do {
1190 rval = qla2x00_get_firmware_state(ha, &fw_state);
1191 if (rval == QLA_SUCCESS) {
1192 if (fw_state < FSTATE_LOSS_OF_SYNC) {
1193 ha->device_flags &= ~DFLG_NO_CABLE;
1194 }
1195 if (fw_state == FSTATE_READY) {
1196 DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
1197 ha->host_no));
1198
1199 qla2x00_get_retry_cnt(ha, &ha->retry_count,
1200 &ha->login_timeout, &ha->r_a_tov);
1201
1202 rval = QLA_SUCCESS;
1203 break;
1204 }
1205
1206 rval = QLA_FUNCTION_FAILED;
1207
1208 if (atomic_read(&ha->loop_down_timer) &&
Andrew Vasquez7d7abc72006-06-23 16:11:17 -07001209 fw_state != FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210 /* Loop down. Timeout on min_wait for states
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001211 * other than Wait for Login.
1212 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (time_after_eq(jiffies, mtime)) {
1214 qla_printk(KERN_INFO, ha,
1215 "Cable is unplugged...\n");
1216
1217 ha->device_flags |= DFLG_NO_CABLE;
1218 break;
1219 }
1220 }
1221 } else {
1222 /* Mailbox cmd failed. Timeout on min_wait. */
1223 if (time_after_eq(jiffies, mtime))
1224 break;
1225 }
1226
1227 if (time_after_eq(jiffies, wtime))
1228 break;
1229
1230 /* Delay for a while */
1231 msleep(500);
1232
1233 DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
1234 ha->host_no, fw_state, jiffies));
1235 } while (1);
1236
1237 DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
1238 ha->host_no, fw_state, jiffies));
1239
1240 if (rval) {
1241 DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
1242 ha->host_no));
1243 }
1244
1245 return (rval);
1246}
1247
1248/*
1249* qla2x00_configure_hba
1250* Setup adapter context.
1251*
1252* Input:
1253* ha = adapter state pointer.
1254*
1255* Returns:
1256* 0 = success
1257*
1258* Context:
1259* Kernel context.
1260*/
1261static int
1262qla2x00_configure_hba(scsi_qla_host_t *ha)
1263{
1264 int rval;
1265 uint16_t loop_id;
1266 uint16_t topo;
1267 uint8_t al_pa;
1268 uint8_t area;
1269 uint8_t domain;
1270 char connect_type[22];
1271
1272 /* Get host addresses. */
1273 rval = qla2x00_get_adapter_id(ha,
1274 &loop_id, &al_pa, &area, &domain, &topo);
1275 if (rval != QLA_SUCCESS) {
Andrew Vasquez23443b12005-12-06 10:57:06 -08001276 if (LOOP_TRANSITION(ha) || atomic_read(&ha->loop_down_timer) ||
Ravi Anand33135aa2005-11-08 14:37:20 -08001277 (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
1278 DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
1279 __func__, ha->host_no));
1280 } else {
1281 qla_printk(KERN_WARNING, ha,
1282 "ERROR -- Unable to get host loop ID.\n");
1283 set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
1284 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285 return (rval);
1286 }
1287
1288 if (topo == 4) {
1289 qla_printk(KERN_INFO, ha,
1290 "Cannot get topology - retrying.\n");
1291 return (QLA_FUNCTION_FAILED);
1292 }
1293
1294 ha->loop_id = loop_id;
1295
1296 /* initialize */
1297 ha->min_external_loopid = SNS_FIRST_LOOP_ID;
1298 ha->operating_mode = LOOP;
1299
1300 switch (topo) {
1301 case 0:
1302 DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
1303 ha->host_no));
1304 ha->current_topology = ISP_CFG_NL;
1305 strcpy(connect_type, "(Loop)");
1306 break;
1307
1308 case 1:
1309 DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
1310 ha->host_no));
1311 ha->current_topology = ISP_CFG_FL;
1312 strcpy(connect_type, "(FL_Port)");
1313 break;
1314
1315 case 2:
1316 DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
1317 ha->host_no));
1318 ha->operating_mode = P2P;
1319 ha->current_topology = ISP_CFG_N;
1320 strcpy(connect_type, "(N_Port-to-N_Port)");
1321 break;
1322
1323 case 3:
1324 DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
1325 ha->host_no));
1326 ha->operating_mode = P2P;
1327 ha->current_topology = ISP_CFG_F;
1328 strcpy(connect_type, "(F_Port)");
1329 break;
1330
1331 default:
1332 DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
1333 "Using NL.\n",
1334 ha->host_no, topo));
1335 ha->current_topology = ISP_CFG_NL;
1336 strcpy(connect_type, "(Loop)");
1337 break;
1338 }
1339
1340 /* Save Host port and loop ID. */
1341 /* byte order - Big Endian */
1342 ha->d_id.b.domain = domain;
1343 ha->d_id.b.area = area;
1344 ha->d_id.b.al_pa = al_pa;
1345
1346 if (!ha->flags.init_done)
1347 qla_printk(KERN_INFO, ha,
1348 "Topology - %s, Host Loop address 0x%x\n",
1349 connect_type, ha->loop_id);
1350
1351 if (rval) {
1352 DEBUG2_3(printk("scsi(%ld): FAILED.\n", ha->host_no));
1353 } else {
1354 DEBUG3(printk("scsi(%ld): exiting normally.\n", ha->host_no));
1355 }
1356
1357 return(rval);
1358}
1359
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001360static inline void
1361qla2x00_set_model_info(scsi_qla_host_t *ha, uint8_t *model, size_t len, char *def)
1362{
1363 char *st, *en;
1364 uint16_t index;
1365
1366 if (memcmp(model, BINZERO, len) != 0) {
1367 strncpy(ha->model_number, model, len);
1368 st = en = ha->model_number;
1369 en += len - 1;
1370 while (en > st) {
1371 if (*en != 0x20 && *en != 0x00)
1372 break;
1373 *en-- = '\0';
1374 }
1375
1376 index = (ha->pdev->subsystem_device & 0xff);
1377 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1378 index < QLA_MODEL_NAMES)
1379 ha->model_desc = qla2x00_model_name[index * 2 + 1];
1380 } else {
1381 index = (ha->pdev->subsystem_device & 0xff);
1382 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1383 index < QLA_MODEL_NAMES) {
1384 strcpy(ha->model_number,
1385 qla2x00_model_name[index * 2]);
1386 ha->model_desc = qla2x00_model_name[index * 2 + 1];
1387 } else {
1388 strcpy(ha->model_number, def);
1389 }
1390 }
1391}
1392
David Miller4e08df32007-04-16 12:37:43 -07001393/* On sparc systems, obtain port and node WWN from firmware
1394 * properties.
1395 */
1396static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, nvram_t *nv)
1397{
1398#ifdef CONFIG_SPARC
1399 struct pci_dev *pdev = ha->pdev;
1400 struct pcidev_cookie *pcp = pdev->sysdata;
1401 struct device_node *dp = pcp->prom_node;
1402 u8 *val;
1403 int len;
1404
1405 val = of_get_property(dp, "port-wwn", &len);
1406 if (val && len >= WWN_SIZE)
1407 memcpy(nv->port_name, val, WWN_SIZE);
1408
1409 val = of_get_property(dp, "node-wwn", &len);
1410 if (val && len >= WWN_SIZE)
1411 memcpy(nv->node_name, val, WWN_SIZE);
1412#endif
1413}
1414
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415/*
1416* NVRAM configuration for ISP 2xxx
1417*
1418* Input:
1419* ha = adapter block pointer.
1420*
1421* Output:
1422* initialization control block in response_ring
1423* host adapters parameters in host adapter block
1424*
1425* Returns:
1426* 0 = success.
1427*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001428int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429qla2x00_nvram_config(scsi_qla_host_t *ha)
1430{
David Miller4e08df32007-04-16 12:37:43 -07001431 int rval;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001432 uint8_t chksum = 0;
1433 uint16_t cnt;
1434 uint8_t *dptr1, *dptr2;
1435 init_cb_t *icb = ha->init_cb;
1436 nvram_t *nv = (nvram_t *)ha->request_ring;
1437 uint8_t *ptr = (uint8_t *)ha->request_ring;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001438 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
David Miller4e08df32007-04-16 12:37:43 -07001440 rval = QLA_SUCCESS;
1441
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 /* Determine NVRAM starting address. */
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001443 ha->nvram_size = sizeof(nvram_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 ha->nvram_base = 0;
1445 if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
1446 if ((RD_REG_WORD(&reg->ctrl_status) >> 14) == 1)
1447 ha->nvram_base = 0x80;
1448
1449 /* Get NVRAM data and calculate checksum. */
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001450 ha->isp_ops.read_nvram(ha, ptr, ha->nvram_base, ha->nvram_size);
1451 for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
1452 chksum += *ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453
1454 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
1455 DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001456 ha->nvram_size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001457
1458 /* Bad NVRAM data, set defaults parameters. */
1459 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
1460 nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
1461 /* Reset NVRAM data. */
1462 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
1463 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
1464 nv->nvram_version);
David Miller4e08df32007-04-16 12:37:43 -07001465 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
1466 "invalid -- WWPN) defaults.\n");
1467
1468 /*
1469 * Set default initialization control block.
1470 */
1471 memset(nv, 0, ha->nvram_size);
1472 nv->parameter_block_version = ICB_VERSION;
1473
1474 if (IS_QLA23XX(ha)) {
1475 nv->firmware_options[0] = BIT_2 | BIT_1;
1476 nv->firmware_options[1] = BIT_7 | BIT_5;
1477 nv->add_firmware_options[0] = BIT_5;
1478 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1479 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1480 nv->special_options[1] = BIT_7;
1481 } else if (IS_QLA2200(ha)) {
1482 nv->firmware_options[0] = BIT_2 | BIT_1;
1483 nv->firmware_options[1] = BIT_7 | BIT_5;
1484 nv->add_firmware_options[0] = BIT_5;
1485 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1486 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1487 } else if (IS_QLA2100(ha)) {
1488 nv->firmware_options[0] = BIT_3 | BIT_1;
1489 nv->firmware_options[1] = BIT_5;
1490 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1491 }
1492
1493 nv->max_iocb_allocation = __constant_cpu_to_le16(256);
1494 nv->execution_throttle = __constant_cpu_to_le16(16);
1495 nv->retry_count = 8;
1496 nv->retry_delay = 1;
1497
1498 nv->port_name[0] = 33;
1499 nv->port_name[3] = 224;
1500 nv->port_name[4] = 139;
1501
1502 qla2xxx_nvram_wwn_from_ofw(ha, nv);
1503
1504 nv->login_timeout = 4;
1505
1506 /*
1507 * Set default host adapter parameters
1508 */
1509 nv->host_p[1] = BIT_2;
1510 nv->reset_delay = 5;
1511 nv->port_down_retry_count = 8;
1512 nv->max_luns_per_target = __constant_cpu_to_le16(8);
1513 nv->link_down_timeout = 60;
1514
1515 rval = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 }
1517
1518#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
1519 /*
1520 * The SN2 does not provide BIOS emulation which means you can't change
1521 * potentially bogus BIOS settings. Force the use of default settings
1522 * for link rate and frame size. Hope that the rest of the settings
1523 * are valid.
1524 */
1525 if (ia64_platform_is("sn2")) {
1526 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1527 if (IS_QLA23XX(ha))
1528 nv->special_options[1] = BIT_7;
1529 }
1530#endif
1531
1532 /* Reset Initialization control block */
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001533 memset(icb, 0, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534
1535 /*
1536 * Setup driver NVRAM options.
1537 */
1538 nv->firmware_options[0] |= (BIT_6 | BIT_1);
1539 nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
1540 nv->firmware_options[1] |= (BIT_5 | BIT_0);
1541 nv->firmware_options[1] &= ~BIT_4;
1542
1543 if (IS_QLA23XX(ha)) {
1544 nv->firmware_options[0] |= BIT_2;
1545 nv->firmware_options[0] &= ~BIT_3;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07001546 nv->add_firmware_options[1] |= BIT_5 | BIT_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 if (IS_QLA2300(ha)) {
1549 if (ha->fb_rev == FPM_2310) {
1550 strcpy(ha->model_number, "QLA2310");
1551 } else {
1552 strcpy(ha->model_number, "QLA2300");
1553 }
1554 } else {
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001555 qla2x00_set_model_info(ha, nv->model_number,
1556 sizeof(nv->model_number), "QLA23xx");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 }
1558 } else if (IS_QLA2200(ha)) {
1559 nv->firmware_options[0] |= BIT_2;
1560 /*
1561 * 'Point-to-point preferred, else loop' is not a safe
1562 * connection mode setting.
1563 */
1564 if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
1565 (BIT_5 | BIT_4)) {
1566 /* Force 'loop preferred, else point-to-point'. */
1567 nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
1568 nv->add_firmware_options[0] |= BIT_5;
1569 }
1570 strcpy(ha->model_number, "QLA22xx");
1571 } else /*if (IS_QLA2100(ha))*/ {
1572 strcpy(ha->model_number, "QLA2100");
1573 }
1574
1575 /*
1576 * Copy over NVRAM RISC parameter block to initialization control block.
1577 */
1578 dptr1 = (uint8_t *)icb;
1579 dptr2 = (uint8_t *)&nv->parameter_block_version;
1580 cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
1581 while (cnt--)
1582 *dptr1++ = *dptr2++;
1583
1584 /* Copy 2nd half. */
1585 dptr1 = (uint8_t *)icb->add_firmware_options;
1586 cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
1587 while (cnt--)
1588 *dptr1++ = *dptr2++;
1589
Andrew Vasquez5341e862006-05-17 15:09:16 -07001590 /* Use alternate WWN? */
1591 if (nv->host_p[1] & BIT_7) {
1592 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
1593 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
1594 }
1595
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 /* Prepare nodename */
1597 if ((icb->firmware_options[1] & BIT_6) == 0) {
1598 /*
1599 * Firmware will apply the following mask if the nodename was
1600 * not provided.
1601 */
1602 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
1603 icb->node_name[0] &= 0xF0;
1604 }
1605
1606 /*
1607 * Set host adapter parameters.
1608 */
Andrew Vasquez01819442006-06-23 16:11:10 -07001609 if (nv->host_p[0] & BIT_7)
Andrew Vasquez11010fe2006-10-06 09:54:59 -07001610 ql2xextended_error_logging = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001611 ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
1612 /* Always load RISC code on non ISP2[12]00 chips. */
1613 if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
1614 ha->flags.disable_risc_code_load = 0;
1615 ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
1616 ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
1617 ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
Andrew Vasquez06c22bd2005-08-26 19:09:00 -07001618 ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07001619 ha->flags.disable_serdes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001620
1621 ha->operating_mode =
1622 (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
1623
1624 memcpy(ha->fw_seriallink_options, nv->seriallink_options,
1625 sizeof(ha->fw_seriallink_options));
1626
1627 /* save HBA serial number */
1628 ha->serial0 = icb->port_name[5];
1629 ha->serial1 = icb->port_name[6];
1630 ha->serial2 = icb->port_name[7];
Andrew Vasquez3d716442005-07-06 10:30:26 -07001631 ha->node_name = icb->node_name;
1632 ha->port_name = icb->port_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633
1634 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
1635
1636 ha->retry_count = nv->retry_count;
1637
1638 /* Set minimum login_timeout to 4 seconds. */
1639 if (nv->login_timeout < ql2xlogintimeout)
1640 nv->login_timeout = ql2xlogintimeout;
1641 if (nv->login_timeout < 4)
1642 nv->login_timeout = 4;
1643 ha->login_timeout = nv->login_timeout;
1644 icb->login_timeout = nv->login_timeout;
1645
1646 /* Set minimum RATOV to 200 tenths of a second. */
1647 ha->r_a_tov = 200;
1648
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 ha->loop_reset_delay = nv->reset_delay;
1650
Linus Torvalds1da177e2005-04-16 15:20:36 -07001651 /* Link Down Timeout = 0:
1652 *
1653 * When Port Down timer expires we will start returning
1654 * I/O's to OS with "DID_NO_CONNECT".
1655 *
1656 * Link Down Timeout != 0:
1657 *
1658 * The driver waits for the link to come up after link down
1659 * before returning I/Os to OS with "DID_NO_CONNECT".
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001660 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 if (nv->link_down_timeout == 0) {
1662 ha->loop_down_abort_time =
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001663 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001664 } else {
1665 ha->link_down_timeout = nv->link_down_timeout;
1666 ha->loop_down_abort_time =
1667 (LOOP_DOWN_TIME - ha->link_down_timeout);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001668 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669
Linus Torvalds1da177e2005-04-16 15:20:36 -07001670 /*
1671 * Need enough time to try and get the port back.
1672 */
1673 ha->port_down_retry_count = nv->port_down_retry_count;
1674 if (qlport_down_retry)
1675 ha->port_down_retry_count = qlport_down_retry;
1676 /* Set login_retry_count */
1677 ha->login_retry_count = nv->retry_count;
1678 if (ha->port_down_retry_count == nv->port_down_retry_count &&
1679 ha->port_down_retry_count > 3)
1680 ha->login_retry_count = ha->port_down_retry_count;
1681 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
1682 ha->login_retry_count = ha->port_down_retry_count;
1683 if (ql2xloginretrycount)
1684 ha->login_retry_count = ql2xloginretrycount;
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 icb->lun_enables = __constant_cpu_to_le16(0);
1687 icb->command_resource_count = 0;
1688 icb->immediate_notify_resource_count = 0;
1689 icb->timeout = __constant_cpu_to_le16(0);
1690
1691 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
1692 /* Enable RIO */
1693 icb->firmware_options[0] &= ~BIT_3;
1694 icb->add_firmware_options[0] &=
1695 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
1696 icb->add_firmware_options[0] |= BIT_2;
1697 icb->response_accumulation_timer = 3;
1698 icb->interrupt_delay_timer = 5;
1699
1700 ha->flags.process_response_queue = 1;
1701 } else {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001702 /* Enable ZIO. */
1703 if (!ha->flags.init_done) {
1704 ha->zio_mode = icb->add_firmware_options[0] &
1705 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
1706 ha->zio_timer = icb->interrupt_delay_timer ?
1707 icb->interrupt_delay_timer: 2;
1708 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 icb->add_firmware_options[0] &=
1710 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001711 ha->flags.process_response_queue = 0;
1712 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001713 ha->zio_mode = QLA_ZIO_MODE_6;
1714
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001715 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
1716 "delay (%d us).\n", ha->host_no, ha->zio_mode,
1717 ha->zio_timer * 100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718 qla_printk(KERN_INFO, ha,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001719 "ZIO mode %d enabled; timer delay (%d us).\n",
1720 ha->zio_mode, ha->zio_timer * 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001722 icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
1723 icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724 ha->flags.process_response_queue = 1;
1725 }
1726 }
1727
David Miller4e08df32007-04-16 12:37:43 -07001728 if (rval) {
1729 DEBUG2_3(printk(KERN_WARNING
1730 "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
1731 }
1732 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733}
1734
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001735static void
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001736qla2x00_rport_del(void *data)
1737{
1738 fc_port_t *fcport = data;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001739 struct fc_rport *rport;
1740 unsigned long flags;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001741
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001742 spin_lock_irqsave(&fcport->rport_lock, flags);
1743 rport = fcport->drport;
1744 fcport->drport = NULL;
1745 spin_unlock_irqrestore(&fcport->rport_lock, flags);
1746 if (rport)
1747 fc_remote_port_delete(rport);
1748
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001749}
1750
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751/**
1752 * qla2x00_alloc_fcport() - Allocate a generic fcport.
1753 * @ha: HA context
1754 * @flags: allocation flags
1755 *
1756 * Returns a pointer to the allocated fcport, or NULL, if none available.
1757 */
Adrian Bunk413975a2006-06-30 02:33:06 -07001758static fc_port_t *
Al Viroc53033f2005-10-21 03:22:08 -04001759qla2x00_alloc_fcport(scsi_qla_host_t *ha, gfp_t flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760{
1761 fc_port_t *fcport;
1762
1763 fcport = kmalloc(sizeof(fc_port_t), flags);
1764 if (fcport == NULL)
1765 return (fcport);
1766
1767 /* Setup fcport template structure. */
1768 memset(fcport, 0, sizeof (fc_port_t));
1769 fcport->ha = ha;
1770 fcport->port_type = FCT_UNKNOWN;
1771 fcport->loop_id = FC_NO_LOOP_ID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001772 atomic_set(&fcport->state, FCS_UNCONFIGURED);
1773 fcport->flags = FCF_RLC_SUPPORT;
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07001774 fcport->supported_classes = FC_COS_UNSPECIFIED;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001775 spin_lock_init(&fcport->rport_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776
1777 return (fcport);
1778}
1779
1780/*
1781 * qla2x00_configure_loop
1782 * Updates Fibre Channel Device Database with what is actually on loop.
1783 *
1784 * Input:
1785 * ha = adapter block pointer.
1786 *
1787 * Returns:
1788 * 0 = success.
1789 * 1 = error.
1790 * 2 = database was full and device was not configured.
1791 */
1792static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001793qla2x00_configure_loop(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794{
1795 int rval;
1796 unsigned long flags, save_flags;
1797
1798 rval = QLA_SUCCESS;
1799
1800 /* Get Initiator ID */
1801 if (test_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags)) {
1802 rval = qla2x00_configure_hba(ha);
1803 if (rval != QLA_SUCCESS) {
1804 DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
1805 ha->host_no));
1806 return (rval);
1807 }
1808 }
1809
1810 save_flags = flags = ha->dpc_flags;
1811 DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
1812 ha->host_no, flags));
1813
1814 /*
1815 * If we have both an RSCN and PORT UPDATE pending then handle them
1816 * both at the same time.
1817 */
1818 clear_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
1819 clear_bit(RSCN_UPDATE, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820
1821 /* Determine what we need to do */
1822 if (ha->current_topology == ISP_CFG_FL &&
1823 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
1824
1825 ha->flags.rscn_queue_overflow = 1;
1826 set_bit(RSCN_UPDATE, &flags);
1827
1828 } else if (ha->current_topology == ISP_CFG_F &&
1829 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
1830
1831 ha->flags.rscn_queue_overflow = 1;
1832 set_bit(RSCN_UPDATE, &flags);
1833 clear_bit(LOCAL_LOOP_UPDATE, &flags);
1834
Andrew Vasquez21333b42006-05-17 15:09:56 -07001835 } else if (ha->current_topology == ISP_CFG_N) {
1836 clear_bit(RSCN_UPDATE, &flags);
1837
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 } else if (!ha->flags.online ||
1839 (test_bit(ABORT_ISP_ACTIVE, &flags))) {
1840
1841 ha->flags.rscn_queue_overflow = 1;
1842 set_bit(RSCN_UPDATE, &flags);
1843 set_bit(LOCAL_LOOP_UPDATE, &flags);
1844 }
1845
1846 if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
1847 if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
1848 rval = QLA_FUNCTION_FAILED;
1849 } else {
1850 rval = qla2x00_configure_local_loop(ha);
1851 }
1852 }
1853
1854 if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
Andrew Vasquez23443b12005-12-06 10:57:06 -08001855 if (LOOP_TRANSITION(ha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 rval = QLA_FUNCTION_FAILED;
1857 } else {
1858 rval = qla2x00_configure_fabric(ha);
1859 }
1860 }
1861
1862 if (rval == QLA_SUCCESS) {
1863 if (atomic_read(&ha->loop_down_timer) ||
1864 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
1865 rval = QLA_FUNCTION_FAILED;
1866 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 atomic_set(&ha->loop_state, LOOP_READY);
1868
1869 DEBUG(printk("scsi(%ld): LOOP READY\n", ha->host_no));
1870 }
1871 }
1872
1873 if (rval) {
1874 DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
1875 __func__, ha->host_no));
1876 } else {
1877 DEBUG3(printk("%s: exiting normally\n", __func__));
1878 }
1879
1880 /* Restore state if a resync event occured during processing */
1881 if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
1882 if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
1883 set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
1884 if (test_bit(RSCN_UPDATE, &save_flags))
1885 set_bit(RSCN_UPDATE, &ha->dpc_flags);
1886 }
1887
1888 return (rval);
1889}
1890
1891
1892
1893/*
1894 * qla2x00_configure_local_loop
1895 * Updates Fibre Channel Device Database with local loop devices.
1896 *
1897 * Input:
1898 * ha = adapter block pointer.
1899 *
1900 * Returns:
1901 * 0 = success.
1902 */
1903static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001904qla2x00_configure_local_loop(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905{
1906 int rval, rval2;
1907 int found_devs;
1908 int found;
1909 fc_port_t *fcport, *new_fcport;
1910
1911 uint16_t index;
1912 uint16_t entries;
1913 char *id_iter;
1914 uint16_t loop_id;
1915 uint8_t domain, area, al_pa;
1916
1917 found_devs = 0;
1918 new_fcport = NULL;
1919 entries = MAX_FIBRE_DEVICES;
1920
1921 DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", ha->host_no));
1922 DEBUG3(qla2x00_get_fcal_position_map(ha, NULL));
1923
1924 /* Get list of logged in devices. */
1925 memset(ha->gid_list, 0, GID_LIST_SIZE);
1926 rval = qla2x00_get_id_list(ha, ha->gid_list, ha->gid_list_dma,
1927 &entries);
1928 if (rval != QLA_SUCCESS)
1929 goto cleanup_allocation;
1930
1931 DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
1932 ha->host_no, entries));
1933 DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
1934 entries * sizeof(struct gid_list_info)));
1935
1936 /* Allocate temporary fcport for any new fcports discovered. */
1937 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
1938 if (new_fcport == NULL) {
1939 rval = QLA_MEMORY_ALLOC_FAILED;
1940 goto cleanup_allocation;
1941 }
1942 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
1943
1944 /*
1945 * Mark local devices that were present with FCF_DEVICE_LOST for now.
1946 */
1947 list_for_each_entry(fcport, &ha->fcports, list) {
1948 if (atomic_read(&fcport->state) == FCS_ONLINE &&
1949 fcport->port_type != FCT_BROADCAST &&
1950 (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
1951
1952 DEBUG(printk("scsi(%ld): Marking port lost, "
1953 "loop_id=0x%04x\n",
1954 ha->host_no, fcport->loop_id));
1955
1956 atomic_set(&fcport->state, FCS_DEVICE_LOST);
1957 fcport->flags &= ~FCF_FARP_DONE;
1958 }
1959 }
1960
1961 /* Add devices to port list. */
1962 id_iter = (char *)ha->gid_list;
1963 for (index = 0; index < entries; index++) {
1964 domain = ((struct gid_list_info *)id_iter)->domain;
1965 area = ((struct gid_list_info *)id_iter)->area;
1966 al_pa = ((struct gid_list_info *)id_iter)->al_pa;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001967 if (IS_QLA2100(ha) || IS_QLA2200(ha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 loop_id = (uint16_t)
1969 ((struct gid_list_info *)id_iter)->loop_id_2100;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001970 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 loop_id = le16_to_cpu(
1972 ((struct gid_list_info *)id_iter)->loop_id);
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001973 id_iter += ha->gid_list_info_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974
1975 /* Bypass reserved domain fields. */
1976 if ((domain & 0xf0) == 0xf0)
1977 continue;
1978
1979 /* Bypass if not same domain and area of adapter. */
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07001980 if (area && domain &&
1981 (area != ha->d_id.b.area || domain != ha->d_id.b.domain))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 continue;
1983
1984 /* Bypass invalid local loop ID. */
1985 if (loop_id > LAST_LOCAL_LOOP_ID)
1986 continue;
1987
1988 /* Fill in member data. */
1989 new_fcport->d_id.b.domain = domain;
1990 new_fcport->d_id.b.area = area;
1991 new_fcport->d_id.b.al_pa = al_pa;
1992 new_fcport->loop_id = loop_id;
1993 rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
1994 if (rval2 != QLA_SUCCESS) {
1995 DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
1996 "information -- get_port_database=%x, "
1997 "loop_id=0x%04x\n",
1998 ha->host_no, rval2, new_fcport->loop_id));
andrew.vasquez@qlogic.comc9d02ac2006-01-13 17:05:26 -08001999 DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
2000 ha->host_no));
2001 set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 continue;
2003 }
2004
2005 /* Check for matching device in port list. */
2006 found = 0;
2007 fcport = NULL;
2008 list_for_each_entry(fcport, &ha->fcports, list) {
2009 if (memcmp(new_fcport->port_name, fcport->port_name,
2010 WWN_SIZE))
2011 continue;
2012
2013 fcport->flags &= ~(FCF_FABRIC_DEVICE |
2014 FCF_PERSISTENT_BOUND);
2015 fcport->loop_id = new_fcport->loop_id;
2016 fcport->port_type = new_fcport->port_type;
2017 fcport->d_id.b24 = new_fcport->d_id.b24;
2018 memcpy(fcport->node_name, new_fcport->node_name,
2019 WWN_SIZE);
2020
2021 found++;
2022 break;
2023 }
2024
2025 if (!found) {
2026 /* New device, add to fcports list. */
2027 new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
2028 list_add_tail(&new_fcport->list, &ha->fcports);
2029
2030 /* Allocate a new replacement fcport. */
2031 fcport = new_fcport;
2032 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
2033 if (new_fcport == NULL) {
2034 rval = QLA_MEMORY_ALLOC_FAILED;
2035 goto cleanup_allocation;
2036 }
2037 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2038 }
2039
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002040 /* Base iIDMA settings on HBA port speed. */
2041 switch (ha->link_data_rate) {
2042 case PORT_SPEED_1GB:
2043 fcport->fp_speed = cpu_to_be16(BIT_15);
2044 break;
2045 case PORT_SPEED_2GB:
2046 fcport->fp_speed = cpu_to_be16(BIT_14);
2047 break;
2048 case PORT_SPEED_4GB:
2049 fcport->fp_speed = cpu_to_be16(BIT_13);
2050 break;
2051 }
2052
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 qla2x00_update_fcport(ha, fcport);
2054
2055 found_devs++;
2056 }
2057
2058cleanup_allocation:
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002059 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
2061 if (rval != QLA_SUCCESS) {
2062 DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
2063 "rval=%x\n", ha->host_no, rval));
2064 }
2065
2066 if (found_devs) {
2067 ha->device_flags |= DFLG_LOCAL_DEVICES;
2068 ha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES;
2069 }
2070
2071 return (rval);
2072}
2073
2074static void
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002075qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076{
2077 fc_port_t *fcport;
2078
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002079 qla2x00_mark_all_devices_lost(ha, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002080 list_for_each_entry(fcport, &ha->fcports, list) {
2081 if (fcport->port_type != FCT_TARGET)
2082 continue;
2083
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002084 qla2x00_update_fcport(ha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 }
2086}
2087
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002088static void
2089qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
2090{
2091#define LS_UNKNOWN 2
2092 static char *link_speeds[5] = { "1", "2", "?", "4" };
2093 int rval;
2094 uint16_t port_speed, mb[6];
2095
2096 if (!IS_QLA24XX(ha))
2097 return;
2098
2099 switch (be16_to_cpu(fcport->fp_speed)) {
2100 case BIT_15:
2101 port_speed = PORT_SPEED_1GB;
2102 break;
2103 case BIT_14:
2104 port_speed = PORT_SPEED_2GB;
2105 break;
2106 case BIT_13:
2107 port_speed = PORT_SPEED_4GB;
2108 break;
2109 default:
2110 DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
2111 "unsupported FM port operating speed (%04x).\n",
2112 ha->host_no, fcport->port_name[0], fcport->port_name[1],
2113 fcport->port_name[2], fcport->port_name[3],
2114 fcport->port_name[4], fcport->port_name[5],
2115 fcport->port_name[6], fcport->port_name[7],
2116 be16_to_cpu(fcport->fp_speed)));
2117 port_speed = PORT_SPEED_UNKNOWN;
2118 break;
2119 }
2120 if (port_speed == PORT_SPEED_UNKNOWN)
2121 return;
2122
2123 rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
2124 if (rval != QLA_SUCCESS) {
2125 DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
2126 "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
2127 ha->host_no, fcport->port_name[0], fcport->port_name[1],
2128 fcport->port_name[2], fcport->port_name[3],
2129 fcport->port_name[4], fcport->port_name[5],
2130 fcport->port_name[6], fcport->port_name[7], rval,
2131 port_speed, mb[0], mb[1]));
2132 } else {
2133 DEBUG2(qla_printk(KERN_INFO, ha,
2134 "iIDMA adjusted to %s GB/s on "
2135 "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
2136 link_speeds[port_speed], fcport->port_name[0],
2137 fcport->port_name[1], fcport->port_name[2],
2138 fcport->port_name[3], fcport->port_name[4],
2139 fcport->port_name[5], fcport->port_name[6],
2140 fcport->port_name[7]));
2141 }
2142}
2143
Adrian Bunk23be3312006-11-24 02:46:01 +01002144static void
8482e1182005-04-17 15:04:54 -05002145qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport)
2146{
2147 struct fc_rport_identifiers rport_ids;
bdf79622005-04-17 15:06:53 -05002148 struct fc_rport *rport;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002149 unsigned long flags;
8482e1182005-04-17 15:04:54 -05002150
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002151 if (fcport->drport)
2152 qla2x00_rport_del(fcport);
2153 if (fcport->rport)
2154 return;
8482e1182005-04-17 15:04:54 -05002155
Andrew Vasquezf8b02a82005-08-31 15:21:20 -07002156 rport_ids.node_name = wwn_to_u64(fcport->node_name);
2157 rport_ids.port_name = wwn_to_u64(fcport->port_name);
8482e1182005-04-17 15:04:54 -05002158 rport_ids.port_id = fcport->d_id.b.domain << 16 |
2159 fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
2160 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002161 rport = fc_remote_port_add(ha->host, 0, &rport_ids);
Andrew Vasquez77d74142005-07-08 18:00:36 -07002162 if (!rport) {
2163 qla_printk(KERN_WARNING, ha,
2164 "Unable to allocate fc remote port!\n");
2165 return;
2166 }
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002167 spin_lock_irqsave(&fcport->rport_lock, flags);
2168 fcport->rport = rport;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002169 *((fc_port_t **)rport->dd_data) = fcport;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002170 spin_unlock_irqrestore(&fcport->rport_lock, flags);
2171
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002172 rport->supported_classes = fcport->supported_classes;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002173
2174 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
8482e1182005-04-17 15:04:54 -05002175 if (fcport->port_type == FCT_INITIATOR)
2176 rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
2177 if (fcport->port_type == FCT_TARGET)
2178 rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002179 fc_remote_port_rolechg(rport, rport_ids.roles);
bdf79622005-04-17 15:06:53 -05002180
Andrew Vasquezcc4731f2005-07-06 10:32:37 -07002181 if (rport->scsi_target_id != -1 &&
2182 rport->scsi_target_id < ha->host->max_id)
bdf79622005-04-17 15:06:53 -05002183 fcport->os_target_id = rport->scsi_target_id;
8482e1182005-04-17 15:04:54 -05002184}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185
2186/*
Adrian Bunk23be3312006-11-24 02:46:01 +01002187 * qla2x00_update_fcport
2188 * Updates device on list.
2189 *
2190 * Input:
2191 * ha = adapter block pointer.
2192 * fcport = port structure pointer.
2193 *
2194 * Return:
2195 * 0 - Success
2196 * BIT_0 - error
2197 *
2198 * Context:
2199 * Kernel context.
2200 */
2201void
2202qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
2203{
2204 fcport->ha = ha;
2205 fcport->login_retry = 0;
2206 fcport->port_login_retry_count = ha->port_down_retry_count *
2207 PORT_RETRY_TIME;
2208 atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
2209 PORT_RETRY_TIME);
2210 fcport->flags &= ~FCF_LOGIN_NEEDED;
2211
2212 qla2x00_iidma_fcport(ha, fcport);
2213
2214 atomic_set(&fcport->state, FCS_ONLINE);
2215
2216 qla2x00_reg_remote_port(ha, fcport);
2217}
2218
2219/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220 * qla2x00_configure_fabric
2221 * Setup SNS devices with loop ID's.
2222 *
2223 * Input:
2224 * ha = adapter block pointer.
2225 *
2226 * Returns:
2227 * 0 = success.
2228 * BIT_0 = error
2229 */
2230static int
2231qla2x00_configure_fabric(scsi_qla_host_t *ha)
2232{
2233 int rval, rval2;
2234 fc_port_t *fcport, *fcptemp;
2235 uint16_t next_loopid;
2236 uint16_t mb[MAILBOX_REGISTER_COUNT];
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002237 uint16_t loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 LIST_HEAD(new_fcports);
2239
2240 /* If FL port exists, then SNS is present */
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08002241 if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002242 loop_id = NPH_F_PORT;
2243 else
2244 loop_id = SNS_FL_PORT;
Andrew Vasquez90991c82006-10-02 12:00:46 -07002245 rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 if (rval != QLA_SUCCESS) {
2247 DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
2248 "Port\n", ha->host_no));
2249
2250 ha->device_flags &= ~SWITCH_FOUND;
2251 return (QLA_SUCCESS);
2252 }
Andrew Vasquez90991c82006-10-02 12:00:46 -07002253 ha->device_flags |= SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 /* Mark devices that need re-synchronization. */
2256 rval2 = qla2x00_device_resync(ha);
2257 if (rval2 == QLA_RSCNS_HANDLED) {
2258 /* No point doing the scan, just continue. */
2259 return (QLA_SUCCESS);
2260 }
2261 do {
Andrew Vasquezcca53352005-08-26 19:08:30 -07002262 /* FDMI support. */
2263 if (ql2xfdmienable &&
2264 test_and_clear_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags))
2265 qla2x00_fdmi_register(ha);
2266
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 /* Ensure we are logged into the SNS. */
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08002268 if (IS_QLA24XX(ha) || IS_QLA54XX(ha))
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002269 loop_id = NPH_SNS;
2270 else
2271 loop_id = SIMPLE_NAME_SERVER;
2272 ha->isp_ops.fabric_login(ha, loop_id, 0xff, 0xff,
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002273 0xfc, mb, BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 if (mb[0] != MBS_COMMAND_COMPLETE) {
2275 DEBUG2(qla_printk(KERN_INFO, ha,
2276 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002277 "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 mb[0], mb[1], mb[2], mb[6], mb[7]));
2279 return (QLA_SUCCESS);
2280 }
2281
2282 if (test_and_clear_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags)) {
2283 if (qla2x00_rft_id(ha)) {
2284 /* EMPTY */
2285 DEBUG2(printk("scsi(%ld): Register FC-4 "
2286 "TYPE failed.\n", ha->host_no));
2287 }
2288 if (qla2x00_rff_id(ha)) {
2289 /* EMPTY */
2290 DEBUG2(printk("scsi(%ld): Register FC-4 "
2291 "Features failed.\n", ha->host_no));
2292 }
2293 if (qla2x00_rnn_id(ha)) {
2294 /* EMPTY */
2295 DEBUG2(printk("scsi(%ld): Register Node Name "
2296 "failed.\n", ha->host_no));
2297 } else if (qla2x00_rsnn_nn(ha)) {
2298 /* EMPTY */
2299 DEBUG2(printk("scsi(%ld): Register Symbolic "
2300 "Node Name failed.\n", ha->host_no));
2301 }
2302 }
2303
2304 rval = qla2x00_find_all_fabric_devs(ha, &new_fcports);
2305 if (rval != QLA_SUCCESS)
2306 break;
2307
2308 /*
2309 * Logout all previous fabric devices marked lost, except
2310 * tape devices.
2311 */
2312 list_for_each_entry(fcport, &ha->fcports, list) {
2313 if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
2314 break;
2315
2316 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
2317 continue;
2318
2319 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
2320 qla2x00_mark_device_lost(ha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002321 ql2xplogiabsentdevice, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002322 if (fcport->loop_id != FC_NO_LOOP_ID &&
2323 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2324 fcport->port_type != FCT_INITIATOR &&
2325 fcport->port_type != FCT_BROADCAST) {
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002326 ha->isp_ops.fabric_logout(ha,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002327 fcport->loop_id,
2328 fcport->d_id.b.domain,
2329 fcport->d_id.b.area,
2330 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331 fcport->loop_id = FC_NO_LOOP_ID;
2332 }
2333 }
2334 }
2335
2336 /* Starting free loop ID. */
2337 next_loopid = ha->min_external_loopid;
2338
2339 /*
2340 * Scan through our port list and login entries that need to be
2341 * logged in.
2342 */
2343 list_for_each_entry(fcport, &ha->fcports, list) {
2344 if (atomic_read(&ha->loop_down_timer) ||
2345 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
2346 break;
2347
2348 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2349 (fcport->flags & FCF_LOGIN_NEEDED) == 0)
2350 continue;
2351
2352 if (fcport->loop_id == FC_NO_LOOP_ID) {
2353 fcport->loop_id = next_loopid;
2354 rval = qla2x00_find_new_loop_id(ha, fcport);
2355 if (rval != QLA_SUCCESS) {
2356 /* Ran out of IDs to use */
2357 break;
2358 }
2359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002360 /* Login and update database */
2361 qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
2362 }
2363
2364 /* Exit if out of loop IDs. */
2365 if (rval != QLA_SUCCESS) {
2366 break;
2367 }
2368
2369 /*
2370 * Login and add the new devices to our port list.
2371 */
2372 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
2373 if (atomic_read(&ha->loop_down_timer) ||
2374 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
2375 break;
2376
2377 /* Find a new loop ID to use. */
2378 fcport->loop_id = next_loopid;
2379 rval = qla2x00_find_new_loop_id(ha, fcport);
2380 if (rval != QLA_SUCCESS) {
2381 /* Ran out of IDs to use */
2382 break;
2383 }
2384
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 /* Remove device from the new list and add it to DB */
Akinobu Mita179e0912006-06-26 00:24:41 -07002386 list_move_tail(&fcport->list, &ha->fcports);
bdf79622005-04-17 15:06:53 -05002387
2388 /* Login and update database */
2389 qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 }
2391 } while (0);
2392
2393 /* Free all new device structures not processed. */
2394 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
2395 list_del(&fcport->list);
2396 kfree(fcport);
2397 }
2398
2399 if (rval) {
2400 DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
2401 "rval=%d\n", ha->host_no, rval));
2402 }
2403
2404 return (rval);
2405}
2406
2407
2408/*
2409 * qla2x00_find_all_fabric_devs
2410 *
2411 * Input:
2412 * ha = adapter block pointer.
2413 * dev = database device entry pointer.
2414 *
2415 * Returns:
2416 * 0 = success.
2417 *
2418 * Context:
2419 * Kernel context.
2420 */
2421static int
2422qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
2423{
2424 int rval;
2425 uint16_t loop_id;
2426 fc_port_t *fcport, *new_fcport, *fcptemp;
2427 int found;
2428
2429 sw_info_t *swl;
2430 int swl_idx;
2431 int first_dev, last_dev;
2432 port_id_t wrap, nxt_d_id;
2433
2434 rval = QLA_SUCCESS;
2435
2436 /* Try GID_PT to get device list, else GAN. */
2437 swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC);
2438 if (swl == NULL) {
2439 /*EMPTY*/
2440 DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
2441 "on GA_NXT\n", ha->host_no));
2442 } else {
2443 memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES);
2444 if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) {
2445 kfree(swl);
2446 swl = NULL;
2447 } else if (qla2x00_gpn_id(ha, swl) != QLA_SUCCESS) {
2448 kfree(swl);
2449 swl = NULL;
2450 } else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
2451 kfree(swl);
2452 swl = NULL;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002453 } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
2454 qla2x00_gpsc(ha, swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002455 }
2456 }
2457 swl_idx = 0;
2458
2459 /* Allocate temporary fcport for any new fcports discovered. */
2460 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
2461 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002462 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 return (QLA_MEMORY_ALLOC_FAILED);
2464 }
2465 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
2466
2467 /* Set start port ID scan at adapter ID. */
2468 first_dev = 1;
2469 last_dev = 0;
2470
2471 /* Starting free loop ID. */
2472 loop_id = ha->min_external_loopid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 for (; loop_id <= ha->last_loop_id; loop_id++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -07002474 if (qla2x00_is_reserved_id(ha, loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 continue;
2476
Andrew Vasquez23443b12005-12-06 10:57:06 -08002477 if (atomic_read(&ha->loop_down_timer) || LOOP_TRANSITION(ha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 break;
2479
2480 if (swl != NULL) {
2481 if (last_dev) {
2482 wrap.b24 = new_fcport->d_id.b24;
2483 } else {
2484 new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
2485 memcpy(new_fcport->node_name,
2486 swl[swl_idx].node_name, WWN_SIZE);
2487 memcpy(new_fcport->port_name,
2488 swl[swl_idx].port_name, WWN_SIZE);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002489 memcpy(new_fcport->fabric_port_name,
2490 swl[swl_idx].fabric_port_name, WWN_SIZE);
2491 new_fcport->fp_speed = swl[swl_idx].fp_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002492
2493 if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
2494 last_dev = 1;
2495 }
2496 swl_idx++;
2497 }
2498 } else {
2499 /* Send GA_NXT to the switch */
2500 rval = qla2x00_ga_nxt(ha, new_fcport);
2501 if (rval != QLA_SUCCESS) {
2502 qla_printk(KERN_WARNING, ha,
2503 "SNS scan failed -- assuming zero-entry "
2504 "result...\n");
2505 list_for_each_entry_safe(fcport, fcptemp,
2506 new_fcports, list) {
2507 list_del(&fcport->list);
2508 kfree(fcport);
2509 }
2510 rval = QLA_SUCCESS;
2511 break;
2512 }
2513 }
2514
2515 /* If wrap on switch device list, exit. */
2516 if (first_dev) {
2517 wrap.b24 = new_fcport->d_id.b24;
2518 first_dev = 0;
2519 } else if (new_fcport->d_id.b24 == wrap.b24) {
2520 DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
2521 ha->host_no, new_fcport->d_id.b.domain,
2522 new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
2523 break;
2524 }
2525
2526 /* Bypass if host adapter. */
2527 if (new_fcport->d_id.b24 == ha->d_id.b24)
2528 continue;
2529
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002530 /* Bypass if same domain and area of adapter. */
2531 if (((new_fcport->d_id.b24 & 0xffff00) ==
2532 (ha->d_id.b24 & 0xffff00)) && ha->current_topology ==
2533 ISP_CFG_FL)
2534 continue;
2535
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 /* Bypass reserved domain fields. */
2537 if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
2538 continue;
2539
2540 /* Locate matching device in database. */
2541 found = 0;
2542 list_for_each_entry(fcport, &ha->fcports, list) {
2543 if (memcmp(new_fcport->port_name, fcport->port_name,
2544 WWN_SIZE))
2545 continue;
2546
2547 found++;
2548
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002549 /* Update port state. */
2550 memcpy(fcport->fabric_port_name,
2551 new_fcport->fabric_port_name, WWN_SIZE);
2552 fcport->fp_speed = new_fcport->fp_speed;
2553
Linus Torvalds1da177e2005-04-16 15:20:36 -07002554 /*
2555 * If address the same and state FCS_ONLINE, nothing
2556 * changed.
2557 */
2558 if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
2559 atomic_read(&fcport->state) == FCS_ONLINE) {
2560 break;
2561 }
2562
2563 /*
2564 * If device was not a fabric device before.
2565 */
2566 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
2567 fcport->d_id.b24 = new_fcport->d_id.b24;
2568 fcport->loop_id = FC_NO_LOOP_ID;
2569 fcport->flags |= (FCF_FABRIC_DEVICE |
2570 FCF_LOGIN_NEEDED);
2571 fcport->flags &= ~FCF_PERSISTENT_BOUND;
2572 break;
2573 }
2574
2575 /*
2576 * Port ID changed or device was marked to be updated;
2577 * Log it out if still logged in and mark it for
2578 * relogin later.
2579 */
2580 fcport->d_id.b24 = new_fcport->d_id.b24;
2581 fcport->flags |= FCF_LOGIN_NEEDED;
2582 if (fcport->loop_id != FC_NO_LOOP_ID &&
2583 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2584 fcport->port_type != FCT_INITIATOR &&
2585 fcport->port_type != FCT_BROADCAST) {
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002586 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2587 fcport->d_id.b.domain, fcport->d_id.b.area,
2588 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002589 fcport->loop_id = FC_NO_LOOP_ID;
2590 }
2591
2592 break;
2593 }
2594
2595 if (found)
2596 continue;
2597
2598 /* If device was not in our fcports list, then add it. */
2599 list_add_tail(&new_fcport->list, new_fcports);
2600
2601 /* Allocate a new replacement fcport. */
2602 nxt_d_id.b24 = new_fcport->d_id.b24;
2603 new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
2604 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002605 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606 return (QLA_MEMORY_ALLOC_FAILED);
2607 }
2608 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
2609 new_fcport->d_id.b24 = nxt_d_id.b24;
2610 }
2611
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002612 kfree(swl);
2613 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614
2615 if (!list_empty(new_fcports))
2616 ha->device_flags |= DFLG_FABRIC_DEVICES;
2617
2618 return (rval);
2619}
2620
2621/*
2622 * qla2x00_find_new_loop_id
2623 * Scan through our port list and find a new usable loop ID.
2624 *
2625 * Input:
2626 * ha: adapter state pointer.
2627 * dev: port structure pointer.
2628 *
2629 * Returns:
2630 * qla2x00 local function return status code.
2631 *
2632 * Context:
2633 * Kernel context.
2634 */
Adrian Bunk413975a2006-06-30 02:33:06 -07002635static int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
2637{
2638 int rval;
2639 int found;
2640 fc_port_t *fcport;
2641 uint16_t first_loop_id;
2642
2643 rval = QLA_SUCCESS;
2644
2645 /* Save starting loop ID. */
2646 first_loop_id = dev->loop_id;
2647
2648 for (;;) {
2649 /* Skip loop ID if already used by adapter. */
2650 if (dev->loop_id == ha->loop_id) {
2651 dev->loop_id++;
2652 }
2653
2654 /* Skip reserved loop IDs. */
Andrew Vasquez3d716442005-07-06 10:30:26 -07002655 while (qla2x00_is_reserved_id(ha, dev->loop_id)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 dev->loop_id++;
2657 }
2658
2659 /* Reset loop ID if passed the end. */
2660 if (dev->loop_id > ha->last_loop_id) {
2661 /* first loop ID. */
2662 dev->loop_id = ha->min_external_loopid;
2663 }
2664
2665 /* Check for loop ID being already in use. */
2666 found = 0;
2667 fcport = NULL;
2668 list_for_each_entry(fcport, &ha->fcports, list) {
2669 if (fcport->loop_id == dev->loop_id && fcport != dev) {
2670 /* ID possibly in use */
2671 found++;
2672 break;
2673 }
2674 }
2675
2676 /* If not in use then it is free to use. */
2677 if (!found) {
2678 break;
2679 }
2680
2681 /* ID in use. Try next value. */
2682 dev->loop_id++;
2683
2684 /* If wrap around. No free ID to use. */
2685 if (dev->loop_id == first_loop_id) {
2686 dev->loop_id = FC_NO_LOOP_ID;
2687 rval = QLA_FUNCTION_FAILED;
2688 break;
2689 }
2690 }
2691
2692 return (rval);
2693}
2694
2695/*
2696 * qla2x00_device_resync
2697 * Marks devices in the database that needs resynchronization.
2698 *
2699 * Input:
2700 * ha = adapter block pointer.
2701 *
2702 * Context:
2703 * Kernel context.
2704 */
2705static int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002706qla2x00_device_resync(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707{
2708 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002709 uint32_t mask;
2710 fc_port_t *fcport;
2711 uint32_t rscn_entry;
2712 uint8_t rscn_out_iter;
2713 uint8_t format;
2714 port_id_t d_id;
2715
2716 rval = QLA_RSCNS_HANDLED;
2717
2718 while (ha->rscn_out_ptr != ha->rscn_in_ptr ||
2719 ha->flags.rscn_queue_overflow) {
2720
2721 rscn_entry = ha->rscn_queue[ha->rscn_out_ptr];
2722 format = MSB(MSW(rscn_entry));
2723 d_id.b.domain = LSB(MSW(rscn_entry));
2724 d_id.b.area = MSB(LSW(rscn_entry));
2725 d_id.b.al_pa = LSB(LSW(rscn_entry));
2726
2727 DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
2728 "[%02x/%02x%02x%02x].\n",
2729 ha->host_no, ha->rscn_out_ptr, format, d_id.b.domain,
2730 d_id.b.area, d_id.b.al_pa));
2731
2732 ha->rscn_out_ptr++;
2733 if (ha->rscn_out_ptr == MAX_RSCN_COUNT)
2734 ha->rscn_out_ptr = 0;
2735
2736 /* Skip duplicate entries. */
2737 for (rscn_out_iter = ha->rscn_out_ptr;
2738 !ha->flags.rscn_queue_overflow &&
2739 rscn_out_iter != ha->rscn_in_ptr;
2740 rscn_out_iter = (rscn_out_iter ==
2741 (MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
2742
2743 if (rscn_entry != ha->rscn_queue[rscn_out_iter])
2744 break;
2745
2746 DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
2747 "entry found at [%d].\n", ha->host_no,
2748 rscn_out_iter));
2749
2750 ha->rscn_out_ptr = rscn_out_iter;
2751 }
2752
2753 /* Queue overflow, set switch default case. */
2754 if (ha->flags.rscn_queue_overflow) {
2755 DEBUG(printk("scsi(%ld): device_resync: rscn "
2756 "overflow.\n", ha->host_no));
2757
2758 format = 3;
2759 ha->flags.rscn_queue_overflow = 0;
2760 }
2761
2762 switch (format) {
2763 case 0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002764 mask = 0xffffff;
2765 break;
2766 case 1:
2767 mask = 0xffff00;
2768 break;
2769 case 2:
2770 mask = 0xff0000;
2771 break;
2772 default:
2773 mask = 0x0;
2774 d_id.b24 = 0;
2775 ha->rscn_out_ptr = ha->rscn_in_ptr;
2776 break;
2777 }
2778
2779 rval = QLA_SUCCESS;
2780
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781 list_for_each_entry(fcport, &ha->fcports, list) {
2782 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2783 (fcport->d_id.b24 & mask) != d_id.b24 ||
2784 fcport->port_type == FCT_BROADCAST)
2785 continue;
2786
2787 if (atomic_read(&fcport->state) == FCS_ONLINE) {
2788 if (format != 3 ||
2789 fcport->port_type != FCT_INITIATOR) {
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002790 qla2x00_mark_device_lost(ha, fcport,
2791 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 }
2793 }
2794 fcport->flags &= ~FCF_FARP_DONE;
2795 }
2796 }
2797 return (rval);
2798}
2799
2800/*
2801 * qla2x00_fabric_dev_login
2802 * Login fabric target device and update FC port database.
2803 *
2804 * Input:
2805 * ha: adapter state pointer.
2806 * fcport: port structure list pointer.
2807 * next_loopid: contains value of a new loop ID that can be used
2808 * by the next login attempt.
2809 *
2810 * Returns:
2811 * qla2x00 local function return status code.
2812 *
2813 * Context:
2814 * Kernel context.
2815 */
2816static int
2817qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
2818 uint16_t *next_loopid)
2819{
2820 int rval;
2821 int retry;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002822 uint8_t opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
2824 rval = QLA_SUCCESS;
2825 retry = 0;
2826
2827 rval = qla2x00_fabric_login(ha, fcport, next_loopid);
2828 if (rval == QLA_SUCCESS) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002829 /* Send an ADISC to tape devices.*/
2830 opts = 0;
2831 if (fcport->flags & FCF_TAPE_PRESENT)
2832 opts |= BIT_1;
2833 rval = qla2x00_get_port_database(ha, fcport, opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834 if (rval != QLA_SUCCESS) {
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002835 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2836 fcport->d_id.b.domain, fcport->d_id.b.area,
2837 fcport->d_id.b.al_pa);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002838 qla2x00_mark_device_lost(ha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002839 } else {
2840 qla2x00_update_fcport(ha, fcport);
2841 }
2842 }
2843
2844 return (rval);
2845}
2846
2847/*
2848 * qla2x00_fabric_login
2849 * Issue fabric login command.
2850 *
2851 * Input:
2852 * ha = adapter block pointer.
2853 * device = pointer to FC device type structure.
2854 *
2855 * Returns:
2856 * 0 - Login successfully
2857 * 1 - Login failed
2858 * 2 - Initiator device
2859 * 3 - Fatal error
2860 */
2861int
2862qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
2863 uint16_t *next_loopid)
2864{
2865 int rval;
2866 int retry;
2867 uint16_t tmp_loopid;
2868 uint16_t mb[MAILBOX_REGISTER_COUNT];
2869
2870 retry = 0;
2871 tmp_loopid = 0;
2872
2873 for (;;) {
2874 DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
2875 "for port %02x%02x%02x.\n",
2876 ha->host_no, fcport->loop_id, fcport->d_id.b.domain,
2877 fcport->d_id.b.area, fcport->d_id.b.al_pa));
2878
2879 /* Login fcport on switch. */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002880 ha->isp_ops.fabric_login(ha, fcport->loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 fcport->d_id.b.domain, fcport->d_id.b.area,
2882 fcport->d_id.b.al_pa, mb, BIT_0);
2883 if (mb[0] == MBS_PORT_ID_USED) {
2884 /*
2885 * Device has another loop ID. The firmware team
Andrew Vasquez0107109e2005-07-06 10:31:37 -07002886 * recommends the driver perform an implicit login with
2887 * the specified ID again. The ID we just used is save
2888 * here so we return with an ID that can be tried by
2889 * the next login.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 */
2891 retry++;
2892 tmp_loopid = fcport->loop_id;
2893 fcport->loop_id = mb[1];
2894
2895 DEBUG(printk("Fabric Login: port in use - next "
2896 "loop id=0x%04x, port Id=%02x%02x%02x.\n",
2897 fcport->loop_id, fcport->d_id.b.domain,
2898 fcport->d_id.b.area, fcport->d_id.b.al_pa));
2899
2900 } else if (mb[0] == MBS_COMMAND_COMPLETE) {
2901 /*
2902 * Login succeeded.
2903 */
2904 if (retry) {
2905 /* A retry occurred before. */
2906 *next_loopid = tmp_loopid;
2907 } else {
2908 /*
2909 * No retry occurred before. Just increment the
2910 * ID value for next login.
2911 */
2912 *next_loopid = (fcport->loop_id + 1);
2913 }
2914
2915 if (mb[1] & BIT_0) {
2916 fcport->port_type = FCT_INITIATOR;
2917 } else {
2918 fcport->port_type = FCT_TARGET;
2919 if (mb[1] & BIT_1) {
2920 fcport->flags |= FCF_TAPE_PRESENT;
2921 }
2922 }
2923
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002924 if (mb[10] & BIT_0)
2925 fcport->supported_classes |= FC_COS_CLASS2;
2926 if (mb[10] & BIT_1)
2927 fcport->supported_classes |= FC_COS_CLASS3;
2928
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 rval = QLA_SUCCESS;
2930 break;
2931 } else if (mb[0] == MBS_LOOP_ID_USED) {
2932 /*
2933 * Loop ID already used, try next loop ID.
2934 */
2935 fcport->loop_id++;
2936 rval = qla2x00_find_new_loop_id(ha, fcport);
2937 if (rval != QLA_SUCCESS) {
2938 /* Ran out of loop IDs to use */
2939 break;
2940 }
2941 } else if (mb[0] == MBS_COMMAND_ERROR) {
2942 /*
2943 * Firmware possibly timed out during login. If NO
2944 * retries are left to do then the device is declared
2945 * dead.
2946 */
2947 *next_loopid = fcport->loop_id;
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002948 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2949 fcport->d_id.b.domain, fcport->d_id.b.area,
2950 fcport->d_id.b.al_pa);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002951 qla2x00_mark_device_lost(ha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952
2953 rval = 1;
2954 break;
2955 } else {
2956 /*
2957 * unrecoverable / not handled error
2958 */
2959 DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002960 "loop_id=%x jiffies=%lx.\n",
2961 __func__, ha->host_no, mb[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 fcport->d_id.b.domain, fcport->d_id.b.area,
2963 fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
2964
2965 *next_loopid = fcport->loop_id;
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002966 ha->isp_ops.fabric_logout(ha, fcport->loop_id,
2967 fcport->d_id.b.domain, fcport->d_id.b.area,
2968 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 fcport->loop_id = FC_NO_LOOP_ID;
Andrew Vasquez0eedfcf2005-10-27 11:09:38 -07002970 fcport->login_retry = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971
2972 rval = 3;
2973 break;
2974 }
2975 }
2976
2977 return (rval);
2978}
2979
2980/*
2981 * qla2x00_local_device_login
2982 * Issue local device login command.
2983 *
2984 * Input:
2985 * ha = adapter block pointer.
2986 * loop_id = loop id of device to login to.
2987 *
2988 * Returns (Where's the #define!!!!):
2989 * 0 - Login successfully
2990 * 1 - Login failed
2991 * 3 - Fatal error
2992 */
2993int
andrew.vasquez@qlogic.com9a52a572006-03-09 14:27:44 -08002994qla2x00_local_device_login(scsi_qla_host_t *ha, fc_port_t *fcport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002995{
2996 int rval;
2997 uint16_t mb[MAILBOX_REGISTER_COUNT];
2998
2999 memset(mb, 0, sizeof(mb));
andrew.vasquez@qlogic.com9a52a572006-03-09 14:27:44 -08003000 rval = qla2x00_login_local_device(ha, fcport, mb, BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 if (rval == QLA_SUCCESS) {
3002 /* Interrogate mailbox registers for any errors */
3003 if (mb[0] == MBS_COMMAND_ERROR)
3004 rval = 1;
3005 else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
3006 /* device not in PCB table */
3007 rval = 3;
3008 }
3009
3010 return (rval);
3011}
3012
3013/*
3014 * qla2x00_loop_resync
3015 * Resync with fibre channel devices.
3016 *
3017 * Input:
3018 * ha = adapter block pointer.
3019 *
3020 * Returns:
3021 * 0 = success
3022 */
3023int
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003024qla2x00_loop_resync(scsi_qla_host_t *ha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025{
3026 int rval;
3027 uint32_t wait_time;
3028
3029 rval = QLA_SUCCESS;
3030
3031 atomic_set(&ha->loop_state, LOOP_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
3033 if (ha->flags.online) {
3034 if (!(rval = qla2x00_fw_ready(ha))) {
3035 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3036 wait_time = 256;
3037 do {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038 atomic_set(&ha->loop_state, LOOP_UPDATE);
3039
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003040 /* Issue a marker after FW becomes ready. */
3041 qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
3042 ha->marker_needed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
3044 /* Remap devices on Loop. */
3045 clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
3046
3047 qla2x00_configure_loop(ha);
3048 wait_time--;
3049 } while (!atomic_read(&ha->loop_down_timer) &&
3050 !(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) &&
3051 wait_time &&
3052 (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)));
3053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003054 }
3055
3056 if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
3057 return (QLA_FUNCTION_FAILED);
3058 }
3059
3060 if (rval) {
3061 DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
3062 }
3063
3064 return (rval);
3065}
3066
Linus Torvalds1da177e2005-04-16 15:20:36 -07003067void
3068qla2x00_rescan_fcports(scsi_qla_host_t *ha)
3069{
3070 int rescan_done;
3071 fc_port_t *fcport;
3072
3073 rescan_done = 0;
3074 list_for_each_entry(fcport, &ha->fcports, list) {
3075 if ((fcport->flags & FCF_RESCAN_NEEDED) == 0)
3076 continue;
3077
3078 qla2x00_update_fcport(ha, fcport);
3079 fcport->flags &= ~FCF_RESCAN_NEEDED;
3080
3081 rescan_done = 1;
3082 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003083 qla2x00_probe_for_all_luns(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003084}
3085
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003086void
3087qla2x00_update_fcports(scsi_qla_host_t *ha)
3088{
3089 fc_port_t *fcport;
3090
3091 /* Go with deferred removal of rport references. */
3092 list_for_each_entry(fcport, &ha->fcports, list)
3093 if (fcport->drport)
3094 qla2x00_rport_del(fcport);
3095}
3096
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097/*
3098* qla2x00_abort_isp
3099* Resets ISP and aborts all outstanding commands.
3100*
3101* Input:
3102* ha = adapter block pointer.
3103*
3104* Returns:
3105* 0 = success
3106*/
3107int
3108qla2x00_abort_isp(scsi_qla_host_t *ha)
3109{
Andrew Vasquez476e8972006-08-23 14:54:55 -07003110 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111 unsigned long flags = 0;
3112 uint16_t cnt;
3113 srb_t *sp;
3114 uint8_t status = 0;
3115
3116 if (ha->flags.online) {
3117 ha->flags.online = 0;
3118 clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
3120 qla_printk(KERN_INFO, ha,
3121 "Performing ISP error recovery - ha= %p.\n", ha);
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003122 ha->isp_ops.reset_chip(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123
3124 atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
3125 if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
3126 atomic_set(&ha->loop_state, LOOP_DOWN);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003127 qla2x00_mark_all_devices_lost(ha, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003128 } else {
3129 if (!atomic_read(&ha->loop_down_timer))
3130 atomic_set(&ha->loop_down_timer,
3131 LOOP_DOWN_TIME);
3132 }
3133
3134 spin_lock_irqsave(&ha->hardware_lock, flags);
3135 /* Requeue all commands in outstanding command list. */
3136 for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
3137 sp = ha->outstanding_cmds[cnt];
3138 if (sp) {
3139 ha->outstanding_cmds[cnt] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003140 sp->flags = 0;
f4f051e2005-04-17 15:02:26 -05003141 sp->cmd->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003142 sp->cmd->host_scribble = (unsigned char *)NULL;
f4f051e2005-04-17 15:02:26 -05003143 qla2x00_sp_compl(ha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144 }
3145 }
3146 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3147
Andrew Vasquez30c47662007-01-29 10:22:21 -08003148 ha->isp_ops.get_flash_version(ha, ha->request_ring);
3149
David Miller4e08df32007-04-16 12:37:43 -07003150 ha->isp_ops.nvram_config(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003151
3152 if (!qla2x00_restart_isp(ha)) {
3153 clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
3154
3155 if (!atomic_read(&ha->loop_down_timer)) {
3156 /*
3157 * Issue marker command only when we are going
3158 * to start the I/O .
3159 */
3160 ha->marker_needed = 1;
3161 }
3162
3163 ha->flags.online = 1;
3164
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003165 ha->isp_ops.enable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003166
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003167 ha->isp_abort_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
Andrew Vasquez476e8972006-08-23 14:54:55 -07003169
3170 if (ha->eft) {
3171 rval = qla2x00_trace_control(ha, TC_ENABLE,
3172 ha->eft_dma, EFT_NUM_BUFFERS);
3173 if (rval) {
3174 qla_printk(KERN_WARNING, ha,
3175 "Unable to reinitialize EFT "
3176 "(%d).\n", rval);
3177 }
3178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179 } else { /* failed the ISP abort */
3180 ha->flags.online = 1;
3181 if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
3182 if (ha->isp_abort_cnt == 0) {
3183 qla_printk(KERN_WARNING, ha,
3184 "ISP error recovery failed - "
3185 "board disabled\n");
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003186 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003187 * The next call disables the board
3188 * completely.
3189 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003190 ha->isp_ops.reset_adapter(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003191 ha->flags.online = 0;
3192 clear_bit(ISP_ABORT_RETRY,
3193 &ha->dpc_flags);
3194 status = 0;
3195 } else { /* schedule another ISP abort */
3196 ha->isp_abort_cnt--;
3197 DEBUG(printk("qla%ld: ISP abort - "
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003198 "retry remaining %d\n",
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003199 ha->host_no, ha->isp_abort_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003200 status = 1;
3201 }
3202 } else {
3203 ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
3204 DEBUG(printk("qla2x00(%ld): ISP error recovery "
3205 "- retrying (%d) more times\n",
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003206 ha->host_no, ha->isp_abort_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003207 set_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
3208 status = 1;
3209 }
3210 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003211
Linus Torvalds1da177e2005-04-16 15:20:36 -07003212 }
3213
3214 if (status) {
3215 qla_printk(KERN_INFO, ha,
3216 "qla2x00_abort_isp: **** FAILED ****\n");
3217 } else {
3218 DEBUG(printk(KERN_INFO
3219 "qla2x00_abort_isp(%ld): exiting.\n",
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003220 ha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221 }
3222
3223 return(status);
3224}
3225
3226/*
3227* qla2x00_restart_isp
3228* restarts the ISP after a reset
3229*
3230* Input:
3231* ha = adapter block pointer.
3232*
3233* Returns:
3234* 0 = success
3235*/
3236static int
3237qla2x00_restart_isp(scsi_qla_host_t *ha)
3238{
3239 uint8_t status = 0;
Andrew Vasquez3d716442005-07-06 10:30:26 -07003240 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003241 unsigned long flags = 0;
3242 uint32_t wait_time;
3243
3244 /* If firmware needs to be loaded */
3245 if (qla2x00_isp_firmware(ha)) {
3246 ha->flags.online = 0;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003247 if (!(status = ha->isp_ops.chip_diag(ha))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
3249 status = qla2x00_setup_chip(ha);
3250 goto done;
3251 }
3252
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 spin_lock_irqsave(&ha->hardware_lock, flags);
3254
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08003255 if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003256 /*
3257 * Disable SRAM, Instruction RAM and GP RAM
3258 * parity.
3259 */
3260 WRT_REG_WORD(&reg->hccr,
3261 (HCCR_ENABLE_PARITY + 0x0));
3262 RD_REG_WORD(&reg->hccr);
3263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264
3265 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003266
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 status = qla2x00_setup_chip(ha);
3268
3269 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003270
andrew.vasquez@qlogic.com044cc6c2006-03-09 14:27:13 -08003271 if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003272 /* Enable proper parity */
3273 if (IS_QLA2300(ha))
3274 /* SRAM parity */
3275 WRT_REG_WORD(&reg->hccr,
3276 (HCCR_ENABLE_PARITY + 0x1));
3277 else
3278 /*
3279 * SRAM, Instruction RAM and GP RAM
3280 * parity.
3281 */
3282 WRT_REG_WORD(&reg->hccr,
3283 (HCCR_ENABLE_PARITY + 0x7));
3284 RD_REG_WORD(&reg->hccr);
3285 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
3287 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3288 }
3289 }
3290
3291 done:
3292 if (!status && !(status = qla2x00_init_rings(ha))) {
3293 clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
3294 if (!(status = qla2x00_fw_ready(ha))) {
3295 DEBUG(printk("%s(): Start configure loop, "
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003296 "status = %d\n", __func__, status));
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003297
3298 /* Issue a marker after FW becomes ready. */
3299 qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
3300
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 ha->flags.online = 1;
3302 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3303 wait_time = 256;
3304 do {
3305 clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
3306 qla2x00_configure_loop(ha);
3307 wait_time--;
3308 } while (!atomic_read(&ha->loop_down_timer) &&
3309 !(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) &&
3310 wait_time &&
3311 (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)));
3312 }
3313
3314 /* if no cable then assume it's good */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003315 if ((ha->device_flags & DFLG_NO_CABLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316 status = 0;
3317
3318 DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
3319 __func__,
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003320 status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 }
3322 return (status);
3323}
3324
3325/*
3326* qla2x00_reset_adapter
3327* Reset adapter.
3328*
3329* Input:
3330* ha = adapter block pointer.
3331*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003332void
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333qla2x00_reset_adapter(scsi_qla_host_t *ha)
3334{
3335 unsigned long flags = 0;
Andrew Vasquez3d716442005-07-06 10:30:26 -07003336 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003337
3338 ha->flags.online = 0;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003339 ha->isp_ops.disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 spin_lock_irqsave(&ha->hardware_lock, flags);
3342 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
3343 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3344 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
3345 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3346 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3347}
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003348
3349void
3350qla24xx_reset_adapter(scsi_qla_host_t *ha)
3351{
3352 unsigned long flags = 0;
3353 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
3354
3355 ha->flags.online = 0;
3356 ha->isp_ops.disable_intrs(ha);
3357
3358 spin_lock_irqsave(&ha->hardware_lock, flags);
3359 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
3360 RD_REG_DWORD(&reg->hccr);
3361 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
3362 RD_REG_DWORD(&reg->hccr);
3363 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3364}
3365
David Miller4e08df32007-04-16 12:37:43 -07003366/* On sparc systems, obtain port and node WWN from firmware
3367 * properties.
3368 */
3369static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *ha, struct nvram_24xx *nv)
3370{
3371#ifdef CONFIG_SPARC
3372 struct pci_dev *pdev = ha->pdev;
3373 struct pcidev_cookie *pcp = pdev->sysdata;
3374 struct device_node *dp = pcp->prom_node;
3375 u8 *val;
3376 int len;
3377
3378 val = of_get_property(dp, "port-wwn", &len);
3379 if (val && len >= WWN_SIZE)
3380 memcpy(nv->port_name, val, WWN_SIZE);
3381
3382 val = of_get_property(dp, "node-wwn", &len);
3383 if (val && len >= WWN_SIZE)
3384 memcpy(nv->node_name, val, WWN_SIZE);
3385#endif
3386}
3387
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003388int
3389qla24xx_nvram_config(scsi_qla_host_t *ha)
3390{
David Miller4e08df32007-04-16 12:37:43 -07003391 int rval;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003392 struct init_cb_24xx *icb;
3393 struct nvram_24xx *nv;
3394 uint32_t *dptr;
3395 uint8_t *dptr1, *dptr2;
3396 uint32_t chksum;
3397 uint16_t cnt;
3398
David Miller4e08df32007-04-16 12:37:43 -07003399 rval = QLA_SUCCESS;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003400 icb = (struct init_cb_24xx *)ha->init_cb;
3401 nv = (struct nvram_24xx *)ha->request_ring;
3402
3403 /* Determine NVRAM starting address. */
3404 ha->nvram_size = sizeof(struct nvram_24xx);
3405 ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003406 ha->vpd_size = FA_NVRAM_VPD_SIZE;
3407 ha->vpd_base = FA_NVRAM_VPD0_ADDR;
3408 if (PCI_FUNC(ha->pdev->devfn)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003409 ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003410 ha->vpd_base = FA_NVRAM_VPD1_ADDR;
3411 }
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003412
3413 /* Get NVRAM data and calculate checksum. */
3414 dptr = (uint32_t *)nv;
3415 ha->isp_ops.read_nvram(ha, (uint8_t *)dptr, ha->nvram_base,
3416 ha->nvram_size);
3417 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
3418 chksum += le32_to_cpu(*dptr++);
3419
3420 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
3421 DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
3422 ha->nvram_size));
3423
3424 /* Bad NVRAM data, set defaults parameters. */
3425 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
3426 || nv->id[3] != ' ' ||
3427 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
3428 /* Reset NVRAM data. */
3429 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
3430 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
3431 le16_to_cpu(nv->nvram_version));
David Miller4e08df32007-04-16 12:37:43 -07003432 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
3433 "invalid -- WWPN) defaults.\n");
3434
3435 /*
3436 * Set default initialization control block.
3437 */
3438 memset(nv, 0, ha->nvram_size);
3439 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
3440 nv->version = __constant_cpu_to_le16(ICB_VERSION);
3441 nv->frame_payload_size = __constant_cpu_to_le16(2048);
3442 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3443 nv->exchange_count = __constant_cpu_to_le16(0);
3444 nv->hard_address = __constant_cpu_to_le16(124);
3445 nv->port_name[0] = 0x21;
3446 nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
3447 nv->port_name[2] = 0x00;
3448 nv->port_name[3] = 0xe0;
3449 nv->port_name[4] = 0x8b;
3450 nv->port_name[5] = 0x1c;
3451 nv->port_name[6] = 0x55;
3452 nv->port_name[7] = 0x86;
3453 nv->node_name[0] = 0x20;
3454 nv->node_name[1] = 0x00;
3455 nv->node_name[2] = 0x00;
3456 nv->node_name[3] = 0xe0;
3457 nv->node_name[4] = 0x8b;
3458 nv->node_name[5] = 0x1c;
3459 nv->node_name[6] = 0x55;
3460 nv->node_name[7] = 0x86;
3461 qla24xx_nvram_wwn_from_ofw(ha, nv);
3462 nv->login_retry_count = __constant_cpu_to_le16(8);
3463 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
3464 nv->login_timeout = __constant_cpu_to_le16(0);
3465 nv->firmware_options_1 =
3466 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
3467 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
3468 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
3469 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
3470 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
3471 nv->efi_parameters = __constant_cpu_to_le32(0);
3472 nv->reset_delay = 5;
3473 nv->max_luns_per_target = __constant_cpu_to_le16(128);
3474 nv->port_down_retry_count = __constant_cpu_to_le16(30);
3475 nv->link_down_timeout = __constant_cpu_to_le16(30);
3476
3477 rval = 1;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003478 }
3479
3480 /* Reset Initialization control block */
3481 memset(icb, 0, sizeof(struct init_cb_24xx));
3482
3483 /* Copy 1st segment. */
3484 dptr1 = (uint8_t *)icb;
3485 dptr2 = (uint8_t *)&nv->version;
3486 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
3487 while (cnt--)
3488 *dptr1++ = *dptr2++;
3489
3490 icb->login_retry_count = nv->login_retry_count;
Andrew Vasquez3ea66e22006-06-23 16:11:27 -07003491 icb->link_down_on_nos = nv->link_down_on_nos;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003492
3493 /* Copy 2nd segment. */
3494 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
3495 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
3496 cnt = (uint8_t *)&icb->reserved_3 -
3497 (uint8_t *)&icb->interrupt_delay_timer;
3498 while (cnt--)
3499 *dptr1++ = *dptr2++;
3500
3501 /*
3502 * Setup driver NVRAM options.
3503 */
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08003504 qla2x00_set_model_info(ha, nv->model_name, sizeof(nv->model_name),
3505 "QLA2462");
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003506
Andrew Vasquez5341e862006-05-17 15:09:16 -07003507 /* Use alternate WWN? */
3508 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
3509 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
3510 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
3511 }
3512
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003513 /* Prepare nodename */
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003514 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003515 /*
3516 * Firmware will apply the following mask if the nodename was
3517 * not provided.
3518 */
3519 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
3520 icb->node_name[0] &= 0xF0;
3521 }
3522
3523 /* Set host adapter parameters. */
3524 ha->flags.disable_risc_code_load = 0;
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08003525 ha->flags.enable_lip_reset = 0;
3526 ha->flags.enable_lip_full_login =
3527 le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
3528 ha->flags.enable_target_reset =
3529 le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003530 ha->flags.enable_led_scheme = 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07003531 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003532
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003533 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
3534 (BIT_6 | BIT_5 | BIT_4)) >> 4;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003535
3536 memcpy(ha->fw_seriallink_options24, nv->seriallink_options,
3537 sizeof(ha->fw_seriallink_options24));
3538
3539 /* save HBA serial number */
3540 ha->serial0 = icb->port_name[5];
3541 ha->serial1 = icb->port_name[6];
3542 ha->serial2 = icb->port_name[7];
3543 ha->node_name = icb->node_name;
3544 ha->port_name = icb->port_name;
3545
andrew.vasquez@qlogic.combc8fb3c2006-01-13 17:05:42 -08003546 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3547
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003548 ha->retry_count = le16_to_cpu(nv->login_retry_count);
3549
3550 /* Set minimum login_timeout to 4 seconds. */
3551 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
3552 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
3553 if (le16_to_cpu(nv->login_timeout) < 4)
3554 nv->login_timeout = __constant_cpu_to_le16(4);
3555 ha->login_timeout = le16_to_cpu(nv->login_timeout);
3556 icb->login_timeout = cpu_to_le16(nv->login_timeout);
3557
3558 /* Set minimum RATOV to 200 tenths of a second. */
3559 ha->r_a_tov = 200;
3560
3561 ha->loop_reset_delay = nv->reset_delay;
3562
3563 /* Link Down Timeout = 0:
3564 *
3565 * When Port Down timer expires we will start returning
3566 * I/O's to OS with "DID_NO_CONNECT".
3567 *
3568 * Link Down Timeout != 0:
3569 *
3570 * The driver waits for the link to come up after link down
3571 * before returning I/Os to OS with "DID_NO_CONNECT".
3572 */
3573 if (le16_to_cpu(nv->link_down_timeout) == 0) {
3574 ha->loop_down_abort_time =
3575 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
3576 } else {
3577 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
3578 ha->loop_down_abort_time =
3579 (LOOP_DOWN_TIME - ha->link_down_timeout);
3580 }
3581
3582 /* Need enough time to try and get the port back. */
3583 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
3584 if (qlport_down_retry)
3585 ha->port_down_retry_count = qlport_down_retry;
3586
3587 /* Set login_retry_count */
3588 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
3589 if (ha->port_down_retry_count ==
3590 le16_to_cpu(nv->port_down_retry_count) &&
3591 ha->port_down_retry_count > 3)
3592 ha->login_retry_count = ha->port_down_retry_count;
3593 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
3594 ha->login_retry_count = ha->port_down_retry_count;
3595 if (ql2xloginretrycount)
3596 ha->login_retry_count = ql2xloginretrycount;
3597
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003598 /* Enable ZIO. */
3599 if (!ha->flags.init_done) {
3600 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
3601 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
3602 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
3603 le16_to_cpu(icb->interrupt_delay_timer): 2;
3604 }
3605 icb->firmware_options_2 &= __constant_cpu_to_le32(
3606 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
3607 ha->flags.process_response_queue = 0;
3608 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08003609 ha->zio_mode = QLA_ZIO_MODE_6;
3610
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003611 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
3612 "(%d us).\n", ha->host_no, ha->zio_mode,
3613 ha->zio_timer * 100));
3614 qla_printk(KERN_INFO, ha,
3615 "ZIO mode %d enabled; timer delay (%d us).\n",
3616 ha->zio_mode, ha->zio_timer * 100);
3617
3618 icb->firmware_options_2 |= cpu_to_le32(
3619 (uint32_t)ha->zio_mode);
3620 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
3621 ha->flags.process_response_queue = 1;
3622 }
3623
David Miller4e08df32007-04-16 12:37:43 -07003624 if (rval) {
3625 DEBUG2_3(printk(KERN_WARNING
3626 "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
3627 }
3628 return (rval);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003629}
3630
Adrian Bunk413975a2006-06-30 02:33:06 -07003631static int
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003632qla24xx_load_risc_flash(scsi_qla_host_t *ha, uint32_t *srisc_addr)
3633{
3634 int rval;
3635 int segments, fragment;
3636 uint32_t faddr;
3637 uint32_t *dcode, dlen;
3638 uint32_t risc_addr;
3639 uint32_t risc_size;
3640 uint32_t i;
3641
3642 rval = QLA_SUCCESS;
3643
3644 segments = FA_RISC_CODE_SEGMENTS;
3645 faddr = FA_RISC_CODE_ADDR;
3646 dcode = (uint32_t *)ha->request_ring;
3647 *srisc_addr = 0;
3648
3649 /* Validate firmware image by checking version. */
3650 qla24xx_read_flash_data(ha, dcode, faddr + 4, 4);
3651 for (i = 0; i < 4; i++)
3652 dcode[i] = be32_to_cpu(dcode[i]);
3653 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
3654 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
3655 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
3656 dcode[3] == 0)) {
3657 qla_printk(KERN_WARNING, ha,
3658 "Unable to verify integrity of flash firmware image!\n");
3659 qla_printk(KERN_WARNING, ha,
3660 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
3661 dcode[1], dcode[2], dcode[3]);
3662
3663 return QLA_FUNCTION_FAILED;
3664 }
3665
3666 while (segments && rval == QLA_SUCCESS) {
3667 /* Read segment's load information. */
3668 qla24xx_read_flash_data(ha, dcode, faddr, 4);
3669
3670 risc_addr = be32_to_cpu(dcode[2]);
3671 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
3672 risc_size = be32_to_cpu(dcode[3]);
3673
3674 fragment = 0;
3675 while (risc_size > 0 && rval == QLA_SUCCESS) {
3676 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
3677 if (dlen > risc_size)
3678 dlen = risc_size;
3679
3680 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3681 "addr %x, number of dwords 0x%x, offset 0x%x.\n",
3682 ha->host_no, risc_addr, dlen, faddr));
3683
3684 qla24xx_read_flash_data(ha, dcode, faddr, dlen);
3685 for (i = 0; i < dlen; i++)
3686 dcode[i] = swab32(dcode[i]);
3687
3688 rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
3689 dlen);
3690 if (rval) {
3691 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
3692 "segment %d of firmware\n", ha->host_no,
3693 fragment));
3694 qla_printk(KERN_WARNING, ha,
3695 "[ERROR] Failed to load segment %d of "
3696 "firmware\n", fragment);
3697 break;
3698 }
3699
3700 faddr += dlen;
3701 risc_addr += dlen;
3702 risc_size -= dlen;
3703 fragment++;
3704 }
3705
3706 /* Next segment. */
3707 segments--;
3708 }
3709
3710 return rval;
3711}
3712
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003713#define QLA_FW_URL "ftp://ftp.qlogic.com/outgoing/linux/firmware/"
3714
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003715int
Andrew Vasquez54333832005-11-09 15:49:04 -08003716qla2x00_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
3717{
3718 int rval;
3719 int i, fragment;
3720 uint16_t *wcode, *fwcode;
3721 uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
3722 struct fw_blob *blob;
3723
3724 /* Load firmware blob. */
3725 blob = qla2x00_request_firmware(ha);
3726 if (!blob) {
3727 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003728 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
3729 "from: " QLA_FW_URL ".\n");
Andrew Vasquez54333832005-11-09 15:49:04 -08003730 return QLA_FUNCTION_FAILED;
3731 }
3732
3733 rval = QLA_SUCCESS;
3734
3735 wcode = (uint16_t *)ha->request_ring;
3736 *srisc_addr = 0;
3737 fwcode = (uint16_t *)blob->fw->data;
3738 fwclen = 0;
3739
3740 /* Validate firmware image by checking version. */
3741 if (blob->fw->size < 8 * sizeof(uint16_t)) {
3742 qla_printk(KERN_WARNING, ha,
3743 "Unable to verify integrity of firmware image (%Zd)!\n",
3744 blob->fw->size);
3745 goto fail_fw_integrity;
3746 }
3747 for (i = 0; i < 4; i++)
3748 wcode[i] = be16_to_cpu(fwcode[i + 4]);
3749 if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
3750 wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
3751 wcode[2] == 0 && wcode[3] == 0)) {
3752 qla_printk(KERN_WARNING, ha,
3753 "Unable to verify integrity of firmware image!\n");
3754 qla_printk(KERN_WARNING, ha,
3755 "Firmware data: %04x %04x %04x %04x!\n", wcode[0],
3756 wcode[1], wcode[2], wcode[3]);
3757 goto fail_fw_integrity;
3758 }
3759
3760 seg = blob->segs;
3761 while (*seg && rval == QLA_SUCCESS) {
3762 risc_addr = *seg;
3763 *srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
3764 risc_size = be16_to_cpu(fwcode[3]);
3765
3766 /* Validate firmware image size. */
3767 fwclen += risc_size * sizeof(uint16_t);
3768 if (blob->fw->size < fwclen) {
3769 qla_printk(KERN_WARNING, ha,
3770 "Unable to verify integrity of firmware image "
3771 "(%Zd)!\n", blob->fw->size);
3772 goto fail_fw_integrity;
3773 }
3774
3775 fragment = 0;
3776 while (risc_size > 0 && rval == QLA_SUCCESS) {
3777 wlen = (uint16_t)(ha->fw_transfer_size >> 1);
3778 if (wlen > risc_size)
3779 wlen = risc_size;
3780
3781 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3782 "addr %x, number of words 0x%x.\n", ha->host_no,
3783 risc_addr, wlen));
3784
3785 for (i = 0; i < wlen; i++)
3786 wcode[i] = swab16(fwcode[i]);
3787
3788 rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
3789 wlen);
3790 if (rval) {
3791 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
3792 "segment %d of firmware\n", ha->host_no,
3793 fragment));
3794 qla_printk(KERN_WARNING, ha,
3795 "[ERROR] Failed to load segment %d of "
3796 "firmware\n", fragment);
3797 break;
3798 }
3799
3800 fwcode += wlen;
3801 risc_addr += wlen;
3802 risc_size -= wlen;
3803 fragment++;
3804 }
3805
3806 /* Next segment. */
3807 seg++;
3808 }
3809 return rval;
3810
3811fail_fw_integrity:
3812 return QLA_FUNCTION_FAILED;
3813}
3814
3815int
3816qla24xx_load_risc(scsi_qla_host_t *ha, uint32_t *srisc_addr)
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003817{
3818 int rval;
3819 int segments, fragment;
3820 uint32_t *dcode, dlen;
3821 uint32_t risc_addr;
3822 uint32_t risc_size;
3823 uint32_t i;
Andrew Vasquez54333832005-11-09 15:49:04 -08003824 struct fw_blob *blob;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003825 uint32_t *fwcode, fwclen;
3826
Andrew Vasquez54333832005-11-09 15:49:04 -08003827 /* Load firmware blob. */
3828 blob = qla2x00_request_firmware(ha);
3829 if (!blob) {
3830 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003831 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
3832 "from: " QLA_FW_URL ".\n");
3833
3834 /* Try to load RISC code from flash. */
3835 qla_printk(KERN_ERR, ha, "Attempting to load (potentially "
3836 "outdated) firmware from flash.\n");
3837 return qla24xx_load_risc_flash(ha, srisc_addr);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003838 }
3839
3840 rval = QLA_SUCCESS;
3841
3842 segments = FA_RISC_CODE_SEGMENTS;
3843 dcode = (uint32_t *)ha->request_ring;
3844 *srisc_addr = 0;
Andrew Vasquez54333832005-11-09 15:49:04 -08003845 fwcode = (uint32_t *)blob->fw->data;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003846 fwclen = 0;
3847
3848 /* Validate firmware image by checking version. */
Andrew Vasquez54333832005-11-09 15:49:04 -08003849 if (blob->fw->size < 8 * sizeof(uint32_t)) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003850 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08003851 "Unable to verify integrity of firmware image (%Zd)!\n",
3852 blob->fw->size);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003853 goto fail_fw_integrity;
3854 }
3855 for (i = 0; i < 4; i++)
3856 dcode[i] = be32_to_cpu(fwcode[i + 4]);
3857 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
3858 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
3859 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
3860 dcode[3] == 0)) {
3861 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08003862 "Unable to verify integrity of firmware image!\n");
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003863 qla_printk(KERN_WARNING, ha,
3864 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
3865 dcode[1], dcode[2], dcode[3]);
3866 goto fail_fw_integrity;
3867 }
3868
3869 while (segments && rval == QLA_SUCCESS) {
3870 risc_addr = be32_to_cpu(fwcode[2]);
3871 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
3872 risc_size = be32_to_cpu(fwcode[3]);
3873
3874 /* Validate firmware image size. */
3875 fwclen += risc_size * sizeof(uint32_t);
Andrew Vasquez54333832005-11-09 15:49:04 -08003876 if (blob->fw->size < fwclen) {
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003877 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08003878 "Unable to verify integrity of firmware image "
3879 "(%Zd)!\n", blob->fw->size);
3880
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003881 goto fail_fw_integrity;
3882 }
3883
3884 fragment = 0;
3885 while (risc_size > 0 && rval == QLA_SUCCESS) {
3886 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
3887 if (dlen > risc_size)
3888 dlen = risc_size;
3889
3890 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3891 "addr %x, number of dwords 0x%x.\n", ha->host_no,
3892 risc_addr, dlen));
3893
3894 for (i = 0; i < dlen; i++)
3895 dcode[i] = swab32(fwcode[i]);
3896
andrew.vasquez@qlogic.com590f98e2006-01-13 17:05:37 -08003897 rval = qla2x00_load_ram(ha, ha->request_dma, risc_addr,
3898 dlen);
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003899 if (rval) {
3900 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
3901 "segment %d of firmware\n", ha->host_no,
3902 fragment));
3903 qla_printk(KERN_WARNING, ha,
3904 "[ERROR] Failed to load segment %d of "
3905 "firmware\n", fragment);
3906 break;
3907 }
3908
3909 fwcode += dlen;
3910 risc_addr += dlen;
3911 risc_size -= dlen;
3912 fragment++;
3913 }
3914
3915 /* Next segment. */
3916 segments--;
3917 }
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003918 return rval;
3919
3920fail_fw_integrity:
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003921 return QLA_FUNCTION_FAILED;
Andrew Vasquez0107109e2005-07-06 10:31:37 -07003922}
Andrew Vasquez18c6c122006-10-13 09:33:38 -07003923
3924void
3925qla2x00_try_to_stop_firmware(scsi_qla_host_t *ha)
3926{
3927 int ret, retries;
3928
3929 if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
3930 return;
Andrew Vasquez75edf812007-05-07 07:43:00 -07003931 if (!ha->fw_major_version)
3932 return;
Andrew Vasquez18c6c122006-10-13 09:33:38 -07003933
3934 ret = qla2x00_stop_firmware(ha);
3935 for (retries = 5; ret != QLA_SUCCESS && retries ; retries--) {
3936 qla2x00_reset_chip(ha);
3937 if (qla2x00_chip_diag(ha) != QLA_SUCCESS)
3938 continue;
3939 if (qla2x00_setup_chip(ha) != QLA_SUCCESS)
3940 continue;
3941 qla_printk(KERN_INFO, ha,
3942 "Attempting retry of stop-firmware command...\n");
3943 ret = qla2x00_stop_firmware(ha);
3944 }
3945}