blob: a2747501fdde20161ea8241818ecadc589fe92d3 [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->mbx_flags = 0;
76 ha->isp_abort_cnt = 0;
77 ha->beacon_blink_led = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080078 set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
Anirban Chakraborty73208df2008-12-09 16:45:39 -080080 set_bit(0, ha->req_qid_map);
81 set_bit(0, ha->rsp_qid_map);
82
Andrew Vasquez01071092005-07-06 10:31:37 -070083 qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080084 rval = ha->isp_ops->pci_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 if (rval) {
Andrew Vasquez7c98a042007-01-29 10:22:29 -080086 DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080087 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 return (rval);
89 }
90
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080091 ha->isp_ops->reset_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080093 rval = qla2xxx_get_flash_info(vha);
Andrew Vasquezc00d8992008-09-11 21:22:49 -070094 if (rval) {
95 DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080096 vha->host_no));
Andrew Vasquezc00d8992008-09-11 21:22:49 -070097 return (rval);
98 }
99
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800100 ha->isp_ops->get_flash_version(vha, req->ring);
Andrew Vasquez30c47662007-01-29 10:22:21 -0800101
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
Andrew Vasquez01071092005-07-06 10:31:37 -0700103
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800104 ha->isp_ops->nvram_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105
Andrew Vasquezd4c760c2006-06-23 16:10:39 -0700106 if (ha->flags.disable_serdes) {
107 /* Mask HBA via NVRAM settings? */
108 qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
109 "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800110 vha->port_name[0], vha->port_name[1],
111 vha->port_name[2], vha->port_name[3],
112 vha->port_name[4], vha->port_name[5],
113 vha->port_name[6], vha->port_name[7]);
Andrew Vasquezd4c760c2006-06-23 16:10:39 -0700114 return QLA_FUNCTION_FAILED;
115 }
116
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
118
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800119 if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
120 rval = ha->isp_ops->chip_diag(vha);
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800121 if (rval)
122 return (rval);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800123 rval = qla2x00_setup_chip(vha);
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800124 if (rval)
125 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126 }
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700127 if (IS_QLA84XX(ha)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800128 ha->cs84xx = qla84xx_get_chip(vha);
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700129 if (!ha->cs84xx) {
130 qla_printk(KERN_ERR, ha,
131 "Unable to configure ISP84XX.\n");
132 return QLA_FUNCTION_FAILED;
133 }
134 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800135 rval = qla2x00_init_rings(vha);
Lalit Chandivade2533cf62009-03-24 09:08:07 -0700136 ha->flags.chip_reset_done = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
138 return (rval);
139}
140
141/**
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700142 * qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 * @ha: HA context
144 *
145 * Returns 0 on success.
146 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700147int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800148qla2100_pci_config(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700150 uint16_t w;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700151 unsigned long flags;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800152 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700153 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700156 pci_try_set_mwi(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700159 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
161
Andrew Vasquez737faec2008-10-24 15:13:45 -0700162 pci_disable_rom(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700164 /* Get PCI bus information. */
165 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700166 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700167 spin_unlock_irqrestore(&ha->hardware_lock, flags);
168
169 return QLA_SUCCESS;
170}
171
172/**
173 * qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
174 * @ha: HA context
175 *
176 * Returns 0 on success.
177 */
178int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800179qla2300_pci_config(scsi_qla_host_t *vha)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700180{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700181 uint16_t w;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700182 unsigned long flags = 0;
183 uint32_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800184 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700185 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700186
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700187 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700188 pci_try_set_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700189
190 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700191 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700192
193 if (IS_QLA2322(ha) || IS_QLA6322(ha))
194 w &= ~PCI_COMMAND_INTX_DISABLE;
Andrew Vasqueza157b102007-05-07 07:43:01 -0700195 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700196
197 /*
198 * If this is a 2300 card and not 2312, reset the
199 * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
200 * the 2310 also reports itself as a 2300 so we need to get the
201 * fb revision level -- a 6 indicates it really is a 2300 and
202 * not a 2310.
203 */
204 if (IS_QLA2300(ha)) {
205 spin_lock_irqsave(&ha->hardware_lock, flags);
206
207 /* Pause RISC. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700208 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700209 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700210 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700211 break;
212
213 udelay(10);
214 }
215
216 /* Select FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700217 WRT_REG_WORD(&reg->ctrl_status, 0x20);
218 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700219
220 /* Get the fb rev level */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700221 ha->fb_rev = RD_FB_CMD_REG(ha, reg);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700222
223 if (ha->fb_rev == FPM_2300)
Andrew Vasqueza157b102007-05-07 07:43:01 -0700224 pci_clear_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700225
226 /* Deselect FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700227 WRT_REG_WORD(&reg->ctrl_status, 0x0);
228 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700229
230 /* Release RISC module. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700231 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700232 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700233 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700234 break;
235
236 udelay(10);
237 }
238
239 spin_unlock_irqrestore(&ha->hardware_lock, flags);
240 }
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700241
242 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
243
Andrew Vasquez737faec2008-10-24 15:13:45 -0700244 pci_disable_rom(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700245
246 /* Get PCI bus information. */
247 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700248 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700249 spin_unlock_irqrestore(&ha->hardware_lock, flags);
250
251 return QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252}
253
254/**
Andrew Vasquez01071092005-07-06 10:31:37 -0700255 * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
256 * @ha: HA context
257 *
258 * Returns 0 on success.
259 */
260int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800261qla24xx_pci_config(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700262{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700263 uint16_t w;
Andrew Vasquez01071092005-07-06 10:31:37 -0700264 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800265 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -0700266 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
Andrew Vasquez01071092005-07-06 10:31:37 -0700267
268 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700269 pci_try_set_mwi(ha->pdev);
Andrew Vasquez01071092005-07-06 10:31:37 -0700270
271 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700272 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquez01071092005-07-06 10:31:37 -0700273 w &= ~PCI_COMMAND_INTX_DISABLE;
274 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
275
276 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
277
278 /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
Andrew Vasquezf85ec182007-07-19 15:06:01 -0700279 if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
280 pcix_set_mmrbc(ha->pdev, 2048);
Andrew Vasquez01071092005-07-06 10:31:37 -0700281
282 /* PCIe -- adjust Maximum Read Request Size (2048). */
Andrew Vasquezf85ec182007-07-19 15:06:01 -0700283 if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
284 pcie_set_readrq(ha->pdev, 2048);
Andrew Vasquez01071092005-07-06 10:31:37 -0700285
Andrew Vasquez737faec2008-10-24 15:13:45 -0700286 pci_disable_rom(ha->pdev);
Andrew Vasquez01071092005-07-06 10:31:37 -0700287
Auke Kok44c10132007-06-08 15:46:36 -0700288 ha->chip_revision = ha->pdev->revision;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -0800289
Andrew Vasquez01071092005-07-06 10:31:37 -0700290 /* Get PCI bus information. */
291 spin_lock_irqsave(&ha->hardware_lock, flags);
292 ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
293 spin_unlock_irqrestore(&ha->hardware_lock, flags);
294
295 return QLA_SUCCESS;
296}
297
298/**
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700299 * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
300 * @ha: HA context
301 *
302 * Returns 0 on success.
303 */
304int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800305qla25xx_pci_config(scsi_qla_host_t *vha)
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700306{
307 uint16_t w;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800308 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700309
310 pci_set_master(ha->pdev);
311 pci_try_set_mwi(ha->pdev);
312
313 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
314 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
315 w &= ~PCI_COMMAND_INTX_DISABLE;
316 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
317
318 /* PCIe -- adjust Maximum Read Request Size (2048). */
319 if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
320 pcie_set_readrq(ha->pdev, 2048);
321
Andrew Vasquez737faec2008-10-24 15:13:45 -0700322 pci_disable_rom(ha->pdev);
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700323
324 ha->chip_revision = ha->pdev->revision;
325
326 return QLA_SUCCESS;
327}
328
329/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 * qla2x00_isp_firmware() - Choose firmware image.
331 * @ha: HA context
332 *
333 * Returns 0 on success.
334 */
335static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800336qla2x00_isp_firmware(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
338 int rval;
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700339 uint16_t loop_id, topo, sw_cap;
340 uint8_t domain, area, al_pa;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800341 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 /* Assume loading risc code */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700344 rval = QLA_FUNCTION_FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345
346 if (ha->flags.disable_risc_code_load) {
347 DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800348 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
350
351 /* Verify checksum of loaded RISC code. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800352 rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700353 if (rval == QLA_SUCCESS) {
354 /* And, verify we are not in ROM code. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800355 rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700356 &area, &domain, &topo, &sw_cap);
357 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 }
359
360 if (rval) {
361 DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800362 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 }
364
365 return (rval);
366}
367
368/**
369 * qla2x00_reset_chip() - Reset ISP chip.
370 * @ha: HA context
371 *
372 * Returns 0 on success.
373 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700374void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800375qla2x00_reset_chip(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376{
377 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800378 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700379 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 uint32_t cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 uint16_t cmd;
382
Andrew Vasquezfd34f552007-07-19 15:06:00 -0700383 ha->isp_ops->disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384
385 spin_lock_irqsave(&ha->hardware_lock, flags);
386
387 /* Turn off master enable */
388 cmd = 0;
389 pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
390 cmd &= ~PCI_COMMAND_MASTER;
391 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
392
393 if (!IS_QLA2100(ha)) {
394 /* Pause RISC. */
395 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
396 if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
397 for (cnt = 0; cnt < 30000; cnt++) {
398 if ((RD_REG_WORD(&reg->hccr) &
399 HCCR_RISC_PAUSE) != 0)
400 break;
401 udelay(100);
402 }
403 } else {
404 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
405 udelay(10);
406 }
407
408 /* Select FPM registers. */
409 WRT_REG_WORD(&reg->ctrl_status, 0x20);
410 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
411
412 /* FPM Soft Reset. */
413 WRT_REG_WORD(&reg->fpm_diag_config, 0x100);
414 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
415
416 /* Toggle Fpm Reset. */
417 if (!IS_QLA2200(ha)) {
418 WRT_REG_WORD(&reg->fpm_diag_config, 0x0);
419 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
420 }
421
422 /* Select frame buffer registers. */
423 WRT_REG_WORD(&reg->ctrl_status, 0x10);
424 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
425
426 /* Reset frame buffer FIFOs. */
427 if (IS_QLA2200(ha)) {
428 WRT_FB_CMD_REG(ha, reg, 0xa000);
429 RD_FB_CMD_REG(ha, reg); /* PCI Posting. */
430 } else {
431 WRT_FB_CMD_REG(ha, reg, 0x00fc);
432
433 /* Read back fb_cmd until zero or 3 seconds max */
434 for (cnt = 0; cnt < 3000; cnt++) {
435 if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
436 break;
437 udelay(100);
438 }
439 }
440
441 /* Select RISC module registers. */
442 WRT_REG_WORD(&reg->ctrl_status, 0);
443 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
444
445 /* Reset RISC processor. */
446 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
447 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
448
449 /* Release RISC processor. */
450 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
451 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
452 }
453
454 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
455 WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);
456
457 /* Reset ISP chip. */
458 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
459
460 /* Wait for RISC to recover from reset. */
461 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
462 /*
463 * It is necessary to for a delay here since the card doesn't
464 * respond to PCI reads during a reset. On some architectures
465 * this will result in an MCA.
466 */
467 udelay(20);
468 for (cnt = 30000; cnt; cnt--) {
469 if ((RD_REG_WORD(&reg->ctrl_status) &
470 CSR_ISP_SOFT_RESET) == 0)
471 break;
472 udelay(100);
473 }
474 } else
475 udelay(10);
476
477 /* Reset RISC processor. */
478 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
479
480 WRT_REG_WORD(&reg->semaphore, 0);
481
482 /* Release RISC processor. */
483 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
484 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
485
486 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
487 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquezffb39f02006-05-17 15:09:06 -0700488 if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 udelay(100);
492 }
493 } else
494 udelay(100);
495
496 /* Turn on master enable */
497 cmd |= PCI_COMMAND_MASTER;
498 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
499
500 /* Disable RISC pause on FPM parity error. */
501 if (!IS_QLA2100(ha)) {
502 WRT_REG_WORD(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
503 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
504 }
505
506 spin_unlock_irqrestore(&ha->hardware_lock, flags);
507}
508
509/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700510 * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
Andrew Vasquez01071092005-07-06 10:31:37 -0700511 * @ha: HA context
512 *
513 * Returns 0 on success.
514 */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700515static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800516qla24xx_reset_risc(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700517{
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -0700518 int hw_evt = 0;
Andrew Vasquez01071092005-07-06 10:31:37 -0700519 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800520 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -0700521 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
522 uint32_t cnt, d2;
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800523 uint16_t wd;
Andrew Vasquez01071092005-07-06 10:31:37 -0700524
Andrew Vasquez01071092005-07-06 10:31:37 -0700525 spin_lock_irqsave(&ha->hardware_lock, flags);
526
527 /* Reset RISC. */
528 WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
529 for (cnt = 0; cnt < 30000; cnt++) {
530 if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
531 break;
532
533 udelay(10);
534 }
535
536 WRT_REG_DWORD(&reg->ctrl_status,
537 CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800538 pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700539
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800540 udelay(100);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700541 /* Wait for firmware to complete NVRAM accesses. */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700542 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
543 for (cnt = 10000 ; cnt && d2; cnt--) {
544 udelay(5);
545 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
546 barrier();
547 }
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -0700548 if (cnt == 0)
549 hw_evt = 1;
Andrew Vasquez88c26662005-07-08 17:59:26 -0700550
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800551 /* Wait for soft-reset to complete. */
Andrew Vasquez01071092005-07-06 10:31:37 -0700552 d2 = RD_REG_DWORD(&reg->ctrl_status);
553 for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
554 udelay(5);
555 d2 = RD_REG_DWORD(&reg->ctrl_status);
556 barrier();
557 }
558
559 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
560 RD_REG_DWORD(&reg->hccr);
561
562 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
563 RD_REG_DWORD(&reg->hccr);
564
565 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
566 RD_REG_DWORD(&reg->hccr);
567
568 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
569 for (cnt = 6000000 ; cnt && d2; cnt--) {
570 udelay(5);
571 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
572 barrier();
573 }
574
575 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquez124f85e2009-01-05 11:18:06 -0800576
577 if (IS_NOPOLLING_TYPE(ha))
578 ha->isp_ops->enable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700579}
580
581/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700582 * qla24xx_reset_chip() - Reset ISP24xx chip.
583 * @ha: HA context
584 *
585 * Returns 0 on success.
586 */
587void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800588qla24xx_reset_chip(scsi_qla_host_t *vha)
Andrew Vasquez88c26662005-07-08 17:59:26 -0700589{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800590 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezfd34f552007-07-19 15:06:00 -0700591 ha->isp_ops->disable_intrs(ha);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700592
593 /* Perform RISC reset. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800594 qla24xx_reset_risc(vha);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700595}
596
597/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 * qla2x00_chip_diag() - Test chip for proper operation.
599 * @ha: HA context
600 *
601 * Returns 0 on success.
602 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700603int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800604qla2x00_chip_diag(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605{
606 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800607 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700608 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 unsigned long flags = 0;
610 uint16_t data;
611 uint32_t cnt;
612 uint16_t mb[5];
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800613 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614
615 /* Assume a failed state */
616 rval = QLA_FUNCTION_FAILED;
617
618 DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800619 vha->host_no, (u_long)&reg->flash_address));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620
621 spin_lock_irqsave(&ha->hardware_lock, flags);
622
623 /* Reset ISP chip. */
624 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
625
626 /*
627 * We need to have a delay here since the card will not respond while
628 * in reset causing an MCA on some architectures.
629 */
630 udelay(20);
631 data = qla2x00_debounce_register(&reg->ctrl_status);
632 for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
633 udelay(5);
634 data = RD_REG_WORD(&reg->ctrl_status);
635 barrier();
636 }
637
638 if (!cnt)
639 goto chip_diag_failed;
640
641 DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
642 ha->host_no));
643
644 /* Reset RISC processor. */
645 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
646 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
647
648 /* Workaround for QLA2312 PCI parity error */
649 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
650 data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
651 for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
652 udelay(5);
653 data = RD_MAILBOX_REG(ha, reg, 0);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700654 barrier();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
656 } else
657 udelay(10);
658
659 if (!cnt)
660 goto chip_diag_failed;
661
662 /* Check product ID of chip */
663 DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no));
664
665 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
666 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
667 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
668 mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
669 if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
670 mb[3] != PROD_ID_3) {
671 qla_printk(KERN_WARNING, ha,
672 "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
673
674 goto chip_diag_failed;
675 }
676 ha->product_id[0] = mb[1];
677 ha->product_id[1] = mb[2];
678 ha->product_id[2] = mb[3];
679 ha->product_id[3] = mb[4];
680
681 /* Adjust fw RISC transfer size */
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800682 if (req->length > 1024)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
684 else
685 ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800686 req->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
688 if (IS_QLA2200(ha) &&
689 RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
690 /* Limit firmware transfer size with a 2200A */
691 DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800692 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -0800694 ha->device_type |= DT_ISP2200A;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 ha->fw_transfer_size = 128;
696 }
697
698 /* Wrap Incoming Mailboxes Test. */
699 spin_unlock_irqrestore(&ha->hardware_lock, flags);
700
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800701 DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
702 rval = qla2x00_mbx_reg_test(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 if (rval) {
704 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800705 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 qla_printk(KERN_WARNING, ha,
707 "Failed mailbox send register test\n");
708 }
709 else {
710 /* Flag a successful rval */
711 rval = QLA_SUCCESS;
712 }
713 spin_lock_irqsave(&ha->hardware_lock, flags);
714
715chip_diag_failed:
716 if (rval)
717 DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800718 "****\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 spin_unlock_irqrestore(&ha->hardware_lock, flags);
721
722 return (rval);
723}
724
725/**
Andrew Vasquez01071092005-07-06 10:31:37 -0700726 * qla24xx_chip_diag() - Test ISP24xx for proper operation.
727 * @ha: HA context
728 *
729 * Returns 0 on success.
730 */
731int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800732qla24xx_chip_diag(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700733{
734 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800735 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800736 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -0700737
Andrew Vasquez88c26662005-07-08 17:59:26 -0700738 /* Perform RISC reset. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800739 qla24xx_reset_risc(vha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700740
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800741 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
Andrew Vasquez01071092005-07-06 10:31:37 -0700742
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800743 rval = qla2x00_mbx_reg_test(vha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700744 if (rval) {
745 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800746 vha->host_no));
Andrew Vasquez01071092005-07-06 10:31:37 -0700747 qla_printk(KERN_WARNING, ha,
748 "Failed mailbox send register test\n");
749 } else {
750 /* Flag a successful rval */
751 rval = QLA_SUCCESS;
752 }
753
754 return rval;
755}
756
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700757void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800758qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700759{
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700760 int rval;
761 uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800762 eft_size, fce_size, mq_size;
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800763 dma_addr_t tc_dma;
764 void *tc;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800765 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800766 struct req_que *req = ha->req_q_map[0];
767 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700768
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700769 if (ha->fw_dump) {
770 qla_printk(KERN_WARNING, ha,
771 "Firmware dump previously allocated.\n");
772 return;
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700773 }
774
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700775 ha->fw_dumped = 0;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800776 fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700777 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
778 fixed_size = sizeof(struct qla2100_fw_dump);
779 } else if (IS_QLA23XX(ha)) {
780 fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
781 mem_size = (ha->fw_memory_size - 0x11000 + 1) *
782 sizeof(uint16_t);
Andrew Vasqueze4289242007-07-19 15:05:56 -0700783 } else if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800784 if (IS_QLA81XX(ha))
785 fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
786 else if (IS_QLA25XX(ha))
787 fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
788 else
789 fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700790 mem_size = (ha->fw_memory_size - 0x100000 + 1) *
791 sizeof(uint32_t);
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800792 if (ha->mqenable)
793 mq_size = sizeof(struct qla2xxx_mq_chain);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700794
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700795 /* Allocate memory for Fibre Channel Event Buffer. */
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800796 if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700797 goto try_eft;
798
799 tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
800 GFP_KERNEL);
801 if (!tc) {
802 qla_printk(KERN_WARNING, ha, "Unable to allocate "
803 "(%d KB) for FCE.\n", FCE_SIZE / 1024);
Anirban Chakraborty17d98632008-12-18 10:06:15 -0800804 goto try_eft;
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700805 }
806
807 memset(tc, 0, FCE_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800808 rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS,
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700809 ha->fce_mb, &ha->fce_bufs);
810 if (rval) {
811 qla_printk(KERN_WARNING, ha, "Unable to initialize "
812 "FCE (%d).\n", rval);
813 dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
814 tc_dma);
815 ha->flags.fce_enabled = 0;
Anirban Chakraborty17d98632008-12-18 10:06:15 -0800816 goto try_eft;
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700817 }
818
819 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
820 FCE_SIZE / 1024);
821
Giridhar Malavali7d9dade2009-03-24 09:07:58 -0700822 fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
Andrew Vasquez436a7b12008-07-10 16:55:54 -0700823 ha->flags.fce_enabled = 1;
824 ha->fce_dma = tc_dma;
825 ha->fce = tc;
826try_eft:
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700827 /* Allocate memory for Extended Trace Buffer. */
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800828 tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700829 GFP_KERNEL);
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800830 if (!tc) {
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700831 qla_printk(KERN_WARNING, ha, "Unable to allocate "
832 "(%d KB) for EFT.\n", EFT_SIZE / 1024);
833 goto cont_alloc;
834 }
835
Andrew Vasquezfc447652008-01-17 09:02:18 -0800836 memset(tc, 0, EFT_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800837 rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700838 if (rval) {
839 qla_printk(KERN_WARNING, ha, "Unable to initialize "
840 "EFT (%d).\n", rval);
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800841 dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
842 tc_dma);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700843 goto cont_alloc;
844 }
845
846 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
847 EFT_SIZE / 1024);
848
849 eft_size = EFT_SIZE;
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800850 ha->eft_dma = tc_dma;
851 ha->eft = tc;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700852 }
853cont_alloc:
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800854 req_q_size = req->length * sizeof(request_t);
855 rsp_q_size = rsp->length * sizeof(response_t);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700856
857 dump_size = offsetof(struct qla2xxx_fw_dump, isp);
858 dump_size += fixed_size + mem_size + req_q_size + rsp_q_size +
Andrew Vasquezbb99de62009-01-05 11:18:08 -0800859 eft_size;
860 ha->chain_offset = dump_size;
861 dump_size += mq_size + fce_size;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700862
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700863 ha->fw_dump = vmalloc(dump_size);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700864 if (!ha->fw_dump) {
Andrew Vasquez01071092005-07-06 10:31:37 -0700865 qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700866 "firmware dump!!!\n", dump_size / 1024);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700867
868 if (ha->eft) {
869 dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
870 ha->eft_dma);
871 ha->eft = NULL;
872 ha->eft_dma = 0;
873 }
874 return;
875 }
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700876 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
877 dump_size / 1024);
878
879 ha->fw_dump_len = dump_size;
880 ha->fw_dump->signature[0] = 'Q';
881 ha->fw_dump->signature[1] = 'L';
882 ha->fw_dump->signature[2] = 'G';
883 ha->fw_dump->signature[3] = 'C';
884 ha->fw_dump->version = __constant_htonl(1);
885
886 ha->fw_dump->fixed_size = htonl(fixed_size);
887 ha->fw_dump->mem_size = htonl(mem_size);
888 ha->fw_dump->req_q_size = htonl(req_q_size);
889 ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
890
891 ha->fw_dump->eft_size = htonl(eft_size);
892 ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
893 ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
894
895 ha->fw_dump->header_size =
896 htonl(offsetof(struct qla2xxx_fw_dump, isp));
Andrew Vasquez01071092005-07-06 10:31:37 -0700897}
898
899/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 * qla2x00_resize_request_q() - Resize request queue given available ISP memory.
901 * @ha: HA context
902 *
903 * Returns 0 on success.
904 */
905static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800906qla2x00_resize_request_q(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907{
908 int rval;
909 uint16_t fw_iocb_cnt = 0;
910 uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM;
911 dma_addr_t request_dma;
912 request_t *request_ring;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800913 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800914 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 /* Valid only on recent ISPs. */
917 if (IS_QLA2100(ha) || IS_QLA2200(ha))
918 return;
919
920 /* Retrieve IOCB counts available to the firmware. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800921 rval = qla2x00_get_resource_cnts(vha, NULL, NULL, NULL, &fw_iocb_cnt,
922 &ha->max_npiv_vports);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (rval)
924 return;
925 /* No point in continuing if current settings are sufficient. */
926 if (fw_iocb_cnt < 1024)
927 return;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800928 if (req->length >= request_q_length)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 return;
930
931 /* Attempt to claim larger area for request queue. */
932 request_ring = dma_alloc_coherent(&ha->pdev->dev,
933 (request_q_length + 1) * sizeof(request_t), &request_dma,
934 GFP_KERNEL);
935 if (request_ring == NULL)
936 return;
937
938 /* Resize successful, report extensions. */
939 qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n",
940 (ha->fw_memory_size + 1) / 1024);
941 qla_printk(KERN_INFO, ha, "Resizing request queue depth "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800942 "(%d -> %d)...\n", req->length, request_q_length);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943
944 /* Clear old allocations. */
945 dma_free_coherent(&ha->pdev->dev,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800946 (req->length + 1) * sizeof(request_t), req->ring,
947 req->dma);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 /* Begin using larger queue. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800950 req->length = request_q_length;
951 req->ring = request_ring;
952 req->dma = request_dma;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953}
954
955/**
956 * qla2x00_setup_chip() - Load and start RISC firmware.
957 * @ha: HA context
958 *
959 * Returns 0 on success.
960 */
961static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800962qla2x00_setup_chip(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963{
Andrew Vasquez01071092005-07-06 10:31:37 -0700964 int rval;
965 uint32_t srisc_address = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800966 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3db06522008-01-31 12:33:49 -0800967 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
968 unsigned long flags;
Andrew Vasquezdda772e2009-03-24 09:08:00 -0700969 uint16_t fw_major_version;
Andrew Vasquez3db06522008-01-31 12:33:49 -0800970
971 if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
972 /* Disable SRAM, Instruction RAM and GP RAM parity. */
973 spin_lock_irqsave(&ha->hardware_lock, flags);
974 WRT_REG_WORD(&reg->hccr, (HCCR_ENABLE_PARITY + 0x0));
975 RD_REG_WORD(&reg->hccr);
976 spin_unlock_irqrestore(&ha->hardware_lock, flags);
977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979 /* Load firmware sequences */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800980 rval = ha->isp_ops->load_risc(vha, &srisc_address);
Andrew Vasquez01071092005-07-06 10:31:37 -0700981 if (rval == QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800983 "code.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800985 rval = qla2x00_verify_checksum(vha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 if (rval == QLA_SUCCESS) {
987 /* Start firmware execution. */
988 DEBUG(printk("scsi(%ld): Checksum OK, start "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800989 "firmware.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800991 rval = qla2x00_execute_fw(vha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 /* Retrieve firmware information. */
Andrew Vasquezdda772e2009-03-24 09:08:00 -0700993 if (rval == QLA_SUCCESS) {
994 fw_major_version = ha->fw_major_version;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800995 qla2x00_get_fw_version(vha,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 &ha->fw_major_version,
997 &ha->fw_minor_version,
998 &ha->fw_subminor_version,
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800999 &ha->fw_attributes, &ha->fw_memory_size,
Andrew Vasquez55a96152009-03-24 09:08:03 -07001000 ha->mpi_version, &ha->mpi_capabilities,
1001 ha->phy_version);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001002 ha->flags.npiv_supported = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001003 if (IS_QLA2XXX_MIDTYPE(ha) &&
Mike Hernandez946fb892008-08-13 21:36:59 -07001004 (ha->fw_attributes & BIT_2)) {
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001005 ha->flags.npiv_supported = 1;
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001006 if ((!ha->max_npiv_vports) ||
1007 ((ha->max_npiv_vports + 1) %
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001008 MIN_MULTI_ID_FABRIC))
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001009 ha->max_npiv_vports =
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001010 MIN_MULTI_ID_FABRIC - 1;
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001011 }
Andrew Vasquezdda772e2009-03-24 09:08:00 -07001012 if (!fw_major_version) {
1013 qla2x00_resize_request_q(vha);
1014 if (ql2xallocfwdump)
1015 qla2x00_alloc_fw_dump(vha);
1016 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 }
1018 } else {
1019 DEBUG2(printk(KERN_INFO
1020 "scsi(%ld): ISP Firmware failed checksum.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001021 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
1023 }
1024
Andrew Vasquez3db06522008-01-31 12:33:49 -08001025 if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
1026 /* Enable proper parity. */
1027 spin_lock_irqsave(&ha->hardware_lock, flags);
1028 if (IS_QLA2300(ha))
1029 /* SRAM parity */
1030 WRT_REG_WORD(&reg->hccr, HCCR_ENABLE_PARITY + 0x1);
1031 else
1032 /* SRAM, Instruction RAM and GP RAM parity */
1033 WRT_REG_WORD(&reg->hccr, HCCR_ENABLE_PARITY + 0x7);
1034 RD_REG_WORD(&reg->hccr);
1035 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1036 }
1037
Joe Carnuccio1d2874d2009-03-24 09:08:06 -07001038 if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
1039 uint32_t size;
1040
1041 rval = qla81xx_fac_get_sector_size(vha, &size);
1042 if (rval == QLA_SUCCESS) {
1043 ha->flags.fac_supported = 1;
1044 ha->fdt_block_size = size << 2;
1045 } else {
1046 qla_printk(KERN_ERR, ha,
1047 "Unsupported FAC firmware (%d.%02d.%02d).\n",
1048 ha->fw_major_version, ha->fw_minor_version,
1049 ha->fw_subminor_version);
1050 }
1051 }
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 if (rval) {
1054 DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001055 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057
1058 return (rval);
1059}
1060
1061/**
1062 * qla2x00_init_response_q_entries() - Initializes response queue entries.
1063 * @ha: HA context
1064 *
1065 * Beginning of request ring has initialization control block already built
1066 * by nvram config routine.
1067 *
1068 * Returns 0 on success.
1069 */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001070void
1071qla2x00_init_response_q_entries(struct rsp_que *rsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
1073 uint16_t cnt;
1074 response_t *pkt;
1075
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001076 pkt = rsp->ring_ptr;
1077 for (cnt = 0; cnt < rsp->length; cnt++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 pkt->signature = RESPONSE_PROCESSED;
1079 pkt++;
1080 }
1081
1082}
1083
1084/**
1085 * qla2x00_update_fw_options() - Read and process firmware options.
1086 * @ha: HA context
1087 *
1088 * Returns 0 on success.
1089 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001090void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001091qla2x00_update_fw_options(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092{
1093 uint16_t swing, emphasis, tx_sens, rx_sens;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001094 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
1096 memset(ha->fw_options, 0, sizeof(ha->fw_options));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001097 qla2x00_get_fw_options(vha, ha->fw_options);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099 if (IS_QLA2100(ha) || IS_QLA2200(ha))
1100 return;
1101
1102 /* Serial Link options. */
1103 DEBUG3(printk("scsi(%ld): Serial link options:\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001104 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
1106 sizeof(ha->fw_seriallink_options)));
1107
1108 ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
1109 if (ha->fw_seriallink_options[3] & BIT_2) {
1110 ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
1111
1112 /* 1G settings */
1113 swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
1114 emphasis = (ha->fw_seriallink_options[2] &
1115 (BIT_4 | BIT_3)) >> 3;
1116 tx_sens = ha->fw_seriallink_options[0] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001117 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 rx_sens = (ha->fw_seriallink_options[0] &
1119 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
1120 ha->fw_options[10] = (emphasis << 14) | (swing << 8);
1121 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
1122 if (rx_sens == 0x0)
1123 rx_sens = 0x3;
1124 ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
1125 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1126 ha->fw_options[10] |= BIT_5 |
1127 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1128 (tx_sens & (BIT_1 | BIT_0));
1129
1130 /* 2G settings */
1131 swing = (ha->fw_seriallink_options[2] &
1132 (BIT_7 | BIT_6 | BIT_5)) >> 5;
1133 emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
1134 tx_sens = ha->fw_seriallink_options[1] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001135 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 rx_sens = (ha->fw_seriallink_options[1] &
1137 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
1138 ha->fw_options[11] = (emphasis << 14) | (swing << 8);
1139 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
1140 if (rx_sens == 0x0)
1141 rx_sens = 0x3;
1142 ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
1143 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1144 ha->fw_options[11] |= BIT_5 |
1145 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1146 (tx_sens & (BIT_1 | BIT_0));
1147 }
1148
1149 /* FCP2 options. */
1150 /* Return command IOCBs without waiting for an ABTS to complete. */
1151 ha->fw_options[3] |= BIT_13;
1152
1153 /* LED scheme. */
1154 if (ha->flags.enable_led_scheme)
1155 ha->fw_options[2] |= BIT_12;
1156
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08001157 /* Detect ISP6312. */
1158 if (IS_QLA6312(ha))
1159 ha->fw_options[2] |= BIT_13;
1160
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 /* Update firmware options. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001162 qla2x00_set_fw_options(vha, ha->fw_options);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163}
1164
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001165void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001166qla24xx_update_fw_options(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07001167{
1168 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001169 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07001170
1171 /* Update Serial Link options. */
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001172 if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
Andrew Vasquez01071092005-07-06 10:31:37 -07001173 return;
1174
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001175 rval = qla2x00_set_serdes_params(vha,
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001176 le16_to_cpu(ha->fw_seriallink_options24[1]),
1177 le16_to_cpu(ha->fw_seriallink_options24[2]),
1178 le16_to_cpu(ha->fw_seriallink_options24[3]));
Andrew Vasquez01071092005-07-06 10:31:37 -07001179 if (rval != QLA_SUCCESS) {
1180 qla_printk(KERN_WARNING, ha,
1181 "Unable to update Serial Link options (%x).\n", rval);
1182 }
1183}
1184
1185void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001186qla2x00_config_rings(struct scsi_qla_host *vha)
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001187{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001188 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001189 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001190 struct req_que *req = ha->req_q_map[0];
1191 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001192
1193 /* Setup ring parameters in initialization control block. */
1194 ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0);
1195 ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001196 ha->init_cb->request_q_length = cpu_to_le16(req->length);
1197 ha->init_cb->response_q_length = cpu_to_le16(rsp->length);
1198 ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
1199 ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
1200 ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
1201 ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001202
1203 WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
1204 WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
1205 WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0);
1206 WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0);
1207 RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */
1208}
1209
Andrew Vasquez01071092005-07-06 10:31:37 -07001210void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001211qla24xx_config_rings(struct scsi_qla_host *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07001212{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001213 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001214 device_reg_t __iomem *reg = ISP_QUE_REG(ha, 0);
1215 struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
1216 struct qla_msix_entry *msix;
Andrew Vasquez01071092005-07-06 10:31:37 -07001217 struct init_cb_24xx *icb;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001218 uint16_t rid = 0;
1219 struct req_que *req = ha->req_q_map[0];
1220 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -07001221
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001222/* Setup ring parameters in initialization control block. */
Andrew Vasquez01071092005-07-06 10:31:37 -07001223 icb = (struct init_cb_24xx *)ha->init_cb;
1224 icb->request_q_outpointer = __constant_cpu_to_le16(0);
1225 icb->response_q_inpointer = __constant_cpu_to_le16(0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001226 icb->request_q_length = cpu_to_le16(req->length);
1227 icb->response_q_length = cpu_to_le16(rsp->length);
1228 icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
1229 icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
1230 icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
1231 icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
Andrew Vasquez01071092005-07-06 10:31:37 -07001232
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001233 if (ha->mqenable) {
1234 icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
1235 icb->rid = __constant_cpu_to_le16(rid);
1236 if (ha->flags.msix_enabled) {
1237 msix = &ha->msix_entries[1];
1238 DEBUG2_17(printk(KERN_INFO
1239 "Reistering vector 0x%x for base que\n", msix->entry));
1240 icb->msix = cpu_to_le16(msix->entry);
1241 }
1242 /* Use alternate PCI bus number */
1243 if (MSB(rid))
1244 icb->firmware_options_2 |=
1245 __constant_cpu_to_le32(BIT_19);
1246 /* Use alternate PCI devfn */
1247 if (LSB(rid))
1248 icb->firmware_options_2 |=
1249 __constant_cpu_to_le32(BIT_18);
1250
Anirban Chakraborty618a7522009-02-08 20:50:11 -08001251 icb->firmware_options_2 &= __constant_cpu_to_le32(~BIT_22);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001252 icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001253
1254 WRT_REG_DWORD(&reg->isp25mq.req_q_in, 0);
1255 WRT_REG_DWORD(&reg->isp25mq.req_q_out, 0);
1256 WRT_REG_DWORD(&reg->isp25mq.rsp_q_in, 0);
1257 WRT_REG_DWORD(&reg->isp25mq.rsp_q_out, 0);
1258 } else {
1259 WRT_REG_DWORD(&reg->isp24.req_q_in, 0);
1260 WRT_REG_DWORD(&reg->isp24.req_q_out, 0);
1261 WRT_REG_DWORD(&reg->isp24.rsp_q_in, 0);
1262 WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0);
1263 }
1264 /* PCI posting */
1265 RD_REG_DWORD(&ioreg->hccr);
Andrew Vasquez01071092005-07-06 10:31:37 -07001266}
1267
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268/**
1269 * qla2x00_init_rings() - Initializes firmware.
1270 * @ha: HA context
1271 *
1272 * Beginning of request ring has initialization control block already built
1273 * by nvram config routine.
1274 *
1275 * Returns 0 on success.
1276 */
1277static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001278qla2x00_init_rings(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279{
1280 int rval;
1281 unsigned long flags = 0;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001282 int cnt, que;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001283 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001284 struct req_que *req;
1285 struct rsp_que *rsp;
1286 struct scsi_qla_host *vp;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001287 struct mid_init_cb_24xx *mid_init_cb =
1288 (struct mid_init_cb_24xx *) ha->init_cb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289
1290 spin_lock_irqsave(&ha->hardware_lock, flags);
1291
1292 /* Clear outstanding commands array. */
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001293 for (que = 0; que < ha->max_queues; que++) {
1294 req = ha->req_q_map[que];
1295 if (!req)
1296 continue;
1297 for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
1298 req->outstanding_cmds[cnt] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001299
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001300 req->current_outstanding_cmd = 0;
1301
1302 /* Initialize firmware. */
1303 req->ring_ptr = req->ring;
1304 req->ring_index = 0;
1305 req->cnt = req->length;
1306 }
1307
1308 for (que = 0; que < ha->max_queues; que++) {
1309 rsp = ha->rsp_q_map[que];
1310 if (!rsp)
1311 continue;
1312 rsp->ring_ptr = rsp->ring;
1313 rsp->ring_index = 0;
1314
1315 /* Initialize response queue entries */
1316 qla2x00_init_response_q_entries(rsp);
1317 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318
1319 /* Clear RSCN queue. */
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001320 list_for_each_entry(vp, &ha->vp_list, list) {
1321 vp->rscn_in_ptr = 0;
1322 vp->rscn_out_ptr = 0;
1323 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001324 ha->isp_ops->config_rings(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
1326 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1327
1328 /* Update any ISP specific firmware options before initialization. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001329 ha->isp_ops->update_fw_options(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001330
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001331 DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001332
Lalit Chandivade605aa2b2009-03-05 11:07:01 -08001333 if (ha->flags.npiv_supported) {
1334 if (ha->operating_mode == LOOP)
1335 ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1;
Seokmann Juc48339d2008-01-17 09:02:19 -08001336 mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
Lalit Chandivade605aa2b2009-03-05 11:07:01 -08001337 }
1338
Seokmann Juc48339d2008-01-17 09:02:19 -08001339
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001340 mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001341
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001342 rval = qla2x00_init_firmware(vha, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343 if (rval) {
1344 DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001345 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001346 } else {
1347 DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001348 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 }
1350
1351 return (rval);
1352}
1353
1354/**
1355 * qla2x00_fw_ready() - Waits for firmware ready.
1356 * @ha: HA context
1357 *
1358 * Returns 0 on success.
1359 */
1360static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001361qla2x00_fw_ready(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362{
1363 int rval;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001364 unsigned long wtime, mtime, cs84xx_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 uint16_t min_wait; /* Minimum wait time if loop is down */
1366 uint16_t wait_time; /* Wait time if loop is coming ready */
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001367 uint16_t state[3];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001368 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370 rval = QLA_SUCCESS;
1371
1372 /* 20 seconds for loop down. */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001373 min_wait = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374
1375 /*
1376 * Firmware should take at most one RATOV to login, plus 5 seconds for
1377 * our own processing.
1378 */
1379 if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
1380 wait_time = min_wait;
1381 }
1382
1383 /* Min wait time if loop down */
1384 mtime = jiffies + (min_wait * HZ);
1385
1386 /* wait time before firmware ready */
1387 wtime = jiffies + (wait_time * HZ);
1388
1389 /* Wait for ISP to finish LIP */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001390 if (!vha->flags.init_done)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
1392
1393 DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001394 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001395
1396 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001397 rval = qla2x00_get_firmware_state(vha, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398 if (rval == QLA_SUCCESS) {
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001399 if (state[0] < FSTATE_LOSS_OF_SYNC) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001400 vha->device_flags &= ~DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 }
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001402 if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
1403 DEBUG16(printk("scsi(%ld): fw_state=%x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001404 "84xx=%x.\n", vha->host_no, state[0],
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001405 state[2]));
1406 if ((state[2] & FSTATE_LOGGED_IN) &&
1407 (state[2] & FSTATE_WAITING_FOR_VERIFY)) {
1408 DEBUG16(printk("scsi(%ld): Sending "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001409 "verify iocb.\n", vha->host_no));
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001410
1411 cs84xx_time = jiffies;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001412 rval = qla84xx_init_chip(vha);
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001413 if (rval != QLA_SUCCESS)
1414 break;
1415
1416 /* Add time taken to initialize. */
1417 cs84xx_time = jiffies - cs84xx_time;
1418 wtime += cs84xx_time;
1419 mtime += cs84xx_time;
1420 DEBUG16(printk("scsi(%ld): Increasing "
1421 "wait time by %ld. New time %ld\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001422 vha->host_no, cs84xx_time, wtime));
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001423 }
1424 } else if (state[0] == FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425 DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001426 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001428 qla2x00_get_retry_cnt(vha, &ha->retry_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429 &ha->login_timeout, &ha->r_a_tov);
1430
1431 rval = QLA_SUCCESS;
1432 break;
1433 }
1434
1435 rval = QLA_FUNCTION_FAILED;
1436
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001437 if (atomic_read(&vha->loop_down_timer) &&
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001438 state[0] != FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 /* Loop down. Timeout on min_wait for states
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001440 * other than Wait for Login.
1441 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 if (time_after_eq(jiffies, mtime)) {
1443 qla_printk(KERN_INFO, ha,
1444 "Cable is unplugged...\n");
1445
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001446 vha->device_flags |= DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001447 break;
1448 }
1449 }
1450 } else {
1451 /* Mailbox cmd failed. Timeout on min_wait. */
1452 if (time_after_eq(jiffies, mtime))
1453 break;
1454 }
1455
1456 if (time_after_eq(jiffies, wtime))
1457 break;
1458
1459 /* Delay for a while */
1460 msleep(500);
1461
1462 DEBUG3(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 } while (1);
1465
1466 DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001467 vha->host_no, state[0], jiffies));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468
1469 if (rval) {
1470 DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001471 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 }
1473
1474 return (rval);
1475}
1476
1477/*
1478* qla2x00_configure_hba
1479* Setup adapter context.
1480*
1481* Input:
1482* ha = adapter state pointer.
1483*
1484* Returns:
1485* 0 = success
1486*
1487* Context:
1488* Kernel context.
1489*/
1490static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001491qla2x00_configure_hba(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492{
1493 int rval;
1494 uint16_t loop_id;
1495 uint16_t topo;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001496 uint16_t sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 uint8_t al_pa;
1498 uint8_t area;
1499 uint8_t domain;
1500 char connect_type[22];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001501 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 /* Get host addresses. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001504 rval = qla2x00_get_adapter_id(vha,
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001505 &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 if (rval != QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001507 if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
Ravi Anand33135aa2005-11-08 14:37:20 -08001508 (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
1509 DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001510 __func__, vha->host_no));
Ravi Anand33135aa2005-11-08 14:37:20 -08001511 } else {
1512 qla_printk(KERN_WARNING, ha,
1513 "ERROR -- Unable to get host loop ID.\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001514 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Ravi Anand33135aa2005-11-08 14:37:20 -08001515 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516 return (rval);
1517 }
1518
1519 if (topo == 4) {
1520 qla_printk(KERN_INFO, ha,
1521 "Cannot get topology - retrying.\n");
1522 return (QLA_FUNCTION_FAILED);
1523 }
1524
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001525 vha->loop_id = loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
1527 /* initialize */
1528 ha->min_external_loopid = SNS_FIRST_LOOP_ID;
1529 ha->operating_mode = LOOP;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001530 ha->switch_cap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
1532 switch (topo) {
1533 case 0:
1534 DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001535 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 ha->current_topology = ISP_CFG_NL;
1537 strcpy(connect_type, "(Loop)");
1538 break;
1539
1540 case 1:
1541 DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001542 vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001543 ha->switch_cap = sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 ha->current_topology = ISP_CFG_FL;
1545 strcpy(connect_type, "(FL_Port)");
1546 break;
1547
1548 case 2:
1549 DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001550 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551 ha->operating_mode = P2P;
1552 ha->current_topology = ISP_CFG_N;
1553 strcpy(connect_type, "(N_Port-to-N_Port)");
1554 break;
1555
1556 case 3:
1557 DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001558 vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001559 ha->switch_cap = sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560 ha->operating_mode = P2P;
1561 ha->current_topology = ISP_CFG_F;
1562 strcpy(connect_type, "(F_Port)");
1563 break;
1564
1565 default:
1566 DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
1567 "Using NL.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001568 vha->host_no, topo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 ha->current_topology = ISP_CFG_NL;
1570 strcpy(connect_type, "(Loop)");
1571 break;
1572 }
1573
1574 /* Save Host port and loop ID. */
1575 /* byte order - Big Endian */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001576 vha->d_id.b.domain = domain;
1577 vha->d_id.b.area = area;
1578 vha->d_id.b.al_pa = al_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001579
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001580 if (!vha->flags.init_done)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 qla_printk(KERN_INFO, ha,
1582 "Topology - %s, Host Loop address 0x%x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001583 connect_type, vha->loop_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584
1585 if (rval) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001586 DEBUG2_3(printk("scsi(%ld): FAILED.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001587 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001588 DEBUG3(printk("scsi(%ld): exiting normally.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001589 }
1590
1591 return(rval);
1592}
1593
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001594static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001595qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
1596 char *def)
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001597{
1598 char *st, *en;
1599 uint16_t index;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001600 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001601
1602 if (memcmp(model, BINZERO, len) != 0) {
1603 strncpy(ha->model_number, model, len);
1604 st = en = ha->model_number;
1605 en += len - 1;
1606 while (en > st) {
1607 if (*en != 0x20 && *en != 0x00)
1608 break;
1609 *en-- = '\0';
1610 }
1611
1612 index = (ha->pdev->subsystem_device & 0xff);
1613 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1614 index < QLA_MODEL_NAMES)
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001615 strncpy(ha->model_desc,
1616 qla2x00_model_name[index * 2 + 1],
1617 sizeof(ha->model_desc) - 1);
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001618 } else {
1619 index = (ha->pdev->subsystem_device & 0xff);
1620 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
1621 index < QLA_MODEL_NAMES) {
1622 strcpy(ha->model_number,
1623 qla2x00_model_name[index * 2]);
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001624 strncpy(ha->model_desc,
1625 qla2x00_model_name[index * 2 + 1],
1626 sizeof(ha->model_desc) - 1);
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001627 } else {
1628 strcpy(ha->model_number, def);
1629 }
1630 }
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001631 if (IS_FWI2_CAPABLE(ha))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001632 qla2xxx_get_vpd_field(vha, "\x82", ha->model_desc,
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001633 sizeof(ha->model_desc));
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001634}
1635
David Miller4e08df32007-04-16 12:37:43 -07001636/* On sparc systems, obtain port and node WWN from firmware
1637 * properties.
1638 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001639static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *vha, nvram_t *nv)
David Miller4e08df32007-04-16 12:37:43 -07001640{
1641#ifdef CONFIG_SPARC
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001642 struct qla_hw_data *ha = vha->hw;
David Miller4e08df32007-04-16 12:37:43 -07001643 struct pci_dev *pdev = ha->pdev;
David S. Miller15576bc2007-05-08 00:36:49 -07001644 struct device_node *dp = pci_device_to_OF_node(pdev);
1645 const u8 *val;
David Miller4e08df32007-04-16 12:37:43 -07001646 int len;
1647
1648 val = of_get_property(dp, "port-wwn", &len);
1649 if (val && len >= WWN_SIZE)
1650 memcpy(nv->port_name, val, WWN_SIZE);
1651
1652 val = of_get_property(dp, "node-wwn", &len);
1653 if (val && len >= WWN_SIZE)
1654 memcpy(nv->node_name, val, WWN_SIZE);
1655#endif
1656}
1657
Linus Torvalds1da177e2005-04-16 15:20:36 -07001658/*
1659* NVRAM configuration for ISP 2xxx
1660*
1661* Input:
1662* ha = adapter block pointer.
1663*
1664* Output:
1665* initialization control block in response_ring
1666* host adapters parameters in host adapter block
1667*
1668* Returns:
1669* 0 = success.
1670*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001671int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001672qla2x00_nvram_config(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673{
David Miller4e08df32007-04-16 12:37:43 -07001674 int rval;
Andrew Vasquez01071092005-07-06 10:31:37 -07001675 uint8_t chksum = 0;
1676 uint16_t cnt;
1677 uint8_t *dptr1, *dptr2;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001678 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07001679 init_cb_t *icb = ha->init_cb;
Seokmann Ju281afe12007-07-26 13:43:34 -07001680 nvram_t *nv = ha->nvram;
1681 uint8_t *ptr = ha->nvram;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001682 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001683
David Miller4e08df32007-04-16 12:37:43 -07001684 rval = QLA_SUCCESS;
1685
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 /* Determine NVRAM starting address. */
Andrew Vasquez01071092005-07-06 10:31:37 -07001687 ha->nvram_size = sizeof(nvram_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001688 ha->nvram_base = 0;
1689 if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
1690 if ((RD_REG_WORD(&reg->ctrl_status) >> 14) == 1)
1691 ha->nvram_base = 0x80;
1692
1693 /* Get NVRAM data and calculate checksum. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001694 ha->isp_ops->read_nvram(vha, ptr, ha->nvram_base, ha->nvram_size);
Andrew Vasquez01071092005-07-06 10:31:37 -07001695 for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
1696 chksum += *ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001697
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001698 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
Seokmann Ju281afe12007-07-26 13:43:34 -07001699 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700
1701 /* Bad NVRAM data, set defaults parameters. */
1702 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
1703 nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
1704 /* Reset NVRAM data. */
1705 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
1706 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
1707 nv->nvram_version);
David Miller4e08df32007-04-16 12:37:43 -07001708 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
1709 "invalid -- WWPN) defaults.\n");
1710
1711 /*
1712 * Set default initialization control block.
1713 */
1714 memset(nv, 0, ha->nvram_size);
1715 nv->parameter_block_version = ICB_VERSION;
1716
1717 if (IS_QLA23XX(ha)) {
1718 nv->firmware_options[0] = BIT_2 | BIT_1;
1719 nv->firmware_options[1] = BIT_7 | BIT_5;
1720 nv->add_firmware_options[0] = BIT_5;
1721 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1722 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1723 nv->special_options[1] = BIT_7;
1724 } else if (IS_QLA2200(ha)) {
1725 nv->firmware_options[0] = BIT_2 | BIT_1;
1726 nv->firmware_options[1] = BIT_7 | BIT_5;
1727 nv->add_firmware_options[0] = BIT_5;
1728 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1729 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1730 } else if (IS_QLA2100(ha)) {
1731 nv->firmware_options[0] = BIT_3 | BIT_1;
1732 nv->firmware_options[1] = BIT_5;
1733 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1734 }
1735
1736 nv->max_iocb_allocation = __constant_cpu_to_le16(256);
1737 nv->execution_throttle = __constant_cpu_to_le16(16);
1738 nv->retry_count = 8;
1739 nv->retry_delay = 1;
1740
1741 nv->port_name[0] = 33;
1742 nv->port_name[3] = 224;
1743 nv->port_name[4] = 139;
1744
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001745 qla2xxx_nvram_wwn_from_ofw(vha, nv);
David Miller4e08df32007-04-16 12:37:43 -07001746
1747 nv->login_timeout = 4;
1748
1749 /*
1750 * Set default host adapter parameters
1751 */
1752 nv->host_p[1] = BIT_2;
1753 nv->reset_delay = 5;
1754 nv->port_down_retry_count = 8;
1755 nv->max_luns_per_target = __constant_cpu_to_le16(8);
1756 nv->link_down_timeout = 60;
1757
1758 rval = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759 }
1760
1761#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
1762 /*
1763 * The SN2 does not provide BIOS emulation which means you can't change
1764 * potentially bogus BIOS settings. Force the use of default settings
1765 * for link rate and frame size. Hope that the rest of the settings
1766 * are valid.
1767 */
1768 if (ia64_platform_is("sn2")) {
1769 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1770 if (IS_QLA23XX(ha))
1771 nv->special_options[1] = BIT_7;
1772 }
1773#endif
1774
1775 /* Reset Initialization control block */
Andrew Vasquez01071092005-07-06 10:31:37 -07001776 memset(icb, 0, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777
1778 /*
1779 * Setup driver NVRAM options.
1780 */
1781 nv->firmware_options[0] |= (BIT_6 | BIT_1);
1782 nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
1783 nv->firmware_options[1] |= (BIT_5 | BIT_0);
1784 nv->firmware_options[1] &= ~BIT_4;
1785
1786 if (IS_QLA23XX(ha)) {
1787 nv->firmware_options[0] |= BIT_2;
1788 nv->firmware_options[0] &= ~BIT_3;
Andrew Vasquez01071092005-07-06 10:31:37 -07001789 nv->add_firmware_options[1] |= BIT_5 | BIT_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790
1791 if (IS_QLA2300(ha)) {
1792 if (ha->fb_rev == FPM_2310) {
1793 strcpy(ha->model_number, "QLA2310");
1794 } else {
1795 strcpy(ha->model_number, "QLA2300");
1796 }
1797 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001798 qla2x00_set_model_info(vha, nv->model_number,
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001799 sizeof(nv->model_number), "QLA23xx");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 }
1801 } else if (IS_QLA2200(ha)) {
1802 nv->firmware_options[0] |= BIT_2;
1803 /*
1804 * 'Point-to-point preferred, else loop' is not a safe
1805 * connection mode setting.
1806 */
1807 if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
1808 (BIT_5 | BIT_4)) {
1809 /* Force 'loop preferred, else point-to-point'. */
1810 nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
1811 nv->add_firmware_options[0] |= BIT_5;
1812 }
1813 strcpy(ha->model_number, "QLA22xx");
1814 } else /*if (IS_QLA2100(ha))*/ {
1815 strcpy(ha->model_number, "QLA2100");
1816 }
1817
1818 /*
1819 * Copy over NVRAM RISC parameter block to initialization control block.
1820 */
1821 dptr1 = (uint8_t *)icb;
1822 dptr2 = (uint8_t *)&nv->parameter_block_version;
1823 cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
1824 while (cnt--)
1825 *dptr1++ = *dptr2++;
1826
1827 /* Copy 2nd half. */
1828 dptr1 = (uint8_t *)icb->add_firmware_options;
1829 cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
1830 while (cnt--)
1831 *dptr1++ = *dptr2++;
1832
Andrew Vasquez5341e862006-05-17 15:09:16 -07001833 /* Use alternate WWN? */
1834 if (nv->host_p[1] & BIT_7) {
1835 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
1836 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
1837 }
1838
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 /* Prepare nodename */
1840 if ((icb->firmware_options[1] & BIT_6) == 0) {
1841 /*
1842 * Firmware will apply the following mask if the nodename was
1843 * not provided.
1844 */
1845 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
1846 icb->node_name[0] &= 0xF0;
1847 }
1848
1849 /*
1850 * Set host adapter parameters.
1851 */
Andrew Vasquez01819442006-06-23 16:11:10 -07001852 if (nv->host_p[0] & BIT_7)
Andrew Vasquez11010fe2006-10-06 09:54:59 -07001853 ql2xextended_error_logging = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
1855 /* Always load RISC code on non ISP2[12]00 chips. */
1856 if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
1857 ha->flags.disable_risc_code_load = 0;
1858 ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
1859 ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
1860 ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
Andrew Vasquez06c22bd2005-08-26 19:09:00 -07001861 ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07001862 ha->flags.disable_serdes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
1864 ha->operating_mode =
1865 (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
1866
1867 memcpy(ha->fw_seriallink_options, nv->seriallink_options,
1868 sizeof(ha->fw_seriallink_options));
1869
1870 /* save HBA serial number */
1871 ha->serial0 = icb->port_name[5];
1872 ha->serial1 = icb->port_name[6];
1873 ha->serial2 = icb->port_name[7];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001874 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
1875 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876
1877 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
1878
1879 ha->retry_count = nv->retry_count;
1880
1881 /* Set minimum login_timeout to 4 seconds. */
1882 if (nv->login_timeout < ql2xlogintimeout)
1883 nv->login_timeout = ql2xlogintimeout;
1884 if (nv->login_timeout < 4)
1885 nv->login_timeout = 4;
1886 ha->login_timeout = nv->login_timeout;
1887 icb->login_timeout = nv->login_timeout;
1888
Andrew Vasquez00a537b2008-02-28 14:06:11 -08001889 /* Set minimum RATOV to 100 tenths of a second. */
1890 ha->r_a_tov = 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 ha->loop_reset_delay = nv->reset_delay;
1893
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 /* Link Down Timeout = 0:
1895 *
1896 * When Port Down timer expires we will start returning
1897 * I/O's to OS with "DID_NO_CONNECT".
1898 *
1899 * Link Down Timeout != 0:
1900 *
1901 * The driver waits for the link to come up after link down
1902 * before returning I/Os to OS with "DID_NO_CONNECT".
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001903 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001904 if (nv->link_down_timeout == 0) {
1905 ha->loop_down_abort_time =
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001906 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001907 } else {
1908 ha->link_down_timeout = nv->link_down_timeout;
1909 ha->loop_down_abort_time =
1910 (LOOP_DOWN_TIME - ha->link_down_timeout);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001911 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 /*
1914 * Need enough time to try and get the port back.
1915 */
1916 ha->port_down_retry_count = nv->port_down_retry_count;
1917 if (qlport_down_retry)
1918 ha->port_down_retry_count = qlport_down_retry;
1919 /* Set login_retry_count */
1920 ha->login_retry_count = nv->retry_count;
1921 if (ha->port_down_retry_count == nv->port_down_retry_count &&
1922 ha->port_down_retry_count > 3)
1923 ha->login_retry_count = ha->port_down_retry_count;
1924 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
1925 ha->login_retry_count = ha->port_down_retry_count;
1926 if (ql2xloginretrycount)
1927 ha->login_retry_count = ql2xloginretrycount;
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 icb->lun_enables = __constant_cpu_to_le16(0);
1930 icb->command_resource_count = 0;
1931 icb->immediate_notify_resource_count = 0;
1932 icb->timeout = __constant_cpu_to_le16(0);
1933
1934 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
1935 /* Enable RIO */
1936 icb->firmware_options[0] &= ~BIT_3;
1937 icb->add_firmware_options[0] &=
1938 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
1939 icb->add_firmware_options[0] |= BIT_2;
1940 icb->response_accumulation_timer = 3;
1941 icb->interrupt_delay_timer = 5;
1942
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001943 vha->flags.process_response_queue = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 } else {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001945 /* Enable ZIO. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001946 if (!vha->flags.init_done) {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001947 ha->zio_mode = icb->add_firmware_options[0] &
1948 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
1949 ha->zio_timer = icb->interrupt_delay_timer ?
1950 icb->interrupt_delay_timer: 2;
1951 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 icb->add_firmware_options[0] &=
1953 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001954 vha->flags.process_response_queue = 0;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001955 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08001956 ha->zio_mode = QLA_ZIO_MODE_6;
1957
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001958 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001959 "delay (%d us).\n", vha->host_no, ha->zio_mode,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001960 ha->zio_timer * 100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001961 qla_printk(KERN_INFO, ha,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001962 "ZIO mode %d enabled; timer delay (%d us).\n",
1963 ha->zio_mode, ha->zio_timer * 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07001965 icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
1966 icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001967 vha->flags.process_response_queue = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968 }
1969 }
1970
David Miller4e08df32007-04-16 12:37:43 -07001971 if (rval) {
1972 DEBUG2_3(printk(KERN_WARNING
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001973 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
David Miller4e08df32007-04-16 12:37:43 -07001974 }
1975 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976}
1977
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001978static void
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001979qla2x00_rport_del(void *data)
1980{
1981 fc_port_t *fcport = data;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001982 struct fc_rport *rport;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001983
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001984 spin_lock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001985 rport = fcport->drport;
1986 fcport->drport = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001987 spin_unlock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08001988 if (rport)
1989 fc_remote_port_delete(rport);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04001990}
1991
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992/**
1993 * qla2x00_alloc_fcport() - Allocate a generic fcport.
1994 * @ha: HA context
1995 * @flags: allocation flags
1996 *
1997 * Returns a pointer to the allocated fcport, or NULL, if none available.
1998 */
Adrian Bunk413975a2006-06-30 02:33:06 -07001999static fc_port_t *
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002000qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
2002 fc_port_t *fcport;
2003
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002004 fcport = kzalloc(sizeof(fc_port_t), flags);
2005 if (!fcport)
2006 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
2008 /* Setup fcport template structure. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002009 fcport->vha = vha;
2010 fcport->vp_idx = vha->vp_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 fcport->port_type = FCT_UNKNOWN;
2012 fcport->loop_id = FC_NO_LOOP_ID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002013 atomic_set(&fcport->state, FCS_UNCONFIGURED);
2014 fcport->flags = FCF_RLC_SUPPORT;
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002015 fcport->supported_classes = FC_COS_UNSPECIFIED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002017 return fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018}
2019
2020/*
2021 * qla2x00_configure_loop
2022 * Updates Fibre Channel Device Database with what is actually on loop.
2023 *
2024 * Input:
2025 * ha = adapter block pointer.
2026 *
2027 * Returns:
2028 * 0 = success.
2029 * 1 = error.
2030 * 2 = database was full and device was not configured.
2031 */
2032static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002033qla2x00_configure_loop(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034{
2035 int rval;
2036 unsigned long flags, save_flags;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002037 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038 rval = QLA_SUCCESS;
2039
2040 /* Get Initiator ID */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002041 if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) {
2042 rval = qla2x00_configure_hba(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043 if (rval != QLA_SUCCESS) {
2044 DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002045 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 return (rval);
2047 }
2048 }
2049
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002050 save_flags = flags = vha->dpc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002051 DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002052 vha->host_no, flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053
2054 /*
2055 * If we have both an RSCN and PORT UPDATE pending then handle them
2056 * both at the same time.
2057 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002058 clear_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
2059 clear_bit(RSCN_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060
2061 /* Determine what we need to do */
2062 if (ha->current_topology == ISP_CFG_FL &&
2063 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
2064
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002065 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 set_bit(RSCN_UPDATE, &flags);
2067
2068 } else if (ha->current_topology == ISP_CFG_F &&
2069 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
2070
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002071 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002072 set_bit(RSCN_UPDATE, &flags);
2073 clear_bit(LOCAL_LOOP_UPDATE, &flags);
2074
Andrew Vasquez21333b42006-05-17 15:09:56 -07002075 } else if (ha->current_topology == ISP_CFG_N) {
2076 clear_bit(RSCN_UPDATE, &flags);
2077
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002078 } else if (!vha->flags.online ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079 (test_bit(ABORT_ISP_ACTIVE, &flags))) {
2080
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002081 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 set_bit(RSCN_UPDATE, &flags);
2083 set_bit(LOCAL_LOOP_UPDATE, &flags);
2084 }
2085
2086 if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002087 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002088 rval = QLA_FUNCTION_FAILED;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002089 else
2090 rval = qla2x00_configure_local_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 }
2092
2093 if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002094 if (LOOP_TRANSITION(vha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002095 rval = QLA_FUNCTION_FAILED;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002096 else
2097 rval = qla2x00_configure_fabric(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002098 }
2099
2100 if (rval == QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002101 if (atomic_read(&vha->loop_down_timer) ||
2102 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 rval = QLA_FUNCTION_FAILED;
2104 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002105 atomic_set(&vha->loop_state, LOOP_READY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002107 DEBUG(printk("scsi(%ld): LOOP READY\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 }
2109 }
2110
2111 if (rval) {
2112 DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002113 __func__, vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 } else {
2115 DEBUG3(printk("%s: exiting normally\n", __func__));
2116 }
2117
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -07002118 /* Restore state if a resync event occurred during processing */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002119 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120 if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002121 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002122 if (test_bit(RSCN_UPDATE, &save_flags))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002123 set_bit(RSCN_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 }
2125
2126 return (rval);
2127}
2128
2129
2130
2131/*
2132 * qla2x00_configure_local_loop
2133 * Updates Fibre Channel Device Database with local loop devices.
2134 *
2135 * Input:
2136 * ha = adapter block pointer.
2137 *
2138 * Returns:
2139 * 0 = success.
2140 */
2141static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002142qla2x00_configure_local_loop(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002143{
2144 int rval, rval2;
2145 int found_devs;
2146 int found;
2147 fc_port_t *fcport, *new_fcport;
2148
2149 uint16_t index;
2150 uint16_t entries;
2151 char *id_iter;
2152 uint16_t loop_id;
2153 uint8_t domain, area, al_pa;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002154 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
2156 found_devs = 0;
2157 new_fcport = NULL;
2158 entries = MAX_FIBRE_DEVICES;
2159
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002160 DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", vha->host_no));
2161 DEBUG3(qla2x00_get_fcal_position_map(vha, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
2163 /* Get list of logged in devices. */
2164 memset(ha->gid_list, 0, GID_LIST_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002165 rval = qla2x00_get_id_list(vha, ha->gid_list, ha->gid_list_dma,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 &entries);
2167 if (rval != QLA_SUCCESS)
2168 goto cleanup_allocation;
2169
2170 DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
2171 ha->host_no, entries));
2172 DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
2173 entries * sizeof(struct gid_list_info)));
2174
2175 /* Allocate temporary fcport for any new fcports discovered. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002176 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 if (new_fcport == NULL) {
2178 rval = QLA_MEMORY_ALLOC_FAILED;
2179 goto cleanup_allocation;
2180 }
2181 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2182
2183 /*
2184 * Mark local devices that were present with FCF_DEVICE_LOST for now.
2185 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002186 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 if (atomic_read(&fcport->state) == FCS_ONLINE &&
2188 fcport->port_type != FCT_BROADCAST &&
2189 (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
2190
2191 DEBUG(printk("scsi(%ld): Marking port lost, "
2192 "loop_id=0x%04x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002193 vha->host_no, fcport->loop_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194
2195 atomic_set(&fcport->state, FCS_DEVICE_LOST);
2196 fcport->flags &= ~FCF_FARP_DONE;
2197 }
2198 }
2199
2200 /* Add devices to port list. */
2201 id_iter = (char *)ha->gid_list;
2202 for (index = 0; index < entries; index++) {
2203 domain = ((struct gid_list_info *)id_iter)->domain;
2204 area = ((struct gid_list_info *)id_iter)->area;
2205 al_pa = ((struct gid_list_info *)id_iter)->al_pa;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002206 if (IS_QLA2100(ha) || IS_QLA2200(ha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207 loop_id = (uint16_t)
2208 ((struct gid_list_info *)id_iter)->loop_id_2100;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002209 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 loop_id = le16_to_cpu(
2211 ((struct gid_list_info *)id_iter)->loop_id);
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002212 id_iter += ha->gid_list_info_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213
2214 /* Bypass reserved domain fields. */
2215 if ((domain & 0xf0) == 0xf0)
2216 continue;
2217
2218 /* Bypass if not same domain and area of adapter. */
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002219 if (area && domain &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002220 (area != vha->d_id.b.area || domain != vha->d_id.b.domain))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 continue;
2222
2223 /* Bypass invalid local loop ID. */
2224 if (loop_id > LAST_LOCAL_LOOP_ID)
2225 continue;
2226
2227 /* Fill in member data. */
2228 new_fcport->d_id.b.domain = domain;
2229 new_fcport->d_id.b.area = area;
2230 new_fcport->d_id.b.al_pa = al_pa;
2231 new_fcport->loop_id = loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002232 new_fcport->vp_idx = vha->vp_idx;
2233 rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002234 if (rval2 != QLA_SUCCESS) {
2235 DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
2236 "information -- get_port_database=%x, "
2237 "loop_id=0x%04x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002238 vha->host_no, rval2, new_fcport->loop_id));
andrew.vasquez@qlogic.comc9d02ac2006-01-13 17:05:26 -08002239 DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002240 vha->host_no));
2241 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002242 continue;
2243 }
2244
2245 /* Check for matching device in port list. */
2246 found = 0;
2247 fcport = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002248 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 if (memcmp(new_fcport->port_name, fcport->port_name,
2250 WWN_SIZE))
2251 continue;
2252
2253 fcport->flags &= ~(FCF_FABRIC_DEVICE |
2254 FCF_PERSISTENT_BOUND);
2255 fcport->loop_id = new_fcport->loop_id;
2256 fcport->port_type = new_fcport->port_type;
2257 fcport->d_id.b24 = new_fcport->d_id.b24;
2258 memcpy(fcport->node_name, new_fcport->node_name,
2259 WWN_SIZE);
2260
2261 found++;
2262 break;
2263 }
2264
2265 if (!found) {
2266 /* New device, add to fcports list. */
2267 new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002268 if (vha->vp_idx) {
2269 new_fcport->vha = vha;
2270 new_fcport->vp_idx = vha->vp_idx;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002271 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002272 list_add_tail(&new_fcport->list, &vha->vp_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002273
2274 /* Allocate a new replacement fcport. */
2275 fcport = new_fcport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002276 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002277 if (new_fcport == NULL) {
2278 rval = QLA_MEMORY_ALLOC_FAILED;
2279 goto cleanup_allocation;
2280 }
2281 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2282 }
2283
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002284 /* Base iIDMA settings on HBA port speed. */
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002285 fcport->fp_speed = ha->link_data_rate;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002286
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002287 qla2x00_update_fcport(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002288
2289 found_devs++;
2290 }
2291
2292cleanup_allocation:
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002293 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002294
2295 if (rval != QLA_SUCCESS) {
2296 DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002297 "rval=%x\n", vha->host_no, rval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 }
2299
2300 if (found_devs) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002301 vha->device_flags |= DFLG_LOCAL_DEVICES;
2302 vha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303 }
2304
2305 return (rval);
2306}
2307
2308static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002309qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002310{
2311#define LS_UNKNOWN 2
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002312 static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002313 int rval;
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002314 uint16_t mb[6];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002315 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002316
Andrew Vasquezc76f2c02007-07-19 15:05:57 -07002317 if (!IS_IIDMA_CAPABLE(ha))
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002318 return;
2319
Andrew Vasquez39bd9622007-09-20 14:07:34 -07002320 if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
2321 fcport->fp_speed > ha->link_data_rate)
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002322 return;
2323
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002324 rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002325 mb);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002326 if (rval != QLA_SUCCESS) {
2327 DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
2328 "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002329 vha->host_no, fcport->port_name[0], fcport->port_name[1],
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002330 fcport->port_name[2], fcport->port_name[3],
2331 fcport->port_name[4], fcport->port_name[5],
2332 fcport->port_name[6], fcport->port_name[7], rval,
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002333 fcport->fp_speed, mb[0], mb[1]));
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002334 } else {
2335 DEBUG2(qla_printk(KERN_INFO, ha,
2336 "iIDMA adjusted to %s GB/s on "
2337 "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002338 link_speeds[fcport->fp_speed], fcport->port_name[0],
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002339 fcport->port_name[1], fcport->port_name[2],
2340 fcport->port_name[3], fcport->port_name[4],
2341 fcport->port_name[5], fcport->port_name[6],
2342 fcport->port_name[7]));
2343 }
2344}
2345
Adrian Bunk23be3312006-11-24 02:46:01 +01002346static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002347qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
8482e112005-04-17 15:04:54 -05002348{
2349 struct fc_rport_identifiers rport_ids;
bdf79622005-04-17 15:06:53 -05002350 struct fc_rport *rport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002351 struct qla_hw_data *ha = vha->hw;
8482e112005-04-17 15:04:54 -05002352
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002353 if (fcport->drport)
2354 qla2x00_rport_del(fcport);
8482e112005-04-17 15:04:54 -05002355
Andrew Vasquezf8b02a82005-08-31 15:21:20 -07002356 rport_ids.node_name = wwn_to_u64(fcport->node_name);
2357 rport_ids.port_name = wwn_to_u64(fcport->port_name);
8482e112005-04-17 15:04:54 -05002358 rport_ids.port_id = fcport->d_id.b.domain << 16 |
2359 fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
2360 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002361 fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids);
Andrew Vasquez77d74142005-07-08 18:00:36 -07002362 if (!rport) {
2363 qla_printk(KERN_WARNING, ha,
2364 "Unable to allocate fc remote port!\n");
2365 return;
2366 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002367 spin_lock_irq(fcport->vha->host->host_lock);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002368 *((fc_port_t **)rport->dd_data) = fcport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002369 spin_unlock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002370
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002371 rport->supported_classes = fcport->supported_classes;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002372
2373 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
8482e112005-04-17 15:04:54 -05002374 if (fcport->port_type == FCT_INITIATOR)
2375 rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
2376 if (fcport->port_type == FCT_TARGET)
2377 rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002378 fc_remote_port_rolechg(rport, rport_ids.roles);
8482e112005-04-17 15:04:54 -05002379}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380
2381/*
Adrian Bunk23be3312006-11-24 02:46:01 +01002382 * qla2x00_update_fcport
2383 * Updates device on list.
2384 *
2385 * Input:
2386 * ha = adapter block pointer.
2387 * fcport = port structure pointer.
2388 *
2389 * Return:
2390 * 0 - Success
2391 * BIT_0 - error
2392 *
2393 * Context:
2394 * Kernel context.
2395 */
2396void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002397qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
Adrian Bunk23be3312006-11-24 02:46:01 +01002398{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002399 struct qla_hw_data *ha = vha->hw;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002400
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002401 fcport->vha = vha;
Adrian Bunk23be3312006-11-24 02:46:01 +01002402 fcport->login_retry = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002403 fcport->port_login_retry_count = ha->port_down_retry_count *
Adrian Bunk23be3312006-11-24 02:46:01 +01002404 PORT_RETRY_TIME;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002405 atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
Adrian Bunk23be3312006-11-24 02:46:01 +01002406 PORT_RETRY_TIME);
2407 fcport->flags &= ~FCF_LOGIN_NEEDED;
2408
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002409 qla2x00_iidma_fcport(vha, fcport);
Adrian Bunk23be3312006-11-24 02:46:01 +01002410
2411 atomic_set(&fcport->state, FCS_ONLINE);
2412
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002413 qla2x00_reg_remote_port(vha, fcport);
Adrian Bunk23be3312006-11-24 02:46:01 +01002414}
2415
2416/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 * qla2x00_configure_fabric
2418 * Setup SNS devices with loop ID's.
2419 *
2420 * Input:
2421 * ha = adapter block pointer.
2422 *
2423 * Returns:
2424 * 0 = success.
2425 * BIT_0 = error
2426 */
2427static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002428qla2x00_configure_fabric(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429{
2430 int rval, rval2;
2431 fc_port_t *fcport, *fcptemp;
2432 uint16_t next_loopid;
2433 uint16_t mb[MAILBOX_REGISTER_COUNT];
Andrew Vasquez01071092005-07-06 10:31:37 -07002434 uint16_t loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 LIST_HEAD(new_fcports);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002436 struct qla_hw_data *ha = vha->hw;
2437 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
2439 /* If FL port exists, then SNS is present */
Andrew Vasqueze4289242007-07-19 15:05:56 -07002440 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez01071092005-07-06 10:31:37 -07002441 loop_id = NPH_F_PORT;
2442 else
2443 loop_id = SNS_FL_PORT;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002444 rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 if (rval != QLA_SUCCESS) {
2446 DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002447 "Port\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002449 vha->device_flags &= ~SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450 return (QLA_SUCCESS);
2451 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002452 vha->device_flags |= SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453
2454 /* Mark devices that need re-synchronization. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002455 rval2 = qla2x00_device_resync(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 if (rval2 == QLA_RSCNS_HANDLED) {
2457 /* No point doing the scan, just continue. */
2458 return (QLA_SUCCESS);
2459 }
2460 do {
Andrew Vasquezcca53352005-08-26 19:08:30 -07002461 /* FDMI support. */
2462 if (ql2xfdmienable &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002463 test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags))
2464 qla2x00_fdmi_register(vha);
Andrew Vasquezcca53352005-08-26 19:08:30 -07002465
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466 /* Ensure we are logged into the SNS. */
Andrew Vasqueze4289242007-07-19 15:05:56 -07002467 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez01071092005-07-06 10:31:37 -07002468 loop_id = NPH_SNS;
2469 else
2470 loop_id = SIMPLE_NAME_SERVER;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002471 ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002472 0xfc, mb, BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 if (mb[0] != MBS_COMMAND_COMPLETE) {
2474 DEBUG2(qla_printk(KERN_INFO, ha,
2475 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
Andrew Vasquez01071092005-07-06 10:31:37 -07002476 "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002477 mb[0], mb[1], mb[2], mb[6], mb[7]));
2478 return (QLA_SUCCESS);
2479 }
2480
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002481 if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
2482 if (qla2x00_rft_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 /* EMPTY */
2484 DEBUG2(printk("scsi(%ld): Register FC-4 "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002485 "TYPE failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002487 if (qla2x00_rff_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 /* EMPTY */
2489 DEBUG2(printk("scsi(%ld): Register FC-4 "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002490 "Features failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002491 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002492 if (qla2x00_rnn_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 /* EMPTY */
2494 DEBUG2(printk("scsi(%ld): Register Node Name "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002495 "failed.\n", vha->host_no));
2496 } else if (qla2x00_rsnn_nn(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002497 /* EMPTY */
2498 DEBUG2(printk("scsi(%ld): Register Symbolic "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002499 "Node Name failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002500 }
2501 }
2502
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002503 rval = qla2x00_find_all_fabric_devs(vha, &new_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504 if (rval != QLA_SUCCESS)
2505 break;
2506
2507 /*
2508 * Logout all previous fabric devices marked lost, except
2509 * tape devices.
2510 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002511 list_for_each_entry(fcport, &vha->vp_fcports, list) {
2512 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513 break;
2514
2515 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
2516 continue;
2517
2518 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002519 qla2x00_mark_device_lost(vha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002520 ql2xplogiabsentdevice, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 if (fcport->loop_id != FC_NO_LOOP_ID &&
2522 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2523 fcport->port_type != FCT_INITIATOR &&
2524 fcport->port_type != FCT_BROADCAST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002525 ha->isp_ops->fabric_logout(vha,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002526 fcport->loop_id,
2527 fcport->d_id.b.domain,
2528 fcport->d_id.b.area,
2529 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530 fcport->loop_id = FC_NO_LOOP_ID;
2531 }
2532 }
2533 }
2534
2535 /* Starting free loop ID. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002536 next_loopid = ha->min_external_loopid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
2538 /*
2539 * Scan through our port list and login entries that need to be
2540 * logged in.
2541 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002542 list_for_each_entry(fcport, &vha->vp_fcports, list) {
2543 if (atomic_read(&vha->loop_down_timer) ||
2544 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 break;
2546
2547 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2548 (fcport->flags & FCF_LOGIN_NEEDED) == 0)
2549 continue;
2550
2551 if (fcport->loop_id == FC_NO_LOOP_ID) {
2552 fcport->loop_id = next_loopid;
Seokmann Jud4486fd2008-04-03 13:13:28 -07002553 rval = qla2x00_find_new_loop_id(
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002554 base_vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 if (rval != QLA_SUCCESS) {
2556 /* Ran out of IDs to use */
2557 break;
2558 }
2559 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002560 /* Login and update database */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002561 qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 }
2563
2564 /* Exit if out of loop IDs. */
2565 if (rval != QLA_SUCCESS) {
2566 break;
2567 }
2568
2569 /*
2570 * Login and add the new devices to our port list.
2571 */
2572 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002573 if (atomic_read(&vha->loop_down_timer) ||
2574 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 break;
2576
2577 /* Find a new loop ID to use. */
2578 fcport->loop_id = next_loopid;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002579 rval = qla2x00_find_new_loop_id(base_vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 if (rval != QLA_SUCCESS) {
2581 /* Ran out of IDs to use */
2582 break;
2583 }
2584
bdf79622005-04-17 15:06:53 -05002585 /* Login and update database */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002586 qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002587
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002588 if (vha->vp_idx) {
2589 fcport->vha = vha;
2590 fcport->vp_idx = vha->vp_idx;
2591 }
2592 list_move_tail(&fcport->list, &vha->vp_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593 }
2594 } while (0);
2595
2596 /* Free all new device structures not processed. */
2597 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
2598 list_del(&fcport->list);
2599 kfree(fcport);
2600 }
2601
2602 if (rval) {
2603 DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002604 "rval=%d\n", vha->host_no, rval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605 }
2606
2607 return (rval);
2608}
2609
2610
2611/*
2612 * qla2x00_find_all_fabric_devs
2613 *
2614 * Input:
2615 * ha = adapter block pointer.
2616 * dev = database device entry pointer.
2617 *
2618 * Returns:
2619 * 0 = success.
2620 *
2621 * Context:
2622 * Kernel context.
2623 */
2624static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002625qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
2626 struct list_head *new_fcports)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627{
2628 int rval;
2629 uint16_t loop_id;
2630 fc_port_t *fcport, *new_fcport, *fcptemp;
2631 int found;
2632
2633 sw_info_t *swl;
2634 int swl_idx;
2635 int first_dev, last_dev;
2636 port_id_t wrap, nxt_d_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002637 struct qla_hw_data *ha = vha->hw;
2638 struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002639 struct scsi_qla_host *tvp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640
2641 rval = QLA_SUCCESS;
2642
2643 /* Try GID_PT to get device list, else GAN. */
Andrew Vasquez4b892582008-09-11 21:22:48 -07002644 swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002645 if (!swl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 /*EMPTY*/
2647 DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002648 "on GA_NXT\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002650 if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 kfree(swl);
2652 swl = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002653 } else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 kfree(swl);
2655 swl = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002656 } else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657 kfree(swl);
2658 swl = NULL;
Andrew Vasqueze5896bd2008-07-10 16:55:52 -07002659 } else if (ql2xiidmaenable &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002660 qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) {
2661 qla2x00_gpsc(vha, swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662 }
2663 }
2664 swl_idx = 0;
2665
2666 /* Allocate temporary fcport for any new fcports discovered. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002667 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002669 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 return (QLA_MEMORY_ALLOC_FAILED);
2671 }
2672 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002673 /* Set start port ID scan at adapter ID. */
2674 first_dev = 1;
2675 last_dev = 0;
2676
2677 /* Starting free loop ID. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002678 loop_id = ha->min_external_loopid;
2679 for (; loop_id <= ha->max_loop_id; loop_id++) {
2680 if (qla2x00_is_reserved_id(vha, loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681 continue;
2682
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002683 if (atomic_read(&vha->loop_down_timer) || LOOP_TRANSITION(vha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684 break;
2685
2686 if (swl != NULL) {
2687 if (last_dev) {
2688 wrap.b24 = new_fcport->d_id.b24;
2689 } else {
2690 new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
2691 memcpy(new_fcport->node_name,
2692 swl[swl_idx].node_name, WWN_SIZE);
2693 memcpy(new_fcport->port_name,
2694 swl[swl_idx].port_name, WWN_SIZE);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002695 memcpy(new_fcport->fabric_port_name,
2696 swl[swl_idx].fabric_port_name, WWN_SIZE);
2697 new_fcport->fp_speed = swl[swl_idx].fp_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
2699 if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
2700 last_dev = 1;
2701 }
2702 swl_idx++;
2703 }
2704 } else {
2705 /* Send GA_NXT to the switch */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002706 rval = qla2x00_ga_nxt(vha, new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 if (rval != QLA_SUCCESS) {
2708 qla_printk(KERN_WARNING, ha,
2709 "SNS scan failed -- assuming zero-entry "
2710 "result...\n");
2711 list_for_each_entry_safe(fcport, fcptemp,
2712 new_fcports, list) {
2713 list_del(&fcport->list);
2714 kfree(fcport);
2715 }
2716 rval = QLA_SUCCESS;
2717 break;
2718 }
2719 }
2720
2721 /* If wrap on switch device list, exit. */
2722 if (first_dev) {
2723 wrap.b24 = new_fcport->d_id.b24;
2724 first_dev = 0;
2725 } else if (new_fcport->d_id.b24 == wrap.b24) {
2726 DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002727 vha->host_no, new_fcport->d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
2729 break;
2730 }
2731
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002732 /* Bypass if same physical adapter. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002733 if (new_fcport->d_id.b24 == base_vha->d_id.b24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 continue;
2735
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002736 /* Bypass virtual ports of the same host. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002737 found = 0;
2738 if (ha->num_vhosts) {
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002739 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002740 if (new_fcport->d_id.b24 == vp->d_id.b24) {
2741 found = 1;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002742 break;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002743 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002744 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002745 if (found)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002746 continue;
2747 }
2748
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002749 /* Bypass if same domain and area of adapter. */
2750 if (((new_fcport->d_id.b24 & 0xffff00) ==
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002751 (vha->d_id.b24 & 0xffff00)) && ha->current_topology ==
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002752 ISP_CFG_FL)
2753 continue;
2754
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 /* Bypass reserved domain fields. */
2756 if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
2757 continue;
2758
2759 /* Locate matching device in database. */
2760 found = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002761 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 if (memcmp(new_fcport->port_name, fcport->port_name,
2763 WWN_SIZE))
2764 continue;
2765
2766 found++;
2767
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002768 /* Update port state. */
2769 memcpy(fcport->fabric_port_name,
2770 new_fcport->fabric_port_name, WWN_SIZE);
2771 fcport->fp_speed = new_fcport->fp_speed;
2772
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 /*
2774 * If address the same and state FCS_ONLINE, nothing
2775 * changed.
2776 */
2777 if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
2778 atomic_read(&fcport->state) == FCS_ONLINE) {
2779 break;
2780 }
2781
2782 /*
2783 * If device was not a fabric device before.
2784 */
2785 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
2786 fcport->d_id.b24 = new_fcport->d_id.b24;
2787 fcport->loop_id = FC_NO_LOOP_ID;
2788 fcport->flags |= (FCF_FABRIC_DEVICE |
2789 FCF_LOGIN_NEEDED);
2790 fcport->flags &= ~FCF_PERSISTENT_BOUND;
2791 break;
2792 }
2793
2794 /*
2795 * Port ID changed or device was marked to be updated;
2796 * Log it out if still logged in and mark it for
2797 * relogin later.
2798 */
2799 fcport->d_id.b24 = new_fcport->d_id.b24;
2800 fcport->flags |= FCF_LOGIN_NEEDED;
2801 if (fcport->loop_id != FC_NO_LOOP_ID &&
2802 (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
2803 fcport->port_type != FCT_INITIATOR &&
2804 fcport->port_type != FCT_BROADCAST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002805 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002806 fcport->d_id.b.domain, fcport->d_id.b.area,
2807 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 fcport->loop_id = FC_NO_LOOP_ID;
2809 }
2810
2811 break;
2812 }
2813
2814 if (found)
2815 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002816 /* If device was not in our fcports list, then add it. */
2817 list_add_tail(&new_fcport->list, new_fcports);
2818
2819 /* Allocate a new replacement fcport. */
2820 nxt_d_id.b24 = new_fcport->d_id.b24;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002821 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002823 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 return (QLA_MEMORY_ALLOC_FAILED);
2825 }
2826 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
2827 new_fcport->d_id.b24 = nxt_d_id.b24;
2828 }
2829
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002830 kfree(swl);
2831 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832
2833 if (!list_empty(new_fcports))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002834 vha->device_flags |= DFLG_FABRIC_DEVICES;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836 return (rval);
2837}
2838
2839/*
2840 * qla2x00_find_new_loop_id
2841 * Scan through our port list and find a new usable loop ID.
2842 *
2843 * Input:
2844 * ha: adapter state pointer.
2845 * dev: port structure pointer.
2846 *
2847 * Returns:
2848 * qla2x00 local function return status code.
2849 *
2850 * Context:
2851 * Kernel context.
2852 */
Adrian Bunk413975a2006-06-30 02:33:06 -07002853static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002854qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855{
2856 int rval;
2857 int found;
2858 fc_port_t *fcport;
2859 uint16_t first_loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002860 struct qla_hw_data *ha = vha->hw;
2861 struct scsi_qla_host *vp;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002862 struct scsi_qla_host *tvp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
2864 rval = QLA_SUCCESS;
2865
2866 /* Save starting loop ID. */
2867 first_loop_id = dev->loop_id;
2868
2869 for (;;) {
2870 /* Skip loop ID if already used by adapter. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002871 if (dev->loop_id == vha->loop_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 dev->loop_id++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873
2874 /* Skip reserved loop IDs. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002875 while (qla2x00_is_reserved_id(vha, dev->loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876 dev->loop_id++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
2878 /* Reset loop ID if passed the end. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002879 if (dev->loop_id > ha->max_loop_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 /* first loop ID. */
2881 dev->loop_id = ha->min_external_loopid;
2882 }
2883
2884 /* Check for loop ID being already in use. */
2885 found = 0;
2886 fcport = NULL;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002887 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002888 list_for_each_entry(fcport, &vp->vp_fcports, list) {
2889 if (fcport->loop_id == dev->loop_id &&
2890 fcport != dev) {
2891 /* ID possibly in use */
2892 found++;
2893 break;
2894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002895 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002896 if (found)
2897 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898 }
2899
2900 /* If not in use then it is free to use. */
2901 if (!found) {
2902 break;
2903 }
2904
2905 /* ID in use. Try next value. */
2906 dev->loop_id++;
2907
2908 /* If wrap around. No free ID to use. */
2909 if (dev->loop_id == first_loop_id) {
2910 dev->loop_id = FC_NO_LOOP_ID;
2911 rval = QLA_FUNCTION_FAILED;
2912 break;
2913 }
2914 }
2915
2916 return (rval);
2917}
2918
2919/*
2920 * qla2x00_device_resync
2921 * Marks devices in the database that needs resynchronization.
2922 *
2923 * Input:
2924 * ha = adapter block pointer.
2925 *
2926 * Context:
2927 * Kernel context.
2928 */
2929static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002930qla2x00_device_resync(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002931{
2932 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 uint32_t mask;
2934 fc_port_t *fcport;
2935 uint32_t rscn_entry;
2936 uint8_t rscn_out_iter;
2937 uint8_t format;
2938 port_id_t d_id;
2939
2940 rval = QLA_RSCNS_HANDLED;
2941
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002942 while (vha->rscn_out_ptr != vha->rscn_in_ptr ||
2943 vha->flags.rscn_queue_overflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002944
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002945 rscn_entry = vha->rscn_queue[vha->rscn_out_ptr];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 format = MSB(MSW(rscn_entry));
2947 d_id.b.domain = LSB(MSW(rscn_entry));
2948 d_id.b.area = MSB(LSW(rscn_entry));
2949 d_id.b.al_pa = LSB(LSW(rscn_entry));
2950
2951 DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
2952 "[%02x/%02x%02x%02x].\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002953 vha->host_no, vha->rscn_out_ptr, format, d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 d_id.b.area, d_id.b.al_pa));
2955
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002956 vha->rscn_out_ptr++;
2957 if (vha->rscn_out_ptr == MAX_RSCN_COUNT)
2958 vha->rscn_out_ptr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959
2960 /* Skip duplicate entries. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002961 for (rscn_out_iter = vha->rscn_out_ptr;
2962 !vha->flags.rscn_queue_overflow &&
2963 rscn_out_iter != vha->rscn_in_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 rscn_out_iter = (rscn_out_iter ==
2965 (MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
2966
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002967 if (rscn_entry != vha->rscn_queue[rscn_out_iter])
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 break;
2969
2970 DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002971 "entry found at [%d].\n", vha->host_no,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 rscn_out_iter));
2973
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002974 vha->rscn_out_ptr = rscn_out_iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975 }
2976
2977 /* Queue overflow, set switch default case. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002978 if (vha->flags.rscn_queue_overflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 DEBUG(printk("scsi(%ld): device_resync: rscn "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002980 "overflow.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
2982 format = 3;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002983 vha->flags.rscn_queue_overflow = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 }
2985
2986 switch (format) {
2987 case 0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002988 mask = 0xffffff;
2989 break;
2990 case 1:
2991 mask = 0xffff00;
2992 break;
2993 case 2:
2994 mask = 0xff0000;
2995 break;
2996 default:
2997 mask = 0x0;
2998 d_id.b24 = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002999 vha->rscn_out_ptr = vha->rscn_in_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003000 break;
3001 }
3002
3003 rval = QLA_SUCCESS;
3004
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003005 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
3007 (fcport->d_id.b24 & mask) != d_id.b24 ||
3008 fcport->port_type == FCT_BROADCAST)
3009 continue;
3010
3011 if (atomic_read(&fcport->state) == FCS_ONLINE) {
3012 if (format != 3 ||
3013 fcport->port_type != FCT_INITIATOR) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003014 qla2x00_mark_device_lost(vha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003015 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 }
3017 }
3018 fcport->flags &= ~FCF_FARP_DONE;
3019 }
3020 }
3021 return (rval);
3022}
3023
3024/*
3025 * qla2x00_fabric_dev_login
3026 * Login fabric target device and update FC port database.
3027 *
3028 * Input:
3029 * ha: adapter state pointer.
3030 * fcport: port structure list pointer.
3031 * next_loopid: contains value of a new loop ID that can be used
3032 * by the next login attempt.
3033 *
3034 * Returns:
3035 * qla2x00 local function return status code.
3036 *
3037 * Context:
3038 * Kernel context.
3039 */
3040static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003041qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 uint16_t *next_loopid)
3043{
3044 int rval;
3045 int retry;
Andrew Vasquez01071092005-07-06 10:31:37 -07003046 uint8_t opts;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003047 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048
3049 rval = QLA_SUCCESS;
3050 retry = 0;
3051
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003052 rval = qla2x00_fabric_login(vha, fcport, next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 if (rval == QLA_SUCCESS) {
Andrew Vasquez01071092005-07-06 10:31:37 -07003054 /* Send an ADISC to tape devices.*/
3055 opts = 0;
3056 if (fcport->flags & FCF_TAPE_PRESENT)
3057 opts |= BIT_1;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003058 rval = qla2x00_get_port_database(vha, fcport, opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003059 if (rval != QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003060 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003061 fcport->d_id.b.domain, fcport->d_id.b.area,
3062 fcport->d_id.b.al_pa);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003063 qla2x00_mark_device_lost(vha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003065 qla2x00_update_fcport(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003066 }
3067 }
3068
3069 return (rval);
3070}
3071
3072/*
3073 * qla2x00_fabric_login
3074 * Issue fabric login command.
3075 *
3076 * Input:
3077 * ha = adapter block pointer.
3078 * device = pointer to FC device type structure.
3079 *
3080 * Returns:
3081 * 0 - Login successfully
3082 * 1 - Login failed
3083 * 2 - Initiator device
3084 * 3 - Fatal error
3085 */
3086int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003087qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003088 uint16_t *next_loopid)
3089{
3090 int rval;
3091 int retry;
3092 uint16_t tmp_loopid;
3093 uint16_t mb[MAILBOX_REGISTER_COUNT];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003094 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003095
3096 retry = 0;
3097 tmp_loopid = 0;
3098
3099 for (;;) {
3100 DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
3101 "for port %02x%02x%02x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003102 vha->host_no, fcport->loop_id, fcport->d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003103 fcport->d_id.b.area, fcport->d_id.b.al_pa));
3104
3105 /* Login fcport on switch. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003106 ha->isp_ops->fabric_login(vha, fcport->loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003107 fcport->d_id.b.domain, fcport->d_id.b.area,
3108 fcport->d_id.b.al_pa, mb, BIT_0);
3109 if (mb[0] == MBS_PORT_ID_USED) {
3110 /*
3111 * Device has another loop ID. The firmware team
Andrew Vasquez01071092005-07-06 10:31:37 -07003112 * recommends the driver perform an implicit login with
3113 * the specified ID again. The ID we just used is save
3114 * here so we return with an ID that can be tried by
3115 * the next login.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003116 */
3117 retry++;
3118 tmp_loopid = fcport->loop_id;
3119 fcport->loop_id = mb[1];
3120
3121 DEBUG(printk("Fabric Login: port in use - next "
3122 "loop id=0x%04x, port Id=%02x%02x%02x.\n",
3123 fcport->loop_id, fcport->d_id.b.domain,
3124 fcport->d_id.b.area, fcport->d_id.b.al_pa));
3125
3126 } else if (mb[0] == MBS_COMMAND_COMPLETE) {
3127 /*
3128 * Login succeeded.
3129 */
3130 if (retry) {
3131 /* A retry occurred before. */
3132 *next_loopid = tmp_loopid;
3133 } else {
3134 /*
3135 * No retry occurred before. Just increment the
3136 * ID value for next login.
3137 */
3138 *next_loopid = (fcport->loop_id + 1);
3139 }
3140
3141 if (mb[1] & BIT_0) {
3142 fcport->port_type = FCT_INITIATOR;
3143 } else {
3144 fcport->port_type = FCT_TARGET;
3145 if (mb[1] & BIT_1) {
3146 fcport->flags |= FCF_TAPE_PRESENT;
3147 }
3148 }
3149
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07003150 if (mb[10] & BIT_0)
3151 fcport->supported_classes |= FC_COS_CLASS2;
3152 if (mb[10] & BIT_1)
3153 fcport->supported_classes |= FC_COS_CLASS3;
3154
Linus Torvalds1da177e2005-04-16 15:20:36 -07003155 rval = QLA_SUCCESS;
3156 break;
3157 } else if (mb[0] == MBS_LOOP_ID_USED) {
3158 /*
3159 * Loop ID already used, try next loop ID.
3160 */
3161 fcport->loop_id++;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003162 rval = qla2x00_find_new_loop_id(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003163 if (rval != QLA_SUCCESS) {
3164 /* Ran out of loop IDs to use */
3165 break;
3166 }
3167 } else if (mb[0] == MBS_COMMAND_ERROR) {
3168 /*
3169 * Firmware possibly timed out during login. If NO
3170 * retries are left to do then the device is declared
3171 * dead.
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);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003177 qla2x00_mark_device_lost(vha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003178
3179 rval = 1;
3180 break;
3181 } else {
3182 /*
3183 * unrecoverable / not handled error
3184 */
3185 DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003186 "loop_id=%x jiffies=%lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003187 __func__, vha->host_no, mb[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 fcport->d_id.b.domain, fcport->d_id.b.area,
3189 fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
3190
3191 *next_loopid = fcport->loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003192 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003193 fcport->d_id.b.domain, fcport->d_id.b.area,
3194 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 fcport->loop_id = FC_NO_LOOP_ID;
Andrew Vasquez0eedfcf2005-10-27 11:09:38 -07003196 fcport->login_retry = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
3198 rval = 3;
3199 break;
3200 }
3201 }
3202
3203 return (rval);
3204}
3205
3206/*
3207 * qla2x00_local_device_login
3208 * Issue local device login command.
3209 *
3210 * Input:
3211 * ha = adapter block pointer.
3212 * loop_id = loop id of device to login to.
3213 *
3214 * Returns (Where's the #define!!!!):
3215 * 0 - Login successfully
3216 * 1 - Login failed
3217 * 3 - Fatal error
3218 */
3219int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003220qla2x00_local_device_login(scsi_qla_host_t *vha, fc_port_t *fcport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221{
3222 int rval;
3223 uint16_t mb[MAILBOX_REGISTER_COUNT];
3224
3225 memset(mb, 0, sizeof(mb));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003226 rval = qla2x00_login_local_device(vha, fcport, mb, BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 if (rval == QLA_SUCCESS) {
3228 /* Interrogate mailbox registers for any errors */
3229 if (mb[0] == MBS_COMMAND_ERROR)
3230 rval = 1;
3231 else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
3232 /* device not in PCB table */
3233 rval = 3;
3234 }
3235
3236 return (rval);
3237}
3238
3239/*
3240 * qla2x00_loop_resync
3241 * Resync with fibre channel devices.
3242 *
3243 * Input:
3244 * ha = adapter block pointer.
3245 *
3246 * Returns:
3247 * 0 = success
3248 */
3249int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003250qla2x00_loop_resync(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251{
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003252 int rval = QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 uint32_t wait_time;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003254 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003255 struct req_que *req = ha->req_q_map[vha->req_ques[0]];
3256 struct rsp_que *rsp = req->rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003258 atomic_set(&vha->loop_state, LOOP_UPDATE);
3259 clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
3260 if (vha->flags.online) {
3261 if (!(rval = qla2x00_fw_ready(vha))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3263 wait_time = 256;
3264 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003265 atomic_set(&vha->loop_state, LOOP_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003266
Andrew Vasquez01071092005-07-06 10:31:37 -07003267 /* Issue a marker after FW becomes ready. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003268 qla2x00_marker(vha, req, rsp, 0, 0,
3269 MK_SYNC_ALL);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003270 vha->marker_needed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271
3272 /* Remap devices on Loop. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003273 clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003274
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003275 qla2x00_configure_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003276 wait_time--;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003277 } while (!atomic_read(&vha->loop_down_timer) &&
3278 !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
3279 && wait_time && (test_bit(LOOP_RESYNC_NEEDED,
3280 &vha->dpc_flags)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003281 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 }
3283
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003284 if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285 return (QLA_FUNCTION_FAILED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003286
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003287 if (rval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003289
3290 return (rval);
3291}
3292
Linus Torvalds1da177e2005-04-16 15:20:36 -07003293void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003294qla2x00_update_fcports(scsi_qla_host_t *vha)
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003295{
3296 fc_port_t *fcport;
3297
3298 /* Go with deferred removal of rport references. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003299 list_for_each_entry(fcport, &vha->vp_fcports, list)
3300 if (fcport && fcport->drport &&
Andrew Vasquezc9c5ced2008-07-24 08:31:49 -07003301 atomic_read(&fcport->state) != FCS_UNCONFIGURED)
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003302 qla2x00_rport_del(fcport);
3303}
3304
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305/*
3306* qla2x00_abort_isp
3307* Resets ISP and aborts all outstanding commands.
3308*
3309* Input:
3310* ha = adapter block pointer.
3311*
3312* Returns:
3313* 0 = success
3314*/
3315int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003316qla2x00_abort_isp(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003317{
Andrew Vasquez476e8972006-08-23 14:54:55 -07003318 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319 uint8_t status = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003320 struct qla_hw_data *ha = vha->hw;
3321 struct scsi_qla_host *vp;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003322 struct scsi_qla_host *tvp;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003323 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003324
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003325 if (vha->flags.online) {
3326 vha->flags.online = 0;
Lalit Chandivade2533cf62009-03-24 09:08:07 -07003327 ha->flags.chip_reset_done = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003328 clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Harish Zunjarraoe5f5f6f2008-07-10 16:55:49 -07003329 ha->qla_stats.total_isp_aborts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003330
3331 qla_printk(KERN_INFO, ha,
3332 "Performing ISP error recovery - ha= %p.\n", ha);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003333 ha->isp_ops->reset_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003335 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
3336 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
3337 atomic_set(&vha->loop_state, LOOP_DOWN);
3338 qla2x00_mark_all_devices_lost(vha, 0);
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003339 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003340 qla2x00_mark_all_devices_lost(vp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003342 if (!atomic_read(&vha->loop_down_timer))
3343 atomic_set(&vha->loop_down_timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003344 LOOP_DOWN_TIME);
3345 }
3346
Linus Torvalds1da177e2005-04-16 15:20:36 -07003347 /* Requeue all commands in outstanding command list. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003348 qla2x00_abort_all_cmds(vha, DID_RESET << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003350 ha->isp_ops->get_flash_version(vha, req->ring);
Andrew Vasquez30c47662007-01-29 10:22:21 -08003351
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003352 ha->isp_ops->nvram_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003353
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003354 if (!qla2x00_restart_isp(vha)) {
3355 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003356
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003357 if (!atomic_read(&vha->loop_down_timer)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003358 /*
3359 * Issue marker command only when we are going
3360 * to start the I/O .
3361 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003362 vha->marker_needed = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003363 }
3364
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003365 vha->flags.online = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003366
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003367 ha->isp_ops->enable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003368
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003369 ha->isp_abort_cnt = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003370 clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
Andrew Vasquez476e8972006-08-23 14:54:55 -07003371
Andrew Vasquezdf613b92008-01-17 09:02:17 -08003372 if (ha->fce) {
3373 ha->flags.fce_enabled = 1;
3374 memset(ha->fce, 0,
3375 fce_calc_size(ha->fce_bufs));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003376 rval = qla2x00_enable_fce_trace(vha,
Andrew Vasquezdf613b92008-01-17 09:02:17 -08003377 ha->fce_dma, ha->fce_bufs, ha->fce_mb,
3378 &ha->fce_bufs);
3379 if (rval) {
3380 qla_printk(KERN_WARNING, ha,
3381 "Unable to reinitialize FCE "
3382 "(%d).\n", rval);
3383 ha->flags.fce_enabled = 0;
3384 }
3385 }
Andrew Vasquez436a7b12008-07-10 16:55:54 -07003386
3387 if (ha->eft) {
3388 memset(ha->eft, 0, EFT_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003389 rval = qla2x00_enable_eft_trace(vha,
Andrew Vasquez436a7b12008-07-10 16:55:54 -07003390 ha->eft_dma, EFT_NUM_BUFFERS);
3391 if (rval) {
3392 qla_printk(KERN_WARNING, ha,
3393 "Unable to reinitialize EFT "
3394 "(%d).\n", rval);
3395 }
3396 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003397 } else { /* failed the ISP abort */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003398 vha->flags.online = 1;
3399 if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003400 if (ha->isp_abort_cnt == 0) {
3401 qla_printk(KERN_WARNING, ha,
3402 "ISP error recovery failed - "
3403 "board disabled\n");
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003404 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003405 * The next call disables the board
3406 * completely.
3407 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003408 ha->isp_ops->reset_adapter(vha);
3409 vha->flags.online = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003410 clear_bit(ISP_ABORT_RETRY,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003411 &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003412 status = 0;
3413 } else { /* schedule another ISP abort */
3414 ha->isp_abort_cnt--;
3415 DEBUG(printk("qla%ld: ISP abort - "
Andrew Vasquez01071092005-07-06 10:31:37 -07003416 "retry remaining %d\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003417 vha->host_no, ha->isp_abort_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003418 status = 1;
3419 }
3420 } else {
3421 ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
3422 DEBUG(printk("qla2x00(%ld): ISP error recovery "
3423 "- retrying (%d) more times\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003424 vha->host_no, ha->isp_abort_cnt));
3425 set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003426 status = 1;
3427 }
3428 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003429
Linus Torvalds1da177e2005-04-16 15:20:36 -07003430 }
3431
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003432 if (!status) {
3433 DEBUG(printk(KERN_INFO
3434 "qla2x00_abort_isp(%ld): succeeded.\n",
3435 vha->host_no));
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003436 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003437 if (vp->vp_idx)
3438 qla2x00_vp_abort_isp(vp);
3439 }
3440 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003441 qla_printk(KERN_INFO, ha,
3442 "qla2x00_abort_isp: **** FAILED ****\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 }
3444
3445 return(status);
3446}
3447
3448/*
3449* qla2x00_restart_isp
3450* restarts the ISP after a reset
3451*
3452* Input:
3453* ha = adapter block pointer.
3454*
3455* Returns:
3456* 0 = success
3457*/
3458static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003459qla2x00_restart_isp(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003460{
Andrew Vasquezc6b2fca2009-03-05 11:07:03 -08003461 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462 uint32_t wait_time;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003463 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003464 struct req_que *req = ha->req_q_map[0];
3465 struct rsp_que *rsp = ha->rsp_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003466
3467 /* If firmware needs to be loaded */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003468 if (qla2x00_isp_firmware(vha)) {
3469 vha->flags.online = 0;
3470 status = ha->isp_ops->chip_diag(vha);
3471 if (!status)
3472 status = qla2x00_setup_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473 }
3474
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003475 if (!status && !(status = qla2x00_init_rings(vha))) {
3476 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Lalit Chandivade2533cf62009-03-24 09:08:07 -07003477 ha->flags.chip_reset_done = 1;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003478 /* Initialize the queues in use */
3479 qla25xx_init_queues(ha);
3480
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003481 status = qla2x00_fw_ready(vha);
3482 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 DEBUG(printk("%s(): Start configure loop, "
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003484 "status = %d\n", __func__, status));
Andrew Vasquez01071092005-07-06 10:31:37 -07003485
3486 /* Issue a marker after FW becomes ready. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003487 qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
Andrew Vasquez01071092005-07-06 10:31:37 -07003488
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003489 vha->flags.online = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3491 wait_time = 256;
3492 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003493 clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
3494 qla2x00_configure_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495 wait_time--;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003496 } while (!atomic_read(&vha->loop_down_timer) &&
3497 !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
3498 && wait_time && (test_bit(LOOP_RESYNC_NEEDED,
3499 &vha->dpc_flags)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500 }
3501
3502 /* if no cable then assume it's good */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003503 if ((vha->device_flags & DFLG_NO_CABLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003504 status = 0;
3505
3506 DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
3507 __func__,
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003508 status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003509 }
3510 return (status);
3511}
3512
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003513static int
3514qla25xx_init_queues(struct qla_hw_data *ha)
3515{
3516 struct rsp_que *rsp = NULL;
3517 struct req_que *req = NULL;
3518 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
3519 int ret = -1;
3520 int i;
3521
3522 for (i = 1; i < ha->max_queues; i++) {
3523 rsp = ha->rsp_q_map[i];
3524 if (rsp) {
3525 rsp->options &= ~BIT_0;
Anirban Chakraborty618a7522009-02-08 20:50:11 -08003526 ret = qla25xx_init_rsp_que(base_vha, rsp);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003527 if (ret != QLA_SUCCESS)
3528 DEBUG2_17(printk(KERN_WARNING
3529 "%s Rsp que:%d init failed\n", __func__,
3530 rsp->id));
3531 else
3532 DEBUG2_17(printk(KERN_INFO
3533 "%s Rsp que:%d inited\n", __func__,
3534 rsp->id));
3535 }
3536 req = ha->req_q_map[i];
3537 if (req) {
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003538 /* Clear outstanding commands array. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003539 req->options &= ~BIT_0;
Anirban Chakraborty618a7522009-02-08 20:50:11 -08003540 ret = qla25xx_init_req_que(base_vha, req);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003541 if (ret != QLA_SUCCESS)
3542 DEBUG2_17(printk(KERN_WARNING
3543 "%s Req que:%d init failed\n", __func__,
3544 req->id));
3545 else
3546 DEBUG2_17(printk(KERN_WARNING
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003547 "%s Req que:%d inited\n", __func__,
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003548 req->id));
3549 }
3550 }
3551 return ret;
3552}
3553
Linus Torvalds1da177e2005-04-16 15:20:36 -07003554/*
3555* qla2x00_reset_adapter
3556* Reset adapter.
3557*
3558* Input:
3559* ha = adapter block pointer.
3560*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003561void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003562qla2x00_reset_adapter(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003563{
3564 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003565 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -07003566 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567
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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003570
Linus Torvalds1da177e2005-04-16 15:20:36 -07003571 spin_lock_irqsave(&ha->hardware_lock, flags);
3572 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
3573 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3574 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
3575 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3576 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3577}
Andrew Vasquez01071092005-07-06 10:31:37 -07003578
3579void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003580qla24xx_reset_adapter(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07003581{
3582 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003583 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07003584 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
3585
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003586 vha->flags.online = 0;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003587 ha->isp_ops->disable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -07003588
3589 spin_lock_irqsave(&ha->hardware_lock, flags);
3590 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
3591 RD_REG_DWORD(&reg->hccr);
3592 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
3593 RD_REG_DWORD(&reg->hccr);
3594 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquez09ff36d2009-01-22 09:45:30 -08003595
3596 if (IS_NOPOLLING_TYPE(ha))
3597 ha->isp_ops->enable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -07003598}
3599
David Miller4e08df32007-04-16 12:37:43 -07003600/* On sparc systems, obtain port and node WWN from firmware
3601 * properties.
3602 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003603static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *vha,
3604 struct nvram_24xx *nv)
David Miller4e08df32007-04-16 12:37:43 -07003605{
3606#ifdef CONFIG_SPARC
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003607 struct qla_hw_data *ha = vha->hw;
David Miller4e08df32007-04-16 12:37:43 -07003608 struct pci_dev *pdev = ha->pdev;
David S. Miller15576bc2007-05-08 00:36:49 -07003609 struct device_node *dp = pci_device_to_OF_node(pdev);
3610 const u8 *val;
David Miller4e08df32007-04-16 12:37:43 -07003611 int len;
3612
3613 val = of_get_property(dp, "port-wwn", &len);
3614 if (val && len >= WWN_SIZE)
3615 memcpy(nv->port_name, val, WWN_SIZE);
3616
3617 val = of_get_property(dp, "node-wwn", &len);
3618 if (val && len >= WWN_SIZE)
3619 memcpy(nv->node_name, val, WWN_SIZE);
3620#endif
3621}
3622
Andrew Vasquez01071092005-07-06 10:31:37 -07003623int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003624qla24xx_nvram_config(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07003625{
David Miller4e08df32007-04-16 12:37:43 -07003626 int rval;
Andrew Vasquez01071092005-07-06 10:31:37 -07003627 struct init_cb_24xx *icb;
3628 struct nvram_24xx *nv;
3629 uint32_t *dptr;
3630 uint8_t *dptr1, *dptr2;
3631 uint32_t chksum;
3632 uint16_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003633 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07003634
David Miller4e08df32007-04-16 12:37:43 -07003635 rval = QLA_SUCCESS;
Andrew Vasquez01071092005-07-06 10:31:37 -07003636 icb = (struct init_cb_24xx *)ha->init_cb;
Seokmann Ju281afe12007-07-26 13:43:34 -07003637 nv = ha->nvram;
Andrew Vasquez01071092005-07-06 10:31:37 -07003638
3639 /* Determine NVRAM starting address. */
3640 ha->nvram_size = sizeof(struct nvram_24xx);
3641 ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003642 ha->vpd_size = FA_NVRAM_VPD_SIZE;
3643 ha->vpd_base = FA_NVRAM_VPD0_ADDR;
3644 if (PCI_FUNC(ha->pdev->devfn)) {
Andrew Vasquez01071092005-07-06 10:31:37 -07003645 ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003646 ha->vpd_base = FA_NVRAM_VPD1_ADDR;
3647 }
Andrew Vasquez01071092005-07-06 10:31:37 -07003648
Seokmann Ju281afe12007-07-26 13:43:34 -07003649 /* Get VPD data into cache */
3650 ha->vpd = ha->nvram + VPD_OFFSET;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003651 ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
Seokmann Ju281afe12007-07-26 13:43:34 -07003652 ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
3653
3654 /* Get NVRAM data into cache and calculate checksum. */
Andrew Vasquez01071092005-07-06 10:31:37 -07003655 dptr = (uint32_t *)nv;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003656 ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
Andrew Vasquez01071092005-07-06 10:31:37 -07003657 ha->nvram_size);
3658 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
3659 chksum += le32_to_cpu(*dptr++);
3660
3661 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
Seokmann Ju281afe12007-07-26 13:43:34 -07003662 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
Andrew Vasquez01071092005-07-06 10:31:37 -07003663
3664 /* Bad NVRAM data, set defaults parameters. */
3665 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
3666 || nv->id[3] != ' ' ||
3667 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
3668 /* Reset NVRAM data. */
3669 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
3670 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
3671 le16_to_cpu(nv->nvram_version));
David Miller4e08df32007-04-16 12:37:43 -07003672 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
3673 "invalid -- WWPN) defaults.\n");
3674
3675 /*
3676 * Set default initialization control block.
3677 */
3678 memset(nv, 0, ha->nvram_size);
3679 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
3680 nv->version = __constant_cpu_to_le16(ICB_VERSION);
3681 nv->frame_payload_size = __constant_cpu_to_le16(2048);
3682 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3683 nv->exchange_count = __constant_cpu_to_le16(0);
3684 nv->hard_address = __constant_cpu_to_le16(124);
3685 nv->port_name[0] = 0x21;
3686 nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
3687 nv->port_name[2] = 0x00;
3688 nv->port_name[3] = 0xe0;
3689 nv->port_name[4] = 0x8b;
3690 nv->port_name[5] = 0x1c;
3691 nv->port_name[6] = 0x55;
3692 nv->port_name[7] = 0x86;
3693 nv->node_name[0] = 0x20;
3694 nv->node_name[1] = 0x00;
3695 nv->node_name[2] = 0x00;
3696 nv->node_name[3] = 0xe0;
3697 nv->node_name[4] = 0x8b;
3698 nv->node_name[5] = 0x1c;
3699 nv->node_name[6] = 0x55;
3700 nv->node_name[7] = 0x86;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003701 qla24xx_nvram_wwn_from_ofw(vha, nv);
David Miller4e08df32007-04-16 12:37:43 -07003702 nv->login_retry_count = __constant_cpu_to_le16(8);
3703 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
3704 nv->login_timeout = __constant_cpu_to_le16(0);
3705 nv->firmware_options_1 =
3706 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
3707 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
3708 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
3709 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
3710 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
3711 nv->efi_parameters = __constant_cpu_to_le32(0);
3712 nv->reset_delay = 5;
3713 nv->max_luns_per_target = __constant_cpu_to_le16(128);
3714 nv->port_down_retry_count = __constant_cpu_to_le16(30);
3715 nv->link_down_timeout = __constant_cpu_to_le16(30);
3716
3717 rval = 1;
Andrew Vasquez01071092005-07-06 10:31:37 -07003718 }
3719
3720 /* Reset Initialization control block */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003721 memset(icb, 0, ha->init_cb_size);
Andrew Vasquez01071092005-07-06 10:31:37 -07003722
3723 /* Copy 1st segment. */
3724 dptr1 = (uint8_t *)icb;
3725 dptr2 = (uint8_t *)&nv->version;
3726 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
3727 while (cnt--)
3728 *dptr1++ = *dptr2++;
3729
3730 icb->login_retry_count = nv->login_retry_count;
Andrew Vasquez3ea66e22006-06-23 16:11:27 -07003731 icb->link_down_on_nos = nv->link_down_on_nos;
Andrew Vasquez01071092005-07-06 10:31:37 -07003732
3733 /* Copy 2nd segment. */
3734 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
3735 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
3736 cnt = (uint8_t *)&icb->reserved_3 -
3737 (uint8_t *)&icb->interrupt_delay_timer;
3738 while (cnt--)
3739 *dptr1++ = *dptr2++;
3740
3741 /*
3742 * Setup driver NVRAM options.
3743 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003744 qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08003745 "QLA2462");
Andrew Vasquez01071092005-07-06 10:31:37 -07003746
Andrew Vasquez5341e862006-05-17 15:09:16 -07003747 /* Use alternate WWN? */
3748 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
3749 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
3750 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
3751 }
3752
Andrew Vasquez01071092005-07-06 10:31:37 -07003753 /* Prepare nodename */
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003754 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
Andrew Vasquez01071092005-07-06 10:31:37 -07003755 /*
3756 * Firmware will apply the following mask if the nodename was
3757 * not provided.
3758 */
3759 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
3760 icb->node_name[0] &= 0xF0;
3761 }
3762
3763 /* Set host adapter parameters. */
3764 ha->flags.disable_risc_code_load = 0;
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08003765 ha->flags.enable_lip_reset = 0;
3766 ha->flags.enable_lip_full_login =
3767 le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
3768 ha->flags.enable_target_reset =
3769 le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
Andrew Vasquez01071092005-07-06 10:31:37 -07003770 ha->flags.enable_led_scheme = 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07003771 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
Andrew Vasquez01071092005-07-06 10:31:37 -07003772
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07003773 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
3774 (BIT_6 | BIT_5 | BIT_4)) >> 4;
Andrew Vasquez01071092005-07-06 10:31:37 -07003775
3776 memcpy(ha->fw_seriallink_options24, nv->seriallink_options,
3777 sizeof(ha->fw_seriallink_options24));
3778
3779 /* save HBA serial number */
3780 ha->serial0 = icb->port_name[5];
3781 ha->serial1 = icb->port_name[6];
3782 ha->serial2 = icb->port_name[7];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003783 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
3784 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
Andrew Vasquez01071092005-07-06 10:31:37 -07003785
andrew.vasquez@qlogic.combc8fb3c2006-01-13 17:05:42 -08003786 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3787
Andrew Vasquez01071092005-07-06 10:31:37 -07003788 ha->retry_count = le16_to_cpu(nv->login_retry_count);
3789
3790 /* Set minimum login_timeout to 4 seconds. */
3791 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
3792 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
3793 if (le16_to_cpu(nv->login_timeout) < 4)
3794 nv->login_timeout = __constant_cpu_to_le16(4);
3795 ha->login_timeout = le16_to_cpu(nv->login_timeout);
Seokmann Juc6852c42008-04-24 15:21:29 -07003796 icb->login_timeout = nv->login_timeout;
Andrew Vasquez01071092005-07-06 10:31:37 -07003797
Andrew Vasquez00a537b2008-02-28 14:06:11 -08003798 /* Set minimum RATOV to 100 tenths of a second. */
3799 ha->r_a_tov = 100;
Andrew Vasquez01071092005-07-06 10:31:37 -07003800
3801 ha->loop_reset_delay = nv->reset_delay;
3802
3803 /* Link Down Timeout = 0:
3804 *
3805 * When Port Down timer expires we will start returning
3806 * I/O's to OS with "DID_NO_CONNECT".
3807 *
3808 * Link Down Timeout != 0:
3809 *
3810 * The driver waits for the link to come up after link down
3811 * before returning I/Os to OS with "DID_NO_CONNECT".
3812 */
3813 if (le16_to_cpu(nv->link_down_timeout) == 0) {
3814 ha->loop_down_abort_time =
3815 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
3816 } else {
3817 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
3818 ha->loop_down_abort_time =
3819 (LOOP_DOWN_TIME - ha->link_down_timeout);
3820 }
3821
3822 /* Need enough time to try and get the port back. */
3823 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
3824 if (qlport_down_retry)
3825 ha->port_down_retry_count = qlport_down_retry;
3826
3827 /* Set login_retry_count */
3828 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
3829 if (ha->port_down_retry_count ==
3830 le16_to_cpu(nv->port_down_retry_count) &&
3831 ha->port_down_retry_count > 3)
3832 ha->login_retry_count = ha->port_down_retry_count;
3833 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
3834 ha->login_retry_count = ha->port_down_retry_count;
3835 if (ql2xloginretrycount)
3836 ha->login_retry_count = ql2xloginretrycount;
3837
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003838 /* Enable ZIO. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003839 if (!vha->flags.init_done) {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003840 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
3841 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
3842 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
3843 le16_to_cpu(icb->interrupt_delay_timer): 2;
3844 }
3845 icb->firmware_options_2 &= __constant_cpu_to_le32(
3846 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003847 vha->flags.process_response_queue = 0;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003848 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08003849 ha->zio_mode = QLA_ZIO_MODE_6;
3850
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003851 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003852 "(%d us).\n", vha->host_no, ha->zio_mode,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003853 ha->zio_timer * 100));
3854 qla_printk(KERN_INFO, ha,
3855 "ZIO mode %d enabled; timer delay (%d us).\n",
3856 ha->zio_mode, ha->zio_timer * 100);
3857
3858 icb->firmware_options_2 |= cpu_to_le32(
3859 (uint32_t)ha->zio_mode);
3860 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003861 vha->flags.process_response_queue = 1;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07003862 }
3863
David Miller4e08df32007-04-16 12:37:43 -07003864 if (rval) {
3865 DEBUG2_3(printk(KERN_WARNING
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003866 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
David Miller4e08df32007-04-16 12:37:43 -07003867 }
3868 return (rval);
Andrew Vasquez01071092005-07-06 10:31:37 -07003869}
3870
Adrian Bunk413975a2006-06-30 02:33:06 -07003871static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003872qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003873{
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003874 int rval = QLA_SUCCESS;
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003875 int segments, fragment;
3876 uint32_t faddr;
3877 uint32_t *dcode, dlen;
3878 uint32_t risc_addr;
3879 uint32_t risc_size;
3880 uint32_t i;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003881 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003882 struct req_que *req = ha->req_q_map[0];
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08003883
3884 qla_printk(KERN_INFO, ha,
3885 "FW: Loading from flash (%x)...\n", ha->flt_region_fw);
3886
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003887 rval = QLA_SUCCESS;
3888
3889 segments = FA_RISC_CODE_SEGMENTS;
Andrew Vasquezc00d8992008-09-11 21:22:49 -07003890 faddr = ha->flt_region_fw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003891 dcode = (uint32_t *)req->ring;
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003892 *srisc_addr = 0;
3893
3894 /* Validate firmware image by checking version. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003895 qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003896 for (i = 0; i < 4; i++)
3897 dcode[i] = be32_to_cpu(dcode[i]);
3898 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
3899 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
3900 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
3901 dcode[3] == 0)) {
3902 qla_printk(KERN_WARNING, ha,
3903 "Unable to verify integrity of flash firmware image!\n");
3904 qla_printk(KERN_WARNING, ha,
3905 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
3906 dcode[1], dcode[2], dcode[3]);
3907
3908 return QLA_FUNCTION_FAILED;
3909 }
3910
3911 while (segments && rval == QLA_SUCCESS) {
3912 /* Read segment's load information. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003913 qla24xx_read_flash_data(vha, dcode, faddr, 4);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003914
3915 risc_addr = be32_to_cpu(dcode[2]);
3916 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
3917 risc_size = be32_to_cpu(dcode[3]);
3918
3919 fragment = 0;
3920 while (risc_size > 0 && rval == QLA_SUCCESS) {
3921 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
3922 if (dlen > risc_size)
3923 dlen = risc_size;
3924
3925 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
3926 "addr %x, number of dwords 0x%x, offset 0x%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003927 vha->host_no, risc_addr, dlen, faddr));
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003928
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003929 qla24xx_read_flash_data(vha, dcode, faddr, dlen);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003930 for (i = 0; i < dlen; i++)
3931 dcode[i] = swab32(dcode[i]);
3932
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003933 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003934 dlen);
3935 if (rval) {
3936 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003937 "segment %d of firmware\n", vha->host_no,
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003938 fragment));
3939 qla_printk(KERN_WARNING, ha,
3940 "[ERROR] Failed to load segment %d of "
3941 "firmware\n", fragment);
3942 break;
3943 }
3944
3945 faddr += dlen;
3946 risc_addr += dlen;
3947 risc_size -= dlen;
3948 fragment++;
3949 }
3950
3951 /* Next segment. */
3952 segments--;
3953 }
3954
3955 return rval;
3956}
3957
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003958#define QLA_FW_URL "ftp://ftp.qlogic.com/outgoing/linux/firmware/"
3959
Andrew Vasquez01071092005-07-06 10:31:37 -07003960int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003961qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquez54333832005-11-09 15:49:04 -08003962{
3963 int rval;
3964 int i, fragment;
3965 uint16_t *wcode, *fwcode;
3966 uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
3967 struct fw_blob *blob;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003968 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003969 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez54333832005-11-09 15:49:04 -08003970
3971 /* Load firmware blob. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003972 blob = qla2x00_request_firmware(vha);
Andrew Vasquez54333832005-11-09 15:49:04 -08003973 if (!blob) {
3974 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07003975 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
3976 "from: " QLA_FW_URL ".\n");
Andrew Vasquez54333832005-11-09 15:49:04 -08003977 return QLA_FUNCTION_FAILED;
3978 }
3979
3980 rval = QLA_SUCCESS;
3981
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003982 wcode = (uint16_t *)req->ring;
Andrew Vasquez54333832005-11-09 15:49:04 -08003983 *srisc_addr = 0;
3984 fwcode = (uint16_t *)blob->fw->data;
3985 fwclen = 0;
3986
3987 /* Validate firmware image by checking version. */
3988 if (blob->fw->size < 8 * sizeof(uint16_t)) {
3989 qla_printk(KERN_WARNING, ha,
3990 "Unable to verify integrity of firmware image (%Zd)!\n",
3991 blob->fw->size);
3992 goto fail_fw_integrity;
3993 }
3994 for (i = 0; i < 4; i++)
3995 wcode[i] = be16_to_cpu(fwcode[i + 4]);
3996 if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
3997 wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
3998 wcode[2] == 0 && wcode[3] == 0)) {
3999 qla_printk(KERN_WARNING, ha,
4000 "Unable to verify integrity of firmware image!\n");
4001 qla_printk(KERN_WARNING, ha,
4002 "Firmware data: %04x %04x %04x %04x!\n", wcode[0],
4003 wcode[1], wcode[2], wcode[3]);
4004 goto fail_fw_integrity;
4005 }
4006
4007 seg = blob->segs;
4008 while (*seg && rval == QLA_SUCCESS) {
4009 risc_addr = *seg;
4010 *srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
4011 risc_size = be16_to_cpu(fwcode[3]);
4012
4013 /* Validate firmware image size. */
4014 fwclen += risc_size * sizeof(uint16_t);
4015 if (blob->fw->size < fwclen) {
4016 qla_printk(KERN_WARNING, ha,
4017 "Unable to verify integrity of firmware image "
4018 "(%Zd)!\n", blob->fw->size);
4019 goto fail_fw_integrity;
4020 }
4021
4022 fragment = 0;
4023 while (risc_size > 0 && rval == QLA_SUCCESS) {
4024 wlen = (uint16_t)(ha->fw_transfer_size >> 1);
4025 if (wlen > risc_size)
4026 wlen = risc_size;
4027
4028 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004029 "addr %x, number of words 0x%x.\n", vha->host_no,
Andrew Vasquez54333832005-11-09 15:49:04 -08004030 risc_addr, wlen));
4031
4032 for (i = 0; i < wlen; i++)
4033 wcode[i] = swab16(fwcode[i]);
4034
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004035 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
Andrew Vasquez54333832005-11-09 15:49:04 -08004036 wlen);
4037 if (rval) {
4038 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004039 "segment %d of firmware\n", vha->host_no,
Andrew Vasquez54333832005-11-09 15:49:04 -08004040 fragment));
4041 qla_printk(KERN_WARNING, ha,
4042 "[ERROR] Failed to load segment %d of "
4043 "firmware\n", fragment);
4044 break;
4045 }
4046
4047 fwcode += wlen;
4048 risc_addr += wlen;
4049 risc_size -= wlen;
4050 fragment++;
4051 }
4052
4053 /* Next segment. */
4054 seg++;
4055 }
4056 return rval;
4057
4058fail_fw_integrity:
4059 return QLA_FUNCTION_FAILED;
4060}
4061
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004062static int
4063qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquez01071092005-07-06 10:31:37 -07004064{
4065 int rval;
4066 int segments, fragment;
4067 uint32_t *dcode, dlen;
4068 uint32_t risc_addr;
4069 uint32_t risc_size;
4070 uint32_t i;
Andrew Vasquez54333832005-11-09 15:49:04 -08004071 struct fw_blob *blob;
Andrew Vasquez01071092005-07-06 10:31:37 -07004072 uint32_t *fwcode, fwclen;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004073 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004074 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -07004075
Andrew Vasquez54333832005-11-09 15:49:04 -08004076 /* Load firmware blob. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004077 blob = qla2x00_request_firmware(vha);
Andrew Vasquez54333832005-11-09 15:49:04 -08004078 if (!blob) {
4079 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004080 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
4081 "from: " QLA_FW_URL ".\n");
4082
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004083 return QLA_FUNCTION_FAILED;
Andrew Vasquez01071092005-07-06 10:31:37 -07004084 }
4085
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004086 qla_printk(KERN_INFO, ha,
4087 "FW: Loading via request-firmware...\n");
4088
Andrew Vasquez01071092005-07-06 10:31:37 -07004089 rval = QLA_SUCCESS;
4090
4091 segments = FA_RISC_CODE_SEGMENTS;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004092 dcode = (uint32_t *)req->ring;
Andrew Vasquez01071092005-07-06 10:31:37 -07004093 *srisc_addr = 0;
Andrew Vasquez54333832005-11-09 15:49:04 -08004094 fwcode = (uint32_t *)blob->fw->data;
Andrew Vasquez01071092005-07-06 10:31:37 -07004095 fwclen = 0;
4096
4097 /* Validate firmware image by checking version. */
Andrew Vasquez54333832005-11-09 15:49:04 -08004098 if (blob->fw->size < 8 * sizeof(uint32_t)) {
Andrew Vasquez01071092005-07-06 10:31:37 -07004099 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004100 "Unable to verify integrity of firmware image (%Zd)!\n",
4101 blob->fw->size);
Andrew Vasquez01071092005-07-06 10:31:37 -07004102 goto fail_fw_integrity;
4103 }
4104 for (i = 0; i < 4; i++)
4105 dcode[i] = be32_to_cpu(fwcode[i + 4]);
4106 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
4107 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
4108 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
4109 dcode[3] == 0)) {
4110 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004111 "Unable to verify integrity of firmware image!\n");
Andrew Vasquez01071092005-07-06 10:31:37 -07004112 qla_printk(KERN_WARNING, ha,
4113 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
4114 dcode[1], dcode[2], dcode[3]);
4115 goto fail_fw_integrity;
4116 }
4117
4118 while (segments && rval == QLA_SUCCESS) {
4119 risc_addr = be32_to_cpu(fwcode[2]);
4120 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
4121 risc_size = be32_to_cpu(fwcode[3]);
4122
4123 /* Validate firmware image size. */
4124 fwclen += risc_size * sizeof(uint32_t);
Andrew Vasquez54333832005-11-09 15:49:04 -08004125 if (blob->fw->size < fwclen) {
Andrew Vasquez01071092005-07-06 10:31:37 -07004126 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004127 "Unable to verify integrity of firmware image "
4128 "(%Zd)!\n", blob->fw->size);
4129
Andrew Vasquez01071092005-07-06 10:31:37 -07004130 goto fail_fw_integrity;
4131 }
4132
4133 fragment = 0;
4134 while (risc_size > 0 && rval == QLA_SUCCESS) {
4135 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
4136 if (dlen > risc_size)
4137 dlen = risc_size;
4138
4139 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004140 "addr %x, number of dwords 0x%x.\n", vha->host_no,
Andrew Vasquez01071092005-07-06 10:31:37 -07004141 risc_addr, dlen));
4142
4143 for (i = 0; i < dlen; i++)
4144 dcode[i] = swab32(fwcode[i]);
4145
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004146 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
andrew.vasquez@qlogic.com590f98e2006-01-13 17:05:37 -08004147 dlen);
Andrew Vasquez01071092005-07-06 10:31:37 -07004148 if (rval) {
4149 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004150 "segment %d of firmware\n", vha->host_no,
Andrew Vasquez01071092005-07-06 10:31:37 -07004151 fragment));
4152 qla_printk(KERN_WARNING, ha,
4153 "[ERROR] Failed to load segment %d of "
4154 "firmware\n", fragment);
4155 break;
4156 }
4157
4158 fwcode += dlen;
4159 risc_addr += dlen;
4160 risc_size -= dlen;
4161 fragment++;
4162 }
4163
4164 /* Next segment. */
4165 segments--;
4166 }
Andrew Vasquez01071092005-07-06 10:31:37 -07004167 return rval;
4168
4169fail_fw_integrity:
Andrew Vasquez01071092005-07-06 10:31:37 -07004170 return QLA_FUNCTION_FAILED;
Andrew Vasquez01071092005-07-06 10:31:37 -07004171}
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004172
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004173int
4174qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
4175{
4176 int rval;
4177
4178 /*
4179 * FW Load priority:
4180 * 1) Firmware via request-firmware interface (.bin file).
4181 * 2) Firmware residing in flash.
4182 */
4183 rval = qla24xx_load_risc_blob(vha, srisc_addr);
4184 if (rval == QLA_SUCCESS)
4185 return rval;
4186
4187 return qla24xx_load_risc_flash(vha, srisc_addr);
4188}
4189
4190int
4191qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
4192{
4193 int rval;
4194
4195 /*
4196 * FW Load priority:
4197 * 1) Firmware residing in flash.
4198 * 2) Firmware via request-firmware interface (.bin file).
4199 */
4200 rval = qla24xx_load_risc_flash(vha, srisc_addr);
4201 if (rval == QLA_SUCCESS)
4202 return rval;
4203
4204 return qla24xx_load_risc_blob(vha, srisc_addr);
4205}
4206
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004207void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004208qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004209{
4210 int ret, retries;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004211 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004212
Andrew Vasqueze4289242007-07-19 15:05:56 -07004213 if (!IS_FWI2_CAPABLE(ha))
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004214 return;
Andrew Vasquez75edf812007-05-07 07:43:00 -07004215 if (!ha->fw_major_version)
4216 return;
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004217
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004218 ret = qla2x00_stop_firmware(vha);
Andrew Vasquez7c7f1f22008-02-28 14:06:09 -08004219 for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
4220 retries ; retries--) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004221 ha->isp_ops->reset_chip(vha);
4222 if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004223 continue;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004224 if (qla2x00_setup_chip(vha) != QLA_SUCCESS)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004225 continue;
4226 qla_printk(KERN_INFO, ha,
4227 "Attempting retry of stop-firmware command...\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004228 ret = qla2x00_stop_firmware(vha);
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004229 }
4230}
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004231
4232int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004233qla24xx_configure_vhba(scsi_qla_host_t *vha)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004234{
4235 int rval = QLA_SUCCESS;
4236 uint16_t mb[MAILBOX_REGISTER_COUNT];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004237 struct qla_hw_data *ha = vha->hw;
4238 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08004239 struct req_que *req = ha->req_q_map[vha->req_ques[0]];
4240 struct rsp_que *rsp = req->rsp;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004241
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004242 if (!vha->vp_idx)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004243 return -EINVAL;
4244
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004245 rval = qla2x00_fw_ready(base_vha);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004246 if (rval == QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004247 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004248 qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004249 }
4250
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004251 vha->flags.management_server_logged_in = 0;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004252
4253 /* Login to SNS first */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004254 ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004255 if (mb[0] != MBS_COMMAND_COMPLETE) {
4256 DEBUG15(qla_printk(KERN_INFO, ha,
4257 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
4258 "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
4259 mb[0], mb[1], mb[2], mb[6], mb[7]));
4260 return (QLA_FUNCTION_FAILED);
4261 }
4262
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004263 atomic_set(&vha->loop_down_timer, 0);
4264 atomic_set(&vha->loop_state, LOOP_UP);
4265 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
4266 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
4267 rval = qla2x00_loop_resync(base_vha);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004268
4269 return rval;
4270}
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004271
4272/* 84XX Support **************************************************************/
4273
4274static LIST_HEAD(qla_cs84xx_list);
4275static DEFINE_MUTEX(qla_cs84xx_mutex);
4276
4277static struct qla_chip_state_84xx *
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004278qla84xx_get_chip(struct scsi_qla_host *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004279{
4280 struct qla_chip_state_84xx *cs84xx;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004281 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004282
4283 mutex_lock(&qla_cs84xx_mutex);
4284
4285 /* Find any shared 84xx chip. */
4286 list_for_each_entry(cs84xx, &qla_cs84xx_list, list) {
4287 if (cs84xx->bus == ha->pdev->bus) {
4288 kref_get(&cs84xx->kref);
4289 goto done;
4290 }
4291 }
4292
4293 cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL);
4294 if (!cs84xx)
4295 goto done;
4296
4297 kref_init(&cs84xx->kref);
4298 spin_lock_init(&cs84xx->access_lock);
4299 mutex_init(&cs84xx->fw_update_mutex);
4300 cs84xx->bus = ha->pdev->bus;
4301
4302 list_add_tail(&cs84xx->list, &qla_cs84xx_list);
4303done:
4304 mutex_unlock(&qla_cs84xx_mutex);
4305 return cs84xx;
4306}
4307
4308static void
4309__qla84xx_chip_release(struct kref *kref)
4310{
4311 struct qla_chip_state_84xx *cs84xx =
4312 container_of(kref, struct qla_chip_state_84xx, kref);
4313
4314 mutex_lock(&qla_cs84xx_mutex);
4315 list_del(&cs84xx->list);
4316 mutex_unlock(&qla_cs84xx_mutex);
4317 kfree(cs84xx);
4318}
4319
4320void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004321qla84xx_put_chip(struct scsi_qla_host *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004322{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004323 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004324 if (ha->cs84xx)
4325 kref_put(&ha->cs84xx->kref, __qla84xx_chip_release);
4326}
4327
4328static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004329qla84xx_init_chip(scsi_qla_host_t *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004330{
4331 int rval;
4332 uint16_t status[2];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004333 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004334
4335 mutex_lock(&ha->cs84xx->fw_update_mutex);
4336
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004337 rval = qla84xx_verify_chip(vha, status);
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004338
4339 mutex_unlock(&ha->cs84xx->fw_update_mutex);
4340
4341 return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED:
4342 QLA_SUCCESS;
4343}
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004344
4345/* 81XX Support **************************************************************/
4346
4347int
4348qla81xx_nvram_config(scsi_qla_host_t *vha)
4349{
4350 int rval;
4351 struct init_cb_81xx *icb;
4352 struct nvram_81xx *nv;
4353 uint32_t *dptr;
4354 uint8_t *dptr1, *dptr2;
4355 uint32_t chksum;
4356 uint16_t cnt;
4357 struct qla_hw_data *ha = vha->hw;
4358
4359 rval = QLA_SUCCESS;
4360 icb = (struct init_cb_81xx *)ha->init_cb;
4361 nv = ha->nvram;
4362
4363 /* Determine NVRAM starting address. */
4364 ha->nvram_size = sizeof(struct nvram_81xx);
4365 ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
4366 ha->vpd_size = FA_NVRAM_VPD_SIZE;
4367 ha->vpd_base = FA_NVRAM_VPD0_ADDR;
4368 if (PCI_FUNC(ha->pdev->devfn) & 1) {
4369 ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
4370 ha->vpd_base = FA_NVRAM_VPD1_ADDR;
4371 }
4372
4373 /* Get VPD data into cache */
4374 ha->vpd = ha->nvram + VPD_OFFSET;
4375 ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
4376 ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
4377
4378 /* Get NVRAM data into cache and calculate checksum. */
4379 dptr = (uint32_t *)nv;
4380 ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
4381 ha->nvram_size);
4382 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
4383 chksum += le32_to_cpu(*dptr++);
4384
4385 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
4386 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
4387
4388 /* Bad NVRAM data, set defaults parameters. */
4389 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
4390 || nv->id[3] != ' ' ||
4391 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
4392 /* Reset NVRAM data. */
4393 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
4394 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
4395 le16_to_cpu(nv->nvram_version));
4396 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
4397 "invalid -- WWPN) defaults.\n");
4398
4399 /*
4400 * Set default initialization control block.
4401 */
4402 memset(nv, 0, ha->nvram_size);
4403 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
4404 nv->version = __constant_cpu_to_le16(ICB_VERSION);
4405 nv->frame_payload_size = __constant_cpu_to_le16(2048);
4406 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
4407 nv->exchange_count = __constant_cpu_to_le16(0);
4408 nv->port_name[0] = 0x21;
4409 nv->port_name[1] = 0x00 + PCI_FUNC(ha->pdev->devfn);
4410 nv->port_name[2] = 0x00;
4411 nv->port_name[3] = 0xe0;
4412 nv->port_name[4] = 0x8b;
4413 nv->port_name[5] = 0x1c;
4414 nv->port_name[6] = 0x55;
4415 nv->port_name[7] = 0x86;
4416 nv->node_name[0] = 0x20;
4417 nv->node_name[1] = 0x00;
4418 nv->node_name[2] = 0x00;
4419 nv->node_name[3] = 0xe0;
4420 nv->node_name[4] = 0x8b;
4421 nv->node_name[5] = 0x1c;
4422 nv->node_name[6] = 0x55;
4423 nv->node_name[7] = 0x86;
4424 nv->login_retry_count = __constant_cpu_to_le16(8);
4425 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
4426 nv->login_timeout = __constant_cpu_to_le16(0);
4427 nv->firmware_options_1 =
4428 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
4429 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
4430 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
4431 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
4432 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
4433 nv->efi_parameters = __constant_cpu_to_le32(0);
4434 nv->reset_delay = 5;
4435 nv->max_luns_per_target = __constant_cpu_to_le16(128);
4436 nv->port_down_retry_count = __constant_cpu_to_le16(30);
4437 nv->link_down_timeout = __constant_cpu_to_le16(30);
4438 nv->enode_mac[0] = 0x01;
4439 nv->enode_mac[1] = 0x02;
4440 nv->enode_mac[2] = 0x03;
4441 nv->enode_mac[3] = 0x04;
4442 nv->enode_mac[4] = 0x05;
4443 nv->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
4444
4445 rval = 1;
4446 }
4447
4448 /* Reset Initialization control block */
4449 memset(icb, 0, sizeof(struct init_cb_81xx));
4450
4451 /* Copy 1st segment. */
4452 dptr1 = (uint8_t *)icb;
4453 dptr2 = (uint8_t *)&nv->version;
4454 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
4455 while (cnt--)
4456 *dptr1++ = *dptr2++;
4457
4458 icb->login_retry_count = nv->login_retry_count;
4459
4460 /* Copy 2nd segment. */
4461 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
4462 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
4463 cnt = (uint8_t *)&icb->reserved_5 -
4464 (uint8_t *)&icb->interrupt_delay_timer;
4465 while (cnt--)
4466 *dptr1++ = *dptr2++;
4467
4468 memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
4469 /* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
4470 if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
4471 icb->enode_mac[0] = 0x01;
4472 icb->enode_mac[1] = 0x02;
4473 icb->enode_mac[2] = 0x03;
4474 icb->enode_mac[3] = 0x04;
4475 icb->enode_mac[4] = 0x05;
4476 icb->enode_mac[5] = 0x06 + PCI_FUNC(ha->pdev->devfn);
4477 }
4478
Andrew Vasquezb64b0e82009-03-24 09:08:01 -07004479 /* Use extended-initialization control block. */
4480 memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb));
4481
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004482 /*
4483 * Setup driver NVRAM options.
4484 */
4485 qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
4486 "QLE81XX");
4487
4488 /* Use alternate WWN? */
4489 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
4490 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
4491 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
4492 }
4493
4494 /* Prepare nodename */
4495 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
4496 /*
4497 * Firmware will apply the following mask if the nodename was
4498 * not provided.
4499 */
4500 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
4501 icb->node_name[0] &= 0xF0;
4502 }
4503
4504 /* Set host adapter parameters. */
4505 ha->flags.disable_risc_code_load = 0;
4506 ha->flags.enable_lip_reset = 0;
4507 ha->flags.enable_lip_full_login =
4508 le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
4509 ha->flags.enable_target_reset =
4510 le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
4511 ha->flags.enable_led_scheme = 0;
4512 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
4513
4514 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
4515 (BIT_6 | BIT_5 | BIT_4)) >> 4;
4516
4517 /* save HBA serial number */
4518 ha->serial0 = icb->port_name[5];
4519 ha->serial1 = icb->port_name[6];
4520 ha->serial2 = icb->port_name[7];
4521 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
4522 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
4523
4524 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
4525
4526 ha->retry_count = le16_to_cpu(nv->login_retry_count);
4527
4528 /* Set minimum login_timeout to 4 seconds. */
4529 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
4530 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
4531 if (le16_to_cpu(nv->login_timeout) < 4)
4532 nv->login_timeout = __constant_cpu_to_le16(4);
4533 ha->login_timeout = le16_to_cpu(nv->login_timeout);
4534 icb->login_timeout = nv->login_timeout;
4535
4536 /* Set minimum RATOV to 100 tenths of a second. */
4537 ha->r_a_tov = 100;
4538
4539 ha->loop_reset_delay = nv->reset_delay;
4540
4541 /* Link Down Timeout = 0:
4542 *
4543 * When Port Down timer expires we will start returning
4544 * I/O's to OS with "DID_NO_CONNECT".
4545 *
4546 * Link Down Timeout != 0:
4547 *
4548 * The driver waits for the link to come up after link down
4549 * before returning I/Os to OS with "DID_NO_CONNECT".
4550 */
4551 if (le16_to_cpu(nv->link_down_timeout) == 0) {
4552 ha->loop_down_abort_time =
4553 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
4554 } else {
4555 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
4556 ha->loop_down_abort_time =
4557 (LOOP_DOWN_TIME - ha->link_down_timeout);
4558 }
4559
4560 /* Need enough time to try and get the port back. */
4561 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
4562 if (qlport_down_retry)
4563 ha->port_down_retry_count = qlport_down_retry;
4564
4565 /* Set login_retry_count */
4566 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
4567 if (ha->port_down_retry_count ==
4568 le16_to_cpu(nv->port_down_retry_count) &&
4569 ha->port_down_retry_count > 3)
4570 ha->login_retry_count = ha->port_down_retry_count;
4571 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
4572 ha->login_retry_count = ha->port_down_retry_count;
4573 if (ql2xloginretrycount)
4574 ha->login_retry_count = ql2xloginretrycount;
4575
4576 /* Enable ZIO. */
4577 if (!vha->flags.init_done) {
4578 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
4579 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
4580 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
4581 le16_to_cpu(icb->interrupt_delay_timer): 2;
4582 }
4583 icb->firmware_options_2 &= __constant_cpu_to_le32(
4584 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
4585 vha->flags.process_response_queue = 0;
4586 if (ha->zio_mode != QLA_ZIO_DISABLED) {
4587 ha->zio_mode = QLA_ZIO_MODE_6;
4588
4589 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
4590 "(%d us).\n", vha->host_no, ha->zio_mode,
4591 ha->zio_timer * 100));
4592 qla_printk(KERN_INFO, ha,
4593 "ZIO mode %d enabled; timer delay (%d us).\n",
4594 ha->zio_mode, ha->zio_timer * 100);
4595
4596 icb->firmware_options_2 |= cpu_to_le32(
4597 (uint32_t)ha->zio_mode);
4598 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
4599 vha->flags.process_response_queue = 1;
4600 }
4601
4602 if (rval) {
4603 DEBUG2_3(printk(KERN_WARNING
4604 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
4605 }
4606 return (rval);
4607}
4608
4609void
4610qla81xx_update_fw_options(scsi_qla_host_t *ha)
4611{
4612}