blob: d525808afc4e79df639dc14f3ef73d4de0e0c210 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Andrew Vasquezfa90c542005-10-27 11:10:08 -07002 * QLogic Fibre Channel HBA Driver
Andrew Vasquez01e58d82008-04-03 13:13:13 -07003 * Copyright (c) 2003-2008 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"
Anirban Chakraborty73208df2008-12-09 16:45:39 -08008#include "qla_gbl.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -07009
10#include <linux/delay.h>
Andrew Vasquez01071092005-07-06 10:31:37 -070011#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012
13#include "qla_devtbl.h"
14
David Miller4e08df32007-04-16 12:37:43 -070015#ifdef CONFIG_SPARC
16#include <asm/prom.h>
David Miller4e08df32007-04-16 12:37:43 -070017#endif
18
Linus Torvalds1da177e2005-04-16 15:20:36 -070019/*
20* QLogic ISP2x00 Hardware Support Function Prototypes.
21*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070022static int qla2x00_isp_firmware(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070023static void qla2x00_resize_request_q(scsi_qla_host_t *);
24static int qla2x00_setup_chip(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070025static int qla2x00_init_rings(scsi_qla_host_t *);
26static int qla2x00_fw_ready(scsi_qla_host_t *);
27static int qla2x00_configure_hba(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028static int qla2x00_configure_loop(scsi_qla_host_t *);
29static int qla2x00_configure_local_loop(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030static int qla2x00_configure_fabric(scsi_qla_host_t *);
31static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
32static int qla2x00_device_resync(scsi_qla_host_t *);
33static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
34 uint16_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
36static int qla2x00_restart_isp(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070037
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080038static int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
Adrian Bunk413975a2006-06-30 02:33:06 -070039
Harihara Kadayam4d4df192008-04-03 13:13:26 -070040static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
41static int qla84xx_init_chip(scsi_qla_host_t *);
Anirban Chakraborty73208df2008-12-09 16:45:39 -080042static int qla25xx_init_queues(struct qla_hw_data *);
Harihara Kadayam4d4df192008-04-03 13:13:26 -070043
Linus Torvalds1da177e2005-04-16 15:20:36 -070044/****************************************************************************/
45/* QLogic ISP2x00 Hardware Support Functions. */
46/****************************************************************************/
47
48/*
49* qla2x00_initialize_adapter
50* Initialize board.
51*
52* Input:
53* ha = adapter block pointer.
54*
55* Returns:
56* 0 = success
57*/
58int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080059qla2x00_initialize_adapter(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -070060{
61 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080062 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -080063 struct req_que *req = ha->req_q_map[0];
Lalit Chandivade2533cf62009-03-24 09:08:07 -070064
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 /* Clear adapter flags. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080066 vha->flags.online = 0;
Lalit Chandivade2533cf62009-03-24 09:08:07 -070067 ha->flags.chip_reset_done = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080068 vha->flags.reset_active = 0;
69 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
70 atomic_set(&vha->loop_state, LOOP_DOWN);
71 vha->device_flags = DFLG_NO_CABLE;
72 vha->dpc_flags = 0;
73 vha->flags.management_server_logged_in = 0;
74 vha->marker_needed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 ha->isp_abort_cnt = 0;
76 ha->beacon_blink_led = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080077 set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Anirban Chakraborty73208df2008-12-09 16:45:39 -080079 set_bit(0, ha->req_qid_map);
80 set_bit(0, ha->rsp_qid_map);
81
Andrew Vasquez01071092005-07-06 10:31:37 -070082 qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080083 rval = ha->isp_ops->pci_config(vha);
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",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080086 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 return (rval);
88 }
89
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080090 ha->isp_ops->reset_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080092 rval = qla2xxx_get_flash_info(vha);
Andrew Vasquezc00d8992008-09-11 21:22:49 -070093 if (rval) {
94 DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080095 vha->host_no));
Andrew Vasquezc00d8992008-09-11 21:22:49 -070096 return (rval);
97 }
98
Anirban Chakraborty73208df2008-12-09 16:45:39 -080099 ha->isp_ops->get_flash_version(vha, req->ring);
Andrew Vasquez30c47662007-01-29 10:22:21 -0800100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
Andrew Vasquez01071092005-07-06 10:31:37 -0700102
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800103 ha->isp_ops->nvram_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Andrew Vasquezd4c760c2006-06-23 16:10:39 -0700105 if (ha->flags.disable_serdes) {
106 /* Mask HBA via NVRAM settings? */
107 qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
108 "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800109 vha->port_name[0], vha->port_name[1],
110 vha->port_name[2], vha->port_name[3],
111 vha->port_name[4], vha->port_name[5],
112 vha->port_name[6], vha->port_name[7]);
Andrew Vasquezd4c760c2006-06-23 16:10:39 -0700113 return QLA_FUNCTION_FAILED;
114 }
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
117
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800118 if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
119 rval = ha->isp_ops->chip_diag(vha);
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800120 if (rval)
121 return (rval);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800122 rval = qla2x00_setup_chip(vha);
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800123 if (rval)
124 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 }
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700126 if (IS_QLA84XX(ha)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800127 ha->cs84xx = qla84xx_get_chip(vha);
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700128 if (!ha->cs84xx) {
129 qla_printk(KERN_ERR, ha,
130 "Unable to configure ISP84XX.\n");
131 return QLA_FUNCTION_FAILED;
132 }
133 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800134 rval = qla2x00_init_rings(vha);
Lalit Chandivade2533cf62009-03-24 09:08:07 -0700135 ha->flags.chip_reset_done = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136
137 return (rval);
138}
139
140/**
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700141 * qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 * @ha: HA context
143 *
144 * Returns 0 on success.
145 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700146int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800147qla2100_pci_config(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700149 uint16_t w;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700150 unsigned long flags;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800151 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700152 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700155 pci_try_set_mwi(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700158 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
160
Andrew Vasquez737faec2008-10-24 15:13:45 -0700161 pci_disable_rom(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700163 /* Get PCI bus information. */
164 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700165 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700166 spin_unlock_irqrestore(&ha->hardware_lock, flags);
167
168 return QLA_SUCCESS;
169}
170
171/**
172 * qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
173 * @ha: HA context
174 *
175 * Returns 0 on success.
176 */
177int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800178qla2300_pci_config(scsi_qla_host_t *vha)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700179{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700180 uint16_t w;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700181 unsigned long flags = 0;
182 uint32_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800183 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700184 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700185
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700186 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700187 pci_try_set_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700188
189 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700190 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700191
192 if (IS_QLA2322(ha) || IS_QLA6322(ha))
193 w &= ~PCI_COMMAND_INTX_DISABLE;
Andrew Vasqueza157b102007-05-07 07:43:01 -0700194 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700195
196 /*
197 * If this is a 2300 card and not 2312, reset the
198 * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
199 * the 2310 also reports itself as a 2300 so we need to get the
200 * fb revision level -- a 6 indicates it really is a 2300 and
201 * not a 2310.
202 */
203 if (IS_QLA2300(ha)) {
204 spin_lock_irqsave(&ha->hardware_lock, flags);
205
206 /* Pause RISC. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700207 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700208 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700209 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700210 break;
211
212 udelay(10);
213 }
214
215 /* Select FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700216 WRT_REG_WORD(&reg->ctrl_status, 0x20);
217 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700218
219 /* Get the fb rev level */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700220 ha->fb_rev = RD_FB_CMD_REG(ha, reg);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700221
222 if (ha->fb_rev == FPM_2300)
Andrew Vasqueza157b102007-05-07 07:43:01 -0700223 pci_clear_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700224
225 /* Deselect FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700226 WRT_REG_WORD(&reg->ctrl_status, 0x0);
227 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700228
229 /* Release RISC module. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700230 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700231 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700232 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700233 break;
234
235 udelay(10);
236 }
237
238 spin_unlock_irqrestore(&ha->hardware_lock, flags);
239 }
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700240
241 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
242
Andrew Vasquez737faec2008-10-24 15:13:45 -0700243 pci_disable_rom(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700244
245 /* Get PCI bus information. */
246 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700247 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700248 spin_unlock_irqrestore(&ha->hardware_lock, flags);
249
250 return QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251}
252
253/**
Andrew Vasquez01071092005-07-06 10:31:37 -0700254 * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
255 * @ha: HA context
256 *
257 * Returns 0 on success.
258 */
259int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800260qla24xx_pci_config(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700261{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700262 uint16_t w;
Andrew Vasquez01071092005-07-06 10:31:37 -0700263 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800264 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -0700265 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
Andrew Vasquez01071092005-07-06 10:31:37 -0700266
267 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700268 pci_try_set_mwi(ha->pdev);
Andrew Vasquez01071092005-07-06 10:31:37 -0700269
270 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700271 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquez01071092005-07-06 10:31:37 -0700272 w &= ~PCI_COMMAND_INTX_DISABLE;
273 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
274
275 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
276
277 /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
Andrew Vasquezf85ec182007-07-19 15:06:01 -0700278 if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
279 pcix_set_mmrbc(ha->pdev, 2048);
Andrew Vasquez01071092005-07-06 10:31:37 -0700280
281 /* PCIe -- adjust Maximum Read Request Size (2048). */
Andrew Vasquezf85ec182007-07-19 15:06:01 -0700282 if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
283 pcie_set_readrq(ha->pdev, 2048);
Andrew Vasquez01071092005-07-06 10:31:37 -0700284
Andrew Vasquez737faec2008-10-24 15:13:45 -0700285 pci_disable_rom(ha->pdev);
Andrew Vasquez01071092005-07-06 10:31:37 -0700286
Auke Kok44c10132007-06-08 15:46:36 -0700287 ha->chip_revision = ha->pdev->revision;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -0800288
Andrew Vasquez01071092005-07-06 10:31:37 -0700289 /* Get PCI bus information. */
290 spin_lock_irqsave(&ha->hardware_lock, flags);
291 ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
292 spin_unlock_irqrestore(&ha->hardware_lock, flags);
293
294 return QLA_SUCCESS;
295}
296
297/**
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700298 * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
299 * @ha: HA context
300 *
301 * Returns 0 on success.
302 */
303int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800304qla25xx_pci_config(scsi_qla_host_t *vha)
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700305{
306 uint16_t w;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800307 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700308
309 pci_set_master(ha->pdev);
310 pci_try_set_mwi(ha->pdev);
311
312 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
313 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
314 w &= ~PCI_COMMAND_INTX_DISABLE;
315 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
316
317 /* PCIe -- adjust Maximum Read Request Size (2048). */
318 if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
319 pcie_set_readrq(ha->pdev, 2048);
320
Andrew Vasquez737faec2008-10-24 15:13:45 -0700321 pci_disable_rom(ha->pdev);
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700322
323 ha->chip_revision = ha->pdev->revision;
324
325 return QLA_SUCCESS;
326}
327
328/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 * qla2x00_isp_firmware() - Choose firmware image.
330 * @ha: HA context
331 *
332 * Returns 0 on success.
333 */
334static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800335qla2x00_isp_firmware(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336{
337 int rval;
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700338 uint16_t loop_id, topo, sw_cap;
339 uint8_t domain, area, al_pa;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800340 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342 /* Assume loading risc code */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700343 rval = QLA_FUNCTION_FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344
345 if (ha->flags.disable_risc_code_load) {
346 DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800347 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
349
350 /* Verify checksum of loaded RISC code. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800351 rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700352 if (rval == QLA_SUCCESS) {
353 /* And, verify we are not in ROM code. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800354 rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700355 &area, &domain, &topo, &sw_cap);
356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
358
359 if (rval) {
360 DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800361 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362 }
363
364 return (rval);
365}
366
367/**
368 * qla2x00_reset_chip() - Reset ISP chip.
369 * @ha: HA context
370 *
371 * Returns 0 on success.
372 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700373void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800374qla2x00_reset_chip(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375{
376 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800377 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700378 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700379 uint32_t cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 uint16_t cmd;
381
Andrew Vasquezfd34f552007-07-19 15:06:00 -0700382 ha->isp_ops->disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
384 spin_lock_irqsave(&ha->hardware_lock, flags);
385
386 /* Turn off master enable */
387 cmd = 0;
388 pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
389 cmd &= ~PCI_COMMAND_MASTER;
390 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
391
392 if (!IS_QLA2100(ha)) {
393 /* Pause RISC. */
394 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
395 if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
396 for (cnt = 0; cnt < 30000; cnt++) {
397 if ((RD_REG_WORD(&reg->hccr) &
398 HCCR_RISC_PAUSE) != 0)
399 break;
400 udelay(100);
401 }
402 } else {
403 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
404 udelay(10);
405 }
406
407 /* Select FPM registers. */
408 WRT_REG_WORD(&reg->ctrl_status, 0x20);
409 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
410
411 /* FPM Soft Reset. */
412 WRT_REG_WORD(&reg->fpm_diag_config, 0x100);
413 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
414
415 /* Toggle Fpm Reset. */
416 if (!IS_QLA2200(ha)) {
417 WRT_REG_WORD(&reg->fpm_diag_config, 0x0);
418 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
419 }
420
421 /* Select frame buffer registers. */
422 WRT_REG_WORD(&reg->ctrl_status, 0x10);
423 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
424
425 /* Reset frame buffer FIFOs. */
426 if (IS_QLA2200(ha)) {
427 WRT_FB_CMD_REG(ha, reg, 0xa000);
428 RD_FB_CMD_REG(ha, reg); /* PCI Posting. */
429 } else {
430 WRT_FB_CMD_REG(ha, reg, 0x00fc);
431
432 /* Read back fb_cmd until zero or 3 seconds max */
433 for (cnt = 0; cnt < 3000; cnt++) {
434 if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
435 break;
436 udelay(100);
437 }
438 }
439
440 /* Select RISC module registers. */
441 WRT_REG_WORD(&reg->ctrl_status, 0);
442 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
443
444 /* Reset RISC processor. */
445 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
446 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
447
448 /* Release RISC processor. */
449 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
450 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
451 }
452
453 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
454 WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);
455
456 /* Reset ISP chip. */
457 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
458
459 /* Wait for RISC to recover from reset. */
460 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
461 /*
462 * It is necessary to for a delay here since the card doesn't
463 * respond to PCI reads during a reset. On some architectures
464 * this will result in an MCA.
465 */
466 udelay(20);
467 for (cnt = 30000; cnt; cnt--) {
468 if ((RD_REG_WORD(&reg->ctrl_status) &
469 CSR_ISP_SOFT_RESET) == 0)
470 break;
471 udelay(100);
472 }
473 } else
474 udelay(10);
475
476 /* Reset RISC processor. */
477 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
478
479 WRT_REG_WORD(&reg->semaphore, 0);
480
481 /* Release RISC processor. */
482 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
483 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
484
485 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
486 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquezffb39f02006-05-17 15:09:06 -0700487 if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
490 udelay(100);
491 }
492 } else
493 udelay(100);
494
495 /* Turn on master enable */
496 cmd |= PCI_COMMAND_MASTER;
497 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
498
499 /* Disable RISC pause on FPM parity error. */
500 if (!IS_QLA2100(ha)) {
501 WRT_REG_WORD(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
502 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
503 }
504
505 spin_unlock_irqrestore(&ha->hardware_lock, flags);
506}
507
508/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700509 * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
Andrew Vasquez01071092005-07-06 10:31:37 -0700510 * @ha: HA context
511 *
512 * Returns 0 on success.
513 */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700514static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800515qla24xx_reset_risc(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700516{
517 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800518 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -0700519 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
520 uint32_t cnt, d2;
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800521 uint16_t wd;
Andrew Vasquez01071092005-07-06 10:31:37 -0700522
Andrew Vasquez01071092005-07-06 10:31:37 -0700523 spin_lock_irqsave(&ha->hardware_lock, flags);
524
525 /* Reset RISC. */
526 WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
527 for (cnt = 0; cnt < 30000; cnt++) {
528 if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
529 break;
530
531 udelay(10);
532 }
533
534 WRT_REG_DWORD(&reg->ctrl_status,
535 CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800536 pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700537
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800538 udelay(100);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700539 /* Wait for firmware to complete NVRAM accesses. */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700540 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
541 for (cnt = 10000 ; cnt && d2; cnt--) {
542 udelay(5);
543 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
544 barrier();
545 }
546
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800547 /* Wait for soft-reset to complete. */
Andrew Vasquez01071092005-07-06 10:31:37 -0700548 d2 = RD_REG_DWORD(&reg->ctrl_status);
549 for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
550 udelay(5);
551 d2 = RD_REG_DWORD(&reg->ctrl_status);
552 barrier();
553 }
554
555 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
556 RD_REG_DWORD(&reg->hccr);
557
558 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
559 RD_REG_DWORD(&reg->hccr);
560
561 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
562 RD_REG_DWORD(&reg->hccr);
563
564 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
565 for (cnt = 6000000 ; cnt && d2; cnt--) {
566 udelay(5);
567 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
568 barrier();
569 }
570
571 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquez124f85e2009-01-05 11:18:06 -0800572
573 if (IS_NOPOLLING_TYPE(ha))
574 ha->isp_ops->enable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700575}
576
577/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700578 * qla24xx_reset_chip() - Reset ISP24xx chip.
579 * @ha: HA context
580 *
581 * Returns 0 on success.
582 */
583void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800584qla24xx_reset_chip(scsi_qla_host_t *vha)
Andrew Vasquez88c26662005-07-08 17:59:26 -0700585{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800586 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezfd34f552007-07-19 15:06:00 -0700587 ha->isp_ops->disable_intrs(ha);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700588
589 /* Perform RISC reset. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800590 qla24xx_reset_risc(vha);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700591}
592
593/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 * qla2x00_chip_diag() - Test chip for proper operation.
595 * @ha: HA context
596 *
597 * Returns 0 on success.
598 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700599int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800600qla2x00_chip_diag(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800603 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700604 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 unsigned long flags = 0;
606 uint16_t data;
607 uint32_t cnt;
608 uint16_t mb[5];
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800609 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 /* Assume a failed state */
612 rval = QLA_FUNCTION_FAILED;
613
614 DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800615 vha->host_no, (u_long)&reg->flash_address));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616
617 spin_lock_irqsave(&ha->hardware_lock, flags);
618
619 /* Reset ISP chip. */
620 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
621
622 /*
623 * We need to have a delay here since the card will not respond while
624 * in reset causing an MCA on some architectures.
625 */
626 udelay(20);
627 data = qla2x00_debounce_register(&reg->ctrl_status);
628 for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
629 udelay(5);
630 data = RD_REG_WORD(&reg->ctrl_status);
631 barrier();
632 }
633
634 if (!cnt)
635 goto chip_diag_failed;
636
637 DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
638 ha->host_no));
639
640 /* Reset RISC processor. */
641 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
642 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
643
644 /* Workaround for QLA2312 PCI parity error */
645 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
646 data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
647 for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
648 udelay(5);
649 data = RD_MAILBOX_REG(ha, reg, 0);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700650 barrier();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 }
652 } else
653 udelay(10);
654
655 if (!cnt)
656 goto chip_diag_failed;
657
658 /* Check product ID of chip */
659 DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no));
660
661 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
662 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
663 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
664 mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
665 if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
666 mb[3] != PROD_ID_3) {
667 qla_printk(KERN_WARNING, ha,
668 "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
669
670 goto chip_diag_failed;
671 }
672 ha->product_id[0] = mb[1];
673 ha->product_id[1] = mb[2];
674 ha->product_id[2] = mb[3];
675 ha->product_id[3] = mb[4];
676
677 /* Adjust fw RISC transfer size */
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800678 if (req->length > 1024)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
680 else
681 ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800682 req->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 if (IS_QLA2200(ha) &&
685 RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
686 /* Limit firmware transfer size with a 2200A */
687 DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800688 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -0800690 ha->device_type |= DT_ISP2200A;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 ha->fw_transfer_size = 128;
692 }
693
694 /* Wrap Incoming Mailboxes Test. */
695 spin_unlock_irqrestore(&ha->hardware_lock, flags);
696
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800697 DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
698 rval = qla2x00_mbx_reg_test(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 if (rval) {
700 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800701 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 qla_printk(KERN_WARNING, ha,
703 "Failed mailbox send register test\n");
704 }
705 else {
706 /* Flag a successful rval */
707 rval = QLA_SUCCESS;
708 }
709 spin_lock_irqsave(&ha->hardware_lock, flags);
710
711chip_diag_failed:
712 if (rval)
713 DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800714 "****\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 spin_unlock_irqrestore(&ha->hardware_lock, flags);
717
718 return (rval);
719}
720
721/**
Andrew Vasquez01071092005-07-06 10:31:37 -0700722 * qla24xx_chip_diag() - Test ISP24xx for proper operation.
723 * @ha: HA context
724 *
725 * Returns 0 on success.
726 */
727int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800728qla24xx_chip_diag(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700729{
730 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800731 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800732 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -0700733
Andrew Vasquez88c26662005-07-08 17:59:26 -0700734 /* Perform RISC reset. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800735 qla24xx_reset_risc(vha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700736
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800737 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
Andrew Vasquez01071092005-07-06 10:31:37 -0700738
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800739 rval = qla2x00_mbx_reg_test(vha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700740 if (rval) {
741 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800742 vha->host_no));
Andrew Vasquez01071092005-07-06 10:31:37 -0700743 qla_printk(KERN_WARNING, ha,
744 "Failed mailbox send register test\n");
745 } else {
746 /* Flag a successful rval */
747 rval = QLA_SUCCESS;
748 }
749
750 return rval;
751}
752
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700753void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800754qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700755{
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700756 int rval;
757 uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800758 eft_size, fce_size, mq_size;
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800759 dma_addr_t tc_dma;
760 void *tc;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800761 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800762 struct req_que *req = ha->req_q_map[0];
763 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700764
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700765 if (ha->fw_dump) {
766 qla_printk(KERN_WARNING, ha,
767 "Firmware dump previously allocated.\n");
768 return;
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700769 }
770
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700771 ha->fw_dumped = 0;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800772 fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700773 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
774 fixed_size = sizeof(struct qla2100_fw_dump);
775 } else if (IS_QLA23XX(ha)) {
776 fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
777 mem_size = (ha->fw_memory_size - 0x11000 + 1) *
778 sizeof(uint16_t);
Andrew Vasqueze4289242007-07-19 15:05:56 -0700779 } else if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800780 if (IS_QLA81XX(ha))
781 fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
782 else if (IS_QLA25XX(ha))
783 fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
784 else
785 fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700786 mem_size = (ha->fw_memory_size - 0x100000 + 1) *
787 sizeof(uint32_t);
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800788 if (ha->mqenable)
789 mq_size = sizeof(struct qla2xxx_mq_chain);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700790
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700791 /* Allocate memory for Fibre Channel Event Buffer. */
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800792 if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700793 goto try_eft;
794
795 tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
796 GFP_KERNEL);
797 if (!tc) {
798 qla_printk(KERN_WARNING, ha, "Unable to allocate "
799 "(%d KB) for FCE.\n", FCE_SIZE / 1024);
Anirban Chakraborty17d98632008-12-18 10:06:15 -0800800 goto try_eft;
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700801 }
802
803 memset(tc, 0, FCE_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800804 rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS,
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700805 ha->fce_mb, &ha->fce_bufs);
806 if (rval) {
807 qla_printk(KERN_WARNING, ha, "Unable to initialize "
808 "FCE (%d).\n", rval);
809 dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
810 tc_dma);
811 ha->flags.fce_enabled = 0;
Anirban Chakraborty17d98632008-12-18 10:06:15 -0800812 goto try_eft;
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700813 }
814
815 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
816 FCE_SIZE / 1024);
817
Giridhar Malavali7d9dade2009-03-24 09:07:58 -0700818 fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700819 ha->flags.fce_enabled = 1;
820 ha->fce_dma = tc_dma;
821 ha->fce = tc;
822try_eft:
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700823 /* Allocate memory for Extended Trace Buffer. */
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800824 tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700825 GFP_KERNEL);
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800826 if (!tc) {
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700827 qla_printk(KERN_WARNING, ha, "Unable to allocate "
828 "(%d KB) for EFT.\n", EFT_SIZE / 1024);
829 goto cont_alloc;
830 }
831
Andrew Vasquezfc447652008-01-17 09:02:18 -0800832 memset(tc, 0, EFT_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800833 rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700834 if (rval) {
835 qla_printk(KERN_WARNING, ha, "Unable to initialize "
836 "EFT (%d).\n", rval);
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800837 dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
838 tc_dma);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700839 goto cont_alloc;
840 }
841
842 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
843 EFT_SIZE / 1024);
844
845 eft_size = EFT_SIZE;
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800846 ha->eft_dma = tc_dma;
847 ha->eft = tc;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700848 }
849cont_alloc:
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800850 req_q_size = req->length * sizeof(request_t);
851 rsp_q_size = rsp->length * sizeof(response_t);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700852
853 dump_size = offsetof(struct qla2xxx_fw_dump, isp);
854 dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
Andrew Vasquezbb99de62009-01-05 11:18:08 -0800855 eft_size;
856 ha->chain_offset = dump_size;
857 dump_size += mq_size + fce_size;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700858
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700859 ha->fw_dump = vmalloc(dump_size);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700860 if (!ha->fw_dump) {
Andrew Vasquez01071092005-07-06 10:31:37 -0700861 qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700862 "firmware dump!!!\n", dump_size / 1024);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700863
864 if (ha->eft) {
865 dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
866 ha->eft_dma);
867 ha->eft = NULL;
868 ha->eft_dma = 0;
869 }
870 return;
871 }
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700872 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
873 dump_size / 1024);
874
875 ha->fw_dump_len = dump_size;
876 ha->fw_dump->signature[0] = 'Q';
877 ha->fw_dump->signature[1] = 'L';
878 ha->fw_dump->signature[2] = 'G';
879 ha->fw_dump->signature[3] = 'C';
880 ha->fw_dump->version = __constant_htonl(1);
881
882 ha->fw_dump->fixed_size = htonl(fixed_size);
883 ha->fw_dump->mem_size = htonl(mem_size);
884 ha->fw_dump->req_q_size = htonl(req_q_size);
885 ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
886
887 ha->fw_dump->eft_size = htonl(eft_size);
888 ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
889 ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
890
891 ha->fw_dump->header_size =
892 htonl(offsetof(struct qla2xxx_fw_dump, isp));
Andrew Vasquez01071092005-07-06 10:31:37 -0700893}
894
895/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896 * qla2x00_resize_request_q() - Resize request queue given available ISP memory.
897 * @ha: HA context
898 *
899 * Returns 0 on success.
900 */
901static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800902qla2x00_resize_request_q(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903{
904 int rval;
905 uint16_t fw_iocb_cnt = 0;
906 uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM;
907 dma_addr_t request_dma;
908 request_t *request_ring;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800909 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800910 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
912 /* Valid only on recent ISPs. */
913 if (IS_QLA2100(ha) || IS_QLA2200(ha))
914 return;
915
916 /* Retrieve IOCB counts available to the firmware. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800917 rval = qla2x00_get_resource_cnts(vha, NULL, NULL, NULL, &fw_iocb_cnt,
918 &ha->max_npiv_vports);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 if (rval)
920 return;
921 /* No point in continuing if current settings are sufficient. */
922 if (fw_iocb_cnt < 1024)
923 return;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800924 if (req->length >= request_q_length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 return;
926
927 /* Attempt to claim larger area for request queue. */
928 request_ring = dma_alloc_coherent(&ha->pdev->dev,
929 (request_q_length + 1) * sizeof(request_t), &request_dma,
930 GFP_KERNEL);
931 if (request_ring == NULL)
932 return;
933
934 /* Resize successful, report extensions. */
935 qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n",
936 (ha->fw_memory_size + 1) / 1024);
937 qla_printk(KERN_INFO, ha, "Resizing request queue depth "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800938 "(%d -> %d)...\n", req->length, request_q_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 /* Clear old allocations. */
941 dma_free_coherent(&ha->pdev->dev,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800942 (req->length + 1) * sizeof(request_t), req->ring,
943 req->dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 /* Begin using larger queue. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800946 req->length = request_q_length;
947 req->ring = request_ring;
948 req->dma = request_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949}
950
951/**
952 * qla2x00_setup_chip() - Load and start RISC firmware.
953 * @ha: HA context
954 *
955 * Returns 0 on success.
956 */
957static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800958qla2x00_setup_chip(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959{
Andrew Vasquez01071092005-07-06 10:31:37 -0700960 int rval;
961 uint32_t srisc_address = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800962 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3db06522008-01-31 12:33:49 -0800963 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
964 unsigned long flags;
Andrew Vasquezdda772e2009-03-24 09:08:00 -0700965 uint16_t fw_major_version;
Andrew Vasquez3db06522008-01-31 12:33:49 -0800966
967 if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
968 /* Disable SRAM, Instruction RAM and GP RAM parity. */
969 spin_lock_irqsave(&ha->hardware_lock, flags);
970 WRT_REG_WORD(&reg->hccr, (HCCR_ENABLE_PARITY + 0x0));
971 RD_REG_WORD(&reg->hccr);
972 spin_unlock_irqrestore(&ha->hardware_lock, flags);
973 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
975 /* Load firmware sequences */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800976 rval = ha->isp_ops->load_risc(vha, &srisc_address);
Andrew Vasquez01071092005-07-06 10:31:37 -0700977 if (rval == QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800979 "code.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800981 rval = qla2x00_verify_checksum(vha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (rval == QLA_SUCCESS) {
983 /* Start firmware execution. */
984 DEBUG(printk("scsi(%ld): Checksum OK, start "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800985 "firmware.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800987 rval = qla2x00_execute_fw(vha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 /* Retrieve firmware information. */
Andrew Vasquezdda772e2009-03-24 09:08:00 -0700989 if (rval == QLA_SUCCESS) {
990 fw_major_version = ha->fw_major_version;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800991 qla2x00_get_fw_version(vha,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 &ha->fw_major_version,
993 &ha->fw_minor_version,
994 &ha->fw_subminor_version,
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800995 &ha->fw_attributes, &ha->fw_memory_size,
Andrew Vasquez55a96152009-03-24 09:08:03 -0700996 ha->mpi_version, &ha->mpi_capabilities,
997 ha->phy_version);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700998 ha->flags.npiv_supported = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800999 if (IS_QLA2XXX_MIDTYPE(ha) &&
Mike Hernandez946fb892008-08-13 21:36:59 -07001000 (ha->fw_attributes & BIT_2)) {
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001001 ha->flags.npiv_supported = 1;
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001002 if ((!ha->max_npiv_vports) ||
1003 ((ha->max_npiv_vports + 1) %
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001004 MIN_MULTI_ID_FABRIC))
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001005 ha->max_npiv_vports =
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001006 MIN_MULTI_ID_FABRIC - 1;
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001007 }
Andrew Vasquezdda772e2009-03-24 09:08:00 -07001008 if (!fw_major_version) {
1009 qla2x00_resize_request_q(vha);
1010 if (ql2xallocfwdump)
1011 qla2x00_alloc_fw_dump(vha);
1012 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 }
1014 } else {
1015 DEBUG2(printk(KERN_INFO
1016 "scsi(%ld): ISP Firmware failed checksum.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001017 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 }
1019 }
1020
Andrew Vasquez3db06522008-01-31 12:33:49 -08001021 if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
1022 /* Enable proper parity. */
1023 spin_lock_irqsave(&ha->hardware_lock, flags);
1024 if (IS_QLA2300(ha))
1025 /* SRAM parity */
1026 WRT_REG_WORD(&reg->hccr, HCCR_ENABLE_PARITY + 0x1);
1027 else
1028 /* SRAM, Instruction RAM and GP RAM parity */
1029 WRT_REG_WORD(&reg->hccr, HCCR_ENABLE_PARITY + 0x7);
1030 RD_REG_WORD(&reg->hccr);
1031 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1032 }
1033
Joe Carnuccio1d2874d2009-03-24 09:08:06 -07001034 if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
1035 uint32_t size;
1036
1037 rval = qla81xx_fac_get_sector_size(vha, &size);
1038 if (rval == QLA_SUCCESS) {
1039 ha->flags.fac_supported = 1;
1040 ha->fdt_block_size = size << 2;
1041 } else {
1042 qla_printk(KERN_ERR, ha,
1043 "Unsupported FAC firmware (%d.%02d.%02d).\n",
1044 ha->fw_major_version, ha->fw_minor_version,
1045 ha->fw_subminor_version);
1046 }
1047 }
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 if (rval) {
1050 DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001051 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 }
1053
1054 return (rval);
1055}
1056
1057/**
1058 * qla2x00_init_response_q_entries() - Initializes response queue entries.
1059 * @ha: HA context
1060 *
1061 * Beginning of request ring has initialization control block already built
1062 * by nvram config routine.
1063 *
1064 * Returns 0 on success.
1065 */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001066void
1067qla2x00_init_response_q_entries(struct rsp_que *rsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068{
1069 uint16_t cnt;
1070 response_t *pkt;
1071
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001072 pkt = rsp->ring_ptr;
1073 for (cnt = 0; cnt < rsp->length; cnt++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 pkt->signature = RESPONSE_PROCESSED;
1075 pkt++;
1076 }
1077
1078}
1079
1080/**
1081 * qla2x00_update_fw_options() - Read and process firmware options.
1082 * @ha: HA context
1083 *
1084 * Returns 0 on success.
1085 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001086void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001087qla2x00_update_fw_options(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
1089 uint16_t swing, emphasis, tx_sens, rx_sens;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001090 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092 memset(ha->fw_options, 0, sizeof(ha->fw_options));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001093 qla2x00_get_fw_options(vha, ha->fw_options);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095 if (IS_QLA2100(ha) || IS_QLA2200(ha))
1096 return;
1097
1098 /* Serial Link options. */
1099 DEBUG3(printk("scsi(%ld): Serial link options:\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001100 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
1102 sizeof(ha->fw_seriallink_options)));
1103
1104 ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
1105 if (ha->fw_seriallink_options[3] & BIT_2) {
1106 ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
1107
1108 /* 1G settings */
1109 swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
1110 emphasis = (ha->fw_seriallink_options[2] &
1111 (BIT_4 | BIT_3)) >> 3;
1112 tx_sens = ha->fw_seriallink_options[0] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001113 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114 rx_sens = (ha->fw_seriallink_options[0] &
1115 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
1116 ha->fw_options[10] = (emphasis << 14) | (swing << 8);
1117 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
1118 if (rx_sens == 0x0)
1119 rx_sens = 0x3;
1120 ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
1121 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1122 ha->fw_options[10] |= BIT_5 |
1123 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1124 (tx_sens & (BIT_1 | BIT_0));
1125
1126 /* 2G settings */
1127 swing = (ha->fw_seriallink_options[2] &
1128 (BIT_7 | BIT_6 | BIT_5)) >> 5;
1129 emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
1130 tx_sens = ha->fw_seriallink_options[1] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001131 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 rx_sens = (ha->fw_seriallink_options[1] &
1133 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
1134 ha->fw_options[11] = (emphasis << 14) | (swing << 8);
1135 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
1136 if (rx_sens == 0x0)
1137 rx_sens = 0x3;
1138 ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
1139 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1140 ha->fw_options[11] |= BIT_5 |
1141 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1142 (tx_sens & (BIT_1 | BIT_0));
1143 }
1144
1145 /* FCP2 options. */
1146 /* Return command IOCBs without waiting for an ABTS to complete. */
1147 ha->fw_options[3] |= BIT_13;
1148
1149 /* LED scheme. */
1150 if (ha->flags.enable_led_scheme)
1151 ha->fw_options[2] |= BIT_12;
1152
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08001153 /* Detect ISP6312. */
1154 if (IS_QLA6312(ha))
1155 ha->fw_options[2] |= BIT_13;
1156
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 /* Update firmware options. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001158 qla2x00_set_fw_options(vha, ha->fw_options);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159}
1160
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001161void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001162qla24xx_update_fw_options(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07001163{
1164 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001165 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07001166
1167 /* Update Serial Link options. */
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001168 if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
Andrew Vasquez01071092005-07-06 10:31:37 -07001169 return;
1170
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001171 rval = qla2x00_set_serdes_params(vha,
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001172 le16_to_cpu(ha->fw_seriallink_options24[1]),
1173 le16_to_cpu(ha->fw_seriallink_options24[2]),
1174 le16_to_cpu(ha->fw_seriallink_options24[3]));
Andrew Vasquez01071092005-07-06 10:31:37 -07001175 if (rval != QLA_SUCCESS) {
1176 qla_printk(KERN_WARNING, ha,
1177 "Unable to update Serial Link options (%x).\n", rval);
1178 }
1179}
1180
1181void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001182qla2x00_config_rings(struct scsi_qla_host *vha)
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001183{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001184 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001185 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001186 struct req_que *req = ha->req_q_map[0];
1187 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001188
1189 /* Setup ring parameters in initialization control block. */
1190 ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0);
1191 ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001192 ha->init_cb->request_q_length = cpu_to_le16(req->length);
1193 ha->init_cb->response_q_length = cpu_to_le16(rsp->length);
1194 ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
1195 ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
1196 ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
1197 ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001198
1199 WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
1200 WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
1201 WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0);
1202 WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0);
1203 RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */
1204}
1205
Andrew Vasquez01071092005-07-06 10:31:37 -07001206void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001207qla24xx_config_rings(struct scsi_qla_host *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07001208{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001209 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001210 device_reg_t __iomem *reg = ISP_QUE_REG(ha, 0);
1211 struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
1212 struct qla_msix_entry *msix;
Andrew Vasquez01071092005-07-06 10:31:37 -07001213 struct init_cb_24xx *icb;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001214 uint16_t rid = 0;
1215 struct req_que *req = ha->req_q_map[0];
1216 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -07001217
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001218/* Setup ring parameters in initialization control block. */
Andrew Vasquez01071092005-07-06 10:31:37 -07001219 icb = (struct init_cb_24xx *)ha->init_cb;
1220 icb->request_q_outpointer = __constant_cpu_to_le16(0);
1221 icb->response_q_inpointer = __constant_cpu_to_le16(0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001222 icb->request_q_length = cpu_to_le16(req->length);
1223 icb->response_q_length = cpu_to_le16(rsp->length);
1224 icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
1225 icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
1226 icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
1227 icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
Andrew Vasquez01071092005-07-06 10:31:37 -07001228
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001229 if (ha->mqenable) {
1230 icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
1231 icb->rid = __constant_cpu_to_le16(rid);
1232 if (ha->flags.msix_enabled) {
1233 msix = &ha->msix_entries[1];
1234 DEBUG2_17(printk(KERN_INFO
1235 "Reistering vector 0x%x for base que\n", msix->entry));
1236 icb->msix = cpu_to_le16(msix->entry);
1237 }
1238 /* Use alternate PCI bus number */
1239 if (MSB(rid))
1240 icb->firmware_options_2 |=
1241 __constant_cpu_to_le32(BIT_19);
1242 /* Use alternate PCI devfn */
1243 if (LSB(rid))
1244 icb->firmware_options_2 |=
1245 __constant_cpu_to_le32(BIT_18);
1246
Anirban Chakraborty618a7522009-02-08 20:50:11 -08001247 icb->firmware_options_2 &= __constant_cpu_to_le32(~BIT_22);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001248 icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001249
1250 WRT_REG_DWORD(&reg->isp25mq.req_q_in, 0);
1251 WRT_REG_DWORD(&reg->isp25mq.req_q_out, 0);
1252 WRT_REG_DWORD(&reg->isp25mq.rsp_q_in, 0);
1253 WRT_REG_DWORD(&reg->isp25mq.rsp_q_out, 0);
1254 } else {
1255 WRT_REG_DWORD(&reg->isp24.req_q_in, 0);
1256 WRT_REG_DWORD(&reg->isp24.req_q_out, 0);
1257 WRT_REG_DWORD(&reg->isp24.rsp_q_in, 0);
1258 WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0);
1259 }
1260 /* PCI posting */
1261 RD_REG_DWORD(&ioreg->hccr);
Andrew Vasquez01071092005-07-06 10:31:37 -07001262}
1263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264/**
1265 * qla2x00_init_rings() - Initializes firmware.
1266 * @ha: HA context
1267 *
1268 * Beginning of request ring has initialization control block already built
1269 * by nvram config routine.
1270 *
1271 * Returns 0 on success.
1272 */
1273static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001274qla2x00_init_rings(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275{
1276 int rval;
1277 unsigned long flags = 0;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001278 int cnt, que;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001279 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001280 struct req_que *req;
1281 struct rsp_que *rsp;
1282 struct scsi_qla_host *vp;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001283 struct mid_init_cb_24xx *mid_init_cb =
1284 (struct mid_init_cb_24xx *) ha->init_cb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001285
1286 spin_lock_irqsave(&ha->hardware_lock, flags);
1287
1288 /* Clear outstanding commands array. */
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001289 for (que = 0; que < ha->max_queues; que++) {
1290 req = ha->req_q_map[que];
1291 if (!req)
1292 continue;
1293 for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
1294 req->outstanding_cmds[cnt] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001296 req->current_outstanding_cmd = 0;
1297
1298 /* Initialize firmware. */
1299 req->ring_ptr = req->ring;
1300 req->ring_index = 0;
1301 req->cnt = req->length;
1302 }
1303
1304 for (que = 0; que < ha->max_queues; que++) {
1305 rsp = ha->rsp_q_map[que];
1306 if (!rsp)
1307 continue;
1308 rsp->ring_ptr = rsp->ring;
1309 rsp->ring_index = 0;
1310
1311 /* Initialize response queue entries */
1312 qla2x00_init_response_q_entries(rsp);
1313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314
1315 /* Clear RSCN queue. */
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001316 list_for_each_entry(vp, &ha->vp_list, list) {
1317 vp->rscn_in_ptr = 0;
1318 vp->rscn_out_ptr = 0;
1319 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001320 ha->isp_ops->config_rings(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001321
1322 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1323
1324 /* Update any ISP specific firmware options before initialization. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001325 ha->isp_ops->update_fw_options(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001327 DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001328
Lalit Chandivade605aa2b2009-03-05 11:07:01 -08001329 if (ha->flags.npiv_supported) {
1330 if (ha->operating_mode == LOOP)
1331 ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1;
Seokmann Juc48339d2008-01-17 09:02:19 -08001332 mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
Lalit Chandivade605aa2b2009-03-05 11:07:01 -08001333 }
1334
Seokmann Juc48339d2008-01-17 09:02:19 -08001335
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001336 mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001337
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001338 rval = qla2x00_init_firmware(vha, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 if (rval) {
1340 DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001341 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342 } else {
1343 DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001344 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 }
1346
1347 return (rval);
1348}
1349
1350/**
1351 * qla2x00_fw_ready() - Waits for firmware ready.
1352 * @ha: HA context
1353 *
1354 * Returns 0 on success.
1355 */
1356static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001357qla2x00_fw_ready(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358{
1359 int rval;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001360 unsigned long wtime, mtime, cs84xx_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 uint16_t min_wait; /* Minimum wait time if loop is down */
1362 uint16_t wait_time; /* Wait time if loop is coming ready */
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001363 uint16_t state[3];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001364 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 rval = QLA_SUCCESS;
1367
1368 /* 20 seconds for loop down. */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001369 min_wait = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370
1371 /*
1372 * Firmware should take at most one RATOV to login, plus 5 seconds for
1373 * our own processing.
1374 */
1375 if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
1376 wait_time = min_wait;
1377 }
1378
1379 /* Min wait time if loop down */
1380 mtime = jiffies + (min_wait * HZ);
1381
1382 /* wait time before firmware ready */
1383 wtime = jiffies + (wait_time * HZ);
1384
1385 /* Wait for ISP to finish LIP */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001386 if (!vha->flags.init_done)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001387 qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
1388
1389 DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001390 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
1392 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001393 rval = qla2x00_get_firmware_state(vha, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 if (rval == QLA_SUCCESS) {
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001395 if (state[0] < FSTATE_LOSS_OF_SYNC) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001396 vha->device_flags &= ~DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001397 }
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001398 if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
1399 DEBUG16(printk("scsi(%ld): fw_state=%x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001400 "84xx=%x.\n", vha->host_no, state[0],
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001401 state[2]));
1402 if ((state[2] & FSTATE_LOGGED_IN) &&
1403 (state[2] & FSTATE_WAITING_FOR_VERIFY)) {
1404 DEBUG16(printk("scsi(%ld): Sending "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001405 "verify iocb.\n", vha->host_no));
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001406
1407 cs84xx_time = jiffies;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001408 rval = qla84xx_init_chip(vha);
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001409 if (rval != QLA_SUCCESS)
1410 break;
1411
1412 /* Add time taken to initialize. */
1413 cs84xx_time = jiffies - cs84xx_time;
1414 wtime += cs84xx_time;
1415 mtime += cs84xx_time;
1416 DEBUG16(printk("scsi(%ld): Increasing "
1417 "wait time by %ld. New time %ld\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001418 vha->host_no, cs84xx_time, wtime));
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001419 }
1420 } else if (state[0] == FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001422 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001424 qla2x00_get_retry_cnt(vha, &ha->retry_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 &ha->login_timeout, &ha->r_a_tov);
1426
1427 rval = QLA_SUCCESS;
1428 break;
1429 }
1430
1431 rval = QLA_FUNCTION_FAILED;
1432
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001433 if (atomic_read(&vha->loop_down_timer) &&
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001434 state[0] != FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001435 /* Loop down. Timeout on min_wait for states
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001436 * other than Wait for Login.
1437 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001438 if (time_after_eq(jiffies, mtime)) {
1439 qla_printk(KERN_INFO, ha,
1440 "Cable is unplugged...\n");
1441
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001442 vha->device_flags |= DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 break;
1444 }
1445 }
1446 } else {
1447 /* Mailbox cmd failed. Timeout on min_wait. */
1448 if (time_after_eq(jiffies, mtime))
1449 break;
1450 }
1451
1452 if (time_after_eq(jiffies, wtime))
1453 break;
1454
1455 /* Delay for a while */
1456 msleep(500);
1457
1458 DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001459 vha->host_no, state[0], jiffies));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 } while (1);
1461
1462 DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001463 vha->host_no, state[0], jiffies));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001464
1465 if (rval) {
1466 DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001467 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 }
1469
1470 return (rval);
1471}
1472
1473/*
1474* qla2x00_configure_hba
1475* Setup adapter context.
1476*
1477* Input:
1478* ha = adapter state pointer.
1479*
1480* Returns:
1481* 0 = success
1482*
1483* Context:
1484* Kernel context.
1485*/
1486static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001487qla2x00_configure_hba(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001488{
1489 int rval;
1490 uint16_t loop_id;
1491 uint16_t topo;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001492 uint16_t sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 uint8_t al_pa;
1494 uint8_t area;
1495 uint8_t domain;
1496 char connect_type[22];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001497 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 /* Get host addresses. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001500 rval = qla2x00_get_adapter_id(vha,
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001501 &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 if (rval != QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001503 if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
Ravi Anand33135aa2005-11-08 14:37:20 -08001504 (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
1505 DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001506 __func__, vha->host_no));
Ravi Anand33135aa2005-11-08 14:37:20 -08001507 } else {
1508 qla_printk(KERN_WARNING, ha,
1509 "ERROR -- Unable to get host loop ID.\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001510 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Ravi Anand33135aa2005-11-08 14:37:20 -08001511 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 return (rval);
1513 }
1514
1515 if (topo == 4) {
1516 qla_printk(KERN_INFO, ha,
1517 "Cannot get topology - retrying.\n");
1518 return (QLA_FUNCTION_FAILED);
1519 }
1520
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001521 vha->loop_id = loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522
1523 /* initialize */
1524 ha->min_external_loopid = SNS_FIRST_LOOP_ID;
1525 ha->operating_mode = LOOP;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001526 ha->switch_cap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
1528 switch (topo) {
1529 case 0:
1530 DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001531 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 ha->current_topology = ISP_CFG_NL;
1533 strcpy(connect_type, "(Loop)");
1534 break;
1535
1536 case 1:
1537 DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001538 vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001539 ha->switch_cap = sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 ha->current_topology = ISP_CFG_FL;
1541 strcpy(connect_type, "(FL_Port)");
1542 break;
1543
1544 case 2:
1545 DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001546 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 ha->operating_mode = P2P;
1548 ha->current_topology = ISP_CFG_N;
1549 strcpy(connect_type, "(N_Port-to-N_Port)");
1550 break;
1551
1552 case 3:
1553 DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001554 vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001555 ha->switch_cap = sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556 ha->operating_mode = P2P;
1557 ha->current_topology = ISP_CFG_F;
1558 strcpy(connect_type, "(F_Port)");
1559 break;
1560
1561 default:
1562 DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
1563 "Using NL.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001564 vha->host_no, topo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565 ha->current_topology = ISP_CFG_NL;
1566 strcpy(connect_type, "(Loop)");
1567 break;
1568 }
1569
1570 /* Save Host port and loop ID. */
1571 /* byte order - Big Endian */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001572 vha->d_id.b.domain = domain;
1573 vha->d_id.b.area = area;
1574 vha->d_id.b.al_pa = al_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001576 if (!vha->flags.init_done)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 qla_printk(KERN_INFO, ha,
1578 "Topology - %s, Host Loop address 0x%x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001579 connect_type, vha->loop_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001580
1581 if (rval) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001582 DEBUG2_3(printk("scsi(%ld): FAILED.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001583 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001584 DEBUG3(printk("scsi(%ld): exiting normally.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 }
1586
1587 return(rval);
1588}
1589
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001590static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001591qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
1592 char *def)
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001593{
1594 char *st, *en;
1595 uint16_t index;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001596 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001597
1598 if (memcmp(model, BINZERO, len) != 0) {
1599 strncpy(ha->model_number, model, len);
1600 st = en = ha->model_number;
1601 en += len - 1;
1602 while (en > st) {
1603 if (*en != 0x20 && *en != 0x00)
1604 break;
1605 *en-- = '\0';
1606 }
1607
1608 index = (ha->pdev->subsystem_device & 0xff);
1609 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1610 index < QLA_MODEL_NAMES)
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001611 strncpy(ha->model_desc,
1612 qla2x00_model_name[index * 2 + 1],
1613 sizeof(ha->model_desc) - 1);
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001614 } else {
1615 index = (ha->pdev->subsystem_device & 0xff);
1616 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1617 index < QLA_MODEL_NAMES) {
1618 strcpy(ha->model_number,
1619 qla2x00_model_name[index * 2]);
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001620 strncpy(ha->model_desc,
1621 qla2x00_model_name[index * 2 + 1],
1622 sizeof(ha->model_desc) - 1);
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001623 } else {
1624 strcpy(ha->model_number, def);
1625 }
1626 }
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001627 if (IS_FWI2_CAPABLE(ha))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001628 qla2xxx_get_vpd_field(vha, "\x82", ha->model_desc,
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001629 sizeof(ha->model_desc));
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001630}
1631
David Miller4e08df32007-04-16 12:37:43 -07001632/* On sparc systems, obtain port and node WWN from firmware
1633 * properties.
1634 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001635static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *vha, nvram_t *nv)
David Miller4e08df32007-04-16 12:37:43 -07001636{
1637#ifdef CONFIG_SPARC
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001638 struct qla_hw_data *ha = vha->hw;
David Miller4e08df32007-04-16 12:37:43 -07001639 struct pci_dev *pdev = ha->pdev;
David S. Miller15576bc2007-05-08 00:36:49 -07001640 struct device_node *dp = pci_device_to_OF_node(pdev);
1641 const u8 *val;
David Miller4e08df32007-04-16 12:37:43 -07001642 int len;
1643
1644 val = of_get_property(dp, "port-wwn", &len);
1645 if (val && len >= WWN_SIZE)
1646 memcpy(nv->port_name, val, WWN_SIZE);
1647
1648 val = of_get_property(dp, "node-wwn", &len);
1649 if (val && len >= WWN_SIZE)
1650 memcpy(nv->node_name, val, WWN_SIZE);
1651#endif
1652}
1653
Linus Torvalds1da177e2005-04-16 15:20:36 -07001654/*
1655* NVRAM configuration for ISP 2xxx
1656*
1657* Input:
1658* ha = adapter block pointer.
1659*
1660* Output:
1661* initialization control block in response_ring
1662* host adapters parameters in host adapter block
1663*
1664* Returns:
1665* 0 = success.
1666*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001667int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001668qla2x00_nvram_config(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001669{
David Miller4e08df32007-04-16 12:37:43 -07001670 int rval;
Andrew Vasquez01071092005-07-06 10:31:37 -07001671 uint8_t chksum = 0;
1672 uint16_t cnt;
1673 uint8_t *dptr1, *dptr2;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001674 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07001675 init_cb_t *icb = ha->init_cb;
Seokmann Ju281afe12007-07-26 13:43:34 -07001676 nvram_t *nv = ha->nvram;
1677 uint8_t *ptr = ha->nvram;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001678 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
David Miller4e08df32007-04-16 12:37:43 -07001680 rval = QLA_SUCCESS;
1681
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 /* Determine NVRAM starting address. */
Andrew Vasquez01071092005-07-06 10:31:37 -07001683 ha->nvram_size = sizeof(nvram_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 ha->nvram_base = 0;
1685 if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
1686 if ((RD_REG_WORD(&reg->ctrl_status) >> 14) == 1)
1687 ha->nvram_base = 0x80;
1688
1689 /* Get NVRAM data and calculate checksum. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001690 ha->isp_ops->read_nvram(vha, ptr, ha->nvram_base, ha->nvram_size);
Andrew Vasquez01071092005-07-06 10:31:37 -07001691 for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
1692 chksum += *ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001694 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
Seokmann Ju281afe12007-07-26 13:43:34 -07001695 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696
1697 /* Bad NVRAM data, set defaults parameters. */
1698 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
1699 nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
1700 /* Reset NVRAM data. */
1701 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
1702 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
1703 nv->nvram_version);
David Miller4e08df32007-04-16 12:37:43 -07001704 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
1705 "invalid -- WWPN) defaults.\n");
1706
1707 /*
1708 * Set default initialization control block.
1709 */
1710 memset(nv, 0, ha->nvram_size);
1711 nv->parameter_block_version = ICB_VERSION;
1712
1713 if (IS_QLA23XX(ha)) {
1714 nv->firmware_options[0] = BIT_2 | BIT_1;
1715 nv->firmware_options[1] = BIT_7 | BIT_5;
1716 nv->add_firmware_options[0] = BIT_5;
1717 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1718 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1719 nv->special_options[1] = BIT_7;
1720 } else if (IS_QLA2200(ha)) {
1721 nv->firmware_options[0] = BIT_2 | BIT_1;
1722 nv->firmware_options[1] = BIT_7 | BIT_5;
1723 nv->add_firmware_options[0] = BIT_5;
1724 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1725 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1726 } else if (IS_QLA2100(ha)) {
1727 nv->firmware_options[0] = BIT_3 | BIT_1;
1728 nv->firmware_options[1] = BIT_5;
1729 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1730 }
1731
1732 nv->max_iocb_allocation = __constant_cpu_to_le16(256);
1733 nv->execution_throttle = __constant_cpu_to_le16(16);
1734 nv->retry_count = 8;
1735 nv->retry_delay = 1;
1736
1737 nv->port_name[0] = 33;
1738 nv->port_name[3] = 224;
1739 nv->port_name[4] = 139;
1740
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001741 qla2xxx_nvram_wwn_from_ofw(vha, nv);
David Miller4e08df32007-04-16 12:37:43 -07001742
1743 nv->login_timeout = 4;
1744
1745 /*
1746 * Set default host adapter parameters
1747 */
1748 nv->host_p[1] = BIT_2;
1749 nv->reset_delay = 5;
1750 nv->port_down_retry_count = 8;
1751 nv->max_luns_per_target = __constant_cpu_to_le16(8);
1752 nv->link_down_timeout = 60;
1753
1754 rval = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755 }
1756
1757#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
1758 /*
1759 * The SN2 does not provide BIOS emulation which means you can't change
1760 * potentially bogus BIOS settings. Force the use of default settings
1761 * for link rate and frame size. Hope that the rest of the settings
1762 * are valid.
1763 */
1764 if (ia64_platform_is("sn2")) {
1765 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1766 if (IS_QLA23XX(ha))
1767 nv->special_options[1] = BIT_7;
1768 }
1769#endif
1770
1771 /* Reset Initialization control block */
Andrew Vasquez01071092005-07-06 10:31:37 -07001772 memset(icb, 0, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773
1774 /*
1775 * Setup driver NVRAM options.
1776 */
1777 nv->firmware_options[0] |= (BIT_6 | BIT_1);
1778 nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
1779 nv->firmware_options[1] |= (BIT_5 | BIT_0);
1780 nv->firmware_options[1] &= ~BIT_4;
1781
1782 if (IS_QLA23XX(ha)) {
1783 nv->firmware_options[0] |= BIT_2;
1784 nv->firmware_options[0] &= ~BIT_3;
Andrew Vasquez01071092005-07-06 10:31:37 -07001785 nv->add_firmware_options[1] |= BIT_5 | BIT_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001786
1787 if (IS_QLA2300(ha)) {
1788 if (ha->fb_rev == FPM_2310) {
1789 strcpy(ha->model_number, "QLA2310");
1790 } else {
1791 strcpy(ha->model_number, "QLA2300");
1792 }
1793 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001794 qla2x00_set_model_info(vha, nv->model_number,
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001795 sizeof(nv->model_number), "QLA23xx");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 }
1797 } else if (IS_QLA2200(ha)) {
1798 nv->firmware_options[0] |= BIT_2;
1799 /*
1800 * 'Point-to-point preferred, else loop' is not a safe
1801 * connection mode setting.
1802 */
1803 if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
1804 (BIT_5 | BIT_4)) {
1805 /* Force 'loop preferred, else point-to-point'. */
1806 nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
1807 nv->add_firmware_options[0] |= BIT_5;
1808 }
1809 strcpy(ha->model_number, "QLA22xx");
1810 } else /*if (IS_QLA2100(ha))*/ {
1811 strcpy(ha->model_number, "QLA2100");
1812 }
1813
1814 /*
1815 * Copy over NVRAM RISC parameter block to initialization control block.
1816 */
1817 dptr1 = (uint8_t *)icb;
1818 dptr2 = (uint8_t *)&nv->parameter_block_version;
1819 cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
1820 while (cnt--)
1821 *dptr1++ = *dptr2++;
1822
1823 /* Copy 2nd half. */
1824 dptr1 = (uint8_t *)icb->add_firmware_options;
1825 cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
1826 while (cnt--)
1827 *dptr1++ = *dptr2++;
1828
Andrew Vasquez5341e862006-05-17 15:09:16 -07001829 /* Use alternate WWN? */
1830 if (nv->host_p[1] & BIT_7) {
1831 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
1832 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
1833 }
1834
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835 /* Prepare nodename */
1836 if ((icb->firmware_options[1] & BIT_6) == 0) {
1837 /*
1838 * Firmware will apply the following mask if the nodename was
1839 * not provided.
1840 */
1841 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
1842 icb->node_name[0] &= 0xF0;
1843 }
1844
1845 /*
1846 * Set host adapter parameters.
1847 */
Andrew Vasquez01819442006-06-23 16:11:10 -07001848 if (nv->host_p[0] & BIT_7)
Andrew Vasquez11010fe2006-10-06 09:54:59 -07001849 ql2xextended_error_logging = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850 ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
1851 /* Always load RISC code on non ISP2[12]00 chips. */
1852 if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
1853 ha->flags.disable_risc_code_load = 0;
1854 ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
1855 ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
1856 ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
Andrew Vasquez06c22bd2005-08-26 19:09:00 -07001857 ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07001858 ha->flags.disable_serdes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859
1860 ha->operating_mode =
1861 (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
1862
1863 memcpy(ha->fw_seriallink_options, nv->seriallink_options,
1864 sizeof(ha->fw_seriallink_options));
1865
1866 /* save HBA serial number */
1867 ha->serial0 = icb->port_name[5];
1868 ha->serial1 = icb->port_name[6];
1869 ha->serial2 = icb->port_name[7];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001870 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
1871 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001872
1873 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
1874
1875 ha->retry_count = nv->retry_count;
1876
1877 /* Set minimum login_timeout to 4 seconds. */
1878 if (nv->login_timeout < ql2xlogintimeout)
1879 nv->login_timeout = ql2xlogintimeout;
1880 if (nv->login_timeout < 4)
1881 nv->login_timeout = 4;
1882 ha->login_timeout = nv->login_timeout;
1883 icb->login_timeout = nv->login_timeout;
1884
Andrew Vasquez00a537b2008-02-28 14:06:11 -08001885 /* Set minimum RATOV to 100 tenths of a second. */
1886 ha->r_a_tov = 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 ha->loop_reset_delay = nv->reset_delay;
1889
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 /* Link Down Timeout = 0:
1891 *
1892 * When Port Down timer expires we will start returning
1893 * I/O's to OS with "DID_NO_CONNECT".
1894 *
1895 * Link Down Timeout != 0:
1896 *
1897 * The driver waits for the link to come up after link down
1898 * before returning I/Os to OS with "DID_NO_CONNECT".
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001899 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001900 if (nv->link_down_timeout == 0) {
1901 ha->loop_down_abort_time =
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001902 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903 } else {
1904 ha->link_down_timeout = nv->link_down_timeout;
1905 ha->loop_down_abort_time =
1906 (LOOP_DOWN_TIME - ha->link_down_timeout);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001907 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909 /*
1910 * Need enough time to try and get the port back.
1911 */
1912 ha->port_down_retry_count = nv->port_down_retry_count;
1913 if (qlport_down_retry)
1914 ha->port_down_retry_count = qlport_down_retry;
1915 /* Set login_retry_count */
1916 ha->login_retry_count = nv->retry_count;
1917 if (ha->port_down_retry_count == nv->port_down_retry_count &&
1918 ha->port_down_retry_count > 3)
1919 ha->login_retry_count = ha->port_down_retry_count;
1920 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
1921 ha->login_retry_count = ha->port_down_retry_count;
1922 if (ql2xloginretrycount)
1923 ha->login_retry_count = ql2xloginretrycount;
1924
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 icb->lun_enables = __constant_cpu_to_le16(0);
1926 icb->command_resource_count = 0;
1927 icb->immediate_notify_resource_count = 0;
1928 icb->timeout = __constant_cpu_to_le16(0);
1929
1930 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
1931 /* Enable RIO */
1932 icb->firmware_options[0] &= ~BIT_3;
1933 icb->add_firmware_options[0] &=
1934 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
1935 icb->add_firmware_options[0] |= BIT_2;
1936 icb->response_accumulation_timer = 3;
1937 icb->interrupt_delay_timer = 5;
1938
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001939 vha->flags.process_response_queue = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940 } else {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001941 /* Enable ZIO. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001942 if (!vha->flags.init_done) {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001943 ha->zio_mode = icb->add_firmware_options[0] &
1944 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
1945 ha->zio_timer = icb->interrupt_delay_timer ?
1946 icb->interrupt_delay_timer: 2;
1947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 icb->add_firmware_options[0] &=
1949 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001950 vha->flags.process_response_queue = 0;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001951 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001952 ha->zio_mode = QLA_ZIO_MODE_6;
1953
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001954 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001955 "delay (%d us).\n", vha->host_no, ha->zio_mode,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001956 ha->zio_timer * 100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957 qla_printk(KERN_INFO, ha,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001958 "ZIO mode %d enabled; timer delay (%d us).\n",
1959 ha->zio_mode, ha->zio_timer * 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001961 icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
1962 icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001963 vha->flags.process_response_queue = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 }
1965 }
1966
David Miller4e08df32007-04-16 12:37:43 -07001967 if (rval) {
1968 DEBUG2_3(printk(KERN_WARNING
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001969 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
David Miller4e08df32007-04-16 12:37:43 -07001970 }
1971 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001972}
1973
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001974static void
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001975qla2x00_rport_del(void *data)
1976{
1977 fc_port_t *fcport = data;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001978 struct fc_rport *rport;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001979
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001980 spin_lock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001981 rport = fcport->drport;
1982 fcport->drport = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001983 spin_unlock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001984 if (rport)
1985 fc_remote_port_delete(rport);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001986}
1987
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988/**
1989 * qla2x00_alloc_fcport() - Allocate a generic fcport.
1990 * @ha: HA context
1991 * @flags: allocation flags
1992 *
1993 * Returns a pointer to the allocated fcport, or NULL, if none available.
1994 */
Adrian Bunk413975a2006-06-30 02:33:06 -07001995static fc_port_t *
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001996qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{
1998 fc_port_t *fcport;
1999
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002000 fcport = kzalloc(sizeof(fc_port_t), flags);
2001 if (!fcport)
2002 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003
2004 /* Setup fcport template structure. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002005 fcport->vha = vha;
2006 fcport->vp_idx = vha->vp_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 fcport->port_type = FCT_UNKNOWN;
2008 fcport->loop_id = FC_NO_LOOP_ID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 atomic_set(&fcport->state, FCS_UNCONFIGURED);
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002010 fcport->supported_classes = FC_COS_UNSPECIFIED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002012 return fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013}
2014
2015/*
2016 * qla2x00_configure_loop
2017 * Updates Fibre Channel Device Database with what is actually on loop.
2018 *
2019 * Input:
2020 * ha = adapter block pointer.
2021 *
2022 * Returns:
2023 * 0 = success.
2024 * 1 = error.
2025 * 2 = database was full and device was not configured.
2026 */
2027static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002028qla2x00_configure_loop(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029{
2030 int rval;
2031 unsigned long flags, save_flags;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002032 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 rval = QLA_SUCCESS;
2034
2035 /* Get Initiator ID */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002036 if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) {
2037 rval = qla2x00_configure_hba(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 if (rval != QLA_SUCCESS) {
2039 DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002040 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 return (rval);
2042 }
2043 }
2044
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002045 save_flags = flags = vha->dpc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002047 vha->host_no, flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002048
2049 /*
2050 * If we have both an RSCN and PORT UPDATE pending then handle them
2051 * both at the same time.
2052 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002053 clear_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
2054 clear_bit(RSCN_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055
2056 /* Determine what we need to do */
2057 if (ha->current_topology == ISP_CFG_FL &&
2058 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
2059
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002060 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 set_bit(RSCN_UPDATE, &flags);
2062
2063 } else if (ha->current_topology == ISP_CFG_F &&
2064 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
2065
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002066 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002067 set_bit(RSCN_UPDATE, &flags);
2068 clear_bit(LOCAL_LOOP_UPDATE, &flags);
2069
Andrew Vasquez21333b42006-05-17 15:09:56 -07002070 } else if (ha->current_topology == ISP_CFG_N) {
2071 clear_bit(RSCN_UPDATE, &flags);
2072
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002073 } else if (!vha->flags.online ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002074 (test_bit(ABORT_ISP_ACTIVE, &flags))) {
2075
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002076 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077 set_bit(RSCN_UPDATE, &flags);
2078 set_bit(LOCAL_LOOP_UPDATE, &flags);
2079 }
2080
2081 if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002082 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 rval = QLA_FUNCTION_FAILED;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002084 else
2085 rval = qla2x00_configure_local_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086 }
2087
2088 if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002089 if (LOOP_TRANSITION(vha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 rval = QLA_FUNCTION_FAILED;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002091 else
2092 rval = qla2x00_configure_fabric(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093 }
2094
2095 if (rval == QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002096 if (atomic_read(&vha->loop_down_timer) ||
2097 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 rval = QLA_FUNCTION_FAILED;
2099 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002100 atomic_set(&vha->loop_state, LOOP_READY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002101
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002102 DEBUG(printk("scsi(%ld): LOOP READY\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 }
2104 }
2105
2106 if (rval) {
2107 DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002108 __func__, vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109 } else {
2110 DEBUG3(printk("%s: exiting normally\n", __func__));
2111 }
2112
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -07002113 /* Restore state if a resync event occurred during processing */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002114 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002116 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002117 if (test_bit(RSCN_UPDATE, &save_flags))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002118 set_bit(RSCN_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 }
2120
2121 return (rval);
2122}
2123
2124
2125
2126/*
2127 * qla2x00_configure_local_loop
2128 * Updates Fibre Channel Device Database with local loop devices.
2129 *
2130 * Input:
2131 * ha = adapter block pointer.
2132 *
2133 * Returns:
2134 * 0 = success.
2135 */
2136static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002137qla2x00_configure_local_loop(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138{
2139 int rval, rval2;
2140 int found_devs;
2141 int found;
2142 fc_port_t *fcport, *new_fcport;
2143
2144 uint16_t index;
2145 uint16_t entries;
2146 char *id_iter;
2147 uint16_t loop_id;
2148 uint8_t domain, area, al_pa;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002149 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150
2151 found_devs = 0;
2152 new_fcport = NULL;
2153 entries = MAX_FIBRE_DEVICES;
2154
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002155 DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", vha->host_no));
2156 DEBUG3(qla2x00_get_fcal_position_map(vha, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157
2158 /* Get list of logged in devices. */
2159 memset(ha->gid_list, 0, GID_LIST_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002160 rval = qla2x00_get_id_list(vha, ha->gid_list, ha->gid_list_dma,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 &entries);
2162 if (rval != QLA_SUCCESS)
2163 goto cleanup_allocation;
2164
2165 DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
2166 ha->host_no, entries));
2167 DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
2168 entries * sizeof(struct gid_list_info)));
2169
2170 /* Allocate temporary fcport for any new fcports discovered. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002171 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 if (new_fcport == NULL) {
2173 rval = QLA_MEMORY_ALLOC_FAILED;
2174 goto cleanup_allocation;
2175 }
2176 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2177
2178 /*
2179 * Mark local devices that were present with FCF_DEVICE_LOST for now.
2180 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002181 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 if (atomic_read(&fcport->state) == FCS_ONLINE &&
2183 fcport->port_type != FCT_BROADCAST &&
2184 (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
2185
2186 DEBUG(printk("scsi(%ld): Marking port lost, "
2187 "loop_id=0x%04x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002188 vha->host_no, fcport->loop_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189
2190 atomic_set(&fcport->state, FCS_DEVICE_LOST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191 }
2192 }
2193
2194 /* Add devices to port list. */
2195 id_iter = (char *)ha->gid_list;
2196 for (index = 0; index < entries; index++) {
2197 domain = ((struct gid_list_info *)id_iter)->domain;
2198 area = ((struct gid_list_info *)id_iter)->area;
2199 al_pa = ((struct gid_list_info *)id_iter)->al_pa;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002200 if (IS_QLA2100(ha) || IS_QLA2200(ha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 loop_id = (uint16_t)
2202 ((struct gid_list_info *)id_iter)->loop_id_2100;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002203 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 loop_id = le16_to_cpu(
2205 ((struct gid_list_info *)id_iter)->loop_id);
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002206 id_iter += ha->gid_list_info_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
2208 /* Bypass reserved domain fields. */
2209 if ((domain & 0xf0) == 0xf0)
2210 continue;
2211
2212 /* Bypass if not same domain and area of adapter. */
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002213 if (area && domain &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002214 (area != vha->d_id.b.area || domain != vha->d_id.b.domain))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002215 continue;
2216
2217 /* Bypass invalid local loop ID. */
2218 if (loop_id > LAST_LOCAL_LOOP_ID)
2219 continue;
2220
2221 /* Fill in member data. */
2222 new_fcport->d_id.b.domain = domain;
2223 new_fcport->d_id.b.area = area;
2224 new_fcport->d_id.b.al_pa = al_pa;
2225 new_fcport->loop_id = loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002226 new_fcport->vp_idx = vha->vp_idx;
2227 rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 if (rval2 != QLA_SUCCESS) {
2229 DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
2230 "information -- get_port_database=%x, "
2231 "loop_id=0x%04x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002232 vha->host_no, rval2, new_fcport->loop_id));
andrew.vasquez@qlogic.comc9d02ac2006-01-13 17:05:26 -08002233 DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002234 vha->host_no));
2235 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 continue;
2237 }
2238
2239 /* Check for matching device in port list. */
2240 found = 0;
2241 fcport = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002242 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 if (memcmp(new_fcport->port_name, fcport->port_name,
2244 WWN_SIZE))
2245 continue;
2246
Shyam Sundarddb9b122009-03-24 09:08:10 -07002247 fcport->flags &= ~FCF_FABRIC_DEVICE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 fcport->loop_id = new_fcport->loop_id;
2249 fcport->port_type = new_fcport->port_type;
2250 fcport->d_id.b24 = new_fcport->d_id.b24;
2251 memcpy(fcport->node_name, new_fcport->node_name,
2252 WWN_SIZE);
2253
2254 found++;
2255 break;
2256 }
2257
2258 if (!found) {
2259 /* New device, add to fcports list. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002260 if (vha->vp_idx) {
2261 new_fcport->vha = vha;
2262 new_fcport->vp_idx = vha->vp_idx;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002263 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002264 list_add_tail(&new_fcport->list, &vha->vp_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002265
2266 /* Allocate a new replacement fcport. */
2267 fcport = new_fcport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002268 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 if (new_fcport == NULL) {
2270 rval = QLA_MEMORY_ALLOC_FAILED;
2271 goto cleanup_allocation;
2272 }
2273 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2274 }
2275
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002276 /* Base iIDMA settings on HBA port speed. */
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002277 fcport->fp_speed = ha->link_data_rate;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002278
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002279 qla2x00_update_fcport(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002280
2281 found_devs++;
2282 }
2283
2284cleanup_allocation:
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002285 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002286
2287 if (rval != QLA_SUCCESS) {
2288 DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002289 "rval=%x\n", vha->host_no, rval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002290 }
2291
Linus Torvalds1da177e2005-04-16 15:20:36 -07002292 return (rval);
2293}
2294
2295static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002296qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002297{
2298#define LS_UNKNOWN 2
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002299 static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002300 int rval;
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002301 uint16_t mb[6];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002302 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002303
Andrew Vasquezc76f2c02007-07-19 15:05:57 -07002304 if (!IS_IIDMA_CAPABLE(ha))
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002305 return;
2306
Andrew Vasquez39bd9622007-09-20 14:07:34 -07002307 if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
2308 fcport->fp_speed > ha->link_data_rate)
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002309 return;
2310
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002311 rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002312 mb);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002313 if (rval != QLA_SUCCESS) {
2314 DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
2315 "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002316 vha->host_no, fcport->port_name[0], fcport->port_name[1],
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002317 fcport->port_name[2], fcport->port_name[3],
2318 fcport->port_name[4], fcport->port_name[5],
2319 fcport->port_name[6], fcport->port_name[7], rval,
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002320 fcport->fp_speed, mb[0], mb[1]));
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002321 } else {
2322 DEBUG2(qla_printk(KERN_INFO, ha,
2323 "iIDMA adjusted to %s GB/s on "
2324 "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002325 link_speeds[fcport->fp_speed], fcport->port_name[0],
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002326 fcport->port_name[1], fcport->port_name[2],
2327 fcport->port_name[3], fcport->port_name[4],
2328 fcport->port_name[5], fcport->port_name[6],
2329 fcport->port_name[7]));
2330 }
2331}
2332
Adrian Bunk23be3312006-11-24 02:46:01 +01002333static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002334qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
8482e112005-04-17 15:04:54 -05002335{
2336 struct fc_rport_identifiers rport_ids;
bdf79622005-04-17 15:06:53 -05002337 struct fc_rport *rport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002338 struct qla_hw_data *ha = vha->hw;
8482e112005-04-17 15:04:54 -05002339
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002340 if (fcport->drport)
2341 qla2x00_rport_del(fcport);
8482e112005-04-17 15:04:54 -05002342
Andrew Vasquezf8b02a82005-08-31 15:21:20 -07002343 rport_ids.node_name = wwn_to_u64(fcport->node_name);
2344 rport_ids.port_name = wwn_to_u64(fcport->port_name);
8482e112005-04-17 15:04:54 -05002345 rport_ids.port_id = fcport->d_id.b.domain << 16 |
2346 fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
2347 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002348 fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids);
Andrew Vasquez77d74142005-07-08 18:00:36 -07002349 if (!rport) {
2350 qla_printk(KERN_WARNING, ha,
2351 "Unable to allocate fc remote port!\n");
2352 return;
2353 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002354 spin_lock_irq(fcport->vha->host->host_lock);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002355 *((fc_port_t **)rport->dd_data) = fcport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002356 spin_unlock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002357
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002358 rport->supported_classes = fcport->supported_classes;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002359
2360 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
8482e112005-04-17 15:04:54 -05002361 if (fcport->port_type == FCT_INITIATOR)
2362 rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
2363 if (fcport->port_type == FCT_TARGET)
2364 rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002365 fc_remote_port_rolechg(rport, rport_ids.roles);
8482e112005-04-17 15:04:54 -05002366}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002367
2368/*
Adrian Bunk23be3312006-11-24 02:46:01 +01002369 * qla2x00_update_fcport
2370 * Updates device on list.
2371 *
2372 * Input:
2373 * ha = adapter block pointer.
2374 * fcport = port structure pointer.
2375 *
2376 * Return:
2377 * 0 - Success
2378 * BIT_0 - error
2379 *
2380 * Context:
2381 * Kernel context.
2382 */
2383void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002384qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
Adrian Bunk23be3312006-11-24 02:46:01 +01002385{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002386 struct qla_hw_data *ha = vha->hw;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002387
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002388 fcport->vha = vha;
Adrian Bunk23be3312006-11-24 02:46:01 +01002389 fcport->login_retry = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002390 fcport->port_login_retry_count = ha->port_down_retry_count *
Adrian Bunk23be3312006-11-24 02:46:01 +01002391 PORT_RETRY_TIME;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002392 atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
Adrian Bunk23be3312006-11-24 02:46:01 +01002393 PORT_RETRY_TIME);
2394 fcport->flags &= ~FCF_LOGIN_NEEDED;
2395
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002396 qla2x00_iidma_fcport(vha, fcport);
Adrian Bunk23be3312006-11-24 02:46:01 +01002397
2398 atomic_set(&fcport->state, FCS_ONLINE);
2399
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002400 qla2x00_reg_remote_port(vha, fcport);
Adrian Bunk23be3312006-11-24 02:46:01 +01002401}
2402
2403/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 * qla2x00_configure_fabric
2405 * Setup SNS devices with loop ID's.
2406 *
2407 * Input:
2408 * ha = adapter block pointer.
2409 *
2410 * Returns:
2411 * 0 = success.
2412 * BIT_0 = error
2413 */
2414static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002415qla2x00_configure_fabric(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002416{
2417 int rval, rval2;
2418 fc_port_t *fcport, *fcptemp;
2419 uint16_t next_loopid;
2420 uint16_t mb[MAILBOX_REGISTER_COUNT];
Andrew Vasquez01071092005-07-06 10:31:37 -07002421 uint16_t loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 LIST_HEAD(new_fcports);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002423 struct qla_hw_data *ha = vha->hw;
2424 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426 /* If FL port exists, then SNS is present */
Andrew Vasqueze4289242007-07-19 15:05:56 -07002427 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez01071092005-07-06 10:31:37 -07002428 loop_id = NPH_F_PORT;
2429 else
2430 loop_id = SNS_FL_PORT;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002431 rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432 if (rval != QLA_SUCCESS) {
2433 DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002434 "Port\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002436 vha->device_flags &= ~SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437 return (QLA_SUCCESS);
2438 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002439 vha->device_flags |= SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440
2441 /* Mark devices that need re-synchronization. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002442 rval2 = qla2x00_device_resync(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 if (rval2 == QLA_RSCNS_HANDLED) {
2444 /* No point doing the scan, just continue. */
2445 return (QLA_SUCCESS);
2446 }
2447 do {
Andrew Vasquezcca53352005-08-26 19:08:30 -07002448 /* FDMI support. */
2449 if (ql2xfdmienable &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002450 test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags))
2451 qla2x00_fdmi_register(vha);
Andrew Vasquezcca53352005-08-26 19:08:30 -07002452
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 /* Ensure we are logged into the SNS. */
Andrew Vasqueze4289242007-07-19 15:05:56 -07002454 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez01071092005-07-06 10:31:37 -07002455 loop_id = NPH_SNS;
2456 else
2457 loop_id = SIMPLE_NAME_SERVER;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002458 ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002459 0xfc, mb, BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 if (mb[0] != MBS_COMMAND_COMPLETE) {
2461 DEBUG2(qla_printk(KERN_INFO, ha,
2462 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
Andrew Vasquez01071092005-07-06 10:31:37 -07002463 "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 mb[0], mb[1], mb[2], mb[6], mb[7]));
2465 return (QLA_SUCCESS);
2466 }
2467
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002468 if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
2469 if (qla2x00_rft_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002470 /* EMPTY */
2471 DEBUG2(printk("scsi(%ld): Register FC-4 "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002472 "TYPE failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002474 if (qla2x00_rff_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475 /* EMPTY */
2476 DEBUG2(printk("scsi(%ld): Register FC-4 "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002477 "Features failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002478 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002479 if (qla2x00_rnn_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 /* EMPTY */
2481 DEBUG2(printk("scsi(%ld): Register Node Name "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002482 "failed.\n", vha->host_no));
2483 } else if (qla2x00_rsnn_nn(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002484 /* EMPTY */
2485 DEBUG2(printk("scsi(%ld): Register Symbolic "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002486 "Node Name failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002487 }
2488 }
2489
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002490 rval = qla2x00_find_all_fabric_devs(vha, &new_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 if (rval != QLA_SUCCESS)
2492 break;
2493
2494 /*
2495 * Logout all previous fabric devices marked lost, except
2496 * tape devices.
2497 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002498 list_for_each_entry(fcport, &vha->vp_fcports, list) {
2499 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 break;
2501
2502 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
2503 continue;
2504
2505 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002506 qla2x00_mark_device_lost(vha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002507 ql2xplogiabsentdevice, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508 if (fcport->loop_id != FC_NO_LOOP_ID &&
2509 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2510 fcport->port_type != FCT_INITIATOR &&
2511 fcport->port_type != FCT_BROADCAST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002512 ha->isp_ops->fabric_logout(vha,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002513 fcport->loop_id,
2514 fcport->d_id.b.domain,
2515 fcport->d_id.b.area,
2516 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 fcport->loop_id = FC_NO_LOOP_ID;
2518 }
2519 }
2520 }
2521
2522 /* Starting free loop ID. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002523 next_loopid = ha->min_external_loopid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524
2525 /*
2526 * Scan through our port list and login entries that need to be
2527 * logged in.
2528 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002529 list_for_each_entry(fcport, &vha->vp_fcports, list) {
2530 if (atomic_read(&vha->loop_down_timer) ||
2531 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 break;
2533
2534 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2535 (fcport->flags & FCF_LOGIN_NEEDED) == 0)
2536 continue;
2537
2538 if (fcport->loop_id == FC_NO_LOOP_ID) {
2539 fcport->loop_id = next_loopid;
Seokmann Jud4486fd2008-04-03 13:13:28 -07002540 rval = qla2x00_find_new_loop_id(
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002541 base_vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002542 if (rval != QLA_SUCCESS) {
2543 /* Ran out of IDs to use */
2544 break;
2545 }
2546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 /* Login and update database */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002548 qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 }
2550
2551 /* Exit if out of loop IDs. */
2552 if (rval != QLA_SUCCESS) {
2553 break;
2554 }
2555
2556 /*
2557 * Login and add the new devices to our port list.
2558 */
2559 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002560 if (atomic_read(&vha->loop_down_timer) ||
2561 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 break;
2563
2564 /* Find a new loop ID to use. */
2565 fcport->loop_id = next_loopid;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002566 rval = qla2x00_find_new_loop_id(base_vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 if (rval != QLA_SUCCESS) {
2568 /* Ran out of IDs to use */
2569 break;
2570 }
2571
bdf79622005-04-17 15:06:53 -05002572 /* Login and update database */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002573 qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002574
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002575 if (vha->vp_idx) {
2576 fcport->vha = vha;
2577 fcport->vp_idx = vha->vp_idx;
2578 }
2579 list_move_tail(&fcport->list, &vha->vp_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 }
2581 } while (0);
2582
2583 /* Free all new device structures not processed. */
2584 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
2585 list_del(&fcport->list);
2586 kfree(fcport);
2587 }
2588
2589 if (rval) {
2590 DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002591 "rval=%d\n", vha->host_no, rval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 }
2593
2594 return (rval);
2595}
2596
2597
2598/*
2599 * qla2x00_find_all_fabric_devs
2600 *
2601 * Input:
2602 * ha = adapter block pointer.
2603 * dev = database device entry pointer.
2604 *
2605 * Returns:
2606 * 0 = success.
2607 *
2608 * Context:
2609 * Kernel context.
2610 */
2611static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002612qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
2613 struct list_head *new_fcports)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614{
2615 int rval;
2616 uint16_t loop_id;
2617 fc_port_t *fcport, *new_fcport, *fcptemp;
2618 int found;
2619
2620 sw_info_t *swl;
2621 int swl_idx;
2622 int first_dev, last_dev;
2623 port_id_t wrap, nxt_d_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002624 struct qla_hw_data *ha = vha->hw;
2625 struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002626 struct scsi_qla_host *tvp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628 rval = QLA_SUCCESS;
2629
2630 /* Try GID_PT to get device list, else GAN. */
Andrew Vasquez4b892582008-09-11 21:22:48 -07002631 swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002632 if (!swl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 /*EMPTY*/
2634 DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002635 "on GA_NXT\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002637 if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 kfree(swl);
2639 swl = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002640 } else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002641 kfree(swl);
2642 swl = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002643 } else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 kfree(swl);
2645 swl = NULL;
Andrew Vasqueze5896bd2008-07-10 16:55:52 -07002646 } else if (ql2xiidmaenable &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002647 qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) {
2648 qla2x00_gpsc(vha, swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 }
2650 }
2651 swl_idx = 0;
2652
2653 /* Allocate temporary fcport for any new fcports discovered. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002654 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002656 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 return (QLA_MEMORY_ALLOC_FAILED);
2658 }
2659 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 /* Set start port ID scan at adapter ID. */
2661 first_dev = 1;
2662 last_dev = 0;
2663
2664 /* Starting free loop ID. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002665 loop_id = ha->min_external_loopid;
2666 for (; loop_id <= ha->max_loop_id; loop_id++) {
2667 if (qla2x00_is_reserved_id(vha, loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 continue;
2669
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002670 if (atomic_read(&vha->loop_down_timer) || LOOP_TRANSITION(vha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 break;
2672
2673 if (swl != NULL) {
2674 if (last_dev) {
2675 wrap.b24 = new_fcport->d_id.b24;
2676 } else {
2677 new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
2678 memcpy(new_fcport->node_name,
2679 swl[swl_idx].node_name, WWN_SIZE);
2680 memcpy(new_fcport->port_name,
2681 swl[swl_idx].port_name, WWN_SIZE);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002682 memcpy(new_fcport->fabric_port_name,
2683 swl[swl_idx].fabric_port_name, WWN_SIZE);
2684 new_fcport->fp_speed = swl[swl_idx].fp_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
2686 if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
2687 last_dev = 1;
2688 }
2689 swl_idx++;
2690 }
2691 } else {
2692 /* Send GA_NXT to the switch */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002693 rval = qla2x00_ga_nxt(vha, new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 if (rval != QLA_SUCCESS) {
2695 qla_printk(KERN_WARNING, ha,
2696 "SNS scan failed -- assuming zero-entry "
2697 "result...\n");
2698 list_for_each_entry_safe(fcport, fcptemp,
2699 new_fcports, list) {
2700 list_del(&fcport->list);
2701 kfree(fcport);
2702 }
2703 rval = QLA_SUCCESS;
2704 break;
2705 }
2706 }
2707
2708 /* If wrap on switch device list, exit. */
2709 if (first_dev) {
2710 wrap.b24 = new_fcport->d_id.b24;
2711 first_dev = 0;
2712 } else if (new_fcport->d_id.b24 == wrap.b24) {
2713 DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002714 vha->host_no, new_fcport->d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002715 new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
2716 break;
2717 }
2718
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002719 /* Bypass if same physical adapter. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002720 if (new_fcport->d_id.b24 == base_vha->d_id.b24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002721 continue;
2722
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002723 /* Bypass virtual ports of the same host. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002724 found = 0;
2725 if (ha->num_vhosts) {
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002726 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002727 if (new_fcport->d_id.b24 == vp->d_id.b24) {
2728 found = 1;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002729 break;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002730 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002731 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002732 if (found)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002733 continue;
2734 }
2735
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002736 /* Bypass if same domain and area of adapter. */
2737 if (((new_fcport->d_id.b24 & 0xffff00) ==
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002738 (vha->d_id.b24 & 0xffff00)) && ha->current_topology ==
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002739 ISP_CFG_FL)
2740 continue;
2741
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742 /* Bypass reserved domain fields. */
2743 if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
2744 continue;
2745
2746 /* Locate matching device in database. */
2747 found = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002748 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 if (memcmp(new_fcport->port_name, fcport->port_name,
2750 WWN_SIZE))
2751 continue;
2752
2753 found++;
2754
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002755 /* Update port state. */
2756 memcpy(fcport->fabric_port_name,
2757 new_fcport->fabric_port_name, WWN_SIZE);
2758 fcport->fp_speed = new_fcport->fp_speed;
2759
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 /*
2761 * If address the same and state FCS_ONLINE, nothing
2762 * changed.
2763 */
2764 if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
2765 atomic_read(&fcport->state) == FCS_ONLINE) {
2766 break;
2767 }
2768
2769 /*
2770 * If device was not a fabric device before.
2771 */
2772 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
2773 fcport->d_id.b24 = new_fcport->d_id.b24;
2774 fcport->loop_id = FC_NO_LOOP_ID;
2775 fcport->flags |= (FCF_FABRIC_DEVICE |
2776 FCF_LOGIN_NEEDED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 break;
2778 }
2779
2780 /*
2781 * Port ID changed or device was marked to be updated;
2782 * Log it out if still logged in and mark it for
2783 * relogin later.
2784 */
2785 fcport->d_id.b24 = new_fcport->d_id.b24;
2786 fcport->flags |= FCF_LOGIN_NEEDED;
2787 if (fcport->loop_id != FC_NO_LOOP_ID &&
2788 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2789 fcport->port_type != FCT_INITIATOR &&
2790 fcport->port_type != FCT_BROADCAST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002791 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002792 fcport->d_id.b.domain, fcport->d_id.b.area,
2793 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 fcport->loop_id = FC_NO_LOOP_ID;
2795 }
2796
2797 break;
2798 }
2799
2800 if (found)
2801 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802 /* If device was not in our fcports list, then add it. */
2803 list_add_tail(&new_fcport->list, new_fcports);
2804
2805 /* Allocate a new replacement fcport. */
2806 nxt_d_id.b24 = new_fcport->d_id.b24;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002807 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002809 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002810 return (QLA_MEMORY_ALLOC_FAILED);
2811 }
2812 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
2813 new_fcport->d_id.b24 = nxt_d_id.b24;
2814 }
2815
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002816 kfree(swl);
2817 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819 return (rval);
2820}
2821
2822/*
2823 * qla2x00_find_new_loop_id
2824 * Scan through our port list and find a new usable loop ID.
2825 *
2826 * Input:
2827 * ha: adapter state pointer.
2828 * dev: port structure pointer.
2829 *
2830 * Returns:
2831 * qla2x00 local function return status code.
2832 *
2833 * Context:
2834 * Kernel context.
2835 */
Adrian Bunk413975a2006-06-30 02:33:06 -07002836static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002837qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838{
2839 int rval;
2840 int found;
2841 fc_port_t *fcport;
2842 uint16_t first_loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002843 struct qla_hw_data *ha = vha->hw;
2844 struct scsi_qla_host *vp;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002845 struct scsi_qla_host *tvp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002846
2847 rval = QLA_SUCCESS;
2848
2849 /* Save starting loop ID. */
2850 first_loop_id = dev->loop_id;
2851
2852 for (;;) {
2853 /* Skip loop ID if already used by adapter. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002854 if (dev->loop_id == vha->loop_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 dev->loop_id++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856
2857 /* Skip reserved loop IDs. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002858 while (qla2x00_is_reserved_id(vha, dev->loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859 dev->loop_id++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860
2861 /* Reset loop ID if passed the end. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002862 if (dev->loop_id > ha->max_loop_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863 /* first loop ID. */
2864 dev->loop_id = ha->min_external_loopid;
2865 }
2866
2867 /* Check for loop ID being already in use. */
2868 found = 0;
2869 fcport = NULL;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002870 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002871 list_for_each_entry(fcport, &vp->vp_fcports, list) {
2872 if (fcport->loop_id == dev->loop_id &&
2873 fcport != dev) {
2874 /* ID possibly in use */
2875 found++;
2876 break;
2877 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002879 if (found)
2880 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 }
2882
2883 /* If not in use then it is free to use. */
2884 if (!found) {
2885 break;
2886 }
2887
2888 /* ID in use. Try next value. */
2889 dev->loop_id++;
2890
2891 /* If wrap around. No free ID to use. */
2892 if (dev->loop_id == first_loop_id) {
2893 dev->loop_id = FC_NO_LOOP_ID;
2894 rval = QLA_FUNCTION_FAILED;
2895 break;
2896 }
2897 }
2898
2899 return (rval);
2900}
2901
2902/*
2903 * qla2x00_device_resync
2904 * Marks devices in the database that needs resynchronization.
2905 *
2906 * Input:
2907 * ha = adapter block pointer.
2908 *
2909 * Context:
2910 * Kernel context.
2911 */
2912static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002913qla2x00_device_resync(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914{
2915 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916 uint32_t mask;
2917 fc_port_t *fcport;
2918 uint32_t rscn_entry;
2919 uint8_t rscn_out_iter;
2920 uint8_t format;
2921 port_id_t d_id;
2922
2923 rval = QLA_RSCNS_HANDLED;
2924
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002925 while (vha->rscn_out_ptr != vha->rscn_in_ptr ||
2926 vha->flags.rscn_queue_overflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002928 rscn_entry = vha->rscn_queue[vha->rscn_out_ptr];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 format = MSB(MSW(rscn_entry));
2930 d_id.b.domain = LSB(MSW(rscn_entry));
2931 d_id.b.area = MSB(LSW(rscn_entry));
2932 d_id.b.al_pa = LSB(LSW(rscn_entry));
2933
2934 DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
2935 "[%02x/%02x%02x%02x].\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002936 vha->host_no, vha->rscn_out_ptr, format, d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937 d_id.b.area, d_id.b.al_pa));
2938
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002939 vha->rscn_out_ptr++;
2940 if (vha->rscn_out_ptr == MAX_RSCN_COUNT)
2941 vha->rscn_out_ptr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942
2943 /* Skip duplicate entries. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002944 for (rscn_out_iter = vha->rscn_out_ptr;
2945 !vha->flags.rscn_queue_overflow &&
2946 rscn_out_iter != vha->rscn_in_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 rscn_out_iter = (rscn_out_iter ==
2948 (MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
2949
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002950 if (rscn_entry != vha->rscn_queue[rscn_out_iter])
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 break;
2952
2953 DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002954 "entry found at [%d].\n", vha->host_no,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002955 rscn_out_iter));
2956
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002957 vha->rscn_out_ptr = rscn_out_iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958 }
2959
2960 /* Queue overflow, set switch default case. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002961 if (vha->flags.rscn_queue_overflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 DEBUG(printk("scsi(%ld): device_resync: rscn "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002963 "overflow.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
2965 format = 3;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002966 vha->flags.rscn_queue_overflow = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967 }
2968
2969 switch (format) {
2970 case 0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 mask = 0xffffff;
2972 break;
2973 case 1:
2974 mask = 0xffff00;
2975 break;
2976 case 2:
2977 mask = 0xff0000;
2978 break;
2979 default:
2980 mask = 0x0;
2981 d_id.b24 = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002982 vha->rscn_out_ptr = vha->rscn_in_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002983 break;
2984 }
2985
2986 rval = QLA_SUCCESS;
2987
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002988 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2990 (fcport->d_id.b24 & mask) != d_id.b24 ||
2991 fcport->port_type == FCT_BROADCAST)
2992 continue;
2993
2994 if (atomic_read(&fcport->state) == FCS_ONLINE) {
2995 if (format != 3 ||
2996 fcport->port_type != FCT_INITIATOR) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002997 qla2x00_mark_device_lost(vha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002998 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 }
3000 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 }
3002 }
3003 return (rval);
3004}
3005
3006/*
3007 * qla2x00_fabric_dev_login
3008 * Login fabric target device and update FC port database.
3009 *
3010 * Input:
3011 * ha: adapter state pointer.
3012 * fcport: port structure list pointer.
3013 * next_loopid: contains value of a new loop ID that can be used
3014 * by the next login attempt.
3015 *
3016 * Returns:
3017 * qla2x00 local function return status code.
3018 *
3019 * Context:
3020 * Kernel context.
3021 */
3022static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003023qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 uint16_t *next_loopid)
3025{
3026 int rval;
3027 int retry;
Andrew Vasquez01071092005-07-06 10:31:37 -07003028 uint8_t opts;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003029 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003030
3031 rval = QLA_SUCCESS;
3032 retry = 0;
3033
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003034 rval = qla2x00_fabric_login(vha, fcport, next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003035 if (rval == QLA_SUCCESS) {
Andrew Vasquez01071092005-07-06 10:31:37 -07003036 /* Send an ADISC to tape devices.*/
3037 opts = 0;
3038 if (fcport->flags & FCF_TAPE_PRESENT)
3039 opts |= BIT_1;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003040 rval = qla2x00_get_port_database(vha, fcport, opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 if (rval != QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003042 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003043 fcport->d_id.b.domain, fcport->d_id.b.area,
3044 fcport->d_id.b.al_pa);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003045 qla2x00_mark_device_lost(vha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003047 qla2x00_update_fcport(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 }
3049 }
3050
3051 return (rval);
3052}
3053
3054/*
3055 * qla2x00_fabric_login
3056 * Issue fabric login command.
3057 *
3058 * Input:
3059 * ha = adapter block pointer.
3060 * device = pointer to FC device type structure.
3061 *
3062 * Returns:
3063 * 0 - Login successfully
3064 * 1 - Login failed
3065 * 2 - Initiator device
3066 * 3 - Fatal error
3067 */
3068int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003069qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 uint16_t *next_loopid)
3071{
3072 int rval;
3073 int retry;
3074 uint16_t tmp_loopid;
3075 uint16_t mb[MAILBOX_REGISTER_COUNT];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003076 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
3078 retry = 0;
3079 tmp_loopid = 0;
3080
3081 for (;;) {
3082 DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
3083 "for port %02x%02x%02x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003084 vha->host_no, fcport->loop_id, fcport->d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003085 fcport->d_id.b.area, fcport->d_id.b.al_pa));
3086
3087 /* Login fcport on switch. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003088 ha->isp_ops->fabric_login(vha, fcport->loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 fcport->d_id.b.domain, fcport->d_id.b.area,
3090 fcport->d_id.b.al_pa, mb, BIT_0);
3091 if (mb[0] == MBS_PORT_ID_USED) {
3092 /*
3093 * Device has another loop ID. The firmware team
Andrew Vasquez01071092005-07-06 10:31:37 -07003094 * recommends the driver perform an implicit login with
3095 * the specified ID again. The ID we just used is save
3096 * here so we return with an ID that can be tried by
3097 * the next login.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003098 */
3099 retry++;
3100 tmp_loopid = fcport->loop_id;
3101 fcport->loop_id = mb[1];
3102
3103 DEBUG(printk("Fabric Login: port in use - next "
3104 "loop id=0x%04x, port Id=%02x%02x%02x.\n",
3105 fcport->loop_id, fcport->d_id.b.domain,
3106 fcport->d_id.b.area, fcport->d_id.b.al_pa));
3107
3108 } else if (mb[0] == MBS_COMMAND_COMPLETE) {
3109 /*
3110 * Login succeeded.
3111 */
3112 if (retry) {
3113 /* A retry occurred before. */
3114 *next_loopid = tmp_loopid;
3115 } else {
3116 /*
3117 * No retry occurred before. Just increment the
3118 * ID value for next login.
3119 */
3120 *next_loopid = (fcport->loop_id + 1);
3121 }
3122
3123 if (mb[1] & BIT_0) {
3124 fcport->port_type = FCT_INITIATOR;
3125 } else {
3126 fcport->port_type = FCT_TARGET;
3127 if (mb[1] & BIT_1) {
3128 fcport->flags |= FCF_TAPE_PRESENT;
3129 }
3130 }
3131
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07003132 if (mb[10] & BIT_0)
3133 fcport->supported_classes |= FC_COS_CLASS2;
3134 if (mb[10] & BIT_1)
3135 fcport->supported_classes |= FC_COS_CLASS3;
3136
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 rval = QLA_SUCCESS;
3138 break;
3139 } else if (mb[0] == MBS_LOOP_ID_USED) {
3140 /*
3141 * Loop ID already used, try next loop ID.
3142 */
3143 fcport->loop_id++;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003144 rval = qla2x00_find_new_loop_id(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003145 if (rval != QLA_SUCCESS) {
3146 /* Ran out of loop IDs to use */
3147 break;
3148 }
3149 } else if (mb[0] == MBS_COMMAND_ERROR) {
3150 /*
3151 * Firmware possibly timed out during login. If NO
3152 * retries are left to do then the device is declared
3153 * dead.
3154 */
3155 *next_loopid = fcport->loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003156 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003157 fcport->d_id.b.domain, fcport->d_id.b.area,
3158 fcport->d_id.b.al_pa);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003159 qla2x00_mark_device_lost(vha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003160
3161 rval = 1;
3162 break;
3163 } else {
3164 /*
3165 * unrecoverable / not handled error
3166 */
3167 DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003168 "loop_id=%x jiffies=%lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003169 __func__, vha->host_no, mb[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003170 fcport->d_id.b.domain, fcport->d_id.b.area,
3171 fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
3172
3173 *next_loopid = fcport->loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003174 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003175 fcport->d_id.b.domain, fcport->d_id.b.area,
3176 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 fcport->loop_id = FC_NO_LOOP_ID;
Andrew Vasquez0eedfcf2005-10-27 11:09:38 -07003178 fcport->login_retry = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179
3180 rval = 3;
3181 break;
3182 }
3183 }
3184
3185 return (rval);
3186}
3187
3188/*
3189 * qla2x00_local_device_login
3190 * Issue local device login command.
3191 *
3192 * Input:
3193 * ha = adapter block pointer.
3194 * loop_id = loop id of device to login to.
3195 *
3196 * Returns (Where's the #define!!!!):
3197 * 0 - Login successfully
3198 * 1 - Login failed
3199 * 3 - Fatal error
3200 */
3201int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003202qla2x00_local_device_login(scsi_qla_host_t *vha, fc_port_t *fcport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003203{
3204 int rval;
3205 uint16_t mb[MAILBOX_REGISTER_COUNT];
3206
3207 memset(mb, 0, sizeof(mb));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003208 rval = qla2x00_login_local_device(vha, fcport, mb, BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003209 if (rval == QLA_SUCCESS) {
3210 /* Interrogate mailbox registers for any errors */
3211 if (mb[0] == MBS_COMMAND_ERROR)
3212 rval = 1;
3213 else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
3214 /* device not in PCB table */
3215 rval = 3;
3216 }
3217
3218 return (rval);
3219}
3220
3221/*
3222 * qla2x00_loop_resync
3223 * Resync with fibre channel devices.
3224 *
3225 * Input:
3226 * ha = adapter block pointer.
3227 *
3228 * Returns:
3229 * 0 = success
3230 */
3231int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003232qla2x00_loop_resync(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003234 int rval = QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003235 uint32_t wait_time;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003236 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003237 struct req_que *req = ha->req_q_map[vha->req_ques[0]];
3238 struct rsp_que *rsp = req->rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003239
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003240 atomic_set(&vha->loop_state, LOOP_UPDATE);
3241 clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
3242 if (vha->flags.online) {
3243 if (!(rval = qla2x00_fw_ready(vha))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3245 wait_time = 256;
3246 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003247 atomic_set(&vha->loop_state, LOOP_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248
Andrew Vasquez01071092005-07-06 10:31:37 -07003249 /* Issue a marker after FW becomes ready. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003250 qla2x00_marker(vha, req, rsp, 0, 0,
3251 MK_SYNC_ALL);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003252 vha->marker_needed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253
3254 /* Remap devices on Loop. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003255 clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003257 qla2x00_configure_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 wait_time--;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003259 } while (!atomic_read(&vha->loop_down_timer) &&
3260 !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
3261 && wait_time && (test_bit(LOOP_RESYNC_NEEDED,
3262 &vha->dpc_flags)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003264 }
3265
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003266 if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003267 return (QLA_FUNCTION_FAILED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003269 if (rval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003270 DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271
3272 return (rval);
3273}
3274
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003276qla2x00_update_fcports(scsi_qla_host_t *vha)
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003277{
3278 fc_port_t *fcport;
3279
3280 /* Go with deferred removal of rport references. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003281 list_for_each_entry(fcport, &vha->vp_fcports, list)
3282 if (fcport && fcport->drport &&
Andrew Vasquezc9c5ced2008-07-24 08:31:49 -07003283 atomic_read(&fcport->state) != FCS_UNCONFIGURED)
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003284 qla2x00_rport_del(fcport);
3285}
3286
Linus Torvalds1da177e2005-04-16 15:20:36 -07003287/*
3288* qla2x00_abort_isp
3289* Resets ISP and aborts all outstanding commands.
3290*
3291* Input:
3292* ha = adapter block pointer.
3293*
3294* Returns:
3295* 0 = success
3296*/
3297int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003298qla2x00_abort_isp(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299{
Andrew Vasquez476e8972006-08-23 14:54:55 -07003300 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003301 uint8_t status = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003302 struct qla_hw_data *ha = vha->hw;
3303 struct scsi_qla_host *vp;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003304 struct scsi_qla_host *tvp;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003305 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003306
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003307 if (vha->flags.online) {
3308 vha->flags.online = 0;
Lalit Chandivade2533cf62009-03-24 09:08:07 -07003309 ha->flags.chip_reset_done = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003310 clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Harish Zunjarraoe5f5f6f2008-07-10 16:55:49 -07003311 ha->qla_stats.total_isp_aborts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003312
3313 qla_printk(KERN_INFO, ha,
3314 "Performing ISP error recovery - ha= %p.\n", ha);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003315 ha->isp_ops->reset_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003316
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003317 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
3318 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
3319 atomic_set(&vha->loop_state, LOOP_DOWN);
3320 qla2x00_mark_all_devices_lost(vha, 0);
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003321 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003322 qla2x00_mark_all_devices_lost(vp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003323 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003324 if (!atomic_read(&vha->loop_down_timer))
3325 atomic_set(&vha->loop_down_timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 LOOP_DOWN_TIME);
3327 }
3328
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329 /* Requeue all commands in outstanding command list. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003330 qla2x00_abort_all_cmds(vha, DID_RESET << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003332 ha->isp_ops->get_flash_version(vha, req->ring);
Andrew Vasquez30c47662007-01-29 10:22:21 -08003333
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003334 ha->isp_ops->nvram_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003335
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003336 if (!qla2x00_restart_isp(vha)) {
3337 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003339 if (!atomic_read(&vha->loop_down_timer)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003340 /*
3341 * Issue marker command only when we are going
3342 * to start the I/O .
3343 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003344 vha->marker_needed = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 }
3346
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003347 vha->flags.online = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003348
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003349 ha->isp_ops->enable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003351 ha->isp_abort_cnt = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003352 clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
Andrew Vasquez476e8972006-08-23 14:54:55 -07003353
Andrew Vasquezdf613b92008-01-17 09:02:17 -08003354 if (ha->fce) {
3355 ha->flags.fce_enabled = 1;
3356 memset(ha->fce, 0,
3357 fce_calc_size(ha->fce_bufs));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003358 rval = qla2x00_enable_fce_trace(vha,
Andrew Vasquezdf613b92008-01-17 09:02:17 -08003359 ha->fce_dma, ha->fce_bufs, ha->fce_mb,
3360 &ha->fce_bufs);
3361 if (rval) {
3362 qla_printk(KERN_WARNING, ha,
3363 "Unable to reinitialize FCE "
3364 "(%d).\n", rval);
3365 ha->flags.fce_enabled = 0;
3366 }
3367 }
Andrew Vasquez436a7b12008-07-10 16:55:54 -07003368
3369 if (ha->eft) {
3370 memset(ha->eft, 0, EFT_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003371 rval = qla2x00_enable_eft_trace(vha,
Andrew Vasquez436a7b12008-07-10 16:55:54 -07003372 ha->eft_dma, EFT_NUM_BUFFERS);
3373 if (rval) {
3374 qla_printk(KERN_WARNING, ha,
3375 "Unable to reinitialize EFT "
3376 "(%d).\n", rval);
3377 }
3378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003379 } else { /* failed the ISP abort */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003380 vha->flags.online = 1;
3381 if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003382 if (ha->isp_abort_cnt == 0) {
3383 qla_printk(KERN_WARNING, ha,
3384 "ISP error recovery failed - "
3385 "board disabled\n");
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003386 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003387 * The next call disables the board
3388 * completely.
3389 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003390 ha->isp_ops->reset_adapter(vha);
3391 vha->flags.online = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003392 clear_bit(ISP_ABORT_RETRY,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003393 &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003394 status = 0;
3395 } else { /* schedule another ISP abort */
3396 ha->isp_abort_cnt--;
3397 DEBUG(printk("qla%ld: ISP abort - "
Andrew Vasquez01071092005-07-06 10:31:37 -07003398 "retry remaining %d\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003399 vha->host_no, ha->isp_abort_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 status = 1;
3401 }
3402 } else {
3403 ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
3404 DEBUG(printk("qla2x00(%ld): ISP error recovery "
3405 "- retrying (%d) more times\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003406 vha->host_no, ha->isp_abort_cnt));
3407 set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003408 status = 1;
3409 }
3410 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003411
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 }
3413
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003414 if (!status) {
3415 DEBUG(printk(KERN_INFO
3416 "qla2x00_abort_isp(%ld): succeeded.\n",
3417 vha->host_no));
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003418 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003419 if (vp->vp_idx)
3420 qla2x00_vp_abort_isp(vp);
3421 }
3422 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 qla_printk(KERN_INFO, ha,
3424 "qla2x00_abort_isp: **** FAILED ****\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 }
3426
3427 return(status);
3428}
3429
3430/*
3431* qla2x00_restart_isp
3432* restarts the ISP after a reset
3433*
3434* Input:
3435* ha = adapter block pointer.
3436*
3437* Returns:
3438* 0 = success
3439*/
3440static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003441qla2x00_restart_isp(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003442{
Andrew Vasquezc6b2fca2009-03-05 11:07:03 -08003443 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 uint32_t wait_time;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003445 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003446 struct req_que *req = ha->req_q_map[0];
3447 struct rsp_que *rsp = ha->rsp_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448
3449 /* If firmware needs to be loaded */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003450 if (qla2x00_isp_firmware(vha)) {
3451 vha->flags.online = 0;
3452 status = ha->isp_ops->chip_diag(vha);
3453 if (!status)
3454 status = qla2x00_setup_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003455 }
3456
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003457 if (!status && !(status = qla2x00_init_rings(vha))) {
3458 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Lalit Chandivade2533cf62009-03-24 09:08:07 -07003459 ha->flags.chip_reset_done = 1;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003460 /* Initialize the queues in use */
3461 qla25xx_init_queues(ha);
3462
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003463 status = qla2x00_fw_ready(vha);
3464 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003465 DEBUG(printk("%s(): Start configure loop, "
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003466 "status = %d\n", __func__, status));
Andrew Vasquez01071092005-07-06 10:31:37 -07003467
3468 /* Issue a marker after FW becomes ready. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003469 qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
Andrew Vasquez01071092005-07-06 10:31:37 -07003470
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003471 vha->flags.online = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3473 wait_time = 256;
3474 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003475 clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
3476 qla2x00_configure_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 wait_time--;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003478 } while (!atomic_read(&vha->loop_down_timer) &&
3479 !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
3480 && wait_time && (test_bit(LOOP_RESYNC_NEEDED,
3481 &vha->dpc_flags)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003482 }
3483
3484 /* if no cable then assume it's good */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003485 if ((vha->device_flags & DFLG_NO_CABLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 status = 0;
3487
3488 DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
3489 __func__,
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003490 status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491 }
3492 return (status);
3493}
3494
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003495static int
3496qla25xx_init_queues(struct qla_hw_data *ha)
3497{
3498 struct rsp_que *rsp = NULL;
3499 struct req_que *req = NULL;
3500 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
3501 int ret = -1;
3502 int i;
3503
3504 for (i = 1; i < ha->max_queues; i++) {
3505 rsp = ha->rsp_q_map[i];
3506 if (rsp) {
3507 rsp->options &= ~BIT_0;
Anirban Chakraborty618a7522009-02-08 20:50:11 -08003508 ret = qla25xx_init_rsp_que(base_vha, rsp);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003509 if (ret != QLA_SUCCESS)
3510 DEBUG2_17(printk(KERN_WARNING
3511 "%s Rsp que:%d init failed\n", __func__,
3512 rsp->id));
3513 else
3514 DEBUG2_17(printk(KERN_INFO
3515 "%s Rsp que:%d inited\n", __func__,
3516 rsp->id));
3517 }
3518 req = ha->req_q_map[i];
3519 if (req) {
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003520 /* Clear outstanding commands array. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003521 req->options &= ~BIT_0;
Anirban Chakraborty618a7522009-02-08 20:50:11 -08003522 ret = qla25xx_init_req_que(base_vha, req);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003523 if (ret != QLA_SUCCESS)
3524 DEBUG2_17(printk(KERN_WARNING
3525 "%s Req que:%d init failed\n", __func__,
3526 req->id));
3527 else
3528 DEBUG2_17(printk(KERN_WARNING
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003529 "%s Req que:%d inited\n", __func__,
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003530 req->id));
3531 }
3532 }
3533 return ret;
3534}
3535
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536/*
3537* qla2x00_reset_adapter
3538* Reset adapter.
3539*
3540* Input:
3541* ha = adapter block pointer.
3542*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003543void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003544qla2x00_reset_adapter(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003545{
3546 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003547 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -07003548 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003549
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003550 vha->flags.online = 0;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003551 ha->isp_ops->disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003552
Linus Torvalds1da177e2005-04-16 15:20:36 -07003553 spin_lock_irqsave(&ha->hardware_lock, flags);
3554 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
3555 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3556 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
3557 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3558 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3559}
Andrew Vasquez01071092005-07-06 10:31:37 -07003560
3561void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003562qla24xx_reset_adapter(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07003563{
3564 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003565 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07003566 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
3567
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003568 vha->flags.online = 0;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003569 ha->isp_ops->disable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -07003570
3571 spin_lock_irqsave(&ha->hardware_lock, flags);
3572 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
3573 RD_REG_DWORD(&reg->hccr);
3574 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
3575 RD_REG_DWORD(&reg->hccr);
3576 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquez09ff36d2009-01-22 09:45:30 -08003577
3578 if (IS_NOPOLLING_TYPE(ha))
3579 ha->isp_ops->enable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -07003580}
3581
David Miller4e08df32007-04-16 12:37:43 -07003582/* On sparc systems, obtain port and node WWN from firmware
3583 * properties.
3584 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003585static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *vha,
3586 struct nvram_24xx *nv)
David Miller4e08df32007-04-16 12:37:43 -07003587{
3588#ifdef CONFIG_SPARC
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003589 struct qla_hw_data *ha = vha->hw;
David Miller4e08df32007-04-16 12:37:43 -07003590 struct pci_dev *pdev = ha->pdev;
David S. Miller15576bc2007-05-08 00:36:49 -07003591 struct device_node *dp = pci_device_to_OF_node(pdev);
3592 const u8 *val;
David Miller4e08df32007-04-16 12:37:43 -07003593 int len;
3594
3595 val = of_get_property(dp, "port-wwn", &len);
3596 if (val && len >= WWN_SIZE)
3597 memcpy(nv->port_name, val, WWN_SIZE);
3598
3599 val = of_get_property(dp, "node-wwn", &len);
3600 if (val && len >= WWN_SIZE)
3601 memcpy(nv->node_name, val, WWN_SIZE);
3602#endif
3603}
3604
Andrew Vasquez01071092005-07-06 10:31:37 -07003605int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003606qla24xx_nvram_config(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07003607{
David Miller4e08df32007-04-16 12:37:43 -07003608 int rval;
Andrew Vasquez01071092005-07-06 10:31:37 -07003609 struct init_cb_24xx *icb;
3610 struct nvram_24xx *nv;
3611 uint32_t *dptr;
3612 uint8_t *dptr1, *dptr2;
3613 uint32_t chksum;
3614 uint16_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003615 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07003616
David Miller4e08df32007-04-16 12:37:43 -07003617 rval = QLA_SUCCESS;
Andrew Vasquez01071092005-07-06 10:31:37 -07003618 icb = (struct init_cb_24xx *)ha->init_cb;
Seokmann Ju281afe12007-07-26 13:43:34 -07003619 nv = ha->nvram;
Andrew Vasquez01071092005-07-06 10:31:37 -07003620
3621 /* Determine NVRAM starting address. */
3622 ha->nvram_size = sizeof(struct nvram_24xx);
3623 ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003624 ha->vpd_size = FA_NVRAM_VPD_SIZE;
3625 ha->vpd_base = FA_NVRAM_VPD0_ADDR;
3626 if (PCI_FUNC(ha->pdev->devfn)) {
Andrew Vasquez01071092005-07-06 10:31:37 -07003627 ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003628 ha->vpd_base = FA_NVRAM_VPD1_ADDR;
3629 }
Andrew Vasquez01071092005-07-06 10:31:37 -07003630
Seokmann Ju281afe12007-07-26 13:43:34 -07003631 /* Get VPD data into cache */
3632 ha->vpd = ha->nvram + VPD_OFFSET;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003633 ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
Seokmann Ju281afe12007-07-26 13:43:34 -07003634 ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
3635
3636 /* Get NVRAM data into cache and calculate checksum. */
Andrew Vasquez01071092005-07-06 10:31:37 -07003637 dptr = (uint32_t *)nv;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003638 ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
Andrew Vasquez01071092005-07-06 10:31:37 -07003639 ha->nvram_size);
3640 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
3641 chksum += le32_to_cpu(*dptr++);
3642
3643 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
Seokmann Ju281afe12007-07-26 13:43:34 -07003644 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
Andrew Vasquez01071092005-07-06 10:31:37 -07003645
3646 /* Bad NVRAM data, set defaults parameters. */
3647 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
3648 || nv->id[3] != ' ' ||
3649 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
3650 /* Reset NVRAM data. */
3651 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
3652 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
3653 le16_to_cpu(nv->nvram_version));
David Miller4e08df32007-04-16 12:37:43 -07003654 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
3655 "invalid -- WWPN) defaults.\n");
3656
3657 /*
3658 * Set default initialization control block.
3659 */
3660 memset(nv, 0, ha->nvram_size);
3661 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
3662 nv->version = __constant_cpu_to_le16(ICB_VERSION);
3663 nv->frame_payload_size = __constant_cpu_to_le16(2048);
3664 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3665 nv->exchange_count = __constant_cpu_to_le16(0);
3666 nv->hard_address = __constant_cpu_to_le16(124);
3667 nv->port_name[0] = 0x21;
3668 nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
3669 nv->port_name[2] = 0x00;
3670 nv->port_name[3] = 0xe0;
3671 nv->port_name[4] = 0x8b;
3672 nv->port_name[5] = 0x1c;
3673 nv->port_name[6] = 0x55;
3674 nv->port_name[7] = 0x86;
3675 nv->node_name[0] = 0x20;
3676 nv->node_name[1] = 0x00;
3677 nv->node_name[2] = 0x00;
3678 nv->node_name[3] = 0xe0;
3679 nv->node_name[4] = 0x8b;
3680 nv->node_name[5] = 0x1c;
3681 nv->node_name[6] = 0x55;
3682 nv->node_name[7] = 0x86;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003683 qla24xx_nvram_wwn_from_ofw(vha, nv);
David Miller4e08df32007-04-16 12:37:43 -07003684 nv->login_retry_count = __constant_cpu_to_le16(8);
3685 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
3686 nv->login_timeout = __constant_cpu_to_le16(0);
3687 nv->firmware_options_1 =
3688 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
3689 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
3690 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
3691 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
3692 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
3693 nv->efi_parameters = __constant_cpu_to_le32(0);
3694 nv->reset_delay = 5;
3695 nv->max_luns_per_target = __constant_cpu_to_le16(128);
3696 nv->port_down_retry_count = __constant_cpu_to_le16(30);
3697 nv->link_down_timeout = __constant_cpu_to_le16(30);
3698
3699 rval = 1;
Andrew Vasquez01071092005-07-06 10:31:37 -07003700 }
3701
3702 /* Reset Initialization control block */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003703 memset(icb, 0, ha->init_cb_size);
Andrew Vasquez01071092005-07-06 10:31:37 -07003704
3705 /* Copy 1st segment. */
3706 dptr1 = (uint8_t *)icb;
3707 dptr2 = (uint8_t *)&nv->version;
3708 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
3709 while (cnt--)
3710 *dptr1++ = *dptr2++;
3711
3712 icb->login_retry_count = nv->login_retry_count;
Andrew Vasquez3ea66e22006-06-23 16:11:27 -07003713 icb->link_down_on_nos = nv->link_down_on_nos;
Andrew Vasquez01071092005-07-06 10:31:37 -07003714
3715 /* Copy 2nd segment. */
3716 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
3717 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
3718 cnt = (uint8_t *)&icb->reserved_3 -
3719 (uint8_t *)&icb->interrupt_delay_timer;
3720 while (cnt--)
3721 *dptr1++ = *dptr2++;
3722
3723 /*
3724 * Setup driver NVRAM options.
3725 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003726 qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08003727 "QLA2462");
Andrew Vasquez01071092005-07-06 10:31:37 -07003728
Andrew Vasquez5341e862006-05-17 15:09:16 -07003729 /* Use alternate WWN? */
3730 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
3731 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
3732 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
3733 }
3734
Andrew Vasquez01071092005-07-06 10:31:37 -07003735 /* Prepare nodename */
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003736 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
Andrew Vasquez01071092005-07-06 10:31:37 -07003737 /*
3738 * Firmware will apply the following mask if the nodename was
3739 * not provided.
3740 */
3741 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
3742 icb->node_name[0] &= 0xF0;
3743 }
3744
3745 /* Set host adapter parameters. */
3746 ha->flags.disable_risc_code_load = 0;
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08003747 ha->flags.enable_lip_reset = 0;
3748 ha->flags.enable_lip_full_login =
3749 le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
3750 ha->flags.enable_target_reset =
3751 le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
Andrew Vasquez01071092005-07-06 10:31:37 -07003752 ha->flags.enable_led_scheme = 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07003753 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
Andrew Vasquez01071092005-07-06 10:31:37 -07003754
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003755 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
3756 (BIT_6 | BIT_5 | BIT_4)) >> 4;
Andrew Vasquez01071092005-07-06 10:31:37 -07003757
3758 memcpy(ha->fw_seriallink_options24, nv->seriallink_options,
3759 sizeof(ha->fw_seriallink_options24));
3760
3761 /* save HBA serial number */
3762 ha->serial0 = icb->port_name[5];
3763 ha->serial1 = icb->port_name[6];
3764 ha->serial2 = icb->port_name[7];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003765 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
3766 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
Andrew Vasquez01071092005-07-06 10:31:37 -07003767
andrew.vasquez@qlogic.combc8fb3c2006-01-13 17:05:42 -08003768 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3769
Andrew Vasquez01071092005-07-06 10:31:37 -07003770 ha->retry_count = le16_to_cpu(nv->login_retry_count);
3771
3772 /* Set minimum login_timeout to 4 seconds. */
3773 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
3774 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
3775 if (le16_to_cpu(nv->login_timeout) < 4)
3776 nv->login_timeout = __constant_cpu_to_le16(4);
3777 ha->login_timeout = le16_to_cpu(nv->login_timeout);
Seokmann Juc6852c42008-04-24 15:21:29 -07003778 icb->login_timeout = nv->login_timeout;
Andrew Vasquez01071092005-07-06 10:31:37 -07003779
Andrew Vasquez00a537b2008-02-28 14:06:11 -08003780 /* Set minimum RATOV to 100 tenths of a second. */
3781 ha->r_a_tov = 100;
Andrew Vasquez01071092005-07-06 10:31:37 -07003782
3783 ha->loop_reset_delay = nv->reset_delay;
3784
3785 /* Link Down Timeout = 0:
3786 *
3787 * When Port Down timer expires we will start returning
3788 * I/O's to OS with "DID_NO_CONNECT".
3789 *
3790 * Link Down Timeout != 0:
3791 *
3792 * The driver waits for the link to come up after link down
3793 * before returning I/Os to OS with "DID_NO_CONNECT".
3794 */
3795 if (le16_to_cpu(nv->link_down_timeout) == 0) {
3796 ha->loop_down_abort_time =
3797 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
3798 } else {
3799 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
3800 ha->loop_down_abort_time =
3801 (LOOP_DOWN_TIME - ha->link_down_timeout);
3802 }
3803
3804 /* Need enough time to try and get the port back. */
3805 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
3806 if (qlport_down_retry)
3807 ha->port_down_retry_count = qlport_down_retry;
3808
3809 /* Set login_retry_count */
3810 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
3811 if (ha->port_down_retry_count ==
3812 le16_to_cpu(nv->port_down_retry_count) &&
3813 ha->port_down_retry_count > 3)
3814 ha->login_retry_count = ha->port_down_retry_count;
3815 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
3816 ha->login_retry_count = ha->port_down_retry_count;
3817 if (ql2xloginretrycount)
3818 ha->login_retry_count = ql2xloginretrycount;
3819
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003820 /* Enable ZIO. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003821 if (!vha->flags.init_done) {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003822 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
3823 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
3824 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
3825 le16_to_cpu(icb->interrupt_delay_timer): 2;
3826 }
3827 icb->firmware_options_2 &= __constant_cpu_to_le32(
3828 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003829 vha->flags.process_response_queue = 0;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003830 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08003831 ha->zio_mode = QLA_ZIO_MODE_6;
3832
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003833 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003834 "(%d us).\n", vha->host_no, ha->zio_mode,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003835 ha->zio_timer * 100));
3836 qla_printk(KERN_INFO, ha,
3837 "ZIO mode %d enabled; timer delay (%d us).\n",
3838 ha->zio_mode, ha->zio_timer * 100);
3839
3840 icb->firmware_options_2 |= cpu_to_le32(
3841 (uint32_t)ha->zio_mode);
3842 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003843 vha->flags.process_response_queue = 1;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003844 }
3845
David Miller4e08df32007-04-16 12:37:43 -07003846 if (rval) {
3847 DEBUG2_3(printk(KERN_WARNING
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003848 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
David Miller4e08df32007-04-16 12:37:43 -07003849 }
3850 return (rval);
Andrew Vasquez01071092005-07-06 10:31:37 -07003851}
3852
Adrian Bunk413975a2006-06-30 02:33:06 -07003853static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003854qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003855{
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003856 int rval = QLA_SUCCESS;
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003857 int segments, fragment;
3858 uint32_t faddr;
3859 uint32_t *dcode, dlen;
3860 uint32_t risc_addr;
3861 uint32_t risc_size;
3862 uint32_t i;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003863 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003864 struct req_que *req = ha->req_q_map[0];
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08003865
3866 qla_printk(KERN_INFO, ha,
3867 "FW: Loading from flash (%x)...\n", ha->flt_region_fw);
3868
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003869 rval = QLA_SUCCESS;
3870
3871 segments = FA_RISC_CODE_SEGMENTS;
Andrew Vasquezc00d8992008-09-11 21:22:49 -07003872 faddr = ha->flt_region_fw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003873 dcode = (uint32_t *)req->ring;
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003874 *srisc_addr = 0;
3875
3876 /* Validate firmware image by checking version. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003877 qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003878 for (i = 0; i < 4; i++)
3879 dcode[i] = be32_to_cpu(dcode[i]);
3880 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
3881 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
3882 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
3883 dcode[3] == 0)) {
3884 qla_printk(KERN_WARNING, ha,
3885 "Unable to verify integrity of flash firmware image!\n");
3886 qla_printk(KERN_WARNING, ha,
3887 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
3888 dcode[1], dcode[2], dcode[3]);
3889
3890 return QLA_FUNCTION_FAILED;
3891 }
3892
3893 while (segments && rval == QLA_SUCCESS) {
3894 /* Read segment's load information. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003895 qla24xx_read_flash_data(vha, dcode, faddr, 4);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003896
3897 risc_addr = be32_to_cpu(dcode[2]);
3898 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
3899 risc_size = be32_to_cpu(dcode[3]);
3900
3901 fragment = 0;
3902 while (risc_size > 0 && rval == QLA_SUCCESS) {
3903 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
3904 if (dlen > risc_size)
3905 dlen = risc_size;
3906
3907 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3908 "addr %x, number of dwords 0x%x, offset 0x%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003909 vha->host_no, risc_addr, dlen, faddr));
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003910
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003911 qla24xx_read_flash_data(vha, dcode, faddr, dlen);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003912 for (i = 0; i < dlen; i++)
3913 dcode[i] = swab32(dcode[i]);
3914
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003915 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003916 dlen);
3917 if (rval) {
3918 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003919 "segment %d of firmware\n", vha->host_no,
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003920 fragment));
3921 qla_printk(KERN_WARNING, ha,
3922 "[ERROR] Failed to load segment %d of "
3923 "firmware\n", fragment);
3924 break;
3925 }
3926
3927 faddr += dlen;
3928 risc_addr += dlen;
3929 risc_size -= dlen;
3930 fragment++;
3931 }
3932
3933 /* Next segment. */
3934 segments--;
3935 }
3936
3937 return rval;
3938}
3939
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003940#define QLA_FW_URL "ftp://ftp.qlogic.com/outgoing/linux/firmware/"
3941
Andrew Vasquez01071092005-07-06 10:31:37 -07003942int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003943qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquez54333832005-11-09 15:49:04 -08003944{
3945 int rval;
3946 int i, fragment;
3947 uint16_t *wcode, *fwcode;
3948 uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
3949 struct fw_blob *blob;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003950 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003951 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez54333832005-11-09 15:49:04 -08003952
3953 /* Load firmware blob. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003954 blob = qla2x00_request_firmware(vha);
Andrew Vasquez54333832005-11-09 15:49:04 -08003955 if (!blob) {
3956 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003957 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
3958 "from: " QLA_FW_URL ".\n");
Andrew Vasquez54333832005-11-09 15:49:04 -08003959 return QLA_FUNCTION_FAILED;
3960 }
3961
3962 rval = QLA_SUCCESS;
3963
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003964 wcode = (uint16_t *)req->ring;
Andrew Vasquez54333832005-11-09 15:49:04 -08003965 *srisc_addr = 0;
3966 fwcode = (uint16_t *)blob->fw->data;
3967 fwclen = 0;
3968
3969 /* Validate firmware image by checking version. */
3970 if (blob->fw->size < 8 * sizeof(uint16_t)) {
3971 qla_printk(KERN_WARNING, ha,
3972 "Unable to verify integrity of firmware image (%Zd)!\n",
3973 blob->fw->size);
3974 goto fail_fw_integrity;
3975 }
3976 for (i = 0; i < 4; i++)
3977 wcode[i] = be16_to_cpu(fwcode[i + 4]);
3978 if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
3979 wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
3980 wcode[2] == 0 && wcode[3] == 0)) {
3981 qla_printk(KERN_WARNING, ha,
3982 "Unable to verify integrity of firmware image!\n");
3983 qla_printk(KERN_WARNING, ha,
3984 "Firmware data: %04x %04x %04x %04x!\n", wcode[0],
3985 wcode[1], wcode[2], wcode[3]);
3986 goto fail_fw_integrity;
3987 }
3988
3989 seg = blob->segs;
3990 while (*seg && rval == QLA_SUCCESS) {
3991 risc_addr = *seg;
3992 *srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
3993 risc_size = be16_to_cpu(fwcode[3]);
3994
3995 /* Validate firmware image size. */
3996 fwclen += risc_size * sizeof(uint16_t);
3997 if (blob->fw->size < fwclen) {
3998 qla_printk(KERN_WARNING, ha,
3999 "Unable to verify integrity of firmware image "
4000 "(%Zd)!\n", blob->fw->size);
4001 goto fail_fw_integrity;
4002 }
4003
4004 fragment = 0;
4005 while (risc_size > 0 && rval == QLA_SUCCESS) {
4006 wlen = (uint16_t)(ha->fw_transfer_size >> 1);
4007 if (wlen > risc_size)
4008 wlen = risc_size;
4009
4010 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004011 "addr %x, number of words 0x%x.\n", vha->host_no,
Andrew Vasquez54333832005-11-09 15:49:04 -08004012 risc_addr, wlen));
4013
4014 for (i = 0; i < wlen; i++)
4015 wcode[i] = swab16(fwcode[i]);
4016
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004017 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
Andrew Vasquez54333832005-11-09 15:49:04 -08004018 wlen);
4019 if (rval) {
4020 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004021 "segment %d of firmware\n", vha->host_no,
Andrew Vasquez54333832005-11-09 15:49:04 -08004022 fragment));
4023 qla_printk(KERN_WARNING, ha,
4024 "[ERROR] Failed to load segment %d of "
4025 "firmware\n", fragment);
4026 break;
4027 }
4028
4029 fwcode += wlen;
4030 risc_addr += wlen;
4031 risc_size -= wlen;
4032 fragment++;
4033 }
4034
4035 /* Next segment. */
4036 seg++;
4037 }
4038 return rval;
4039
4040fail_fw_integrity:
4041 return QLA_FUNCTION_FAILED;
4042}
4043
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004044static int
4045qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquez01071092005-07-06 10:31:37 -07004046{
4047 int rval;
4048 int segments, fragment;
4049 uint32_t *dcode, dlen;
4050 uint32_t risc_addr;
4051 uint32_t risc_size;
4052 uint32_t i;
Andrew Vasquez54333832005-11-09 15:49:04 -08004053 struct fw_blob *blob;
Andrew Vasquez01071092005-07-06 10:31:37 -07004054 uint32_t *fwcode, fwclen;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004055 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004056 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -07004057
Andrew Vasquez54333832005-11-09 15:49:04 -08004058 /* Load firmware blob. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004059 blob = qla2x00_request_firmware(vha);
Andrew Vasquez54333832005-11-09 15:49:04 -08004060 if (!blob) {
4061 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004062 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
4063 "from: " QLA_FW_URL ".\n");
4064
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004065 return QLA_FUNCTION_FAILED;
Andrew Vasquez01071092005-07-06 10:31:37 -07004066 }
4067
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004068 qla_printk(KERN_INFO, ha,
4069 "FW: Loading via request-firmware...\n");
4070
Andrew Vasquez01071092005-07-06 10:31:37 -07004071 rval = QLA_SUCCESS;
4072
4073 segments = FA_RISC_CODE_SEGMENTS;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004074 dcode = (uint32_t *)req->ring;
Andrew Vasquez01071092005-07-06 10:31:37 -07004075 *srisc_addr = 0;
Andrew Vasquez54333832005-11-09 15:49:04 -08004076 fwcode = (uint32_t *)blob->fw->data;
Andrew Vasquez01071092005-07-06 10:31:37 -07004077 fwclen = 0;
4078
4079 /* Validate firmware image by checking version. */
Andrew Vasquez54333832005-11-09 15:49:04 -08004080 if (blob->fw->size < 8 * sizeof(uint32_t)) {
Andrew Vasquez01071092005-07-06 10:31:37 -07004081 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004082 "Unable to verify integrity of firmware image (%Zd)!\n",
4083 blob->fw->size);
Andrew Vasquez01071092005-07-06 10:31:37 -07004084 goto fail_fw_integrity;
4085 }
4086 for (i = 0; i < 4; i++)
4087 dcode[i] = be32_to_cpu(fwcode[i + 4]);
4088 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
4089 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
4090 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
4091 dcode[3] == 0)) {
4092 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004093 "Unable to verify integrity of firmware image!\n");
Andrew Vasquez01071092005-07-06 10:31:37 -07004094 qla_printk(KERN_WARNING, ha,
4095 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
4096 dcode[1], dcode[2], dcode[3]);
4097 goto fail_fw_integrity;
4098 }
4099
4100 while (segments && rval == QLA_SUCCESS) {
4101 risc_addr = be32_to_cpu(fwcode[2]);
4102 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
4103 risc_size = be32_to_cpu(fwcode[3]);
4104
4105 /* Validate firmware image size. */
4106 fwclen += risc_size * sizeof(uint32_t);
Andrew Vasquez54333832005-11-09 15:49:04 -08004107 if (blob->fw->size < fwclen) {
Andrew Vasquez01071092005-07-06 10:31:37 -07004108 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004109 "Unable to verify integrity of firmware image "
4110 "(%Zd)!\n", blob->fw->size);
4111
Andrew Vasquez01071092005-07-06 10:31:37 -07004112 goto fail_fw_integrity;
4113 }
4114
4115 fragment = 0;
4116 while (risc_size > 0 && rval == QLA_SUCCESS) {
4117 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
4118 if (dlen > risc_size)
4119 dlen = risc_size;
4120
4121 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004122 "addr %x, number of dwords 0x%x.\n", vha->host_no,
Andrew Vasquez01071092005-07-06 10:31:37 -07004123 risc_addr, dlen));
4124
4125 for (i = 0; i < dlen; i++)
4126 dcode[i] = swab32(fwcode[i]);
4127
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004128 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
andrew.vasquez@qlogic.com590f98e2006-01-13 17:05:37 -08004129 dlen);
Andrew Vasquez01071092005-07-06 10:31:37 -07004130 if (rval) {
4131 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004132 "segment %d of firmware\n", vha->host_no,
Andrew Vasquez01071092005-07-06 10:31:37 -07004133 fragment));
4134 qla_printk(KERN_WARNING, ha,
4135 "[ERROR] Failed to load segment %d of "
4136 "firmware\n", fragment);
4137 break;
4138 }
4139
4140 fwcode += dlen;
4141 risc_addr += dlen;
4142 risc_size -= dlen;
4143 fragment++;
4144 }
4145
4146 /* Next segment. */
4147 segments--;
4148 }
Andrew Vasquez01071092005-07-06 10:31:37 -07004149 return rval;
4150
4151fail_fw_integrity:
Andrew Vasquez01071092005-07-06 10:31:37 -07004152 return QLA_FUNCTION_FAILED;
Andrew Vasquez01071092005-07-06 10:31:37 -07004153}
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004154
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004155int
4156qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
4157{
4158 int rval;
4159
4160 /*
4161 * FW Load priority:
4162 * 1) Firmware via request-firmware interface (.bin file).
4163 * 2) Firmware residing in flash.
4164 */
4165 rval = qla24xx_load_risc_blob(vha, srisc_addr);
4166 if (rval == QLA_SUCCESS)
4167 return rval;
4168
4169 return qla24xx_load_risc_flash(vha, srisc_addr);
4170}
4171
4172int
4173qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
4174{
4175 int rval;
4176
4177 /*
4178 * FW Load priority:
4179 * 1) Firmware residing in flash.
4180 * 2) Firmware via request-firmware interface (.bin file).
4181 */
4182 rval = qla24xx_load_risc_flash(vha, srisc_addr);
4183 if (rval == QLA_SUCCESS)
4184 return rval;
4185
4186 return qla24xx_load_risc_blob(vha, srisc_addr);
4187}
4188
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004189void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004190qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004191{
4192 int ret, retries;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004193 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004194
Andrew Vasqueze4289242007-07-19 15:05:56 -07004195 if (!IS_FWI2_CAPABLE(ha))
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004196 return;
Andrew Vasquez75edf812007-05-07 07:43:00 -07004197 if (!ha->fw_major_version)
4198 return;
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004199
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004200 ret = qla2x00_stop_firmware(vha);
Andrew Vasquez7c7f1f22008-02-28 14:06:09 -08004201 for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
4202 retries ; retries--) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004203 ha->isp_ops->reset_chip(vha);
4204 if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004205 continue;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004206 if (qla2x00_setup_chip(vha) != QLA_SUCCESS)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004207 continue;
4208 qla_printk(KERN_INFO, ha,
4209 "Attempting retry of stop-firmware command...\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004210 ret = qla2x00_stop_firmware(vha);
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004211 }
4212}
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004213
4214int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004215qla24xx_configure_vhba(scsi_qla_host_t *vha)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004216{
4217 int rval = QLA_SUCCESS;
4218 uint16_t mb[MAILBOX_REGISTER_COUNT];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004219 struct qla_hw_data *ha = vha->hw;
4220 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08004221 struct req_que *req = ha->req_q_map[vha->req_ques[0]];
4222 struct rsp_que *rsp = req->rsp;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004223
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004224 if (!vha->vp_idx)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004225 return -EINVAL;
4226
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004227 rval = qla2x00_fw_ready(base_vha);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004228 if (rval == QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004229 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004230 qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004231 }
4232
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004233 vha->flags.management_server_logged_in = 0;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004234
4235 /* Login to SNS first */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004236 ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004237 if (mb[0] != MBS_COMMAND_COMPLETE) {
4238 DEBUG15(qla_printk(KERN_INFO, ha,
4239 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
4240 "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
4241 mb[0], mb[1], mb[2], mb[6], mb[7]));
4242 return (QLA_FUNCTION_FAILED);
4243 }
4244
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004245 atomic_set(&vha->loop_down_timer, 0);
4246 atomic_set(&vha->loop_state, LOOP_UP);
4247 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
4248 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
4249 rval = qla2x00_loop_resync(base_vha);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004250
4251 return rval;
4252}
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004253
4254/* 84XX Support **************************************************************/
4255
4256static LIST_HEAD(qla_cs84xx_list);
4257static DEFINE_MUTEX(qla_cs84xx_mutex);
4258
4259static struct qla_chip_state_84xx *
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004260qla84xx_get_chip(struct scsi_qla_host *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004261{
4262 struct qla_chip_state_84xx *cs84xx;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004263 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004264
4265 mutex_lock(&qla_cs84xx_mutex);
4266
4267 /* Find any shared 84xx chip. */
4268 list_for_each_entry(cs84xx, &qla_cs84xx_list, list) {
4269 if (cs84xx->bus == ha->pdev->bus) {
4270 kref_get(&cs84xx->kref);
4271 goto done;
4272 }
4273 }
4274
4275 cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL);
4276 if (!cs84xx)
4277 goto done;
4278
4279 kref_init(&cs84xx->kref);
4280 spin_lock_init(&cs84xx->access_lock);
4281 mutex_init(&cs84xx->fw_update_mutex);
4282 cs84xx->bus = ha->pdev->bus;
4283
4284 list_add_tail(&cs84xx->list, &qla_cs84xx_list);
4285done:
4286 mutex_unlock(&qla_cs84xx_mutex);
4287 return cs84xx;
4288}
4289
4290static void
4291__qla84xx_chip_release(struct kref *kref)
4292{
4293 struct qla_chip_state_84xx *cs84xx =
4294 container_of(kref, struct qla_chip_state_84xx, kref);
4295
4296 mutex_lock(&qla_cs84xx_mutex);
4297 list_del(&cs84xx->list);
4298 mutex_unlock(&qla_cs84xx_mutex);
4299 kfree(cs84xx);
4300}
4301
4302void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004303qla84xx_put_chip(struct scsi_qla_host *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004304{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004305 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004306 if (ha->cs84xx)
4307 kref_put(&ha->cs84xx->kref, __qla84xx_chip_release);
4308}
4309
4310static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004311qla84xx_init_chip(scsi_qla_host_t *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004312{
4313 int rval;
4314 uint16_t status[2];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004315 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004316
4317 mutex_lock(&ha->cs84xx->fw_update_mutex);
4318
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004319 rval = qla84xx_verify_chip(vha, status);
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004320
4321 mutex_unlock(&ha->cs84xx->fw_update_mutex);
4322
4323 return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED:
4324 QLA_SUCCESS;
4325}
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004326
4327/* 81XX Support **************************************************************/
4328
4329int
4330qla81xx_nvram_config(scsi_qla_host_t *vha)
4331{
4332 int rval;
4333 struct init_cb_81xx *icb;
4334 struct nvram_81xx *nv;
4335 uint32_t *dptr;
4336 uint8_t *dptr1, *dptr2;
4337 uint32_t chksum;
4338 uint16_t cnt;
4339 struct qla_hw_data *ha = vha->hw;
4340
4341 rval = QLA_SUCCESS;
4342 icb = (struct init_cb_81xx *)ha->init_cb;
4343 nv = ha->nvram;
4344
4345 /* Determine NVRAM starting address. */
4346 ha->nvram_size = sizeof(struct nvram_81xx);
4347 ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
4348 ha->vpd_size = FA_NVRAM_VPD_SIZE;
4349 ha->vpd_base = FA_NVRAM_VPD0_ADDR;
4350 if (PCI_FUNC(ha->pdev->devfn) & 1) {
4351 ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
4352 ha->vpd_base = FA_NVRAM_VPD1_ADDR;
4353 }
4354
4355 /* Get VPD data into cache */
4356 ha->vpd = ha->nvram + VPD_OFFSET;
4357 ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
4358 ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
4359
4360 /* Get NVRAM data into cache and calculate checksum. */
4361 dptr = (uint32_t *)nv;
4362 ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
4363 ha->nvram_size);
4364 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
4365 chksum += le32_to_cpu(*dptr++);
4366
4367 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
4368 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
4369
4370 /* Bad NVRAM data, set defaults parameters. */
4371 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
4372 || nv->id[3] != ' ' ||
4373 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
4374 /* Reset NVRAM data. */
4375 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
4376 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
4377 le16_to_cpu(nv->nvram_version));
4378 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
4379 "invalid -- WWPN) defaults.\n");
4380
4381 /*
4382 * Set default initialization control block.
4383 */
4384 memset(nv, 0, ha->nvram_size);
4385 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
4386 nv->version = __constant_cpu_to_le16(ICB_VERSION);
4387 nv->frame_payload_size = __constant_cpu_to_le16(2048);
4388 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
4389 nv->exchange_count = __constant_cpu_to_le16(0);
4390 nv->port_name[0] = 0x21;
4391 nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
4392 nv->port_name[2] = 0x00;
4393 nv->port_name[3] = 0xe0;
4394 nv->port_name[4] = 0x8b;
4395 nv->port_name[5] = 0x1c;
4396 nv->port_name[6] = 0x55;
4397 nv->port_name[7] = 0x86;
4398 nv->node_name[0] = 0x20;
4399 nv->node_name[1] = 0x00;
4400 nv->node_name[2] = 0x00;
4401 nv->node_name[3] = 0xe0;
4402 nv->node_name[4] = 0x8b;
4403 nv->node_name[5] = 0x1c;
4404 nv->node_name[6] = 0x55;
4405 nv->node_name[7] = 0x86;
4406 nv->login_retry_count = __constant_cpu_to_le16(8);
4407 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
4408 nv->login_timeout = __constant_cpu_to_le16(0);
4409 nv->firmware_options_1 =
4410 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
4411 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
4412 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
4413 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
4414 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
4415 nv->efi_parameters = __constant_cpu_to_le32(0);
4416 nv->reset_delay = 5;
4417 nv->max_luns_per_target = __constant_cpu_to_le16(128);
4418 nv->port_down_retry_count = __constant_cpu_to_le16(30);
4419 nv->link_down_timeout = __constant_cpu_to_le16(30);
4420 nv->enode_mac[0] = 0x01;
4421 nv->enode_mac[1] = 0x02;
4422 nv->enode_mac[2] = 0x03;
4423 nv->enode_mac[3] = 0x04;
4424 nv->enode_mac[4] = 0x05;
4425 nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
4426
4427 rval = 1;
4428 }
4429
4430 /* Reset Initialization control block */
4431 memset(icb, 0, sizeof(struct init_cb_81xx));
4432
4433 /* Copy 1st segment. */
4434 dptr1 = (uint8_t *)icb;
4435 dptr2 = (uint8_t *)&nv->version;
4436 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
4437 while (cnt--)
4438 *dptr1++ = *dptr2++;
4439
4440 icb->login_retry_count = nv->login_retry_count;
4441
4442 /* Copy 2nd segment. */
4443 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
4444 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
4445 cnt = (uint8_t *)&icb->reserved_5 -
4446 (uint8_t *)&icb->interrupt_delay_timer;
4447 while (cnt--)
4448 *dptr1++ = *dptr2++;
4449
4450 memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
4451 /* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
4452 if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
4453 icb->enode_mac[0] = 0x01;
4454 icb->enode_mac[1] = 0x02;
4455 icb->enode_mac[2] = 0x03;
4456 icb->enode_mac[3] = 0x04;
4457 icb->enode_mac[4] = 0x05;
4458 icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
4459 }
4460
Andrew Vasquezb64b0e82009-03-24 09:08:01 -07004461 /* Use extended-initialization control block. */
4462 memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb));
4463
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004464 /*
4465 * Setup driver NVRAM options.
4466 */
4467 qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
4468 "QLE81XX");
4469
4470 /* Use alternate WWN? */
4471 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
4472 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
4473 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
4474 }
4475
4476 /* Prepare nodename */
4477 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
4478 /*
4479 * Firmware will apply the following mask if the nodename was
4480 * not provided.
4481 */
4482 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
4483 icb->node_name[0] &= 0xF0;
4484 }
4485
4486 /* Set host adapter parameters. */
4487 ha->flags.disable_risc_code_load = 0;
4488 ha->flags.enable_lip_reset = 0;
4489 ha->flags.enable_lip_full_login =
4490 le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
4491 ha->flags.enable_target_reset =
4492 le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
4493 ha->flags.enable_led_scheme = 0;
4494 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
4495
4496 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
4497 (BIT_6 | BIT_5 | BIT_4)) >> 4;
4498
4499 /* save HBA serial number */
4500 ha->serial0 = icb->port_name[5];
4501 ha->serial1 = icb->port_name[6];
4502 ha->serial2 = icb->port_name[7];
4503 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
4504 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
4505
4506 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
4507
4508 ha->retry_count = le16_to_cpu(nv->login_retry_count);
4509
4510 /* Set minimum login_timeout to 4 seconds. */
4511 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
4512 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
4513 if (le16_to_cpu(nv->login_timeout) < 4)
4514 nv->login_timeout = __constant_cpu_to_le16(4);
4515 ha->login_timeout = le16_to_cpu(nv->login_timeout);
4516 icb->login_timeout = nv->login_timeout;
4517
4518 /* Set minimum RATOV to 100 tenths of a second. */
4519 ha->r_a_tov = 100;
4520
4521 ha->loop_reset_delay = nv->reset_delay;
4522
4523 /* Link Down Timeout = 0:
4524 *
4525 * When Port Down timer expires we will start returning
4526 * I/O's to OS with "DID_NO_CONNECT".
4527 *
4528 * Link Down Timeout != 0:
4529 *
4530 * The driver waits for the link to come up after link down
4531 * before returning I/Os to OS with "DID_NO_CONNECT".
4532 */
4533 if (le16_to_cpu(nv->link_down_timeout) == 0) {
4534 ha->loop_down_abort_time =
4535 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
4536 } else {
4537 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
4538 ha->loop_down_abort_time =
4539 (LOOP_DOWN_TIME - ha->link_down_timeout);
4540 }
4541
4542 /* Need enough time to try and get the port back. */
4543 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
4544 if (qlport_down_retry)
4545 ha->port_down_retry_count = qlport_down_retry;
4546
4547 /* Set login_retry_count */
4548 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
4549 if (ha->port_down_retry_count ==
4550 le16_to_cpu(nv->port_down_retry_count) &&
4551 ha->port_down_retry_count > 3)
4552 ha->login_retry_count = ha->port_down_retry_count;
4553 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
4554 ha->login_retry_count = ha->port_down_retry_count;
4555 if (ql2xloginretrycount)
4556 ha->login_retry_count = ql2xloginretrycount;
4557
4558 /* Enable ZIO. */
4559 if (!vha->flags.init_done) {
4560 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
4561 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
4562 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
4563 le16_to_cpu(icb->interrupt_delay_timer): 2;
4564 }
4565 icb->firmware_options_2 &= __constant_cpu_to_le32(
4566 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
4567 vha->flags.process_response_queue = 0;
4568 if (ha->zio_mode != QLA_ZIO_DISABLED) {
4569 ha->zio_mode = QLA_ZIO_MODE_6;
4570
4571 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
4572 "(%d us).\n", vha->host_no, ha->zio_mode,
4573 ha->zio_timer * 100));
4574 qla_printk(KERN_INFO, ha,
4575 "ZIO mode %d enabled; timer delay (%d us).\n",
4576 ha->zio_mode, ha->zio_timer * 100);
4577
4578 icb->firmware_options_2 |= cpu_to_le32(
4579 (uint32_t)ha->zio_mode);
4580 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
4581 vha->flags.process_response_queue = 1;
4582 }
4583
4584 if (rval) {
4585 DEBUG2_3(printk(KERN_WARNING
4586 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
4587 }
4588 return (rval);
4589}
4590
4591void
4592qla81xx_update_fw_options(scsi_qla_host_t *ha)
4593{
4594}