blob: e7fe11486bb899dbd9e2561063e7ec1bafadbbaf [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090011#include <linux/slab.h>
Andrew Vasquez01071092005-07-06 10:31:37 -070012#include <linux/vmalloc.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013
14#include "qla_devtbl.h"
15
David Miller4e08df32007-04-16 12:37:43 -070016#ifdef CONFIG_SPARC
17#include <asm/prom.h>
David Miller4e08df32007-04-16 12:37:43 -070018#endif
19
Linus Torvalds1da177e2005-04-16 15:20:36 -070020/*
21* QLogic ISP2x00 Hardware Support Function Prototypes.
22*/
Linus Torvalds1da177e2005-04-16 15:20:36 -070023static int qla2x00_isp_firmware(scsi_qla_host_t *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070024static 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
Andrew Vasquezac280b62009-08-20 11:06:05 -070044/* SRB Extensions ---------------------------------------------------------- */
45
46static void
47qla2x00_ctx_sp_timeout(unsigned long __data)
48{
49 srb_t *sp = (srb_t *)__data;
50 struct srb_ctx *ctx;
51 fc_port_t *fcport = sp->fcport;
52 struct qla_hw_data *ha = fcport->vha->hw;
53 struct req_que *req;
54 unsigned long flags;
55
56 spin_lock_irqsave(&ha->hardware_lock, flags);
57 req = ha->req_q_map[0];
58 req->outstanding_cmds[sp->handle] = NULL;
59 ctx = sp->ctx;
60 ctx->timeout(sp);
61 spin_unlock_irqrestore(&ha->hardware_lock, flags);
62
63 ctx->free(sp);
64}
65
Giridhar Malavali9a069e12010-01-12 13:02:47 -080066void
Andrew Vasquezac280b62009-08-20 11:06:05 -070067qla2x00_ctx_sp_free(srb_t *sp)
68{
69 struct srb_ctx *ctx = sp->ctx;
70
71 kfree(ctx);
72 mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
73}
74
75inline srb_t *
76qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
77 unsigned long tmo)
78{
79 srb_t *sp;
80 struct qla_hw_data *ha = vha->hw;
81 struct srb_ctx *ctx;
82
83 sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
84 if (!sp)
85 goto done;
86 ctx = kzalloc(size, GFP_KERNEL);
87 if (!ctx) {
88 mempool_free(sp, ha->srb_mempool);
89 goto done;
90 }
91
92 memset(sp, 0, sizeof(*sp));
93 sp->fcport = fcport;
94 sp->ctx = ctx;
95 ctx->free = qla2x00_ctx_sp_free;
96
97 init_timer(&ctx->timer);
98 if (!tmo)
99 goto done;
100 ctx->timer.expires = jiffies + tmo * HZ;
101 ctx->timer.data = (unsigned long)sp;
102 ctx->timer.function = qla2x00_ctx_sp_timeout;
103 add_timer(&ctx->timer);
104done:
105 return sp;
106}
107
108/* Asynchronous Login/Logout Routines -------------------------------------- */
109
110#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
111
112static void
113qla2x00_async_logio_timeout(srb_t *sp)
114{
115 fc_port_t *fcport = sp->fcport;
116 struct srb_logio *lio = sp->ctx;
117
118 DEBUG2(printk(KERN_WARNING
119 "scsi(%ld:%x): Async-%s timeout.\n",
120 fcport->vha->host_no, sp->handle,
121 lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout"));
122
123 if (lio->ctx.type == SRB_LOGIN_CMD)
124 qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
125}
126
127int
128qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
129 uint16_t *data)
130{
131 struct qla_hw_data *ha = vha->hw;
132 srb_t *sp;
133 struct srb_logio *lio;
134 int rval;
135
136 rval = QLA_FUNCTION_FAILED;
137 sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
138 ELS_TMO_2_RATOV(ha) + 2);
139 if (!sp)
140 goto done;
141
142 lio = sp->ctx;
143 lio->ctx.type = SRB_LOGIN_CMD;
144 lio->ctx.timeout = qla2x00_async_logio_timeout;
145 lio->flags |= SRB_LOGIN_COND_PLOGI;
146 if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
147 lio->flags |= SRB_LOGIN_RETRIED;
148 rval = qla2x00_start_sp(sp);
149 if (rval != QLA_SUCCESS)
150 goto done_free_sp;
151
152 DEBUG2(printk(KERN_DEBUG
153 "scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x "
154 "retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id,
155 fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
156 fcport->login_retry));
157 return rval;
158
159done_free_sp:
160 del_timer_sync(&lio->ctx.timer);
161 lio->ctx.free(sp);
162done:
163 return rval;
164}
165
166int
167qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
168{
169 struct qla_hw_data *ha = vha->hw;
170 srb_t *sp;
171 struct srb_logio *lio;
172 int rval;
173
174 rval = QLA_FUNCTION_FAILED;
175 sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
176 ELS_TMO_2_RATOV(ha) + 2);
177 if (!sp)
178 goto done;
179
180 lio = sp->ctx;
181 lio->ctx.type = SRB_LOGOUT_CMD;
182 lio->ctx.timeout = qla2x00_async_logio_timeout;
183 rval = qla2x00_start_sp(sp);
184 if (rval != QLA_SUCCESS)
185 goto done_free_sp;
186
187 DEBUG2(printk(KERN_DEBUG
188 "scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
189 fcport->vha->host_no, sp->handle, fcport->loop_id,
190 fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
191 return rval;
192
193done_free_sp:
194 del_timer_sync(&lio->ctx.timer);
195 lio->ctx.free(sp);
196done:
197 return rval;
198}
199
200int
201qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
202 uint16_t *data)
203{
204 int rval;
205 uint8_t opts = 0;
206
207 switch (data[0]) {
208 case MBS_COMMAND_COMPLETE:
Andrew Vasquezf08b7252010-01-12 12:59:48 -0800209 if (fcport->flags & FCF_FCP2_DEVICE)
Andrew Vasquezac280b62009-08-20 11:06:05 -0700210 opts |= BIT_1;
211 rval = qla2x00_get_port_database(vha, fcport, opts);
212 if (rval != QLA_SUCCESS)
213 qla2x00_mark_device_lost(vha, fcport, 1, 0);
214 else
215 qla2x00_update_fcport(vha, fcport);
216 break;
217 case MBS_COMMAND_ERROR:
218 if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
219 set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
220 else
221 qla2x00_mark_device_lost(vha, fcport, 1, 0);
222 break;
223 case MBS_PORT_ID_USED:
224 fcport->loop_id = data[1];
225 qla2x00_post_async_login_work(vha, fcport, NULL);
226 break;
227 case MBS_LOOP_ID_USED:
228 fcport->loop_id++;
229 rval = qla2x00_find_new_loop_id(vha, fcport);
230 if (rval != QLA_SUCCESS) {
231 qla2x00_mark_device_lost(vha, fcport, 1, 0);
232 break;
233 }
234 qla2x00_post_async_login_work(vha, fcport, NULL);
235 break;
236 }
237 return QLA_SUCCESS;
238}
239
240int
241qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
242 uint16_t *data)
243{
244 qla2x00_mark_device_lost(vha, fcport, 1, 0);
245 return QLA_SUCCESS;
246}
247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248/****************************************************************************/
249/* QLogic ISP2x00 Hardware Support Functions. */
250/****************************************************************************/
251
252/*
253* qla2x00_initialize_adapter
254* Initialize board.
255*
256* Input:
257* ha = adapter block pointer.
258*
259* Returns:
260* 0 = success
261*/
262int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800263qla2x00_initialize_adapter(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264{
265 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800266 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800267 struct req_que *req = ha->req_q_map[0];
Lalit Chandivade2533cf62009-03-24 09:08:07 -0700268
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 /* Clear adapter flags. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800270 vha->flags.online = 0;
Lalit Chandivade2533cf62009-03-24 09:08:07 -0700271 ha->flags.chip_reset_done = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800272 vha->flags.reset_active = 0;
Andrew Vasquez85880802009-12-15 21:29:46 -0800273 ha->flags.pci_channel_io_perm_failure = 0;
274 ha->flags.eeh_busy = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800275 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
276 atomic_set(&vha->loop_state, LOOP_DOWN);
277 vha->device_flags = DFLG_NO_CABLE;
278 vha->dpc_flags = 0;
279 vha->flags.management_server_logged_in = 0;
280 vha->marker_needed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281 ha->isp_abort_cnt = 0;
282 ha->beacon_blink_led = 0;
283
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800284 set_bit(0, ha->req_qid_map);
285 set_bit(0, ha->rsp_qid_map);
286
Andrew Vasquez01071092005-07-06 10:31:37 -0700287 qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800288 rval = ha->isp_ops->pci_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 if (rval) {
Andrew Vasquez7c98a042007-01-29 10:22:29 -0800290 DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800291 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 return (rval);
293 }
294
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800295 ha->isp_ops->reset_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800297 rval = qla2xxx_get_flash_info(vha);
Andrew Vasquezc00d8992008-09-11 21:22:49 -0700298 if (rval) {
299 DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800300 vha->host_no));
Andrew Vasquezc00d8992008-09-11 21:22:49 -0700301 return (rval);
302 }
303
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800304 ha->isp_ops->get_flash_version(vha, req->ring);
Andrew Vasquez30c47662007-01-29 10:22:21 -0800305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
Andrew Vasquez01071092005-07-06 10:31:37 -0700307
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800308 ha->isp_ops->nvram_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Andrew Vasquezd4c760c2006-06-23 16:10:39 -0700310 if (ha->flags.disable_serdes) {
311 /* Mask HBA via NVRAM settings? */
312 qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
313 "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800314 vha->port_name[0], vha->port_name[1],
315 vha->port_name[2], vha->port_name[3],
316 vha->port_name[4], vha->port_name[5],
317 vha->port_name[6], vha->port_name[7]);
Andrew Vasquezd4c760c2006-06-23 16:10:39 -0700318 return QLA_FUNCTION_FAILED;
319 }
320
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
322
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800323 if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
324 rval = ha->isp_ops->chip_diag(vha);
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800325 if (rval)
326 return (rval);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800327 rval = qla2x00_setup_chip(vha);
Andrew Vasquezd19044c2006-11-22 08:22:19 -0800328 if (rval)
329 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 }
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700331 if (IS_QLA84XX(ha)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800332 ha->cs84xx = qla84xx_get_chip(vha);
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700333 if (!ha->cs84xx) {
334 qla_printk(KERN_ERR, ha,
335 "Unable to configure ISP84XX.\n");
336 return QLA_FUNCTION_FAILED;
337 }
338 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800339 rval = qla2x00_init_rings(vha);
Lalit Chandivade2533cf62009-03-24 09:08:07 -0700340 ha->flags.chip_reset_done = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
Giridhar Malavali9a069e12010-01-12 13:02:47 -0800342 if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
343 /* Issue verify 84xx FW IOCB to complete 84xx initialization */
344 rval = qla84xx_init_chip(vha);
345 if (rval != QLA_SUCCESS) {
346 qla_printk(KERN_ERR, ha,
347 "Unable to initialize ISP84XX.\n");
348 qla84xx_put_chip(vha);
349 }
350 }
351
Sarang Radke09ff7012010-03-19 17:03:59 -0700352 if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) {
353 if (qla24xx_read_fcp_prio_cfg(vha))
354 qla_printk(KERN_ERR, ha,
355 "Unable to read FCP priority data.\n");
356 }
357
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 return (rval);
359}
360
361/**
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700362 * qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 * @ha: HA context
364 *
365 * Returns 0 on success.
366 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700367int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800368qla2100_pci_config(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700370 uint16_t w;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700371 unsigned long flags;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800372 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700373 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374
Linus Torvalds1da177e2005-04-16 15:20:36 -0700375 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700376 pci_try_set_mwi(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700379 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
381
Andrew Vasquez737faec2008-10-24 15:13:45 -0700382 pci_disable_rom(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700384 /* Get PCI bus information. */
385 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700386 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700387 spin_unlock_irqrestore(&ha->hardware_lock, flags);
388
389 return QLA_SUCCESS;
390}
391
392/**
393 * qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
394 * @ha: HA context
395 *
396 * Returns 0 on success.
397 */
398int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800399qla2300_pci_config(scsi_qla_host_t *vha)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700400{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700401 uint16_t w;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700402 unsigned long flags = 0;
403 uint32_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800404 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700405 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700406
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700407 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700408 pci_try_set_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700409
410 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700411 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700412
413 if (IS_QLA2322(ha) || IS_QLA6322(ha))
414 w &= ~PCI_COMMAND_INTX_DISABLE;
Andrew Vasqueza157b102007-05-07 07:43:01 -0700415 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700416
417 /*
418 * If this is a 2300 card and not 2312, reset the
419 * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
420 * the 2310 also reports itself as a 2300 so we need to get the
421 * fb revision level -- a 6 indicates it really is a 2300 and
422 * not a 2310.
423 */
424 if (IS_QLA2300(ha)) {
425 spin_lock_irqsave(&ha->hardware_lock, flags);
426
427 /* Pause RISC. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700428 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700429 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700430 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700431 break;
432
433 udelay(10);
434 }
435
436 /* Select FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700437 WRT_REG_WORD(&reg->ctrl_status, 0x20);
438 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700439
440 /* Get the fb rev level */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700441 ha->fb_rev = RD_FB_CMD_REG(ha, reg);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700442
443 if (ha->fb_rev == FPM_2300)
Andrew Vasqueza157b102007-05-07 07:43:01 -0700444 pci_clear_mwi(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700445
446 /* Deselect FPM registers. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700447 WRT_REG_WORD(&reg->ctrl_status, 0x0);
448 RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700449
450 /* Release RISC module. */
Andrew Vasquez3d716442005-07-06 10:30:26 -0700451 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700452 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquez3d716442005-07-06 10:30:26 -0700453 if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0)
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700454 break;
455
456 udelay(10);
457 }
458
459 spin_unlock_irqrestore(&ha->hardware_lock, flags);
460 }
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700461
462 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
463
Andrew Vasquez737faec2008-10-24 15:13:45 -0700464 pci_disable_rom(ha->pdev);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700465
466 /* Get PCI bus information. */
467 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasquez3d716442005-07-06 10:30:26 -0700468 ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700469 spin_unlock_irqrestore(&ha->hardware_lock, flags);
470
471 return QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472}
473
474/**
Andrew Vasquez01071092005-07-06 10:31:37 -0700475 * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
476 * @ha: HA context
477 *
478 * Returns 0 on success.
479 */
480int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800481qla24xx_pci_config(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700482{
Andrew Vasqueza157b102007-05-07 07:43:01 -0700483 uint16_t w;
Andrew Vasquez01071092005-07-06 10:31:37 -0700484 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800485 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -0700486 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
Andrew Vasquez01071092005-07-06 10:31:37 -0700487
488 pci_set_master(ha->pdev);
Andrew Vasquezaf6177d2007-07-19 15:06:02 -0700489 pci_try_set_mwi(ha->pdev);
Andrew Vasquez01071092005-07-06 10:31:37 -0700490
491 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
Andrew Vasqueza157b102007-05-07 07:43:01 -0700492 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Andrew Vasquez01071092005-07-06 10:31:37 -0700493 w &= ~PCI_COMMAND_INTX_DISABLE;
494 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
495
496 pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
497
498 /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
Andrew Vasquezf85ec182007-07-19 15:06:01 -0700499 if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
500 pcix_set_mmrbc(ha->pdev, 2048);
Andrew Vasquez01071092005-07-06 10:31:37 -0700501
502 /* PCIe -- adjust Maximum Read Request Size (2048). */
Andrew Vasquezf85ec182007-07-19 15:06:01 -0700503 if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
504 pcie_set_readrq(ha->pdev, 2048);
Andrew Vasquez01071092005-07-06 10:31:37 -0700505
Andrew Vasquez737faec2008-10-24 15:13:45 -0700506 pci_disable_rom(ha->pdev);
Andrew Vasquez01071092005-07-06 10:31:37 -0700507
Auke Kok44c10132007-06-08 15:46:36 -0700508 ha->chip_revision = ha->pdev->revision;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -0800509
Andrew Vasquez01071092005-07-06 10:31:37 -0700510 /* Get PCI bus information. */
511 spin_lock_irqsave(&ha->hardware_lock, flags);
512 ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
513 spin_unlock_irqrestore(&ha->hardware_lock, flags);
514
515 return QLA_SUCCESS;
516}
517
518/**
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700519 * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
520 * @ha: HA context
521 *
522 * Returns 0 on success.
523 */
524int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800525qla25xx_pci_config(scsi_qla_host_t *vha)
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700526{
527 uint16_t w;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800528 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700529
530 pci_set_master(ha->pdev);
531 pci_try_set_mwi(ha->pdev);
532
533 pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
534 w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
535 w &= ~PCI_COMMAND_INTX_DISABLE;
536 pci_write_config_word(ha->pdev, PCI_COMMAND, w);
537
538 /* PCIe -- adjust Maximum Read Request Size (2048). */
539 if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
540 pcie_set_readrq(ha->pdev, 2048);
541
Andrew Vasquez737faec2008-10-24 15:13:45 -0700542 pci_disable_rom(ha->pdev);
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700543
544 ha->chip_revision = ha->pdev->revision;
545
546 return QLA_SUCCESS;
547}
548
549/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 * qla2x00_isp_firmware() - Choose firmware image.
551 * @ha: HA context
552 *
553 * Returns 0 on success.
554 */
555static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800556qla2x00_isp_firmware(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557{
558 int rval;
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700559 uint16_t loop_id, topo, sw_cap;
560 uint8_t domain, area, al_pa;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800561 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 /* Assume loading risc code */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700564 rval = QLA_FUNCTION_FAILED;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565
566 if (ha->flags.disable_risc_code_load) {
567 DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800568 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
570
571 /* Verify checksum of loaded RISC code. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800572 rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700573 if (rval == QLA_SUCCESS) {
574 /* And, verify we are not in ROM code. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800575 rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
Andrew Vasquez42e421b2008-07-10 16:56:01 -0700576 &area, &domain, &topo, &sw_cap);
577 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 }
579
580 if (rval) {
581 DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800582 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 }
584
585 return (rval);
586}
587
588/**
589 * qla2x00_reset_chip() - Reset ISP chip.
590 * @ha: HA context
591 *
592 * Returns 0 on success.
593 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700594void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800595qla2x00_reset_chip(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
597 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800598 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700599 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 uint32_t cnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 uint16_t cmd;
602
Andrew Vasquez85880802009-12-15 21:29:46 -0800603 if (unlikely(pci_channel_offline(ha->pdev)))
604 return;
605
Andrew Vasquezfd34f552007-07-19 15:06:00 -0700606 ha->isp_ops->disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 spin_lock_irqsave(&ha->hardware_lock, flags);
609
610 /* Turn off master enable */
611 cmd = 0;
612 pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
613 cmd &= ~PCI_COMMAND_MASTER;
614 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
615
616 if (!IS_QLA2100(ha)) {
617 /* Pause RISC. */
618 WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
619 if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
620 for (cnt = 0; cnt < 30000; cnt++) {
621 if ((RD_REG_WORD(&reg->hccr) &
622 HCCR_RISC_PAUSE) != 0)
623 break;
624 udelay(100);
625 }
626 } else {
627 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
628 udelay(10);
629 }
630
631 /* Select FPM registers. */
632 WRT_REG_WORD(&reg->ctrl_status, 0x20);
633 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
634
635 /* FPM Soft Reset. */
636 WRT_REG_WORD(&reg->fpm_diag_config, 0x100);
637 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
638
639 /* Toggle Fpm Reset. */
640 if (!IS_QLA2200(ha)) {
641 WRT_REG_WORD(&reg->fpm_diag_config, 0x0);
642 RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
643 }
644
645 /* Select frame buffer registers. */
646 WRT_REG_WORD(&reg->ctrl_status, 0x10);
647 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
648
649 /* Reset frame buffer FIFOs. */
650 if (IS_QLA2200(ha)) {
651 WRT_FB_CMD_REG(ha, reg, 0xa000);
652 RD_FB_CMD_REG(ha, reg); /* PCI Posting. */
653 } else {
654 WRT_FB_CMD_REG(ha, reg, 0x00fc);
655
656 /* Read back fb_cmd until zero or 3 seconds max */
657 for (cnt = 0; cnt < 3000; cnt++) {
658 if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
659 break;
660 udelay(100);
661 }
662 }
663
664 /* Select RISC module registers. */
665 WRT_REG_WORD(&reg->ctrl_status, 0);
666 RD_REG_WORD(&reg->ctrl_status); /* PCI Posting. */
667
668 /* Reset RISC processor. */
669 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
670 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
671
672 /* Release RISC processor. */
673 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
674 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
675 }
676
677 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
678 WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);
679
680 /* Reset ISP chip. */
681 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
682
683 /* Wait for RISC to recover from reset. */
684 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
685 /*
686 * It is necessary to for a delay here since the card doesn't
687 * respond to PCI reads during a reset. On some architectures
688 * this will result in an MCA.
689 */
690 udelay(20);
691 for (cnt = 30000; cnt; cnt--) {
692 if ((RD_REG_WORD(&reg->ctrl_status) &
693 CSR_ISP_SOFT_RESET) == 0)
694 break;
695 udelay(100);
696 }
697 } else
698 udelay(10);
699
700 /* Reset RISC processor. */
701 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
702
703 WRT_REG_WORD(&reg->semaphore, 0);
704
705 /* Release RISC processor. */
706 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
707 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
708
709 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
710 for (cnt = 0; cnt < 30000; cnt++) {
Andrew Vasquezffb39f02006-05-17 15:09:06 -0700711 if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
714 udelay(100);
715 }
716 } else
717 udelay(100);
718
719 /* Turn on master enable */
720 cmd |= PCI_COMMAND_MASTER;
721 pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
722
723 /* Disable RISC pause on FPM parity error. */
724 if (!IS_QLA2100(ha)) {
725 WRT_REG_WORD(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
726 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
727 }
728
729 spin_unlock_irqrestore(&ha->hardware_lock, flags);
730}
731
732/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700733 * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
Andrew Vasquez01071092005-07-06 10:31:37 -0700734 * @ha: HA context
735 *
736 * Returns 0 on success.
737 */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700738static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800739qla24xx_reset_risc(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700740{
741 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800742 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -0700743 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
744 uint32_t cnt, d2;
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800745 uint16_t wd;
Andrew Vasquez01071092005-07-06 10:31:37 -0700746
Andrew Vasquez01071092005-07-06 10:31:37 -0700747 spin_lock_irqsave(&ha->hardware_lock, flags);
748
749 /* Reset RISC. */
750 WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
751 for (cnt = 0; cnt < 30000; cnt++) {
752 if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
753 break;
754
755 udelay(10);
756 }
757
758 WRT_REG_DWORD(&reg->ctrl_status,
759 CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800760 pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700761
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800762 udelay(100);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700763 /* Wait for firmware to complete NVRAM accesses. */
Andrew Vasquez88c26662005-07-08 17:59:26 -0700764 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
765 for (cnt = 10000 ; cnt && d2; cnt--) {
766 udelay(5);
767 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
768 barrier();
769 }
770
Andrew Vasquez335a1cc2005-11-08 14:37:48 -0800771 /* Wait for soft-reset to complete. */
Andrew Vasquez01071092005-07-06 10:31:37 -0700772 d2 = RD_REG_DWORD(&reg->ctrl_status);
773 for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
774 udelay(5);
775 d2 = RD_REG_DWORD(&reg->ctrl_status);
776 barrier();
777 }
778
779 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
780 RD_REG_DWORD(&reg->hccr);
781
782 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
783 RD_REG_DWORD(&reg->hccr);
784
785 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
786 RD_REG_DWORD(&reg->hccr);
787
788 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
789 for (cnt = 6000000 ; cnt && d2; cnt--) {
790 udelay(5);
791 d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
792 barrier();
793 }
794
795 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquez124f85e2009-01-05 11:18:06 -0800796
797 if (IS_NOPOLLING_TYPE(ha))
798 ha->isp_ops->enable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700799}
800
801/**
Andrew Vasquez88c26662005-07-08 17:59:26 -0700802 * qla24xx_reset_chip() - Reset ISP24xx chip.
803 * @ha: HA context
804 *
805 * Returns 0 on success.
806 */
807void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800808qla24xx_reset_chip(scsi_qla_host_t *vha)
Andrew Vasquez88c26662005-07-08 17:59:26 -0700809{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800810 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez85880802009-12-15 21:29:46 -0800811
812 if (pci_channel_offline(ha->pdev) &&
813 ha->flags.pci_channel_io_perm_failure) {
814 return;
815 }
816
Andrew Vasquezfd34f552007-07-19 15:06:00 -0700817 ha->isp_ops->disable_intrs(ha);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700818
819 /* Perform RISC reset. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800820 qla24xx_reset_risc(vha);
Andrew Vasquez88c26662005-07-08 17:59:26 -0700821}
822
823/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * qla2x00_chip_diag() - Test chip for proper operation.
825 * @ha: HA context
826 *
827 * Returns 0 on success.
828 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -0700829int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800830qla2x00_chip_diag(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831{
832 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800833 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700834 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835 unsigned long flags = 0;
836 uint16_t data;
837 uint32_t cnt;
838 uint16_t mb[5];
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800839 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
841 /* Assume a failed state */
842 rval = QLA_FUNCTION_FAILED;
843
844 DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800845 vha->host_no, (u_long)&reg->flash_address));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846
847 spin_lock_irqsave(&ha->hardware_lock, flags);
848
849 /* Reset ISP chip. */
850 WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
851
852 /*
853 * We need to have a delay here since the card will not respond while
854 * in reset causing an MCA on some architectures.
855 */
856 udelay(20);
857 data = qla2x00_debounce_register(&reg->ctrl_status);
858 for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
859 udelay(5);
860 data = RD_REG_WORD(&reg->ctrl_status);
861 barrier();
862 }
863
864 if (!cnt)
865 goto chip_diag_failed;
866
867 DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
Andrew Vasquez76403352009-04-06 22:33:39 -0700868 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 /* Reset RISC processor. */
871 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
872 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
873
874 /* Workaround for QLA2312 PCI parity error */
875 if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
876 data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
877 for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
878 udelay(5);
879 data = RD_MAILBOX_REG(ha, reg, 0);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700880 barrier();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 }
882 } else
883 udelay(10);
884
885 if (!cnt)
886 goto chip_diag_failed;
887
888 /* Check product ID of chip */
Andrew Vasquez76403352009-04-06 22:33:39 -0700889 DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
892 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
893 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
894 mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
895 if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
896 mb[3] != PROD_ID_3) {
897 qla_printk(KERN_WARNING, ha,
898 "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
899
900 goto chip_diag_failed;
901 }
902 ha->product_id[0] = mb[1];
903 ha->product_id[1] = mb[2];
904 ha->product_id[2] = mb[3];
905 ha->product_id[3] = mb[4];
906
907 /* Adjust fw RISC transfer size */
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800908 if (req->length > 1024)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
910 else
911 ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800912 req->length;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
914 if (IS_QLA2200(ha) &&
915 RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
916 /* Limit firmware transfer size with a 2200A */
917 DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800918 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919
andrew.vasquez@qlogic.comea5b6382006-03-09 14:27:08 -0800920 ha->device_type |= DT_ISP2200A;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 ha->fw_transfer_size = 128;
922 }
923
924 /* Wrap Incoming Mailboxes Test. */
925 spin_unlock_irqrestore(&ha->hardware_lock, flags);
926
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800927 DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
928 rval = qla2x00_mbx_reg_test(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 if (rval) {
930 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800931 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 qla_printk(KERN_WARNING, ha,
933 "Failed mailbox send register test\n");
934 }
935 else {
936 /* Flag a successful rval */
937 rval = QLA_SUCCESS;
938 }
939 spin_lock_irqsave(&ha->hardware_lock, flags);
940
941chip_diag_failed:
942 if (rval)
943 DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800944 "****\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 spin_unlock_irqrestore(&ha->hardware_lock, flags);
947
948 return (rval);
949}
950
951/**
Andrew Vasquez01071092005-07-06 10:31:37 -0700952 * qla24xx_chip_diag() - Test ISP24xx for proper operation.
953 * @ha: HA context
954 *
955 * Returns 0 on success.
956 */
957int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800958qla24xx_chip_diag(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700959{
960 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800961 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800962 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -0700963
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800964 ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
Andrew Vasquez01071092005-07-06 10:31:37 -0700965
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800966 rval = qla2x00_mbx_reg_test(vha);
Andrew Vasquez01071092005-07-06 10:31:37 -0700967 if (rval) {
968 DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800969 vha->host_no));
Andrew Vasquez01071092005-07-06 10:31:37 -0700970 qla_printk(KERN_WARNING, ha,
971 "Failed mailbox send register test\n");
972 } else {
973 /* Flag a successful rval */
974 rval = QLA_SUCCESS;
975 }
976
977 return rval;
978}
979
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700980void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800981qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -0700982{
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700983 int rval;
984 uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800985 eft_size, fce_size, mq_size;
Andrew Vasquezdf613b92008-01-17 09:02:17 -0800986 dma_addr_t tc_dma;
987 void *tc;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800988 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800989 struct req_que *req = ha->req_q_map[0];
990 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700991
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700992 if (ha->fw_dump) {
993 qla_printk(KERN_WARNING, ha,
994 "Firmware dump previously allocated.\n");
995 return;
Andrew Vasquezd4e3e042006-05-17 15:09:50 -0700996 }
997
Andrew Vasqueza7a167b2006-06-23 16:10:29 -0700998 ha->fw_dumped = 0;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800999 fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001000 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
1001 fixed_size = sizeof(struct qla2100_fw_dump);
1002 } else if (IS_QLA23XX(ha)) {
1003 fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
1004 mem_size = (ha->fw_memory_size - 0x11000 + 1) *
1005 sizeof(uint16_t);
Andrew Vasqueze4289242007-07-19 15:05:56 -07001006 } else if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08001007 if (IS_QLA81XX(ha))
1008 fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
1009 else if (IS_QLA25XX(ha))
1010 fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
1011 else
1012 fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001013 mem_size = (ha->fw_memory_size - 0x100000 + 1) *
1014 sizeof(uint32_t);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001015 if (ha->mqenable)
1016 mq_size = sizeof(struct qla2xxx_mq_chain);
Andrew Vasquez436a7b12008-07-10 16:55:54 -07001017 /* Allocate memory for Fibre Channel Event Buffer. */
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08001018 if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
Andrew Vasquez436a7b12008-07-10 16:55:54 -07001019 goto try_eft;
1020
1021 tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
1022 GFP_KERNEL);
1023 if (!tc) {
1024 qla_printk(KERN_WARNING, ha, "Unable to allocate "
1025 "(%d KB) for FCE.\n", FCE_SIZE / 1024);
Anirban Chakraborty17d98632008-12-18 10:06:15 -08001026 goto try_eft;
Andrew Vasquez436a7b12008-07-10 16:55:54 -07001027 }
1028
1029 memset(tc, 0, FCE_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001030 rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS,
Andrew Vasquez436a7b12008-07-10 16:55:54 -07001031 ha->fce_mb, &ha->fce_bufs);
1032 if (rval) {
1033 qla_printk(KERN_WARNING, ha, "Unable to initialize "
1034 "FCE (%d).\n", rval);
1035 dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
1036 tc_dma);
1037 ha->flags.fce_enabled = 0;
Anirban Chakraborty17d98632008-12-18 10:06:15 -08001038 goto try_eft;
Andrew Vasquez436a7b12008-07-10 16:55:54 -07001039 }
1040
1041 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
1042 FCE_SIZE / 1024);
1043
Giridhar Malavali7d9dade2009-03-24 09:07:58 -07001044 fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
Andrew Vasquez436a7b12008-07-10 16:55:54 -07001045 ha->flags.fce_enabled = 1;
1046 ha->fce_dma = tc_dma;
1047 ha->fce = tc;
1048try_eft:
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001049 /* Allocate memory for Extended Trace Buffer. */
Andrew Vasquezdf613b92008-01-17 09:02:17 -08001050 tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001051 GFP_KERNEL);
Andrew Vasquezdf613b92008-01-17 09:02:17 -08001052 if (!tc) {
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001053 qla_printk(KERN_WARNING, ha, "Unable to allocate "
1054 "(%d KB) for EFT.\n", EFT_SIZE / 1024);
1055 goto cont_alloc;
1056 }
1057
Andrew Vasquezfc447652008-01-17 09:02:18 -08001058 memset(tc, 0, EFT_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001059 rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001060 if (rval) {
1061 qla_printk(KERN_WARNING, ha, "Unable to initialize "
1062 "EFT (%d).\n", rval);
Andrew Vasquezdf613b92008-01-17 09:02:17 -08001063 dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
1064 tc_dma);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001065 goto cont_alloc;
1066 }
1067
1068 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
1069 EFT_SIZE / 1024);
1070
1071 eft_size = EFT_SIZE;
Andrew Vasquezdf613b92008-01-17 09:02:17 -08001072 ha->eft_dma = tc_dma;
1073 ha->eft = tc;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001074 }
1075cont_alloc:
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001076 req_q_size = req->length * sizeof(request_t);
1077 rsp_q_size = rsp->length * sizeof(response_t);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001078
1079 dump_size = offsetof(struct qla2xxx_fw_dump, isp);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001080 dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size;
Andrew Vasquezbb99de62009-01-05 11:18:08 -08001081 ha->chain_offset = dump_size;
1082 dump_size += mq_size + fce_size;
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001083
Andrew Vasquezd4e3e042006-05-17 15:09:50 -07001084 ha->fw_dump = vmalloc(dump_size);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001085 if (!ha->fw_dump) {
Andrew Vasquez01071092005-07-06 10:31:37 -07001086 qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
Andrew Vasquezd4e3e042006-05-17 15:09:50 -07001087 "firmware dump!!!\n", dump_size / 1024);
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001088
1089 if (ha->eft) {
1090 dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
1091 ha->eft_dma);
1092 ha->eft = NULL;
1093 ha->eft_dma = 0;
1094 }
1095 return;
1096 }
Andrew Vasqueza7a167b2006-06-23 16:10:29 -07001097 qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
1098 dump_size / 1024);
1099
1100 ha->fw_dump_len = dump_size;
1101 ha->fw_dump->signature[0] = 'Q';
1102 ha->fw_dump->signature[1] = 'L';
1103 ha->fw_dump->signature[2] = 'G';
1104 ha->fw_dump->signature[3] = 'C';
1105 ha->fw_dump->version = __constant_htonl(1);
1106
1107 ha->fw_dump->fixed_size = htonl(fixed_size);
1108 ha->fw_dump->mem_size = htonl(mem_size);
1109 ha->fw_dump->req_q_size = htonl(req_q_size);
1110 ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
1111
1112 ha->fw_dump->eft_size = htonl(eft_size);
1113 ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
1114 ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
1115
1116 ha->fw_dump->header_size =
1117 htonl(offsetof(struct qla2xxx_fw_dump, isp));
Andrew Vasquez01071092005-07-06 10:31:37 -07001118}
1119
Andrew Vasquez18e75552009-06-03 09:55:30 -07001120static int
1121qla81xx_mpi_sync(scsi_qla_host_t *vha)
1122{
1123#define MPS_MASK 0xe0
1124 int rval;
1125 uint16_t dc;
1126 uint32_t dw;
1127 struct qla_hw_data *ha = vha->hw;
1128
1129 if (!IS_QLA81XX(vha->hw))
1130 return QLA_SUCCESS;
1131
1132 rval = qla2x00_write_ram_word(vha, 0x7c00, 1);
1133 if (rval != QLA_SUCCESS) {
1134 DEBUG2(qla_printk(KERN_WARNING, ha,
1135 "Sync-MPI: Unable to acquire semaphore.\n"));
1136 goto done;
1137 }
1138
1139 pci_read_config_word(vha->hw->pdev, 0x54, &dc);
1140 rval = qla2x00_read_ram_word(vha, 0x7a15, &dw);
1141 if (rval != QLA_SUCCESS) {
1142 DEBUG2(qla_printk(KERN_WARNING, ha,
1143 "Sync-MPI: Unable to read sync.\n"));
1144 goto done_release;
1145 }
1146
1147 dc &= MPS_MASK;
1148 if (dc == (dw & MPS_MASK))
1149 goto done_release;
1150
1151 dw &= ~MPS_MASK;
1152 dw |= dc;
1153 rval = qla2x00_write_ram_word(vha, 0x7a15, dw);
1154 if (rval != QLA_SUCCESS) {
1155 DEBUG2(qla_printk(KERN_WARNING, ha,
1156 "Sync-MPI: Unable to gain sync.\n"));
1157 }
1158
1159done_release:
1160 rval = qla2x00_write_ram_word(vha, 0x7c00, 0);
1161 if (rval != QLA_SUCCESS) {
1162 DEBUG2(qla_printk(KERN_WARNING, ha,
1163 "Sync-MPI: Unable to release semaphore.\n"));
1164 }
1165
1166done:
1167 return rval;
1168}
1169
Andrew Vasquez01071092005-07-06 10:31:37 -07001170/**
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 * qla2x00_setup_chip() - Load and start RISC firmware.
1172 * @ha: HA context
1173 *
1174 * Returns 0 on success.
1175 */
1176static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001177qla2x00_setup_chip(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178{
Andrew Vasquez01071092005-07-06 10:31:37 -07001179 int rval;
1180 uint32_t srisc_address = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001181 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3db06522008-01-31 12:33:49 -08001182 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1183 unsigned long flags;
Andrew Vasquezdda772e2009-03-24 09:08:00 -07001184 uint16_t fw_major_version;
Andrew Vasquez3db06522008-01-31 12:33:49 -08001185
1186 if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
1187 /* Disable SRAM, Instruction RAM and GP RAM parity. */
1188 spin_lock_irqsave(&ha->hardware_lock, flags);
1189 WRT_REG_WORD(&reg->hccr, (HCCR_ENABLE_PARITY + 0x0));
1190 RD_REG_WORD(&reg->hccr);
1191 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
Andrew Vasquez18e75552009-06-03 09:55:30 -07001194 qla81xx_mpi_sync(vha);
1195
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 /* Load firmware sequences */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001197 rval = ha->isp_ops->load_risc(vha, &srisc_address);
Andrew Vasquez01071092005-07-06 10:31:37 -07001198 if (rval == QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001200 "code.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001202 rval = qla2x00_verify_checksum(vha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 if (rval == QLA_SUCCESS) {
1204 /* Start firmware execution. */
1205 DEBUG(printk("scsi(%ld): Checksum OK, start "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001206 "firmware.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001208 rval = qla2x00_execute_fw(vha, srisc_address);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 /* Retrieve firmware information. */
Andrew Vasquezdda772e2009-03-24 09:08:00 -07001210 if (rval == QLA_SUCCESS) {
1211 fw_major_version = ha->fw_major_version;
Andrew Vasquezca9e9c32009-06-03 09:55:20 -07001212 rval = qla2x00_get_fw_version(vha,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 &ha->fw_major_version,
1214 &ha->fw_minor_version,
1215 &ha->fw_subminor_version,
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08001216 &ha->fw_attributes, &ha->fw_memory_size,
Andrew Vasquez55a96152009-03-24 09:08:03 -07001217 ha->mpi_version, &ha->mpi_capabilities,
1218 ha->phy_version);
Andrew Vasquezca9e9c32009-06-03 09:55:20 -07001219 if (rval != QLA_SUCCESS)
1220 goto failed;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001221 ha->flags.npiv_supported = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001222 if (IS_QLA2XXX_MIDTYPE(ha) &&
Mike Hernandez946fb892008-08-13 21:36:59 -07001223 (ha->fw_attributes & BIT_2)) {
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001224 ha->flags.npiv_supported = 1;
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001225 if ((!ha->max_npiv_vports) ||
1226 ((ha->max_npiv_vports + 1) %
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001227 MIN_MULTI_ID_FABRIC))
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001228 ha->max_npiv_vports =
Andrew Vasquezeb66dc62007-11-12 10:30:58 -08001229 MIN_MULTI_ID_FABRIC - 1;
Seokmann Ju4d0ea242007-09-20 14:07:43 -07001230 }
Andrew Vasquez24a08132009-03-24 09:08:16 -07001231 qla2x00_get_resource_cnts(vha, NULL,
1232 &ha->fw_xcb_count, NULL, NULL,
Andrew Vasquezf3a0a772009-10-13 15:16:49 -07001233 &ha->max_npiv_vports, NULL);
Andrew Vasquezd743de62009-03-24 09:08:15 -07001234
1235 if (!fw_major_version && ql2xallocfwdump)
1236 qla2x00_alloc_fw_dump(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 }
1238 } else {
1239 DEBUG2(printk(KERN_INFO
1240 "scsi(%ld): ISP Firmware failed checksum.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001241 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 }
1243 }
1244
Andrew Vasquez3db06522008-01-31 12:33:49 -08001245 if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
1246 /* Enable proper parity. */
1247 spin_lock_irqsave(&ha->hardware_lock, flags);
1248 if (IS_QLA2300(ha))
1249 /* SRAM parity */
1250 WRT_REG_WORD(&reg->hccr, HCCR_ENABLE_PARITY + 0x1);
1251 else
1252 /* SRAM, Instruction RAM and GP RAM parity */
1253 WRT_REG_WORD(&reg->hccr, HCCR_ENABLE_PARITY + 0x7);
1254 RD_REG_WORD(&reg->hccr);
1255 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1256 }
1257
Joe Carnuccio1d2874d2009-03-24 09:08:06 -07001258 if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
1259 uint32_t size;
1260
1261 rval = qla81xx_fac_get_sector_size(vha, &size);
1262 if (rval == QLA_SUCCESS) {
1263 ha->flags.fac_supported = 1;
1264 ha->fdt_block_size = size << 2;
1265 } else {
1266 qla_printk(KERN_ERR, ha,
1267 "Unsupported FAC firmware (%d.%02d.%02d).\n",
1268 ha->fw_major_version, ha->fw_minor_version,
1269 ha->fw_subminor_version);
1270 }
1271 }
Andrew Vasquezca9e9c32009-06-03 09:55:20 -07001272failed:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (rval) {
1274 DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001275 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 }
1277
1278 return (rval);
1279}
1280
1281/**
1282 * qla2x00_init_response_q_entries() - Initializes response queue entries.
1283 * @ha: HA context
1284 *
1285 * Beginning of request ring has initialization control block already built
1286 * by nvram config routine.
1287 *
1288 * Returns 0 on success.
1289 */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001290void
1291qla2x00_init_response_q_entries(struct rsp_que *rsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292{
1293 uint16_t cnt;
1294 response_t *pkt;
1295
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001296 rsp->ring_ptr = rsp->ring;
1297 rsp->ring_index = 0;
1298 rsp->status_srb = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001299 pkt = rsp->ring_ptr;
1300 for (cnt = 0; cnt < rsp->length; cnt++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301 pkt->signature = RESPONSE_PROCESSED;
1302 pkt++;
1303 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304}
1305
1306/**
1307 * qla2x00_update_fw_options() - Read and process firmware options.
1308 * @ha: HA context
1309 *
1310 * Returns 0 on success.
1311 */
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001312void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001313qla2x00_update_fw_options(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314{
1315 uint16_t swing, emphasis, tx_sens, rx_sens;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001316 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001317
1318 memset(ha->fw_options, 0, sizeof(ha->fw_options));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001319 qla2x00_get_fw_options(vha, ha->fw_options);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320
1321 if (IS_QLA2100(ha) || IS_QLA2200(ha))
1322 return;
1323
1324 /* Serial Link options. */
1325 DEBUG3(printk("scsi(%ld): Serial link options:\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001326 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
1328 sizeof(ha->fw_seriallink_options)));
1329
1330 ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
1331 if (ha->fw_seriallink_options[3] & BIT_2) {
1332 ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
1333
1334 /* 1G settings */
1335 swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
1336 emphasis = (ha->fw_seriallink_options[2] &
1337 (BIT_4 | BIT_3)) >> 3;
1338 tx_sens = ha->fw_seriallink_options[0] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001339 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 rx_sens = (ha->fw_seriallink_options[0] &
1341 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
1342 ha->fw_options[10] = (emphasis << 14) | (swing << 8);
1343 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
1344 if (rx_sens == 0x0)
1345 rx_sens = 0x3;
1346 ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
1347 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1348 ha->fw_options[10] |= BIT_5 |
1349 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1350 (tx_sens & (BIT_1 | BIT_0));
1351
1352 /* 2G settings */
1353 swing = (ha->fw_seriallink_options[2] &
1354 (BIT_7 | BIT_6 | BIT_5)) >> 5;
1355 emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
1356 tx_sens = ha->fw_seriallink_options[1] &
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001357 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 rx_sens = (ha->fw_seriallink_options[1] &
1359 (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
1360 ha->fw_options[11] = (emphasis << 14) | (swing << 8);
1361 if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
1362 if (rx_sens == 0x0)
1363 rx_sens = 0x3;
1364 ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
1365 } else if (IS_QLA2322(ha) || IS_QLA6322(ha))
1366 ha->fw_options[11] |= BIT_5 |
1367 ((rx_sens & (BIT_1 | BIT_0)) << 2) |
1368 (tx_sens & (BIT_1 | BIT_0));
1369 }
1370
1371 /* FCP2 options. */
1372 /* Return command IOCBs without waiting for an ABTS to complete. */
1373 ha->fw_options[3] |= BIT_13;
1374
1375 /* LED scheme. */
1376 if (ha->flags.enable_led_scheme)
1377 ha->fw_options[2] |= BIT_12;
1378
andrew.vasquez@qlogic.com48c02fd2006-03-09 14:27:18 -08001379 /* Detect ISP6312. */
1380 if (IS_QLA6312(ha))
1381 ha->fw_options[2] |= BIT_13;
1382
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383 /* Update firmware options. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001384 qla2x00_set_fw_options(vha, ha->fw_options);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385}
1386
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001387void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001388qla24xx_update_fw_options(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07001389{
1390 int rval;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001391 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07001392
1393 /* Update Serial Link options. */
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001394 if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
Andrew Vasquez01071092005-07-06 10:31:37 -07001395 return;
1396
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001397 rval = qla2x00_set_serdes_params(vha,
andrew.vasquez@qlogic.comf94097e2006-01-13 17:05:32 -08001398 le16_to_cpu(ha->fw_seriallink_options24[1]),
1399 le16_to_cpu(ha->fw_seriallink_options24[2]),
1400 le16_to_cpu(ha->fw_seriallink_options24[3]));
Andrew Vasquez01071092005-07-06 10:31:37 -07001401 if (rval != QLA_SUCCESS) {
1402 qla_printk(KERN_WARNING, ha,
1403 "Unable to update Serial Link options (%x).\n", rval);
1404 }
1405}
1406
1407void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001408qla2x00_config_rings(struct scsi_qla_host *vha)
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001409{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001410 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001411 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001412 struct req_que *req = ha->req_q_map[0];
1413 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001414
1415 /* Setup ring parameters in initialization control block. */
1416 ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0);
1417 ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001418 ha->init_cb->request_q_length = cpu_to_le16(req->length);
1419 ha->init_cb->response_q_length = cpu_to_le16(rsp->length);
1420 ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
1421 ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
1422 ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
1423 ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001424
1425 WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
1426 WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
1427 WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0);
1428 WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0);
1429 RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */
1430}
1431
Andrew Vasquez01071092005-07-06 10:31:37 -07001432void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001433qla24xx_config_rings(struct scsi_qla_host *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07001434{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001435 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001436 device_reg_t __iomem *reg = ISP_QUE_REG(ha, 0);
1437 struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
1438 struct qla_msix_entry *msix;
Andrew Vasquez01071092005-07-06 10:31:37 -07001439 struct init_cb_24xx *icb;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001440 uint16_t rid = 0;
1441 struct req_que *req = ha->req_q_map[0];
1442 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -07001443
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001444/* Setup ring parameters in initialization control block. */
Andrew Vasquez01071092005-07-06 10:31:37 -07001445 icb = (struct init_cb_24xx *)ha->init_cb;
1446 icb->request_q_outpointer = __constant_cpu_to_le16(0);
1447 icb->response_q_inpointer = __constant_cpu_to_le16(0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001448 icb->request_q_length = cpu_to_le16(req->length);
1449 icb->response_q_length = cpu_to_le16(rsp->length);
1450 icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
1451 icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
1452 icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
1453 icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
Andrew Vasquez01071092005-07-06 10:31:37 -07001454
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001455 if (ha->mqenable) {
1456 icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
1457 icb->rid = __constant_cpu_to_le16(rid);
1458 if (ha->flags.msix_enabled) {
1459 msix = &ha->msix_entries[1];
1460 DEBUG2_17(printk(KERN_INFO
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001461 "Registering vector 0x%x for base que\n", msix->entry));
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001462 icb->msix = cpu_to_le16(msix->entry);
1463 }
1464 /* Use alternate PCI bus number */
1465 if (MSB(rid))
1466 icb->firmware_options_2 |=
1467 __constant_cpu_to_le32(BIT_19);
1468 /* Use alternate PCI devfn */
1469 if (LSB(rid))
1470 icb->firmware_options_2 |=
1471 __constant_cpu_to_le32(BIT_18);
1472
Anirban Chakraborty31557542009-12-02 10:36:55 -08001473 /* Use Disable MSIX Handshake mode for capable adapters */
1474 if (IS_MSIX_NACK_CAPABLE(ha)) {
1475 icb->firmware_options_2 &=
1476 __constant_cpu_to_le32(~BIT_22);
1477 ha->flags.disable_msix_handshake = 1;
1478 qla_printk(KERN_INFO, ha,
1479 "MSIX Handshake Disable Mode turned on\n");
1480 } else {
1481 icb->firmware_options_2 |=
1482 __constant_cpu_to_le32(BIT_22);
1483 }
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001484 icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001485
1486 WRT_REG_DWORD(&reg->isp25mq.req_q_in, 0);
1487 WRT_REG_DWORD(&reg->isp25mq.req_q_out, 0);
1488 WRT_REG_DWORD(&reg->isp25mq.rsp_q_in, 0);
1489 WRT_REG_DWORD(&reg->isp25mq.rsp_q_out, 0);
1490 } else {
1491 WRT_REG_DWORD(&reg->isp24.req_q_in, 0);
1492 WRT_REG_DWORD(&reg->isp24.req_q_out, 0);
1493 WRT_REG_DWORD(&reg->isp24.rsp_q_in, 0);
1494 WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0);
1495 }
1496 /* PCI posting */
1497 RD_REG_DWORD(&ioreg->hccr);
Andrew Vasquez01071092005-07-06 10:31:37 -07001498}
1499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500/**
1501 * qla2x00_init_rings() - Initializes firmware.
1502 * @ha: HA context
1503 *
1504 * Beginning of request ring has initialization control block already built
1505 * by nvram config routine.
1506 *
1507 * Returns 0 on success.
1508 */
1509static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001510qla2x00_init_rings(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001511{
1512 int rval;
1513 unsigned long flags = 0;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001514 int cnt, que;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001515 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001516 struct req_que *req;
1517 struct rsp_que *rsp;
1518 struct scsi_qla_host *vp;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001519 struct mid_init_cb_24xx *mid_init_cb =
1520 (struct mid_init_cb_24xx *) ha->init_cb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521
1522 spin_lock_irqsave(&ha->hardware_lock, flags);
1523
1524 /* Clear outstanding commands array. */
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001525 for (que = 0; que < ha->max_req_queues; que++) {
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001526 req = ha->req_q_map[que];
1527 if (!req)
1528 continue;
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001529 for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001530 req->outstanding_cmds[cnt] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001532 req->current_outstanding_cmd = 1;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001533
1534 /* Initialize firmware. */
1535 req->ring_ptr = req->ring;
1536 req->ring_index = 0;
1537 req->cnt = req->length;
1538 }
1539
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001540 for (que = 0; que < ha->max_rsp_queues; que++) {
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001541 rsp = ha->rsp_q_map[que];
1542 if (!rsp)
1543 continue;
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001544 /* Initialize response queue entries */
1545 qla2x00_init_response_q_entries(rsp);
1546 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 /* Clear RSCN queue. */
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08001549 list_for_each_entry(vp, &ha->vp_list, list) {
1550 vp->rscn_in_ptr = 0;
1551 vp->rscn_out_ptr = 0;
1552 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001553 ha->isp_ops->config_rings(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
1555 spin_unlock_irqrestore(&ha->hardware_lock, flags);
1556
1557 /* Update any ISP specific firmware options before initialization. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001558 ha->isp_ops->update_fw_options(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001559
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001560 DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001561
Lalit Chandivade605aa2b2009-03-05 11:07:01 -08001562 if (ha->flags.npiv_supported) {
1563 if (ha->operating_mode == LOOP)
1564 ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1;
Seokmann Juc48339d2008-01-17 09:02:19 -08001565 mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
Lalit Chandivade605aa2b2009-03-05 11:07:01 -08001566 }
1567
Andrew Vasquez24a08132009-03-24 09:08:16 -07001568 if (IS_FWI2_CAPABLE(ha)) {
1569 mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
1570 mid_init_cb->init_cb.execution_throttle =
1571 cpu_to_le16(ha->fw_xcb_count);
1572 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001573
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001574 rval = qla2x00_init_firmware(vha, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 if (rval) {
1576 DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001577 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 } else {
1579 DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001580 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 }
1582
1583 return (rval);
1584}
1585
1586/**
1587 * qla2x00_fw_ready() - Waits for firmware ready.
1588 * @ha: HA context
1589 *
1590 * Returns 0 on success.
1591 */
1592static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001593qla2x00_fw_ready(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594{
1595 int rval;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001596 unsigned long wtime, mtime, cs84xx_time;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001597 uint16_t min_wait; /* Minimum wait time if loop is down */
1598 uint16_t wait_time; /* Wait time if loop is coming ready */
Andrew Vasquez656e8912009-06-03 09:55:29 -07001599 uint16_t state[5];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001600 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601
1602 rval = QLA_SUCCESS;
1603
1604 /* 20 seconds for loop down. */
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001605 min_wait = 20;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001606
1607 /*
1608 * Firmware should take at most one RATOV to login, plus 5 seconds for
1609 * our own processing.
1610 */
1611 if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
1612 wait_time = min_wait;
1613 }
1614
1615 /* Min wait time if loop down */
1616 mtime = jiffies + (min_wait * HZ);
1617
1618 /* wait time before firmware ready */
1619 wtime = jiffies + (wait_time * HZ);
1620
1621 /* Wait for ISP to finish LIP */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001622 if (!vha->flags.init_done)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001623 qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
1624
1625 DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001626 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627
1628 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001629 rval = qla2x00_get_firmware_state(vha, state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 if (rval == QLA_SUCCESS) {
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001631 if (state[0] < FSTATE_LOSS_OF_SYNC) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001632 vha->device_flags &= ~DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001633 }
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001634 if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
1635 DEBUG16(printk("scsi(%ld): fw_state=%x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001636 "84xx=%x.\n", vha->host_no, state[0],
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001637 state[2]));
1638 if ((state[2] & FSTATE_LOGGED_IN) &&
1639 (state[2] & FSTATE_WAITING_FOR_VERIFY)) {
1640 DEBUG16(printk("scsi(%ld): Sending "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001641 "verify iocb.\n", vha->host_no));
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001642
1643 cs84xx_time = jiffies;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001644 rval = qla84xx_init_chip(vha);
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001645 if (rval != QLA_SUCCESS)
1646 break;
1647
1648 /* Add time taken to initialize. */
1649 cs84xx_time = jiffies - cs84xx_time;
1650 wtime += cs84xx_time;
1651 mtime += cs84xx_time;
1652 DEBUG16(printk("scsi(%ld): Increasing "
1653 "wait time by %ld. New time %ld\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001654 vha->host_no, cs84xx_time, wtime));
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001655 }
1656 } else if (state[0] == FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001658 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001660 qla2x00_get_retry_cnt(vha, &ha->retry_count,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661 &ha->login_timeout, &ha->r_a_tov);
1662
1663 rval = QLA_SUCCESS;
1664 break;
1665 }
1666
1667 rval = QLA_FUNCTION_FAILED;
1668
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001669 if (atomic_read(&vha->loop_down_timer) &&
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001670 state[0] != FSTATE_READY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671 /* Loop down. Timeout on min_wait for states
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001672 * other than Wait for Login.
1673 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 if (time_after_eq(jiffies, mtime)) {
1675 qla_printk(KERN_INFO, ha,
1676 "Cable is unplugged...\n");
1677
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001678 vha->device_flags |= DFLG_NO_CABLE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 break;
1680 }
1681 }
1682 } else {
1683 /* Mailbox cmd failed. Timeout on min_wait. */
1684 if (time_after_eq(jiffies, mtime))
1685 break;
1686 }
1687
1688 if (time_after_eq(jiffies, wtime))
1689 break;
1690
1691 /* Delay for a while */
1692 msleep(500);
1693
1694 DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001695 vha->host_no, state[0], jiffies));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001696 } while (1);
1697
Andrew Vasquez656e8912009-06-03 09:55:29 -07001698 DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n",
1699 vha->host_no, state[0], state[1], state[2], state[3], state[4],
1700 jiffies));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
1702 if (rval) {
1703 DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001704 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 }
1706
1707 return (rval);
1708}
1709
1710/*
1711* qla2x00_configure_hba
1712* Setup adapter context.
1713*
1714* Input:
1715* ha = adapter state pointer.
1716*
1717* Returns:
1718* 0 = success
1719*
1720* Context:
1721* Kernel context.
1722*/
1723static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001724qla2x00_configure_hba(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725{
1726 int rval;
1727 uint16_t loop_id;
1728 uint16_t topo;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001729 uint16_t sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001730 uint8_t al_pa;
1731 uint8_t area;
1732 uint8_t domain;
1733 char connect_type[22];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001734 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001735
1736 /* Get host addresses. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001737 rval = qla2x00_get_adapter_id(vha,
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001738 &loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 if (rval != QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001740 if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
Ravi Anand33135aa2005-11-08 14:37:20 -08001741 (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
1742 DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001743 __func__, vha->host_no));
Ravi Anand33135aa2005-11-08 14:37:20 -08001744 } else {
1745 qla_printk(KERN_WARNING, ha,
1746 "ERROR -- Unable to get host loop ID.\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001747 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Ravi Anand33135aa2005-11-08 14:37:20 -08001748 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 return (rval);
1750 }
1751
1752 if (topo == 4) {
1753 qla_printk(KERN_INFO, ha,
1754 "Cannot get topology - retrying.\n");
1755 return (QLA_FUNCTION_FAILED);
1756 }
1757
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001758 vha->loop_id = loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001759
1760 /* initialize */
1761 ha->min_external_loopid = SNS_FIRST_LOOP_ID;
1762 ha->operating_mode = LOOP;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001763 ha->switch_cap = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764
1765 switch (topo) {
1766 case 0:
1767 DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001768 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 ha->current_topology = ISP_CFG_NL;
1770 strcpy(connect_type, "(Loop)");
1771 break;
1772
1773 case 1:
1774 DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001775 vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001776 ha->switch_cap = sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 ha->current_topology = ISP_CFG_FL;
1778 strcpy(connect_type, "(FL_Port)");
1779 break;
1780
1781 case 2:
1782 DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001783 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784 ha->operating_mode = P2P;
1785 ha->current_topology = ISP_CFG_N;
1786 strcpy(connect_type, "(N_Port-to-N_Port)");
1787 break;
1788
1789 case 3:
1790 DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001791 vha->host_no));
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001792 ha->switch_cap = sw_cap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001793 ha->operating_mode = P2P;
1794 ha->current_topology = ISP_CFG_F;
1795 strcpy(connect_type, "(F_Port)");
1796 break;
1797
1798 default:
1799 DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
1800 "Using NL.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001801 vha->host_no, topo));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 ha->current_topology = ISP_CFG_NL;
1803 strcpy(connect_type, "(Loop)");
1804 break;
1805 }
1806
1807 /* Save Host port and loop ID. */
1808 /* byte order - Big Endian */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001809 vha->d_id.b.domain = domain;
1810 vha->d_id.b.area = area;
1811 vha->d_id.b.al_pa = al_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001813 if (!vha->flags.init_done)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814 qla_printk(KERN_INFO, ha,
1815 "Topology - %s, Host Loop address 0x%x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001816 connect_type, vha->loop_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001817
1818 if (rval) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001819 DEBUG2_3(printk("scsi(%ld): FAILED.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001821 DEBUG3(printk("scsi(%ld): exiting normally.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 }
1823
1824 return(rval);
1825}
1826
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001827static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001828qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
1829 char *def)
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001830{
1831 char *st, *en;
1832 uint16_t index;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001833 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezab671142009-08-25 11:36:17 -07001834 int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
1835 !IS_QLA81XX(ha);
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001836
1837 if (memcmp(model, BINZERO, len) != 0) {
1838 strncpy(ha->model_number, model, len);
1839 st = en = ha->model_number;
1840 en += len - 1;
1841 while (en > st) {
1842 if (*en != 0x20 && *en != 0x00)
1843 break;
1844 *en-- = '\0';
1845 }
1846
1847 index = (ha->pdev->subsystem_device & 0xff);
Andrew Vasquez7d0dba12009-04-06 22:33:45 -07001848 if (use_tbl &&
1849 ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001850 index < QLA_MODEL_NAMES)
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001851 strncpy(ha->model_desc,
1852 qla2x00_model_name[index * 2 + 1],
1853 sizeof(ha->model_desc) - 1);
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001854 } else {
1855 index = (ha->pdev->subsystem_device & 0xff);
Andrew Vasquez7d0dba12009-04-06 22:33:45 -07001856 if (use_tbl &&
1857 ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001858 index < QLA_MODEL_NAMES) {
1859 strcpy(ha->model_number,
1860 qla2x00_model_name[index * 2]);
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001861 strncpy(ha->model_desc,
1862 qla2x00_model_name[index * 2 + 1],
1863 sizeof(ha->model_desc) - 1);
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001864 } else {
1865 strcpy(ha->model_number, def);
1866 }
1867 }
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001868 if (IS_FWI2_CAPABLE(ha))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001869 qla2xxx_get_vpd_field(vha, "\x82", ha->model_desc,
Joe Carnuccio1ee27142008-07-10 16:55:53 -07001870 sizeof(ha->model_desc));
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08001871}
1872
David Miller4e08df32007-04-16 12:37:43 -07001873/* On sparc systems, obtain port and node WWN from firmware
1874 * properties.
1875 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001876static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *vha, nvram_t *nv)
David Miller4e08df32007-04-16 12:37:43 -07001877{
1878#ifdef CONFIG_SPARC
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001879 struct qla_hw_data *ha = vha->hw;
David Miller4e08df32007-04-16 12:37:43 -07001880 struct pci_dev *pdev = ha->pdev;
David S. Miller15576bc2007-05-08 00:36:49 -07001881 struct device_node *dp = pci_device_to_OF_node(pdev);
1882 const u8 *val;
David Miller4e08df32007-04-16 12:37:43 -07001883 int len;
1884
1885 val = of_get_property(dp, "port-wwn", &len);
1886 if (val && len >= WWN_SIZE)
1887 memcpy(nv->port_name, val, WWN_SIZE);
1888
1889 val = of_get_property(dp, "node-wwn", &len);
1890 if (val && len >= WWN_SIZE)
1891 memcpy(nv->node_name, val, WWN_SIZE);
1892#endif
1893}
1894
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895/*
1896* NVRAM configuration for ISP 2xxx
1897*
1898* Input:
1899* ha = adapter block pointer.
1900*
1901* Output:
1902* initialization control block in response_ring
1903* host adapters parameters in host adapter block
1904*
1905* Returns:
1906* 0 = success.
1907*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07001908int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001909qla2x00_nvram_config(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910{
David Miller4e08df32007-04-16 12:37:43 -07001911 int rval;
Andrew Vasquez01071092005-07-06 10:31:37 -07001912 uint8_t chksum = 0;
1913 uint16_t cnt;
1914 uint8_t *dptr1, *dptr2;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001915 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07001916 init_cb_t *icb = ha->init_cb;
Seokmann Ju281afe12007-07-26 13:43:34 -07001917 nvram_t *nv = ha->nvram;
1918 uint8_t *ptr = ha->nvram;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001919 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920
David Miller4e08df32007-04-16 12:37:43 -07001921 rval = QLA_SUCCESS;
1922
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 /* Determine NVRAM starting address. */
Andrew Vasquez01071092005-07-06 10:31:37 -07001924 ha->nvram_size = sizeof(nvram_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001925 ha->nvram_base = 0;
1926 if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
1927 if ((RD_REG_WORD(&reg->ctrl_status) >> 14) == 1)
1928 ha->nvram_base = 0x80;
1929
1930 /* Get NVRAM data and calculate checksum. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001931 ha->isp_ops->read_nvram(vha, ptr, ha->nvram_base, ha->nvram_size);
Andrew Vasquez01071092005-07-06 10:31:37 -07001932 for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
1933 chksum += *ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001935 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
Seokmann Ju281afe12007-07-26 13:43:34 -07001936 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001937
1938 /* Bad NVRAM data, set defaults parameters. */
1939 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
1940 nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
1941 /* Reset NVRAM data. */
1942 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
1943 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
1944 nv->nvram_version);
David Miller4e08df32007-04-16 12:37:43 -07001945 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
1946 "invalid -- WWPN) defaults.\n");
1947
1948 /*
1949 * Set default initialization control block.
1950 */
1951 memset(nv, 0, ha->nvram_size);
1952 nv->parameter_block_version = ICB_VERSION;
1953
1954 if (IS_QLA23XX(ha)) {
1955 nv->firmware_options[0] = BIT_2 | BIT_1;
1956 nv->firmware_options[1] = BIT_7 | BIT_5;
1957 nv->add_firmware_options[0] = BIT_5;
1958 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1959 nv->frame_payload_size = __constant_cpu_to_le16(2048);
1960 nv->special_options[1] = BIT_7;
1961 } else if (IS_QLA2200(ha)) {
1962 nv->firmware_options[0] = BIT_2 | BIT_1;
1963 nv->firmware_options[1] = BIT_7 | BIT_5;
1964 nv->add_firmware_options[0] = BIT_5;
1965 nv->add_firmware_options[1] = BIT_5 | BIT_4;
1966 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1967 } else if (IS_QLA2100(ha)) {
1968 nv->firmware_options[0] = BIT_3 | BIT_1;
1969 nv->firmware_options[1] = BIT_5;
1970 nv->frame_payload_size = __constant_cpu_to_le16(1024);
1971 }
1972
1973 nv->max_iocb_allocation = __constant_cpu_to_le16(256);
1974 nv->execution_throttle = __constant_cpu_to_le16(16);
1975 nv->retry_count = 8;
1976 nv->retry_delay = 1;
1977
1978 nv->port_name[0] = 33;
1979 nv->port_name[3] = 224;
1980 nv->port_name[4] = 139;
1981
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001982 qla2xxx_nvram_wwn_from_ofw(vha, nv);
David Miller4e08df32007-04-16 12:37:43 -07001983
1984 nv->login_timeout = 4;
1985
1986 /*
1987 * Set default host adapter parameters
1988 */
1989 nv->host_p[1] = BIT_2;
1990 nv->reset_delay = 5;
1991 nv->port_down_retry_count = 8;
1992 nv->max_luns_per_target = __constant_cpu_to_le16(8);
1993 nv->link_down_timeout = 60;
1994
1995 rval = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996 }
1997
1998#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
1999 /*
2000 * The SN2 does not provide BIOS emulation which means you can't change
2001 * potentially bogus BIOS settings. Force the use of default settings
2002 * for link rate and frame size. Hope that the rest of the settings
2003 * are valid.
2004 */
2005 if (ia64_platform_is("sn2")) {
2006 nv->frame_payload_size = __constant_cpu_to_le16(2048);
2007 if (IS_QLA23XX(ha))
2008 nv->special_options[1] = BIT_7;
2009 }
2010#endif
2011
2012 /* Reset Initialization control block */
Andrew Vasquez01071092005-07-06 10:31:37 -07002013 memset(icb, 0, ha->init_cb_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014
2015 /*
2016 * Setup driver NVRAM options.
2017 */
2018 nv->firmware_options[0] |= (BIT_6 | BIT_1);
2019 nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
2020 nv->firmware_options[1] |= (BIT_5 | BIT_0);
2021 nv->firmware_options[1] &= ~BIT_4;
2022
2023 if (IS_QLA23XX(ha)) {
2024 nv->firmware_options[0] |= BIT_2;
2025 nv->firmware_options[0] &= ~BIT_3;
Andrew Vasquez01071092005-07-06 10:31:37 -07002026 nv->add_firmware_options[1] |= BIT_5 | BIT_4;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027
2028 if (IS_QLA2300(ha)) {
2029 if (ha->fb_rev == FPM_2310) {
2030 strcpy(ha->model_number, "QLA2310");
2031 } else {
2032 strcpy(ha->model_number, "QLA2300");
2033 }
2034 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002035 qla2x00_set_model_info(vha, nv->model_number,
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08002036 sizeof(nv->model_number), "QLA23xx");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 }
2038 } else if (IS_QLA2200(ha)) {
2039 nv->firmware_options[0] |= BIT_2;
2040 /*
2041 * 'Point-to-point preferred, else loop' is not a safe
2042 * connection mode setting.
2043 */
2044 if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
2045 (BIT_5 | BIT_4)) {
2046 /* Force 'loop preferred, else point-to-point'. */
2047 nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
2048 nv->add_firmware_options[0] |= BIT_5;
2049 }
2050 strcpy(ha->model_number, "QLA22xx");
2051 } else /*if (IS_QLA2100(ha))*/ {
2052 strcpy(ha->model_number, "QLA2100");
2053 }
2054
2055 /*
2056 * Copy over NVRAM RISC parameter block to initialization control block.
2057 */
2058 dptr1 = (uint8_t *)icb;
2059 dptr2 = (uint8_t *)&nv->parameter_block_version;
2060 cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
2061 while (cnt--)
2062 *dptr1++ = *dptr2++;
2063
2064 /* Copy 2nd half. */
2065 dptr1 = (uint8_t *)icb->add_firmware_options;
2066 cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
2067 while (cnt--)
2068 *dptr1++ = *dptr2++;
2069
Andrew Vasquez5341e862006-05-17 15:09:16 -07002070 /* Use alternate WWN? */
2071 if (nv->host_p[1] & BIT_7) {
2072 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
2073 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
2074 }
2075
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 /* Prepare nodename */
2077 if ((icb->firmware_options[1] & BIT_6) == 0) {
2078 /*
2079 * Firmware will apply the following mask if the nodename was
2080 * not provided.
2081 */
2082 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
2083 icb->node_name[0] &= 0xF0;
2084 }
2085
2086 /*
2087 * Set host adapter parameters.
2088 */
Andrew Vasquez01819442006-06-23 16:11:10 -07002089 if (nv->host_p[0] & BIT_7)
Andrew Vasquez11010fe2006-10-06 09:54:59 -07002090 ql2xextended_error_logging = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
2092 /* Always load RISC code on non ISP2[12]00 chips. */
2093 if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
2094 ha->flags.disable_risc_code_load = 0;
2095 ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
2096 ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
2097 ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
Andrew Vasquez06c22bd2005-08-26 19:09:00 -07002098 ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07002099 ha->flags.disable_serdes = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100
2101 ha->operating_mode =
2102 (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
2103
2104 memcpy(ha->fw_seriallink_options, nv->seriallink_options,
2105 sizeof(ha->fw_seriallink_options));
2106
2107 /* save HBA serial number */
2108 ha->serial0 = icb->port_name[5];
2109 ha->serial1 = icb->port_name[6];
2110 ha->serial2 = icb->port_name[7];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002111 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
2112 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
2114 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
2115
2116 ha->retry_count = nv->retry_count;
2117
2118 /* Set minimum login_timeout to 4 seconds. */
2119 if (nv->login_timeout < ql2xlogintimeout)
2120 nv->login_timeout = ql2xlogintimeout;
2121 if (nv->login_timeout < 4)
2122 nv->login_timeout = 4;
2123 ha->login_timeout = nv->login_timeout;
2124 icb->login_timeout = nv->login_timeout;
2125
Andrew Vasquez00a537b2008-02-28 14:06:11 -08002126 /* Set minimum RATOV to 100 tenths of a second. */
2127 ha->r_a_tov = 100;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128
Linus Torvalds1da177e2005-04-16 15:20:36 -07002129 ha->loop_reset_delay = nv->reset_delay;
2130
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131 /* Link Down Timeout = 0:
2132 *
2133 * When Port Down timer expires we will start returning
2134 * I/O's to OS with "DID_NO_CONNECT".
2135 *
2136 * Link Down Timeout != 0:
2137 *
2138 * The driver waits for the link to come up after link down
2139 * before returning I/Os to OS with "DID_NO_CONNECT".
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002140 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 if (nv->link_down_timeout == 0) {
2142 ha->loop_down_abort_time =
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04002143 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 } else {
2145 ha->link_down_timeout = nv->link_down_timeout;
2146 ha->loop_down_abort_time =
2147 (LOOP_DOWN_TIME - ha->link_down_timeout);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07002148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 /*
2151 * Need enough time to try and get the port back.
2152 */
2153 ha->port_down_retry_count = nv->port_down_retry_count;
2154 if (qlport_down_retry)
2155 ha->port_down_retry_count = qlport_down_retry;
2156 /* Set login_retry_count */
2157 ha->login_retry_count = nv->retry_count;
2158 if (ha->port_down_retry_count == nv->port_down_retry_count &&
2159 ha->port_down_retry_count > 3)
2160 ha->login_retry_count = ha->port_down_retry_count;
2161 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
2162 ha->login_retry_count = ha->port_down_retry_count;
2163 if (ql2xloginretrycount)
2164 ha->login_retry_count = ql2xloginretrycount;
2165
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 icb->lun_enables = __constant_cpu_to_le16(0);
2167 icb->command_resource_count = 0;
2168 icb->immediate_notify_resource_count = 0;
2169 icb->timeout = __constant_cpu_to_le16(0);
2170
2171 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
2172 /* Enable RIO */
2173 icb->firmware_options[0] &= ~BIT_3;
2174 icb->add_firmware_options[0] &=
2175 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
2176 icb->add_firmware_options[0] |= BIT_2;
2177 icb->response_accumulation_timer = 3;
2178 icb->interrupt_delay_timer = 5;
2179
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002180 vha->flags.process_response_queue = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 } else {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07002182 /* Enable ZIO. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002183 if (!vha->flags.init_done) {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07002184 ha->zio_mode = icb->add_firmware_options[0] &
2185 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
2186 ha->zio_timer = icb->interrupt_delay_timer ?
2187 icb->interrupt_delay_timer: 2;
2188 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002189 icb->add_firmware_options[0] &=
2190 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002191 vha->flags.process_response_queue = 0;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07002192 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08002193 ha->zio_mode = QLA_ZIO_MODE_6;
2194
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07002195 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002196 "delay (%d us).\n", vha->host_no, ha->zio_mode,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07002197 ha->zio_timer * 100));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 qla_printk(KERN_INFO, ha,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07002199 "ZIO mode %d enabled; timer delay (%d us).\n",
2200 ha->zio_mode, ha->zio_timer * 100);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07002202 icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
2203 icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002204 vha->flags.process_response_queue = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 }
2206 }
2207
David Miller4e08df32007-04-16 12:37:43 -07002208 if (rval) {
2209 DEBUG2_3(printk(KERN_WARNING
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002210 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
David Miller4e08df32007-04-16 12:37:43 -07002211 }
2212 return (rval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002213}
2214
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002215static void
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002216qla2x00_rport_del(void *data)
2217{
2218 fc_port_t *fcport = data;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002219 struct fc_rport *rport;
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002220
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002221 spin_lock_irq(fcport->vha->host->host_lock);
Andrew Vasquezac280b62009-08-20 11:06:05 -07002222 rport = fcport->drport ? fcport->drport: fcport->rport;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002223 fcport->drport = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002224 spin_unlock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002225 if (rport)
2226 fc_remote_port_delete(rport);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002227}
2228
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229/**
2230 * qla2x00_alloc_fcport() - Allocate a generic fcport.
2231 * @ha: HA context
2232 * @flags: allocation flags
2233 *
2234 * Returns a pointer to the allocated fcport, or NULL, if none available.
2235 */
Giridhar Malavali9a069e12010-01-12 13:02:47 -08002236fc_port_t *
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002237qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238{
2239 fc_port_t *fcport;
2240
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002241 fcport = kzalloc(sizeof(fc_port_t), flags);
2242 if (!fcport)
2243 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244
2245 /* Setup fcport template structure. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002246 fcport->vha = vha;
2247 fcport->vp_idx = vha->vp_idx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 fcport->port_type = FCT_UNKNOWN;
2249 fcport->loop_id = FC_NO_LOOP_ID;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002250 atomic_set(&fcport->state, FCS_UNCONFIGURED);
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002251 fcport->supported_classes = FC_COS_UNSPECIFIED;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002252
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002253 return fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254}
2255
2256/*
2257 * qla2x00_configure_loop
2258 * Updates Fibre Channel Device Database with what is actually on loop.
2259 *
2260 * Input:
2261 * ha = adapter block pointer.
2262 *
2263 * Returns:
2264 * 0 = success.
2265 * 1 = error.
2266 * 2 = database was full and device was not configured.
2267 */
2268static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002269qla2x00_configure_loop(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002270{
2271 int rval;
2272 unsigned long flags, save_flags;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002273 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002274 rval = QLA_SUCCESS;
2275
2276 /* Get Initiator ID */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002277 if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) {
2278 rval = qla2x00_configure_hba(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002279 if (rval != QLA_SUCCESS) {
2280 DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002281 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002282 return (rval);
2283 }
2284 }
2285
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002286 save_flags = flags = vha->dpc_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002288 vha->host_no, flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289
2290 /*
2291 * If we have both an RSCN and PORT UPDATE pending then handle them
2292 * both at the same time.
2293 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002294 clear_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
2295 clear_bit(RSCN_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
Michael Hernandez3064ff32009-12-15 21:29:44 -08002297 qla2x00_get_data_rate(vha);
2298
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 /* Determine what we need to do */
2300 if (ha->current_topology == ISP_CFG_FL &&
2301 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
2302
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002303 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 set_bit(RSCN_UPDATE, &flags);
2305
2306 } else if (ha->current_topology == ISP_CFG_F &&
2307 (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
2308
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002309 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002310 set_bit(RSCN_UPDATE, &flags);
2311 clear_bit(LOCAL_LOOP_UPDATE, &flags);
2312
Andrew Vasquez21333b42006-05-17 15:09:56 -07002313 } else if (ha->current_topology == ISP_CFG_N) {
2314 clear_bit(RSCN_UPDATE, &flags);
2315
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002316 } else if (!vha->flags.online ||
Linus Torvalds1da177e2005-04-16 15:20:36 -07002317 (test_bit(ABORT_ISP_ACTIVE, &flags))) {
2318
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002319 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320 set_bit(RSCN_UPDATE, &flags);
2321 set_bit(LOCAL_LOOP_UPDATE, &flags);
2322 }
2323
2324 if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002325 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 rval = QLA_FUNCTION_FAILED;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002327 else
2328 rval = qla2x00_configure_local_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 }
2330
2331 if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002332 if (LOOP_TRANSITION(vha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 rval = QLA_FUNCTION_FAILED;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002334 else
2335 rval = qla2x00_configure_fabric(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336 }
2337
2338 if (rval == QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002339 if (atomic_read(&vha->loop_down_timer) ||
2340 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 rval = QLA_FUNCTION_FAILED;
2342 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002343 atomic_set(&vha->loop_state, LOOP_READY);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002345 DEBUG(printk("scsi(%ld): LOOP READY\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002346 }
2347 }
2348
2349 if (rval) {
2350 DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002351 __func__, vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 } else {
2353 DEBUG3(printk("%s: exiting normally\n", __func__));
2354 }
2355
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -07002356 /* Restore state if a resync event occurred during processing */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002357 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002359 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Andrew Vasquezf4658b62009-06-03 09:55:21 -07002360 if (test_bit(RSCN_UPDATE, &save_flags)) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002361 set_bit(RSCN_UPDATE, &vha->dpc_flags);
Andrew Vasquezf4658b62009-06-03 09:55:21 -07002362 vha->flags.rscn_queue_overflow = 1;
2363 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002364 }
2365
2366 return (rval);
2367}
2368
2369
2370
2371/*
2372 * qla2x00_configure_local_loop
2373 * Updates Fibre Channel Device Database with local loop devices.
2374 *
2375 * Input:
2376 * ha = adapter block pointer.
2377 *
2378 * Returns:
2379 * 0 = success.
2380 */
2381static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002382qla2x00_configure_local_loop(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383{
2384 int rval, rval2;
2385 int found_devs;
2386 int found;
2387 fc_port_t *fcport, *new_fcport;
2388
2389 uint16_t index;
2390 uint16_t entries;
2391 char *id_iter;
2392 uint16_t loop_id;
2393 uint8_t domain, area, al_pa;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002394 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395
2396 found_devs = 0;
2397 new_fcport = NULL;
2398 entries = MAX_FIBRE_DEVICES;
2399
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002400 DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", vha->host_no));
2401 DEBUG3(qla2x00_get_fcal_position_map(vha, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402
2403 /* Get list of logged in devices. */
2404 memset(ha->gid_list, 0, GID_LIST_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002405 rval = qla2x00_get_id_list(vha, ha->gid_list, ha->gid_list_dma,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 &entries);
2407 if (rval != QLA_SUCCESS)
2408 goto cleanup_allocation;
2409
2410 DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
Andrew Vasquez76403352009-04-06 22:33:39 -07002411 vha->host_no, entries));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
2413 entries * sizeof(struct gid_list_info)));
2414
2415 /* Allocate temporary fcport for any new fcports discovered. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002416 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002417 if (new_fcport == NULL) {
2418 rval = QLA_MEMORY_ALLOC_FAILED;
2419 goto cleanup_allocation;
2420 }
2421 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2422
2423 /*
2424 * Mark local devices that were present with FCF_DEVICE_LOST for now.
2425 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002426 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 if (atomic_read(&fcport->state) == FCS_ONLINE &&
2428 fcport->port_type != FCT_BROADCAST &&
2429 (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
2430
2431 DEBUG(printk("scsi(%ld): Marking port lost, "
2432 "loop_id=0x%04x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002433 vha->host_no, fcport->loop_id));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
2435 atomic_set(&fcport->state, FCS_DEVICE_LOST);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002436 }
2437 }
2438
2439 /* Add devices to port list. */
2440 id_iter = (char *)ha->gid_list;
2441 for (index = 0; index < entries; index++) {
2442 domain = ((struct gid_list_info *)id_iter)->domain;
2443 area = ((struct gid_list_info *)id_iter)->area;
2444 al_pa = ((struct gid_list_info *)id_iter)->al_pa;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002445 if (IS_QLA2100(ha) || IS_QLA2200(ha))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 loop_id = (uint16_t)
2447 ((struct gid_list_info *)id_iter)->loop_id_2100;
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002448 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 loop_id = le16_to_cpu(
2450 ((struct gid_list_info *)id_iter)->loop_id);
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002451 id_iter += ha->gid_list_info_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452
2453 /* Bypass reserved domain fields. */
2454 if ((domain & 0xf0) == 0xf0)
2455 continue;
2456
2457 /* Bypass if not same domain and area of adapter. */
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002458 if (area && domain &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002459 (area != vha->d_id.b.area || domain != vha->d_id.b.domain))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 continue;
2461
2462 /* Bypass invalid local loop ID. */
2463 if (loop_id > LAST_LOCAL_LOOP_ID)
2464 continue;
2465
2466 /* Fill in member data. */
2467 new_fcport->d_id.b.domain = domain;
2468 new_fcport->d_id.b.area = area;
2469 new_fcport->d_id.b.al_pa = al_pa;
2470 new_fcport->loop_id = loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002471 new_fcport->vp_idx = vha->vp_idx;
2472 rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002473 if (rval2 != QLA_SUCCESS) {
2474 DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
2475 "information -- get_port_database=%x, "
2476 "loop_id=0x%04x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002477 vha->host_no, rval2, new_fcport->loop_id));
andrew.vasquez@qlogic.comc9d02ac2006-01-13 17:05:26 -08002478 DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002479 vha->host_no));
2480 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481 continue;
2482 }
2483
2484 /* Check for matching device in port list. */
2485 found = 0;
2486 fcport = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002487 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002488 if (memcmp(new_fcport->port_name, fcport->port_name,
2489 WWN_SIZE))
2490 continue;
2491
Shyam Sundarddb9b122009-03-24 09:08:10 -07002492 fcport->flags &= ~FCF_FABRIC_DEVICE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002493 fcport->loop_id = new_fcport->loop_id;
2494 fcport->port_type = new_fcport->port_type;
2495 fcport->d_id.b24 = new_fcport->d_id.b24;
2496 memcpy(fcport->node_name, new_fcport->node_name,
2497 WWN_SIZE);
2498
2499 found++;
2500 break;
2501 }
2502
2503 if (!found) {
2504 /* New device, add to fcports list. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002505 if (vha->vp_idx) {
2506 new_fcport->vha = vha;
2507 new_fcport->vp_idx = vha->vp_idx;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002508 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002509 list_add_tail(&new_fcport->list, &vha->vp_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511 /* Allocate a new replacement fcport. */
2512 fcport = new_fcport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002513 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002514 if (new_fcport == NULL) {
2515 rval = QLA_MEMORY_ALLOC_FAILED;
2516 goto cleanup_allocation;
2517 }
2518 new_fcport->flags &= ~FCF_FABRIC_DEVICE;
2519 }
2520
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002521 /* Base iIDMA settings on HBA port speed. */
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002522 fcport->fp_speed = ha->link_data_rate;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002523
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002524 qla2x00_update_fcport(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002525
2526 found_devs++;
2527 }
2528
2529cleanup_allocation:
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002530 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531
2532 if (rval != QLA_SUCCESS) {
2533 DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002534 "rval=%x\n", vha->host_no, rval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 }
2536
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537 return (rval);
2538}
2539
2540static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002541qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002542{
2543#define LS_UNKNOWN 2
Andrew Vasquez9f8fdde2009-06-03 09:55:22 -07002544 static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
2545 char *link_speed;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002546 int rval;
Harish Zunjarrao1bb39542009-06-17 10:30:29 -07002547 uint16_t mb[4];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002548 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002549
Andrew Vasquezc76f2c02007-07-19 15:05:57 -07002550 if (!IS_IIDMA_CAPABLE(ha))
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002551 return;
2552
Andrew Vasquez39bd9622007-09-20 14:07:34 -07002553 if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
2554 fcport->fp_speed > ha->link_data_rate)
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002555 return;
2556
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002557 rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002558 mb);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002559 if (rval != QLA_SUCCESS) {
2560 DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
2561 "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002562 vha->host_no, fcport->port_name[0], fcport->port_name[1],
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002563 fcport->port_name[2], fcport->port_name[3],
2564 fcport->port_name[4], fcport->port_name[5],
2565 fcport->port_name[6], fcport->port_name[7], rval,
Andrew Vasqueza3cbdfa2007-08-13 10:13:18 -07002566 fcport->fp_speed, mb[0], mb[1]));
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002567 } else {
Andrew Vasquez9f8fdde2009-06-03 09:55:22 -07002568 link_speed = link_speeds[LS_UNKNOWN];
2569 if (fcport->fp_speed < 5)
2570 link_speed = link_speeds[fcport->fp_speed];
2571 else if (fcport->fp_speed == 0x13)
2572 link_speed = link_speeds[5];
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002573 DEBUG2(qla_printk(KERN_INFO, ha,
2574 "iIDMA adjusted to %s GB/s on "
2575 "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
Andrew Vasquez9f8fdde2009-06-03 09:55:22 -07002576 link_speed, fcport->port_name[0],
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002577 fcport->port_name[1], fcport->port_name[2],
2578 fcport->port_name[3], fcport->port_name[4],
2579 fcport->port_name[5], fcport->port_name[6],
2580 fcport->port_name[7]));
2581 }
2582}
2583
Adrian Bunk23be3312006-11-24 02:46:01 +01002584static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002585qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
8482e112005-04-17 15:04:54 -05002586{
2587 struct fc_rport_identifiers rport_ids;
bdf79622005-04-17 15:06:53 -05002588 struct fc_rport *rport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002589 struct qla_hw_data *ha = vha->hw;
8482e112005-04-17 15:04:54 -05002590
Andrew Vasquezac280b62009-08-20 11:06:05 -07002591 qla2x00_rport_del(fcport);
8482e112005-04-17 15:04:54 -05002592
Andrew Vasquezf8b02a82005-08-31 15:21:20 -07002593 rport_ids.node_name = wwn_to_u64(fcport->node_name);
2594 rport_ids.port_name = wwn_to_u64(fcport->port_name);
8482e112005-04-17 15:04:54 -05002595 rport_ids.port_id = fcport->d_id.b.domain << 16 |
2596 fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
2597 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002598 fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids);
Andrew Vasquez77d74142005-07-08 18:00:36 -07002599 if (!rport) {
2600 qla_printk(KERN_WARNING, ha,
2601 "Unable to allocate fc remote port!\n");
2602 return;
2603 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002604 spin_lock_irq(fcport->vha->host->host_lock);
James.Smart@Emulex.Com19a7b4a2005-10-18 12:03:35 -04002605 *((fc_port_t **)rport->dd_data) = fcport;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002606 spin_unlock_irq(fcport->vha->host->host_lock);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002607
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07002608 rport->supported_classes = fcport->supported_classes;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002609
2610 rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
8482e112005-04-17 15:04:54 -05002611 if (fcport->port_type == FCT_INITIATOR)
2612 rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
2613 if (fcport->port_type == FCT_TARGET)
2614 rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
Andrew Vasquez77d74142005-07-08 18:00:36 -07002615 fc_remote_port_rolechg(rport, rport_ids.roles);
8482e112005-04-17 15:04:54 -05002616}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002617
2618/*
Adrian Bunk23be3312006-11-24 02:46:01 +01002619 * qla2x00_update_fcport
2620 * Updates device on list.
2621 *
2622 * Input:
2623 * ha = adapter block pointer.
2624 * fcport = port structure pointer.
2625 *
2626 * Return:
2627 * 0 - Success
2628 * BIT_0 - error
2629 *
2630 * Context:
2631 * Kernel context.
2632 */
2633void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002634qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
Adrian Bunk23be3312006-11-24 02:46:01 +01002635{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002636 struct qla_hw_data *ha = vha->hw;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002637
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002638 fcport->vha = vha;
Adrian Bunk23be3312006-11-24 02:46:01 +01002639 fcport->login_retry = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002640 fcport->port_login_retry_count = ha->port_down_retry_count *
Adrian Bunk23be3312006-11-24 02:46:01 +01002641 PORT_RETRY_TIME;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002642 atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
Adrian Bunk23be3312006-11-24 02:46:01 +01002643 PORT_RETRY_TIME);
2644 fcport->flags &= ~FCF_LOGIN_NEEDED;
2645
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002646 qla2x00_iidma_fcport(vha, fcport);
Adrian Bunk23be3312006-11-24 02:46:01 +01002647
2648 atomic_set(&fcport->state, FCS_ONLINE);
2649
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002650 qla2x00_reg_remote_port(vha, fcport);
Adrian Bunk23be3312006-11-24 02:46:01 +01002651}
2652
2653/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 * qla2x00_configure_fabric
2655 * Setup SNS devices with loop ID's.
2656 *
2657 * Input:
2658 * ha = adapter block pointer.
2659 *
2660 * Returns:
2661 * 0 = success.
2662 * BIT_0 = error
2663 */
2664static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002665qla2x00_configure_fabric(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666{
2667 int rval, rval2;
2668 fc_port_t *fcport, *fcptemp;
2669 uint16_t next_loopid;
2670 uint16_t mb[MAILBOX_REGISTER_COUNT];
Andrew Vasquez01071092005-07-06 10:31:37 -07002671 uint16_t loop_id;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 LIST_HEAD(new_fcports);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002673 struct qla_hw_data *ha = vha->hw;
2674 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675
2676 /* If FL port exists, then SNS is present */
Andrew Vasqueze4289242007-07-19 15:05:56 -07002677 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez01071092005-07-06 10:31:37 -07002678 loop_id = NPH_F_PORT;
2679 else
2680 loop_id = SNS_FL_PORT;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002681 rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 if (rval != QLA_SUCCESS) {
2683 DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002684 "Port\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002686 vha->device_flags &= ~SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 return (QLA_SUCCESS);
2688 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002689 vha->device_flags |= SWITCH_FOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690
2691 /* Mark devices that need re-synchronization. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002692 rval2 = qla2x00_device_resync(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002693 if (rval2 == QLA_RSCNS_HANDLED) {
2694 /* No point doing the scan, just continue. */
2695 return (QLA_SUCCESS);
2696 }
2697 do {
Andrew Vasquezcca53352005-08-26 19:08:30 -07002698 /* FDMI support. */
2699 if (ql2xfdmienable &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002700 test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags))
2701 qla2x00_fdmi_register(vha);
Andrew Vasquezcca53352005-08-26 19:08:30 -07002702
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 /* Ensure we are logged into the SNS. */
Andrew Vasqueze4289242007-07-19 15:05:56 -07002704 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez01071092005-07-06 10:31:37 -07002705 loop_id = NPH_SNS;
2706 else
2707 loop_id = SIMPLE_NAME_SERVER;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002708 ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
Andrew Vasquezabbd8872005-07-06 10:30:05 -07002709 0xfc, mb, BIT_1 | BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002710 if (mb[0] != MBS_COMMAND_COMPLETE) {
2711 DEBUG2(qla_printk(KERN_INFO, ha,
2712 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
Andrew Vasquez01071092005-07-06 10:31:37 -07002713 "mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 mb[0], mb[1], mb[2], mb[6], mb[7]));
2715 return (QLA_SUCCESS);
2716 }
2717
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002718 if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
2719 if (qla2x00_rft_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 /* EMPTY */
2721 DEBUG2(printk("scsi(%ld): Register FC-4 "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002722 "TYPE failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002724 if (qla2x00_rff_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 /* EMPTY */
2726 DEBUG2(printk("scsi(%ld): Register FC-4 "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002727 "Features failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002729 if (qla2x00_rnn_id(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 /* EMPTY */
2731 DEBUG2(printk("scsi(%ld): Register Node Name "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002732 "failed.\n", vha->host_no));
2733 } else if (qla2x00_rsnn_nn(vha)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 /* EMPTY */
2735 DEBUG2(printk("scsi(%ld): Register Symbolic "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002736 "Node Name failed.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 }
2738 }
2739
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002740 rval = qla2x00_find_all_fabric_devs(vha, &new_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 if (rval != QLA_SUCCESS)
2742 break;
2743
2744 /*
2745 * Logout all previous fabric devices marked lost, except
Andrew Vasquezf08b7252010-01-12 12:59:48 -08002746 * FCP2 devices.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002748 list_for_each_entry(fcport, &vha->vp_fcports, list) {
2749 if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750 break;
2751
2752 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
2753 continue;
2754
2755 if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002756 qla2x00_mark_device_lost(vha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08002757 ql2xplogiabsentdevice, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002758 if (fcport->loop_id != FC_NO_LOOP_ID &&
Andrew Vasquezf08b7252010-01-12 12:59:48 -08002759 (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 fcport->port_type != FCT_INITIATOR &&
2761 fcport->port_type != FCT_BROADCAST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002762 ha->isp_ops->fabric_logout(vha,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07002763 fcport->loop_id,
2764 fcport->d_id.b.domain,
2765 fcport->d_id.b.area,
2766 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002767 fcport->loop_id = FC_NO_LOOP_ID;
2768 }
2769 }
2770 }
2771
2772 /* Starting free loop ID. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002773 next_loopid = ha->min_external_loopid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
2775 /*
2776 * Scan through our port list and login entries that need to be
2777 * logged in.
2778 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002779 list_for_each_entry(fcport, &vha->vp_fcports, list) {
2780 if (atomic_read(&vha->loop_down_timer) ||
2781 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782 break;
2783
2784 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
2785 (fcport->flags & FCF_LOGIN_NEEDED) == 0)
2786 continue;
2787
2788 if (fcport->loop_id == FC_NO_LOOP_ID) {
2789 fcport->loop_id = next_loopid;
Seokmann Jud4486fd2008-04-03 13:13:28 -07002790 rval = qla2x00_find_new_loop_id(
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002791 base_vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002792 if (rval != QLA_SUCCESS) {
2793 /* Ran out of IDs to use */
2794 break;
2795 }
2796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 /* Login and update database */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002798 qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 }
2800
2801 /* Exit if out of loop IDs. */
2802 if (rval != QLA_SUCCESS) {
2803 break;
2804 }
2805
2806 /*
2807 * Login and add the new devices to our port list.
2808 */
2809 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002810 if (atomic_read(&vha->loop_down_timer) ||
2811 test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002812 break;
2813
2814 /* Find a new loop ID to use. */
2815 fcport->loop_id = next_loopid;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002816 rval = qla2x00_find_new_loop_id(base_vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 if (rval != QLA_SUCCESS) {
2818 /* Ran out of IDs to use */
2819 break;
2820 }
2821
bdf79622005-04-17 15:06:53 -05002822 /* Login and update database */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002823 qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002824
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002825 if (vha->vp_idx) {
2826 fcport->vha = vha;
2827 fcport->vp_idx = vha->vp_idx;
2828 }
2829 list_move_tail(&fcport->list, &vha->vp_fcports);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 }
2831 } while (0);
2832
2833 /* Free all new device structures not processed. */
2834 list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
2835 list_del(&fcport->list);
2836 kfree(fcport);
2837 }
2838
2839 if (rval) {
2840 DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002841 "rval=%d\n", vha->host_no, rval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 }
2843
2844 return (rval);
2845}
2846
2847
2848/*
2849 * qla2x00_find_all_fabric_devs
2850 *
2851 * Input:
2852 * ha = adapter block pointer.
2853 * dev = database device entry pointer.
2854 *
2855 * Returns:
2856 * 0 = success.
2857 *
2858 * Context:
2859 * Kernel context.
2860 */
2861static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002862qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
2863 struct list_head *new_fcports)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002864{
2865 int rval;
2866 uint16_t loop_id;
2867 fc_port_t *fcport, *new_fcport, *fcptemp;
2868 int found;
2869
2870 sw_info_t *swl;
2871 int swl_idx;
2872 int first_dev, last_dev;
2873 port_id_t wrap, nxt_d_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002874 struct qla_hw_data *ha = vha->hw;
2875 struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002876 struct scsi_qla_host *tvp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877
2878 rval = QLA_SUCCESS;
2879
2880 /* Try GID_PT to get device list, else GAN. */
Andrew Vasquez4b892582008-09-11 21:22:48 -07002881 swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
Mariusz Kozlowskibbfbbbc2007-08-11 10:13:24 +02002882 if (!swl) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002883 /*EMPTY*/
2884 DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002885 "on GA_NXT\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002887 if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002888 kfree(swl);
2889 swl = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002890 } else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002891 kfree(swl);
2892 swl = NULL;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002893 } else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002894 kfree(swl);
2895 swl = NULL;
Andrew Vasqueze5896bd2008-07-10 16:55:52 -07002896 } else if (ql2xiidmaenable &&
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002897 qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) {
2898 qla2x00_gpsc(vha, swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 }
2900 }
2901 swl_idx = 0;
2902
2903 /* Allocate temporary fcport for any new fcports discovered. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002904 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002905 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08002906 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 return (QLA_MEMORY_ALLOC_FAILED);
2908 }
2909 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 /* Set start port ID scan at adapter ID. */
2911 first_dev = 1;
2912 last_dev = 0;
2913
2914 /* Starting free loop ID. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002915 loop_id = ha->min_external_loopid;
2916 for (; loop_id <= ha->max_loop_id; loop_id++) {
2917 if (qla2x00_is_reserved_id(vha, loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918 continue;
2919
Andrew Vasquezbb2d52b2010-02-18 10:07:27 -08002920 if (atomic_read(&vha->loop_down_timer) ||
2921 LOOP_TRANSITION(vha)) {
2922 atomic_set(&vha->loop_down_timer, 0);
2923 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
2924 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002925 break;
Andrew Vasquezbb2d52b2010-02-18 10:07:27 -08002926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927
2928 if (swl != NULL) {
2929 if (last_dev) {
2930 wrap.b24 = new_fcport->d_id.b24;
2931 } else {
2932 new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
2933 memcpy(new_fcport->node_name,
2934 swl[swl_idx].node_name, WWN_SIZE);
2935 memcpy(new_fcport->port_name,
2936 swl[swl_idx].port_name, WWN_SIZE);
Andrew Vasquezd8b45212006-10-02 12:00:43 -07002937 memcpy(new_fcport->fabric_port_name,
2938 swl[swl_idx].fabric_port_name, WWN_SIZE);
2939 new_fcport->fp_speed = swl[swl_idx].fp_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940
2941 if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
2942 last_dev = 1;
2943 }
2944 swl_idx++;
2945 }
2946 } else {
2947 /* Send GA_NXT to the switch */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002948 rval = qla2x00_ga_nxt(vha, new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 if (rval != QLA_SUCCESS) {
2950 qla_printk(KERN_WARNING, ha,
2951 "SNS scan failed -- assuming zero-entry "
2952 "result...\n");
2953 list_for_each_entry_safe(fcport, fcptemp,
2954 new_fcports, list) {
2955 list_del(&fcport->list);
2956 kfree(fcport);
2957 }
2958 rval = QLA_SUCCESS;
2959 break;
2960 }
2961 }
2962
2963 /* If wrap on switch device list, exit. */
2964 if (first_dev) {
2965 wrap.b24 = new_fcport->d_id.b24;
2966 first_dev = 0;
2967 } else if (new_fcport->d_id.b24 == wrap.b24) {
2968 DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002969 vha->host_no, new_fcport->d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
2971 break;
2972 }
2973
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002974 /* Bypass if same physical adapter. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002975 if (new_fcport->d_id.b24 == base_vha->d_id.b24)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 continue;
2977
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002978 /* Bypass virtual ports of the same host. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002979 found = 0;
2980 if (ha->num_vhosts) {
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08002981 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002982 if (new_fcport->d_id.b24 == vp->d_id.b24) {
2983 found = 1;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002984 break;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002985 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002986 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002987 if (found)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07002988 continue;
2989 }
2990
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002991 /* Bypass if same domain and area of adapter. */
2992 if (((new_fcport->d_id.b24 & 0xffff00) ==
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002993 (vha->d_id.b24 & 0xffff00)) && ha->current_topology ==
Andrew Vasquezf7d289f2005-08-26 19:08:40 -07002994 ISP_CFG_FL)
2995 continue;
2996
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 /* Bypass reserved domain fields. */
2998 if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
2999 continue;
3000
3001 /* Locate matching device in database. */
3002 found = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003003 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004 if (memcmp(new_fcport->port_name, fcport->port_name,
3005 WWN_SIZE))
3006 continue;
3007
3008 found++;
3009
Andrew Vasquezd8b45212006-10-02 12:00:43 -07003010 /* Update port state. */
3011 memcpy(fcport->fabric_port_name,
3012 new_fcport->fabric_port_name, WWN_SIZE);
3013 fcport->fp_speed = new_fcport->fp_speed;
3014
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 /*
3016 * If address the same and state FCS_ONLINE, nothing
3017 * changed.
3018 */
3019 if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
3020 atomic_read(&fcport->state) == FCS_ONLINE) {
3021 break;
3022 }
3023
3024 /*
3025 * If device was not a fabric device before.
3026 */
3027 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
3028 fcport->d_id.b24 = new_fcport->d_id.b24;
3029 fcport->loop_id = FC_NO_LOOP_ID;
3030 fcport->flags |= (FCF_FABRIC_DEVICE |
3031 FCF_LOGIN_NEEDED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 break;
3033 }
3034
3035 /*
3036 * Port ID changed or device was marked to be updated;
3037 * Log it out if still logged in and mark it for
3038 * relogin later.
3039 */
3040 fcport->d_id.b24 = new_fcport->d_id.b24;
3041 fcport->flags |= FCF_LOGIN_NEEDED;
3042 if (fcport->loop_id != FC_NO_LOOP_ID &&
Andrew Vasquezf08b7252010-01-12 12:59:48 -08003043 (fcport->flags & FCF_FCP2_DEVICE) == 0 &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07003044 fcport->port_type != FCT_INITIATOR &&
3045 fcport->port_type != FCT_BROADCAST) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003046 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003047 fcport->d_id.b.domain, fcport->d_id.b.area,
3048 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003049 fcport->loop_id = FC_NO_LOOP_ID;
3050 }
3051
3052 break;
3053 }
3054
3055 if (found)
3056 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 /* If device was not in our fcports list, then add it. */
3058 list_add_tail(&new_fcport->list, new_fcports);
3059
3060 /* Allocate a new replacement fcport. */
3061 nxt_d_id.b24 = new_fcport->d_id.b24;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003062 new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063 if (new_fcport == NULL) {
Jesper Juhlc9475cb2005-11-07 01:01:26 -08003064 kfree(swl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 return (QLA_MEMORY_ALLOC_FAILED);
3066 }
3067 new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
3068 new_fcport->d_id.b24 = nxt_d_id.b24;
3069 }
3070
Jesper Juhlc9475cb2005-11-07 01:01:26 -08003071 kfree(swl);
3072 kfree(new_fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003073
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 return (rval);
3075}
3076
3077/*
3078 * qla2x00_find_new_loop_id
3079 * Scan through our port list and find a new usable loop ID.
3080 *
3081 * Input:
3082 * ha: adapter state pointer.
3083 * dev: port structure pointer.
3084 *
3085 * Returns:
3086 * qla2x00 local function return status code.
3087 *
3088 * Context:
3089 * Kernel context.
3090 */
Adrian Bunk413975a2006-06-30 02:33:06 -07003091static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003092qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003093{
3094 int rval;
3095 int found;
3096 fc_port_t *fcport;
3097 uint16_t first_loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003098 struct qla_hw_data *ha = vha->hw;
3099 struct scsi_qla_host *vp;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003100 struct scsi_qla_host *tvp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101
3102 rval = QLA_SUCCESS;
3103
3104 /* Save starting loop ID. */
3105 first_loop_id = dev->loop_id;
3106
3107 for (;;) {
3108 /* Skip loop ID if already used by adapter. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003109 if (dev->loop_id == vha->loop_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003110 dev->loop_id++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003111
3112 /* Skip reserved loop IDs. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003113 while (qla2x00_is_reserved_id(vha, dev->loop_id))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114 dev->loop_id++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003115
3116 /* Reset loop ID if passed the end. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003117 if (dev->loop_id > ha->max_loop_id) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003118 /* first loop ID. */
3119 dev->loop_id = ha->min_external_loopid;
3120 }
3121
3122 /* Check for loop ID being already in use. */
3123 found = 0;
3124 fcport = NULL;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003125 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003126 list_for_each_entry(fcport, &vp->vp_fcports, list) {
3127 if (fcport->loop_id == dev->loop_id &&
3128 fcport != dev) {
3129 /* ID possibly in use */
3130 found++;
3131 break;
3132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003133 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003134 if (found)
3135 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003136 }
3137
3138 /* If not in use then it is free to use. */
3139 if (!found) {
3140 break;
3141 }
3142
3143 /* ID in use. Try next value. */
3144 dev->loop_id++;
3145
3146 /* If wrap around. No free ID to use. */
3147 if (dev->loop_id == first_loop_id) {
3148 dev->loop_id = FC_NO_LOOP_ID;
3149 rval = QLA_FUNCTION_FAILED;
3150 break;
3151 }
3152 }
3153
3154 return (rval);
3155}
3156
3157/*
3158 * qla2x00_device_resync
3159 * Marks devices in the database that needs resynchronization.
3160 *
3161 * Input:
3162 * ha = adapter block pointer.
3163 *
3164 * Context:
3165 * Kernel context.
3166 */
3167static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003168qla2x00_device_resync(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003169{
3170 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 uint32_t mask;
3172 fc_port_t *fcport;
3173 uint32_t rscn_entry;
3174 uint8_t rscn_out_iter;
3175 uint8_t format;
3176 port_id_t d_id;
3177
3178 rval = QLA_RSCNS_HANDLED;
3179
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003180 while (vha->rscn_out_ptr != vha->rscn_in_ptr ||
3181 vha->flags.rscn_queue_overflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003182
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003183 rscn_entry = vha->rscn_queue[vha->rscn_out_ptr];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003184 format = MSB(MSW(rscn_entry));
3185 d_id.b.domain = LSB(MSW(rscn_entry));
3186 d_id.b.area = MSB(LSW(rscn_entry));
3187 d_id.b.al_pa = LSB(LSW(rscn_entry));
3188
3189 DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
3190 "[%02x/%02x%02x%02x].\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003191 vha->host_no, vha->rscn_out_ptr, format, d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003192 d_id.b.area, d_id.b.al_pa));
3193
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003194 vha->rscn_out_ptr++;
3195 if (vha->rscn_out_ptr == MAX_RSCN_COUNT)
3196 vha->rscn_out_ptr = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003197
3198 /* Skip duplicate entries. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003199 for (rscn_out_iter = vha->rscn_out_ptr;
3200 !vha->flags.rscn_queue_overflow &&
3201 rscn_out_iter != vha->rscn_in_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003202 rscn_out_iter = (rscn_out_iter ==
3203 (MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
3204
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003205 if (rscn_entry != vha->rscn_queue[rscn_out_iter])
Linus Torvalds1da177e2005-04-16 15:20:36 -07003206 break;
3207
3208 DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003209 "entry found at [%d].\n", vha->host_no,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 rscn_out_iter));
3211
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003212 vha->rscn_out_ptr = rscn_out_iter;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213 }
3214
3215 /* Queue overflow, set switch default case. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003216 if (vha->flags.rscn_queue_overflow) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003217 DEBUG(printk("scsi(%ld): device_resync: rscn "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003218 "overflow.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219
3220 format = 3;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003221 vha->flags.rscn_queue_overflow = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003222 }
3223
3224 switch (format) {
3225 case 0:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003226 mask = 0xffffff;
3227 break;
3228 case 1:
3229 mask = 0xffff00;
3230 break;
3231 case 2:
3232 mask = 0xff0000;
3233 break;
3234 default:
3235 mask = 0x0;
3236 d_id.b24 = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003237 vha->rscn_out_ptr = vha->rscn_in_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003238 break;
3239 }
3240
3241 rval = QLA_SUCCESS;
3242
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003243 list_for_each_entry(fcport, &vha->vp_fcports, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003244 if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
3245 (fcport->d_id.b24 & mask) != d_id.b24 ||
3246 fcport->port_type == FCT_BROADCAST)
3247 continue;
3248
3249 if (atomic_read(&fcport->state) == FCS_ONLINE) {
3250 if (format != 3 ||
3251 fcport->port_type != FCT_INITIATOR) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003252 qla2x00_mark_device_lost(vha, fcport,
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003253 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254 }
3255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 }
3257 }
3258 return (rval);
3259}
3260
3261/*
3262 * qla2x00_fabric_dev_login
3263 * Login fabric target device and update FC port database.
3264 *
3265 * Input:
3266 * ha: adapter state pointer.
3267 * fcport: port structure list pointer.
3268 * next_loopid: contains value of a new loop ID that can be used
3269 * by the next login attempt.
3270 *
3271 * Returns:
3272 * qla2x00 local function return status code.
3273 *
3274 * Context:
3275 * Kernel context.
3276 */
3277static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003278qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003279 uint16_t *next_loopid)
3280{
3281 int rval;
3282 int retry;
Andrew Vasquez01071092005-07-06 10:31:37 -07003283 uint8_t opts;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003284 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003285
3286 rval = QLA_SUCCESS;
3287 retry = 0;
3288
Andrew Vasquezac280b62009-08-20 11:06:05 -07003289 if (IS_ALOGIO_CAPABLE(ha)) {
3290 rval = qla2x00_post_async_login_work(vha, fcport, NULL);
3291 if (!rval)
3292 return rval;
3293 }
3294
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003295 rval = qla2x00_fabric_login(vha, fcport, next_loopid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003296 if (rval == QLA_SUCCESS) {
Andrew Vasquezf08b7252010-01-12 12:59:48 -08003297 /* Send an ADISC to FCP2 devices.*/
Andrew Vasquez01071092005-07-06 10:31:37 -07003298 opts = 0;
Andrew Vasquezf08b7252010-01-12 12:59:48 -08003299 if (fcport->flags & FCF_FCP2_DEVICE)
Andrew Vasquez01071092005-07-06 10:31:37 -07003300 opts |= BIT_1;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003301 rval = qla2x00_get_port_database(vha, fcport, opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003302 if (rval != QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003303 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003304 fcport->d_id.b.domain, fcport->d_id.b.area,
3305 fcport->d_id.b.al_pa);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003306 qla2x00_mark_device_lost(vha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003307 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003308 qla2x00_update_fcport(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 }
3310 }
3311
3312 return (rval);
3313}
3314
3315/*
3316 * qla2x00_fabric_login
3317 * Issue fabric login command.
3318 *
3319 * Input:
3320 * ha = adapter block pointer.
3321 * device = pointer to FC device type structure.
3322 *
3323 * Returns:
3324 * 0 - Login successfully
3325 * 1 - Login failed
3326 * 2 - Initiator device
3327 * 3 - Fatal error
3328 */
3329int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003330qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 uint16_t *next_loopid)
3332{
3333 int rval;
3334 int retry;
3335 uint16_t tmp_loopid;
3336 uint16_t mb[MAILBOX_REGISTER_COUNT];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003337 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003338
3339 retry = 0;
3340 tmp_loopid = 0;
3341
3342 for (;;) {
3343 DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
3344 "for port %02x%02x%02x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003345 vha->host_no, fcport->loop_id, fcport->d_id.b.domain,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346 fcport->d_id.b.area, fcport->d_id.b.al_pa));
3347
3348 /* Login fcport on switch. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003349 ha->isp_ops->fabric_login(vha, fcport->loop_id,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003350 fcport->d_id.b.domain, fcport->d_id.b.area,
3351 fcport->d_id.b.al_pa, mb, BIT_0);
3352 if (mb[0] == MBS_PORT_ID_USED) {
3353 /*
3354 * Device has another loop ID. The firmware team
Andrew Vasquez01071092005-07-06 10:31:37 -07003355 * recommends the driver perform an implicit login with
3356 * the specified ID again. The ID we just used is save
3357 * here so we return with an ID that can be tried by
3358 * the next login.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 */
3360 retry++;
3361 tmp_loopid = fcport->loop_id;
3362 fcport->loop_id = mb[1];
3363
3364 DEBUG(printk("Fabric Login: port in use - next "
3365 "loop id=0x%04x, port Id=%02x%02x%02x.\n",
3366 fcport->loop_id, fcport->d_id.b.domain,
3367 fcport->d_id.b.area, fcport->d_id.b.al_pa));
3368
3369 } else if (mb[0] == MBS_COMMAND_COMPLETE) {
3370 /*
3371 * Login succeeded.
3372 */
3373 if (retry) {
3374 /* A retry occurred before. */
3375 *next_loopid = tmp_loopid;
3376 } else {
3377 /*
3378 * No retry occurred before. Just increment the
3379 * ID value for next login.
3380 */
3381 *next_loopid = (fcport->loop_id + 1);
3382 }
3383
3384 if (mb[1] & BIT_0) {
3385 fcport->port_type = FCT_INITIATOR;
3386 } else {
3387 fcport->port_type = FCT_TARGET;
3388 if (mb[1] & BIT_1) {
Santosh Vernekar8474f3a2009-08-25 11:36:16 -07003389 fcport->flags |= FCF_FCP2_DEVICE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003390 }
3391 }
3392
Andrew Vasquezad3e0ed2005-08-26 19:08:10 -07003393 if (mb[10] & BIT_0)
3394 fcport->supported_classes |= FC_COS_CLASS2;
3395 if (mb[10] & BIT_1)
3396 fcport->supported_classes |= FC_COS_CLASS3;
3397
Linus Torvalds1da177e2005-04-16 15:20:36 -07003398 rval = QLA_SUCCESS;
3399 break;
3400 } else if (mb[0] == MBS_LOOP_ID_USED) {
3401 /*
3402 * Loop ID already used, try next loop ID.
3403 */
3404 fcport->loop_id++;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003405 rval = qla2x00_find_new_loop_id(vha, fcport);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003406 if (rval != QLA_SUCCESS) {
3407 /* Ran out of loop IDs to use */
3408 break;
3409 }
3410 } else if (mb[0] == MBS_COMMAND_ERROR) {
3411 /*
3412 * Firmware possibly timed out during login. If NO
3413 * retries are left to do then the device is declared
3414 * dead.
3415 */
3416 *next_loopid = fcport->loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003417 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003418 fcport->d_id.b.domain, fcport->d_id.b.area,
3419 fcport->d_id.b.al_pa);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003420 qla2x00_mark_device_lost(vha, fcport, 1, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421
3422 rval = 1;
3423 break;
3424 } else {
3425 /*
3426 * unrecoverable / not handled error
3427 */
3428 DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003429 "loop_id=%x jiffies=%lx.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003430 __func__, vha->host_no, mb[0],
Linus Torvalds1da177e2005-04-16 15:20:36 -07003431 fcport->d_id.b.domain, fcport->d_id.b.area,
3432 fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
3433
3434 *next_loopid = fcport->loop_id;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003435 ha->isp_ops->fabric_logout(vha, fcport->loop_id,
Andrew Vasquez1c7c6352005-07-06 10:30:57 -07003436 fcport->d_id.b.domain, fcport->d_id.b.area,
3437 fcport->d_id.b.al_pa);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003438 fcport->loop_id = FC_NO_LOOP_ID;
Andrew Vasquez0eedfcf2005-10-27 11:09:38 -07003439 fcport->login_retry = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003440
3441 rval = 3;
3442 break;
3443 }
3444 }
3445
3446 return (rval);
3447}
3448
3449/*
3450 * qla2x00_local_device_login
3451 * Issue local device login command.
3452 *
3453 * Input:
3454 * ha = adapter block pointer.
3455 * loop_id = loop id of device to login to.
3456 *
3457 * Returns (Where's the #define!!!!):
3458 * 0 - Login successfully
3459 * 1 - Login failed
3460 * 3 - Fatal error
3461 */
3462int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003463qla2x00_local_device_login(scsi_qla_host_t *vha, fc_port_t *fcport)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464{
3465 int rval;
3466 uint16_t mb[MAILBOX_REGISTER_COUNT];
3467
3468 memset(mb, 0, sizeof(mb));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003469 rval = qla2x00_login_local_device(vha, fcport, mb, BIT_0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 if (rval == QLA_SUCCESS) {
3471 /* Interrogate mailbox registers for any errors */
3472 if (mb[0] == MBS_COMMAND_ERROR)
3473 rval = 1;
3474 else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
3475 /* device not in PCB table */
3476 rval = 3;
3477 }
3478
3479 return (rval);
3480}
3481
3482/*
3483 * qla2x00_loop_resync
3484 * Resync with fibre channel devices.
3485 *
3486 * Input:
3487 * ha = adapter block pointer.
3488 *
3489 * Returns:
3490 * 0 = success
3491 */
3492int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003493qla2x00_loop_resync(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494{
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003495 int rval = QLA_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496 uint32_t wait_time;
Anirban Chakraborty67c2e932009-04-06 22:33:42 -07003497 struct req_que *req;
3498 struct rsp_que *rsp;
3499
Anirban Chakraborty7163ea82009-08-05 09:18:40 -07003500 if (vha->hw->flags.cpu_affinity_enabled)
Anirban Chakraborty67c2e932009-04-06 22:33:42 -07003501 req = vha->hw->req_q_map[0];
3502 else
3503 req = vha->req;
3504 rsp = req->rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003506 atomic_set(&vha->loop_state, LOOP_UPDATE);
3507 clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
3508 if (vha->flags.online) {
3509 if (!(rval = qla2x00_fw_ready(vha))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3511 wait_time = 256;
3512 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003513 atomic_set(&vha->loop_state, LOOP_UPDATE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514
Andrew Vasquez01071092005-07-06 10:31:37 -07003515 /* Issue a marker after FW becomes ready. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003516 qla2x00_marker(vha, req, rsp, 0, 0,
3517 MK_SYNC_ALL);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003518 vha->marker_needed = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003519
3520 /* Remap devices on Loop. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003521 clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003523 qla2x00_configure_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003524 wait_time--;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003525 } while (!atomic_read(&vha->loop_down_timer) &&
3526 !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
3527 && wait_time && (test_bit(LOOP_RESYNC_NEEDED,
3528 &vha->dpc_flags)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003529 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 }
3531
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003532 if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533 return (QLA_FUNCTION_FAILED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003534
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003535 if (rval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537
3538 return (rval);
3539}
3540
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541void
Andrew Vasquez67becc02009-08-25 11:36:20 -07003542qla2x00_update_fcports(scsi_qla_host_t *base_vha)
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003543{
3544 fc_port_t *fcport;
Andrew Vasquez67becc02009-08-25 11:36:20 -07003545 struct scsi_qla_host *tvp, *vha;
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003546
3547 /* Go with deferred removal of rport references. */
Andrew Vasquez67becc02009-08-25 11:36:20 -07003548 list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list)
3549 list_for_each_entry(fcport, &vha->vp_fcports, list)
3550 if (fcport && fcport->drport &&
3551 atomic_read(&fcport->state) != FCS_UNCONFIGURED)
3552 qla2x00_rport_del(fcport);
andrew.vasquez@qlogic.comd97994d2006-01-20 14:53:13 -08003553}
3554
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555/*
3556* qla2x00_abort_isp
3557* Resets ISP and aborts all outstanding commands.
3558*
3559* Input:
3560* ha = adapter block pointer.
3561*
3562* Returns:
3563* 0 = success
3564*/
3565int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003566qla2x00_abort_isp(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003567{
Andrew Vasquez476e8972006-08-23 14:54:55 -07003568 int rval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 uint8_t status = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003570 struct qla_hw_data *ha = vha->hw;
3571 struct scsi_qla_host *vp;
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003572 struct scsi_qla_host *tvp;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003573 struct req_que *req = ha->req_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003575 if (vha->flags.online) {
3576 vha->flags.online = 0;
Lalit Chandivade2533cf62009-03-24 09:08:07 -07003577 ha->flags.chip_reset_done = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003578 clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Harish Zunjarraoe5f5f6f2008-07-10 16:55:49 -07003579 ha->qla_stats.total_isp_aborts++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580
3581 qla_printk(KERN_INFO, ha,
3582 "Performing ISP error recovery - ha= %p.\n", ha);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003583 ha->isp_ops->reset_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003584
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003585 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
3586 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
3587 atomic_set(&vha->loop_state, LOOP_DOWN);
3588 qla2x00_mark_all_devices_lost(vha, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003590 if (!atomic_read(&vha->loop_down_timer))
3591 atomic_set(&vha->loop_down_timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003592 LOOP_DOWN_TIME);
3593 }
3594
Linus Torvalds1da177e2005-04-16 15:20:36 -07003595 /* Requeue all commands in outstanding command list. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003596 qla2x00_abort_all_cmds(vha, DID_RESET << 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
Andrew Vasquez85880802009-12-15 21:29:46 -08003598 if (unlikely(pci_channel_offline(ha->pdev) &&
3599 ha->flags.pci_channel_io_perm_failure)) {
3600 clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
3601 status = 0;
3602 return status;
3603 }
3604
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003605 ha->isp_ops->get_flash_version(vha, req->ring);
Andrew Vasquez30c47662007-01-29 10:22:21 -08003606
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003607 ha->isp_ops->nvram_config(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003608
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003609 if (!qla2x00_restart_isp(vha)) {
3610 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003611
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003612 if (!atomic_read(&vha->loop_down_timer)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003613 /*
3614 * Issue marker command only when we are going
3615 * to start the I/O .
3616 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003617 vha->marker_needed = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003618 }
3619
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003620 vha->flags.online = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003622 ha->isp_ops->enable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003623
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003624 ha->isp_abort_cnt = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003625 clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
Andrew Vasquez476e8972006-08-23 14:54:55 -07003626
Lalit Chandivade29c53972009-10-13 15:16:47 -07003627 if (IS_QLA81XX(ha))
3628 qla2x00_get_fw_version(vha,
3629 &ha->fw_major_version,
3630 &ha->fw_minor_version,
3631 &ha->fw_subminor_version,
3632 &ha->fw_attributes, &ha->fw_memory_size,
3633 ha->mpi_version, &ha->mpi_capabilities,
3634 ha->phy_version);
3635
Andrew Vasquezdf613b92008-01-17 09:02:17 -08003636 if (ha->fce) {
3637 ha->flags.fce_enabled = 1;
3638 memset(ha->fce, 0,
3639 fce_calc_size(ha->fce_bufs));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003640 rval = qla2x00_enable_fce_trace(vha,
Andrew Vasquezdf613b92008-01-17 09:02:17 -08003641 ha->fce_dma, ha->fce_bufs, ha->fce_mb,
3642 &ha->fce_bufs);
3643 if (rval) {
3644 qla_printk(KERN_WARNING, ha,
3645 "Unable to reinitialize FCE "
3646 "(%d).\n", rval);
3647 ha->flags.fce_enabled = 0;
3648 }
3649 }
Andrew Vasquez436a7b12008-07-10 16:55:54 -07003650
3651 if (ha->eft) {
3652 memset(ha->eft, 0, EFT_SIZE);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003653 rval = qla2x00_enable_eft_trace(vha,
Andrew Vasquez436a7b12008-07-10 16:55:54 -07003654 ha->eft_dma, EFT_NUM_BUFFERS);
3655 if (rval) {
3656 qla_printk(KERN_WARNING, ha,
3657 "Unable to reinitialize EFT "
3658 "(%d).\n", rval);
3659 }
3660 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003661 } else { /* failed the ISP abort */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003662 vha->flags.online = 1;
3663 if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003664 if (ha->isp_abort_cnt == 0) {
3665 qla_printk(KERN_WARNING, ha,
3666 "ISP error recovery failed - "
3667 "board disabled\n");
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003668 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003669 * The next call disables the board
3670 * completely.
3671 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003672 ha->isp_ops->reset_adapter(vha);
3673 vha->flags.online = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003674 clear_bit(ISP_ABORT_RETRY,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003675 &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003676 status = 0;
3677 } else { /* schedule another ISP abort */
3678 ha->isp_abort_cnt--;
3679 DEBUG(printk("qla%ld: ISP abort - "
Andrew Vasquez01071092005-07-06 10:31:37 -07003680 "retry remaining %d\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003681 vha->host_no, ha->isp_abort_cnt));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003682 status = 1;
3683 }
3684 } else {
3685 ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
3686 DEBUG(printk("qla2x00(%ld): ISP error recovery "
3687 "- retrying (%d) more times\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003688 vha->host_no, ha->isp_abort_cnt));
3689 set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 status = 1;
3691 }
3692 }
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07003693
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 }
3695
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003696 if (!status) {
3697 DEBUG(printk(KERN_INFO
3698 "qla2x00_abort_isp(%ld): succeeded.\n",
3699 vha->host_no));
Anirban Chakrabortyee546b62009-03-05 11:07:02 -08003700 list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003701 if (vp->vp_idx)
3702 qla2x00_vp_abort_isp(vp);
3703 }
3704 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003705 qla_printk(KERN_INFO, ha,
3706 "qla2x00_abort_isp: **** FAILED ****\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003707 }
3708
3709 return(status);
3710}
3711
3712/*
3713* qla2x00_restart_isp
3714* restarts the ISP after a reset
3715*
3716* Input:
3717* ha = adapter block pointer.
3718*
3719* Returns:
3720* 0 = success
3721*/
3722static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003723qla2x00_restart_isp(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003724{
Andrew Vasquezc6b2fca2009-03-05 11:07:03 -08003725 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003726 uint32_t wait_time;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003727 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003728 struct req_que *req = ha->req_q_map[0];
3729 struct rsp_que *rsp = ha->rsp_q_map[0];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730
3731 /* If firmware needs to be loaded */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003732 if (qla2x00_isp_firmware(vha)) {
3733 vha->flags.online = 0;
3734 status = ha->isp_ops->chip_diag(vha);
3735 if (!status)
3736 status = qla2x00_setup_chip(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 }
3738
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003739 if (!status && !(status = qla2x00_init_rings(vha))) {
3740 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Lalit Chandivade2533cf62009-03-24 09:08:07 -07003741 ha->flags.chip_reset_done = 1;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003742 /* Initialize the queues in use */
3743 qla25xx_init_queues(ha);
3744
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003745 status = qla2x00_fw_ready(vha);
3746 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003747 DEBUG(printk("%s(): Start configure loop, "
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003748 "status = %d\n", __func__, status));
Andrew Vasquez01071092005-07-06 10:31:37 -07003749
3750 /* Issue a marker after FW becomes ready. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003751 qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
Andrew Vasquez01071092005-07-06 10:31:37 -07003752
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003753 vha->flags.online = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003754 /* Wait at most MAX_TARGET RSCNs for a stable link. */
3755 wait_time = 256;
3756 do {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003757 clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
3758 qla2x00_configure_loop(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003759 wait_time--;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003760 } while (!atomic_read(&vha->loop_down_timer) &&
3761 !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
3762 && wait_time && (test_bit(LOOP_RESYNC_NEEDED,
3763 &vha->dpc_flags)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003764 }
3765
3766 /* if no cable then assume it's good */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003767 if ((vha->device_flags & DFLG_NO_CABLE))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003768 status = 0;
3769
3770 DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
3771 __func__,
Andrew Vasquez744f11fd2006-06-23 16:11:05 -07003772 status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 }
3774 return (status);
3775}
3776
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003777static int
3778qla25xx_init_queues(struct qla_hw_data *ha)
3779{
3780 struct rsp_que *rsp = NULL;
3781 struct req_que *req = NULL;
3782 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
3783 int ret = -1;
3784 int i;
3785
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07003786 for (i = 1; i < ha->max_rsp_queues; i++) {
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003787 rsp = ha->rsp_q_map[i];
3788 if (rsp) {
3789 rsp->options &= ~BIT_0;
Anirban Chakraborty618a7522009-02-08 20:50:11 -08003790 ret = qla25xx_init_rsp_que(base_vha, rsp);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003791 if (ret != QLA_SUCCESS)
3792 DEBUG2_17(printk(KERN_WARNING
3793 "%s Rsp que:%d init failed\n", __func__,
3794 rsp->id));
3795 else
3796 DEBUG2_17(printk(KERN_INFO
3797 "%s Rsp que:%d inited\n", __func__,
3798 rsp->id));
3799 }
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07003800 }
3801 for (i = 1; i < ha->max_req_queues; i++) {
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003802 req = ha->req_q_map[i];
3803 if (req) {
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003804 /* Clear outstanding commands array. */
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003805 req->options &= ~BIT_0;
Anirban Chakraborty618a7522009-02-08 20:50:11 -08003806 ret = qla25xx_init_req_que(base_vha, req);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003807 if (ret != QLA_SUCCESS)
3808 DEBUG2_17(printk(KERN_WARNING
3809 "%s Req que:%d init failed\n", __func__,
3810 req->id));
3811 else
3812 DEBUG2_17(printk(KERN_WARNING
Anirban Chakraborty29bdccb2009-01-08 15:41:08 -08003813 "%s Req que:%d inited\n", __func__,
Anirban Chakraborty73208df2008-12-09 16:45:39 -08003814 req->id));
3815 }
3816 }
3817 return ret;
3818}
3819
Linus Torvalds1da177e2005-04-16 15:20:36 -07003820/*
3821* qla2x00_reset_adapter
3822* Reset adapter.
3823*
3824* Input:
3825* ha = adapter block pointer.
3826*/
Andrew Vasquezabbd8872005-07-06 10:30:05 -07003827void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003828qla2x00_reset_adapter(scsi_qla_host_t *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829{
3830 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003831 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -07003832 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003833
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003834 vha->flags.online = 0;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003835 ha->isp_ops->disable_intrs(ha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836
Linus Torvalds1da177e2005-04-16 15:20:36 -07003837 spin_lock_irqsave(&ha->hardware_lock, flags);
3838 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
3839 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3840 WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
3841 RD_REG_WORD(&reg->hccr); /* PCI Posting. */
3842 spin_unlock_irqrestore(&ha->hardware_lock, flags);
3843}
Andrew Vasquez01071092005-07-06 10:31:37 -07003844
3845void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003846qla24xx_reset_adapter(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07003847{
3848 unsigned long flags = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003849 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07003850 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
3851
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003852 vha->flags.online = 0;
Andrew Vasquezfd34f552007-07-19 15:06:00 -07003853 ha->isp_ops->disable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -07003854
3855 spin_lock_irqsave(&ha->hardware_lock, flags);
3856 WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
3857 RD_REG_DWORD(&reg->hccr);
3858 WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
3859 RD_REG_DWORD(&reg->hccr);
3860 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquez09ff36d2009-01-22 09:45:30 -08003861
3862 if (IS_NOPOLLING_TYPE(ha))
3863 ha->isp_ops->enable_intrs(ha);
Andrew Vasquez01071092005-07-06 10:31:37 -07003864}
3865
David Miller4e08df32007-04-16 12:37:43 -07003866/* On sparc systems, obtain port and node WWN from firmware
3867 * properties.
3868 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003869static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *vha,
3870 struct nvram_24xx *nv)
David Miller4e08df32007-04-16 12:37:43 -07003871{
3872#ifdef CONFIG_SPARC
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003873 struct qla_hw_data *ha = vha->hw;
David Miller4e08df32007-04-16 12:37:43 -07003874 struct pci_dev *pdev = ha->pdev;
David S. Miller15576bc2007-05-08 00:36:49 -07003875 struct device_node *dp = pci_device_to_OF_node(pdev);
3876 const u8 *val;
David Miller4e08df32007-04-16 12:37:43 -07003877 int len;
3878
3879 val = of_get_property(dp, "port-wwn", &len);
3880 if (val && len >= WWN_SIZE)
3881 memcpy(nv->port_name, val, WWN_SIZE);
3882
3883 val = of_get_property(dp, "node-wwn", &len);
3884 if (val && len >= WWN_SIZE)
3885 memcpy(nv->node_name, val, WWN_SIZE);
3886#endif
3887}
3888
Andrew Vasquez01071092005-07-06 10:31:37 -07003889int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003890qla24xx_nvram_config(scsi_qla_host_t *vha)
Andrew Vasquez01071092005-07-06 10:31:37 -07003891{
David Miller4e08df32007-04-16 12:37:43 -07003892 int rval;
Andrew Vasquez01071092005-07-06 10:31:37 -07003893 struct init_cb_24xx *icb;
3894 struct nvram_24xx *nv;
3895 uint32_t *dptr;
3896 uint8_t *dptr1, *dptr2;
3897 uint32_t chksum;
3898 uint16_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003899 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez01071092005-07-06 10:31:37 -07003900
David Miller4e08df32007-04-16 12:37:43 -07003901 rval = QLA_SUCCESS;
Andrew Vasquez01071092005-07-06 10:31:37 -07003902 icb = (struct init_cb_24xx *)ha->init_cb;
Seokmann Ju281afe12007-07-26 13:43:34 -07003903 nv = ha->nvram;
Andrew Vasquez01071092005-07-06 10:31:37 -07003904
3905 /* Determine NVRAM starting address. */
Anirban Chakrabortye5b68a62009-04-06 22:33:50 -07003906 if (ha->flags.port0) {
3907 ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
3908 ha->vpd_base = FA_NVRAM_VPD0_ADDR;
3909 } else {
Andrew Vasquez01071092005-07-06 10:31:37 -07003910 ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
andrew.vasquez@qlogic.com6f641792006-03-09 14:27:34 -08003911 ha->vpd_base = FA_NVRAM_VPD1_ADDR;
3912 }
Anirban Chakrabortye5b68a62009-04-06 22:33:50 -07003913 ha->nvram_size = sizeof(struct nvram_24xx);
3914 ha->vpd_size = FA_NVRAM_VPD_SIZE;
Andrew Vasquez01071092005-07-06 10:31:37 -07003915
Seokmann Ju281afe12007-07-26 13:43:34 -07003916 /* Get VPD data into cache */
3917 ha->vpd = ha->nvram + VPD_OFFSET;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003918 ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
Seokmann Ju281afe12007-07-26 13:43:34 -07003919 ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
3920
3921 /* Get NVRAM data into cache and calculate checksum. */
Andrew Vasquez01071092005-07-06 10:31:37 -07003922 dptr = (uint32_t *)nv;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003923 ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
Andrew Vasquez01071092005-07-06 10:31:37 -07003924 ha->nvram_size);
3925 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
3926 chksum += le32_to_cpu(*dptr++);
3927
Andrew Vasquez76403352009-04-06 22:33:39 -07003928 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
Seokmann Ju281afe12007-07-26 13:43:34 -07003929 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
Andrew Vasquez01071092005-07-06 10:31:37 -07003930
3931 /* Bad NVRAM data, set defaults parameters. */
3932 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
3933 || nv->id[3] != ' ' ||
3934 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
3935 /* Reset NVRAM data. */
3936 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
3937 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
3938 le16_to_cpu(nv->nvram_version));
David Miller4e08df32007-04-16 12:37:43 -07003939 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
3940 "invalid -- WWPN) defaults.\n");
3941
3942 /*
3943 * Set default initialization control block.
3944 */
3945 memset(nv, 0, ha->nvram_size);
3946 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
3947 nv->version = __constant_cpu_to_le16(ICB_VERSION);
3948 nv->frame_payload_size = __constant_cpu_to_le16(2048);
3949 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
3950 nv->exchange_count = __constant_cpu_to_le16(0);
3951 nv->hard_address = __constant_cpu_to_le16(124);
3952 nv->port_name[0] = 0x21;
Anirban Chakrabortye5b68a62009-04-06 22:33:50 -07003953 nv->port_name[1] = 0x00 + ha->port_no;
David Miller4e08df32007-04-16 12:37:43 -07003954 nv->port_name[2] = 0x00;
3955 nv->port_name[3] = 0xe0;
3956 nv->port_name[4] = 0x8b;
3957 nv->port_name[5] = 0x1c;
3958 nv->port_name[6] = 0x55;
3959 nv->port_name[7] = 0x86;
3960 nv->node_name[0] = 0x20;
3961 nv->node_name[1] = 0x00;
3962 nv->node_name[2] = 0x00;
3963 nv->node_name[3] = 0xe0;
3964 nv->node_name[4] = 0x8b;
3965 nv->node_name[5] = 0x1c;
3966 nv->node_name[6] = 0x55;
3967 nv->node_name[7] = 0x86;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003968 qla24xx_nvram_wwn_from_ofw(vha, nv);
David Miller4e08df32007-04-16 12:37:43 -07003969 nv->login_retry_count = __constant_cpu_to_le16(8);
3970 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
3971 nv->login_timeout = __constant_cpu_to_le16(0);
3972 nv->firmware_options_1 =
3973 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
3974 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
3975 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
3976 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
3977 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
3978 nv->efi_parameters = __constant_cpu_to_le32(0);
3979 nv->reset_delay = 5;
3980 nv->max_luns_per_target = __constant_cpu_to_le16(128);
3981 nv->port_down_retry_count = __constant_cpu_to_le16(30);
3982 nv->link_down_timeout = __constant_cpu_to_le16(30);
3983
3984 rval = 1;
Andrew Vasquez01071092005-07-06 10:31:37 -07003985 }
3986
3987 /* Reset Initialization control block */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08003988 memset(icb, 0, ha->init_cb_size);
Andrew Vasquez01071092005-07-06 10:31:37 -07003989
3990 /* Copy 1st segment. */
3991 dptr1 = (uint8_t *)icb;
3992 dptr2 = (uint8_t *)&nv->version;
3993 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
3994 while (cnt--)
3995 *dptr1++ = *dptr2++;
3996
3997 icb->login_retry_count = nv->login_retry_count;
Andrew Vasquez3ea66e22006-06-23 16:11:27 -07003998 icb->link_down_on_nos = nv->link_down_on_nos;
Andrew Vasquez01071092005-07-06 10:31:37 -07003999
4000 /* Copy 2nd segment. */
4001 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
4002 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
4003 cnt = (uint8_t *)&icb->reserved_3 -
4004 (uint8_t *)&icb->interrupt_delay_timer;
4005 while (cnt--)
4006 *dptr1++ = *dptr2++;
4007
4008 /*
4009 * Setup driver NVRAM options.
4010 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004011 qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
Andrew Vasquez9bb9fcf2007-01-29 10:22:24 -08004012 "QLA2462");
Andrew Vasquez01071092005-07-06 10:31:37 -07004013
Andrew Vasquez5341e862006-05-17 15:09:16 -07004014 /* Use alternate WWN? */
4015 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
4016 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
4017 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
4018 }
4019
Andrew Vasquez01071092005-07-06 10:31:37 -07004020 /* Prepare nodename */
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07004021 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
Andrew Vasquez01071092005-07-06 10:31:37 -07004022 /*
4023 * Firmware will apply the following mask if the nodename was
4024 * not provided.
4025 */
4026 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
4027 icb->node_name[0] &= 0xF0;
4028 }
4029
4030 /* Set host adapter parameters. */
4031 ha->flags.disable_risc_code_load = 0;
Andrew Vasquez0c8c39a2006-12-13 19:20:30 -08004032 ha->flags.enable_lip_reset = 0;
4033 ha->flags.enable_lip_full_login =
4034 le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
4035 ha->flags.enable_target_reset =
4036 le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
Andrew Vasquez01071092005-07-06 10:31:37 -07004037 ha->flags.enable_led_scheme = 0;
Andrew Vasquezd4c760c2006-06-23 16:10:39 -07004038 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
Andrew Vasquez01071092005-07-06 10:31:37 -07004039
Andrew Vasquezfd0e7e42006-05-17 15:09:11 -07004040 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
4041 (BIT_6 | BIT_5 | BIT_4)) >> 4;
Andrew Vasquez01071092005-07-06 10:31:37 -07004042
4043 memcpy(ha->fw_seriallink_options24, nv->seriallink_options,
4044 sizeof(ha->fw_seriallink_options24));
4045
4046 /* save HBA serial number */
4047 ha->serial0 = icb->port_name[5];
4048 ha->serial1 = icb->port_name[6];
4049 ha->serial2 = icb->port_name[7];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004050 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
4051 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
Andrew Vasquez01071092005-07-06 10:31:37 -07004052
andrew.vasquez@qlogic.combc8fb3c2006-01-13 17:05:42 -08004053 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
4054
Andrew Vasquez01071092005-07-06 10:31:37 -07004055 ha->retry_count = le16_to_cpu(nv->login_retry_count);
4056
4057 /* Set minimum login_timeout to 4 seconds. */
4058 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
4059 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
4060 if (le16_to_cpu(nv->login_timeout) < 4)
4061 nv->login_timeout = __constant_cpu_to_le16(4);
4062 ha->login_timeout = le16_to_cpu(nv->login_timeout);
Seokmann Juc6852c42008-04-24 15:21:29 -07004063 icb->login_timeout = nv->login_timeout;
Andrew Vasquez01071092005-07-06 10:31:37 -07004064
Andrew Vasquez00a537b2008-02-28 14:06:11 -08004065 /* Set minimum RATOV to 100 tenths of a second. */
4066 ha->r_a_tov = 100;
Andrew Vasquez01071092005-07-06 10:31:37 -07004067
4068 ha->loop_reset_delay = nv->reset_delay;
4069
4070 /* Link Down Timeout = 0:
4071 *
4072 * When Port Down timer expires we will start returning
4073 * I/O's to OS with "DID_NO_CONNECT".
4074 *
4075 * Link Down Timeout != 0:
4076 *
4077 * The driver waits for the link to come up after link down
4078 * before returning I/Os to OS with "DID_NO_CONNECT".
4079 */
4080 if (le16_to_cpu(nv->link_down_timeout) == 0) {
4081 ha->loop_down_abort_time =
4082 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
4083 } else {
4084 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
4085 ha->loop_down_abort_time =
4086 (LOOP_DOWN_TIME - ha->link_down_timeout);
4087 }
4088
4089 /* Need enough time to try and get the port back. */
4090 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
4091 if (qlport_down_retry)
4092 ha->port_down_retry_count = qlport_down_retry;
4093
4094 /* Set login_retry_count */
4095 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
4096 if (ha->port_down_retry_count ==
4097 le16_to_cpu(nv->port_down_retry_count) &&
4098 ha->port_down_retry_count > 3)
4099 ha->login_retry_count = ha->port_down_retry_count;
4100 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
4101 ha->login_retry_count = ha->port_down_retry_count;
4102 if (ql2xloginretrycount)
4103 ha->login_retry_count = ql2xloginretrycount;
4104
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07004105 /* Enable ZIO. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004106 if (!vha->flags.init_done) {
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07004107 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
4108 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
4109 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
4110 le16_to_cpu(icb->interrupt_delay_timer): 2;
4111 }
4112 icb->firmware_options_2 &= __constant_cpu_to_le32(
4113 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004114 vha->flags.process_response_queue = 0;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07004115 if (ha->zio_mode != QLA_ZIO_DISABLED) {
andrew.vasquez@qlogic.com4a59f712006-03-09 14:27:39 -08004116 ha->zio_mode = QLA_ZIO_MODE_6;
4117
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07004118 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004119 "(%d us).\n", vha->host_no, ha->zio_mode,
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07004120 ha->zio_timer * 100));
4121 qla_printk(KERN_INFO, ha,
4122 "ZIO mode %d enabled; timer delay (%d us).\n",
4123 ha->zio_mode, ha->zio_timer * 100);
4124
4125 icb->firmware_options_2 |= cpu_to_le32(
4126 (uint32_t)ha->zio_mode);
4127 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004128 vha->flags.process_response_queue = 1;
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -07004129 }
4130
David Miller4e08df32007-04-16 12:37:43 -07004131 if (rval) {
4132 DEBUG2_3(printk(KERN_WARNING
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004133 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
David Miller4e08df32007-04-16 12:37:43 -07004134 }
4135 return (rval);
Andrew Vasquez01071092005-07-06 10:31:37 -07004136}
4137
Adrian Bunk413975a2006-06-30 02:33:06 -07004138static int
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004139qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
4140 uint32_t faddr)
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004141{
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004142 int rval = QLA_SUCCESS;
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004143 int segments, fragment;
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004144 uint32_t *dcode, dlen;
4145 uint32_t risc_addr;
4146 uint32_t risc_size;
4147 uint32_t i;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004148 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004149 struct req_que *req = ha->req_q_map[0];
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004150
4151 qla_printk(KERN_INFO, ha,
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004152 "FW: Loading from flash (%x)...\n", faddr);
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004153
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004154 rval = QLA_SUCCESS;
4155
4156 segments = FA_RISC_CODE_SEGMENTS;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004157 dcode = (uint32_t *)req->ring;
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004158 *srisc_addr = 0;
4159
4160 /* Validate firmware image by checking version. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004161 qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004162 for (i = 0; i < 4; i++)
4163 dcode[i] = be32_to_cpu(dcode[i]);
4164 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
4165 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
4166 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
4167 dcode[3] == 0)) {
4168 qla_printk(KERN_WARNING, ha,
4169 "Unable to verify integrity of flash firmware image!\n");
4170 qla_printk(KERN_WARNING, ha,
4171 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
4172 dcode[1], dcode[2], dcode[3]);
4173
4174 return QLA_FUNCTION_FAILED;
4175 }
4176
4177 while (segments && rval == QLA_SUCCESS) {
4178 /* Read segment's load information. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004179 qla24xx_read_flash_data(vha, dcode, faddr, 4);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004180
4181 risc_addr = be32_to_cpu(dcode[2]);
4182 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
4183 risc_size = be32_to_cpu(dcode[3]);
4184
4185 fragment = 0;
4186 while (risc_size > 0 && rval == QLA_SUCCESS) {
4187 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
4188 if (dlen > risc_size)
4189 dlen = risc_size;
4190
4191 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
4192 "addr %x, number of dwords 0x%x, offset 0x%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004193 vha->host_no, risc_addr, dlen, faddr));
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004194
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004195 qla24xx_read_flash_data(vha, dcode, faddr, dlen);
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004196 for (i = 0; i < dlen; i++)
4197 dcode[i] = swab32(dcode[i]);
4198
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004199 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004200 dlen);
4201 if (rval) {
4202 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004203 "segment %d of firmware\n", vha->host_no,
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004204 fragment));
4205 qla_printk(KERN_WARNING, ha,
4206 "[ERROR] Failed to load segment %d of "
4207 "firmware\n", fragment);
4208 break;
4209 }
4210
4211 faddr += dlen;
4212 risc_addr += dlen;
4213 risc_size -= dlen;
4214 fragment++;
4215 }
4216
4217 /* Next segment. */
4218 segments--;
4219 }
4220
4221 return rval;
4222}
4223
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004224#define QLA_FW_URL "ftp://ftp.qlogic.com/outgoing/linux/firmware/"
4225
Andrew Vasquez01071092005-07-06 10:31:37 -07004226int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004227qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquez54333832005-11-09 15:49:04 -08004228{
4229 int rval;
4230 int i, fragment;
4231 uint16_t *wcode, *fwcode;
4232 uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
4233 struct fw_blob *blob;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004234 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004235 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez54333832005-11-09 15:49:04 -08004236
4237 /* Load firmware blob. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004238 blob = qla2x00_request_firmware(vha);
Andrew Vasquez54333832005-11-09 15:49:04 -08004239 if (!blob) {
4240 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004241 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
4242 "from: " QLA_FW_URL ".\n");
Andrew Vasquez54333832005-11-09 15:49:04 -08004243 return QLA_FUNCTION_FAILED;
4244 }
4245
4246 rval = QLA_SUCCESS;
4247
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004248 wcode = (uint16_t *)req->ring;
Andrew Vasquez54333832005-11-09 15:49:04 -08004249 *srisc_addr = 0;
4250 fwcode = (uint16_t *)blob->fw->data;
4251 fwclen = 0;
4252
4253 /* Validate firmware image by checking version. */
4254 if (blob->fw->size < 8 * sizeof(uint16_t)) {
4255 qla_printk(KERN_WARNING, ha,
4256 "Unable to verify integrity of firmware image (%Zd)!\n",
4257 blob->fw->size);
4258 goto fail_fw_integrity;
4259 }
4260 for (i = 0; i < 4; i++)
4261 wcode[i] = be16_to_cpu(fwcode[i + 4]);
4262 if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
4263 wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
4264 wcode[2] == 0 && wcode[3] == 0)) {
4265 qla_printk(KERN_WARNING, ha,
4266 "Unable to verify integrity of firmware image!\n");
4267 qla_printk(KERN_WARNING, ha,
4268 "Firmware data: %04x %04x %04x %04x!\n", wcode[0],
4269 wcode[1], wcode[2], wcode[3]);
4270 goto fail_fw_integrity;
4271 }
4272
4273 seg = blob->segs;
4274 while (*seg && rval == QLA_SUCCESS) {
4275 risc_addr = *seg;
4276 *srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
4277 risc_size = be16_to_cpu(fwcode[3]);
4278
4279 /* Validate firmware image size. */
4280 fwclen += risc_size * sizeof(uint16_t);
4281 if (blob->fw->size < fwclen) {
4282 qla_printk(KERN_WARNING, ha,
4283 "Unable to verify integrity of firmware image "
4284 "(%Zd)!\n", blob->fw->size);
4285 goto fail_fw_integrity;
4286 }
4287
4288 fragment = 0;
4289 while (risc_size > 0 && rval == QLA_SUCCESS) {
4290 wlen = (uint16_t)(ha->fw_transfer_size >> 1);
4291 if (wlen > risc_size)
4292 wlen = risc_size;
4293
4294 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004295 "addr %x, number of words 0x%x.\n", vha->host_no,
Andrew Vasquez54333832005-11-09 15:49:04 -08004296 risc_addr, wlen));
4297
4298 for (i = 0; i < wlen; i++)
4299 wcode[i] = swab16(fwcode[i]);
4300
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004301 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
Andrew Vasquez54333832005-11-09 15:49:04 -08004302 wlen);
4303 if (rval) {
4304 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004305 "segment %d of firmware\n", vha->host_no,
Andrew Vasquez54333832005-11-09 15:49:04 -08004306 fragment));
4307 qla_printk(KERN_WARNING, ha,
4308 "[ERROR] Failed to load segment %d of "
4309 "firmware\n", fragment);
4310 break;
4311 }
4312
4313 fwcode += wlen;
4314 risc_addr += wlen;
4315 risc_size -= wlen;
4316 fragment++;
4317 }
4318
4319 /* Next segment. */
4320 seg++;
4321 }
4322 return rval;
4323
4324fail_fw_integrity:
4325 return QLA_FUNCTION_FAILED;
4326}
4327
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004328static int
4329qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
Andrew Vasquez01071092005-07-06 10:31:37 -07004330{
4331 int rval;
4332 int segments, fragment;
4333 uint32_t *dcode, dlen;
4334 uint32_t risc_addr;
4335 uint32_t risc_size;
4336 uint32_t i;
Andrew Vasquez54333832005-11-09 15:49:04 -08004337 struct fw_blob *blob;
Andrew Vasquez01071092005-07-06 10:31:37 -07004338 uint32_t *fwcode, fwclen;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004339 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004340 struct req_que *req = ha->req_q_map[0];
Andrew Vasquez01071092005-07-06 10:31:37 -07004341
Andrew Vasquez54333832005-11-09 15:49:04 -08004342 /* Load firmware blob. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004343 blob = qla2x00_request_firmware(vha);
Andrew Vasquez54333832005-11-09 15:49:04 -08004344 if (!blob) {
4345 qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
Andrew Vasquezd1c61902006-05-17 15:09:00 -07004346 qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
4347 "from: " QLA_FW_URL ".\n");
4348
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004349 return QLA_FUNCTION_FAILED;
Andrew Vasquez01071092005-07-06 10:31:37 -07004350 }
4351
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004352 qla_printk(KERN_INFO, ha,
4353 "FW: Loading via request-firmware...\n");
4354
Andrew Vasquez01071092005-07-06 10:31:37 -07004355 rval = QLA_SUCCESS;
4356
4357 segments = FA_RISC_CODE_SEGMENTS;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004358 dcode = (uint32_t *)req->ring;
Andrew Vasquez01071092005-07-06 10:31:37 -07004359 *srisc_addr = 0;
Andrew Vasquez54333832005-11-09 15:49:04 -08004360 fwcode = (uint32_t *)blob->fw->data;
Andrew Vasquez01071092005-07-06 10:31:37 -07004361 fwclen = 0;
4362
4363 /* Validate firmware image by checking version. */
Andrew Vasquez54333832005-11-09 15:49:04 -08004364 if (blob->fw->size < 8 * sizeof(uint32_t)) {
Andrew Vasquez01071092005-07-06 10:31:37 -07004365 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004366 "Unable to verify integrity of firmware image (%Zd)!\n",
4367 blob->fw->size);
Andrew Vasquez01071092005-07-06 10:31:37 -07004368 goto fail_fw_integrity;
4369 }
4370 for (i = 0; i < 4; i++)
4371 dcode[i] = be32_to_cpu(fwcode[i + 4]);
4372 if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
4373 dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
4374 (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
4375 dcode[3] == 0)) {
4376 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004377 "Unable to verify integrity of firmware image!\n");
Andrew Vasquez01071092005-07-06 10:31:37 -07004378 qla_printk(KERN_WARNING, ha,
4379 "Firmware data: %08x %08x %08x %08x!\n", dcode[0],
4380 dcode[1], dcode[2], dcode[3]);
4381 goto fail_fw_integrity;
4382 }
4383
4384 while (segments && rval == QLA_SUCCESS) {
4385 risc_addr = be32_to_cpu(fwcode[2]);
4386 *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
4387 risc_size = be32_to_cpu(fwcode[3]);
4388
4389 /* Validate firmware image size. */
4390 fwclen += risc_size * sizeof(uint32_t);
Andrew Vasquez54333832005-11-09 15:49:04 -08004391 if (blob->fw->size < fwclen) {
Andrew Vasquez01071092005-07-06 10:31:37 -07004392 qla_printk(KERN_WARNING, ha,
Andrew Vasquez54333832005-11-09 15:49:04 -08004393 "Unable to verify integrity of firmware image "
4394 "(%Zd)!\n", blob->fw->size);
4395
Andrew Vasquez01071092005-07-06 10:31:37 -07004396 goto fail_fw_integrity;
4397 }
4398
4399 fragment = 0;
4400 while (risc_size > 0 && rval == QLA_SUCCESS) {
4401 dlen = (uint32_t)(ha->fw_transfer_size >> 2);
4402 if (dlen > risc_size)
4403 dlen = risc_size;
4404
4405 DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004406 "addr %x, number of dwords 0x%x.\n", vha->host_no,
Andrew Vasquez01071092005-07-06 10:31:37 -07004407 risc_addr, dlen));
4408
4409 for (i = 0; i < dlen; i++)
4410 dcode[i] = swab32(fwcode[i]);
4411
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004412 rval = qla2x00_load_ram(vha, req->dma, risc_addr,
andrew.vasquez@qlogic.com590f98e2006-01-13 17:05:37 -08004413 dlen);
Andrew Vasquez01071092005-07-06 10:31:37 -07004414 if (rval) {
4415 DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004416 "segment %d of firmware\n", vha->host_no,
Andrew Vasquez01071092005-07-06 10:31:37 -07004417 fragment));
4418 qla_printk(KERN_WARNING, ha,
4419 "[ERROR] Failed to load segment %d of "
4420 "firmware\n", fragment);
4421 break;
4422 }
4423
4424 fwcode += dlen;
4425 risc_addr += dlen;
4426 risc_size -= dlen;
4427 fragment++;
4428 }
4429
4430 /* Next segment. */
4431 segments--;
4432 }
Andrew Vasquez01071092005-07-06 10:31:37 -07004433 return rval;
4434
4435fail_fw_integrity:
Andrew Vasquez01071092005-07-06 10:31:37 -07004436 return QLA_FUNCTION_FAILED;
Andrew Vasquez01071092005-07-06 10:31:37 -07004437}
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004438
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004439int
4440qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
4441{
4442 int rval;
4443
Andrew Vasqueze337d902009-04-06 22:33:49 -07004444 if (ql2xfwloadbin == 1)
4445 return qla81xx_load_risc(vha, srisc_addr);
4446
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004447 /*
4448 * FW Load priority:
4449 * 1) Firmware via request-firmware interface (.bin file).
4450 * 2) Firmware residing in flash.
4451 */
4452 rval = qla24xx_load_risc_blob(vha, srisc_addr);
4453 if (rval == QLA_SUCCESS)
4454 return rval;
4455
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004456 return qla24xx_load_risc_flash(vha, srisc_addr,
4457 vha->hw->flt_region_fw);
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004458}
4459
4460int
4461qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
4462{
4463 int rval;
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004464 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004465
Andrew Vasqueze337d902009-04-06 22:33:49 -07004466 if (ql2xfwloadbin == 2)
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004467 goto try_blob_fw;
Andrew Vasqueze337d902009-04-06 22:33:49 -07004468
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004469 /*
4470 * FW Load priority:
4471 * 1) Firmware residing in flash.
4472 * 2) Firmware via request-firmware interface (.bin file).
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004473 * 3) Golden-Firmware residing in flash -- limited operation.
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004474 */
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004475 rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw);
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004476 if (rval == QLA_SUCCESS)
4477 return rval;
4478
Andrew Vasquezcbc8eb62009-06-03 09:55:17 -07004479try_blob_fw:
4480 rval = qla24xx_load_risc_blob(vha, srisc_addr);
4481 if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
4482 return rval;
4483
4484 qla_printk(KERN_ERR, ha,
4485 "FW: Attempting to fallback to golden firmware...\n");
4486 rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
4487 if (rval != QLA_SUCCESS)
4488 return rval;
4489
4490 qla_printk(KERN_ERR, ha,
4491 "FW: Please update operational firmware...\n");
4492 ha->flags.running_gold_fw = 1;
4493
4494 return rval;
Andrew Vasquezeaac30b2009-01-22 09:45:32 -08004495}
4496
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004497void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004498qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004499{
4500 int ret, retries;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004501 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004502
Andrew Vasquez85880802009-12-15 21:29:46 -08004503 if (ha->flags.pci_channel_io_perm_failure)
4504 return;
Andrew Vasqueze4289242007-07-19 15:05:56 -07004505 if (!IS_FWI2_CAPABLE(ha))
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004506 return;
Andrew Vasquez75edf812007-05-07 07:43:00 -07004507 if (!ha->fw_major_version)
4508 return;
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004509
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004510 ret = qla2x00_stop_firmware(vha);
Andrew Vasquez7c7f1f22008-02-28 14:06:09 -08004511 for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
Andrew Vasquezb469a7c2009-04-06 22:33:48 -07004512 ret != QLA_INVALID_COMMAND && retries ; retries--) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004513 ha->isp_ops->reset_chip(vha);
4514 if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004515 continue;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004516 if (qla2x00_setup_chip(vha) != QLA_SUCCESS)
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004517 continue;
4518 qla_printk(KERN_INFO, ha,
4519 "Attempting retry of stop-firmware command...\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004520 ret = qla2x00_stop_firmware(vha);
Andrew Vasquez18c6c122006-10-13 09:33:38 -07004521 }
4522}
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004523
4524int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004525qla24xx_configure_vhba(scsi_qla_host_t *vha)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004526{
4527 int rval = QLA_SUCCESS;
4528 uint16_t mb[MAILBOX_REGISTER_COUNT];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004529 struct qla_hw_data *ha = vha->hw;
4530 struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
Anirban Chakraborty67c2e932009-04-06 22:33:42 -07004531 struct req_que *req;
4532 struct rsp_que *rsp;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004533
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004534 if (!vha->vp_idx)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004535 return -EINVAL;
4536
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004537 rval = qla2x00_fw_ready(base_vha);
Anirban Chakraborty7163ea82009-08-05 09:18:40 -07004538 if (ha->flags.cpu_affinity_enabled)
Anirban Chakraborty67c2e932009-04-06 22:33:42 -07004539 req = ha->req_q_map[0];
4540 else
4541 req = vha->req;
4542 rsp = req->rsp;
4543
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004544 if (rval == QLA_SUCCESS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004545 clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08004546 qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004547 }
4548
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004549 vha->flags.management_server_logged_in = 0;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004550
4551 /* Login to SNS first */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004552 ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004553 if (mb[0] != MBS_COMMAND_COMPLETE) {
4554 DEBUG15(qla_printk(KERN_INFO, ha,
4555 "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
4556 "mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
4557 mb[0], mb[1], mb[2], mb[6], mb[7]));
4558 return (QLA_FUNCTION_FAILED);
4559 }
4560
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004561 atomic_set(&vha->loop_down_timer, 0);
4562 atomic_set(&vha->loop_state, LOOP_UP);
4563 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
4564 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
4565 rval = qla2x00_loop_resync(base_vha);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07004566
4567 return rval;
4568}
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004569
4570/* 84XX Support **************************************************************/
4571
4572static LIST_HEAD(qla_cs84xx_list);
4573static DEFINE_MUTEX(qla_cs84xx_mutex);
4574
4575static struct qla_chip_state_84xx *
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004576qla84xx_get_chip(struct scsi_qla_host *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004577{
4578 struct qla_chip_state_84xx *cs84xx;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004579 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004580
4581 mutex_lock(&qla_cs84xx_mutex);
4582
4583 /* Find any shared 84xx chip. */
4584 list_for_each_entry(cs84xx, &qla_cs84xx_list, list) {
4585 if (cs84xx->bus == ha->pdev->bus) {
4586 kref_get(&cs84xx->kref);
4587 goto done;
4588 }
4589 }
4590
4591 cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL);
4592 if (!cs84xx)
4593 goto done;
4594
4595 kref_init(&cs84xx->kref);
4596 spin_lock_init(&cs84xx->access_lock);
4597 mutex_init(&cs84xx->fw_update_mutex);
4598 cs84xx->bus = ha->pdev->bus;
4599
4600 list_add_tail(&cs84xx->list, &qla_cs84xx_list);
4601done:
4602 mutex_unlock(&qla_cs84xx_mutex);
4603 return cs84xx;
4604}
4605
4606static void
4607__qla84xx_chip_release(struct kref *kref)
4608{
4609 struct qla_chip_state_84xx *cs84xx =
4610 container_of(kref, struct qla_chip_state_84xx, kref);
4611
4612 mutex_lock(&qla_cs84xx_mutex);
4613 list_del(&cs84xx->list);
4614 mutex_unlock(&qla_cs84xx_mutex);
4615 kfree(cs84xx);
4616}
4617
4618void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004619qla84xx_put_chip(struct scsi_qla_host *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004620{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004621 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004622 if (ha->cs84xx)
4623 kref_put(&ha->cs84xx->kref, __qla84xx_chip_release);
4624}
4625
4626static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004627qla84xx_init_chip(scsi_qla_host_t *vha)
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004628{
4629 int rval;
4630 uint16_t status[2];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004631 struct qla_hw_data *ha = vha->hw;
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004632
4633 mutex_lock(&ha->cs84xx->fw_update_mutex);
4634
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08004635 rval = qla84xx_verify_chip(vha, status);
Harihara Kadayam4d4df192008-04-03 13:13:26 -07004636
4637 mutex_unlock(&ha->cs84xx->fw_update_mutex);
4638
4639 return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED:
4640 QLA_SUCCESS;
4641}
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004642
4643/* 81XX Support **************************************************************/
4644
4645int
4646qla81xx_nvram_config(scsi_qla_host_t *vha)
4647{
4648 int rval;
4649 struct init_cb_81xx *icb;
4650 struct nvram_81xx *nv;
4651 uint32_t *dptr;
4652 uint8_t *dptr1, *dptr2;
4653 uint32_t chksum;
4654 uint16_t cnt;
4655 struct qla_hw_data *ha = vha->hw;
4656
4657 rval = QLA_SUCCESS;
4658 icb = (struct init_cb_81xx *)ha->init_cb;
4659 nv = ha->nvram;
4660
4661 /* Determine NVRAM starting address. */
4662 ha->nvram_size = sizeof(struct nvram_81xx);
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004663 ha->vpd_size = FA_NVRAM_VPD_SIZE;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004664
4665 /* Get VPD data into cache */
4666 ha->vpd = ha->nvram + VPD_OFFSET;
Andrew Vasquez3d790382009-03-24 09:08:14 -07004667 ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2,
4668 ha->vpd_size);
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004669
4670 /* Get NVRAM data into cache and calculate checksum. */
Andrew Vasquez3d790382009-03-24 09:08:14 -07004671 ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004672 ha->nvram_size);
Andrew Vasquez3d790382009-03-24 09:08:14 -07004673 dptr = (uint32_t *)nv;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004674 for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
4675 chksum += le32_to_cpu(*dptr++);
4676
Andrew Vasquez76403352009-04-06 22:33:39 -07004677 DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004678 DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
4679
4680 /* Bad NVRAM data, set defaults parameters. */
4681 if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
4682 || nv->id[3] != ' ' ||
4683 nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
4684 /* Reset NVRAM data. */
4685 qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
4686 "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
4687 le16_to_cpu(nv->nvram_version));
4688 qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
4689 "invalid -- WWPN) defaults.\n");
4690
4691 /*
4692 * Set default initialization control block.
4693 */
4694 memset(nv, 0, ha->nvram_size);
4695 nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
4696 nv->version = __constant_cpu_to_le16(ICB_VERSION);
4697 nv->frame_payload_size = __constant_cpu_to_le16(2048);
4698 nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
4699 nv->exchange_count = __constant_cpu_to_le16(0);
4700 nv->port_name[0] = 0x21;
Anirban Chakrabortye5b68a62009-04-06 22:33:50 -07004701 nv->port_name[1] = 0x00 + ha->port_no;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004702 nv->port_name[2] = 0x00;
4703 nv->port_name[3] = 0xe0;
4704 nv->port_name[4] = 0x8b;
4705 nv->port_name[5] = 0x1c;
4706 nv->port_name[6] = 0x55;
4707 nv->port_name[7] = 0x86;
4708 nv->node_name[0] = 0x20;
4709 nv->node_name[1] = 0x00;
4710 nv->node_name[2] = 0x00;
4711 nv->node_name[3] = 0xe0;
4712 nv->node_name[4] = 0x8b;
4713 nv->node_name[5] = 0x1c;
4714 nv->node_name[6] = 0x55;
4715 nv->node_name[7] = 0x86;
4716 nv->login_retry_count = __constant_cpu_to_le16(8);
4717 nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
4718 nv->login_timeout = __constant_cpu_to_le16(0);
4719 nv->firmware_options_1 =
4720 __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
4721 nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
4722 nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
4723 nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
4724 nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
4725 nv->efi_parameters = __constant_cpu_to_le32(0);
4726 nv->reset_delay = 5;
4727 nv->max_luns_per_target = __constant_cpu_to_le16(128);
4728 nv->port_down_retry_count = __constant_cpu_to_le16(30);
4729 nv->link_down_timeout = __constant_cpu_to_le16(30);
Andrew Vasquezeeebcc92009-06-03 09:55:24 -07004730 nv->enode_mac[0] = 0x00;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004731 nv->enode_mac[1] = 0x02;
4732 nv->enode_mac[2] = 0x03;
4733 nv->enode_mac[3] = 0x04;
4734 nv->enode_mac[4] = 0x05;
Anirban Chakrabortye5b68a62009-04-06 22:33:50 -07004735 nv->enode_mac[5] = 0x06 + ha->port_no;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004736
4737 rval = 1;
4738 }
4739
4740 /* Reset Initialization control block */
4741 memset(icb, 0, sizeof(struct init_cb_81xx));
4742
4743 /* Copy 1st segment. */
4744 dptr1 = (uint8_t *)icb;
4745 dptr2 = (uint8_t *)&nv->version;
4746 cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
4747 while (cnt--)
4748 *dptr1++ = *dptr2++;
4749
4750 icb->login_retry_count = nv->login_retry_count;
4751
4752 /* Copy 2nd segment. */
4753 dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
4754 dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
4755 cnt = (uint8_t *)&icb->reserved_5 -
4756 (uint8_t *)&icb->interrupt_delay_timer;
4757 while (cnt--)
4758 *dptr1++ = *dptr2++;
4759
4760 memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
4761 /* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
4762 if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
4763 icb->enode_mac[0] = 0x01;
4764 icb->enode_mac[1] = 0x02;
4765 icb->enode_mac[2] = 0x03;
4766 icb->enode_mac[3] = 0x04;
4767 icb->enode_mac[4] = 0x05;
Anirban Chakrabortye5b68a62009-04-06 22:33:50 -07004768 icb->enode_mac[5] = 0x06 + ha->port_no;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004769 }
4770
Andrew Vasquezb64b0e82009-03-24 09:08:01 -07004771 /* Use extended-initialization control block. */
4772 memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb));
4773
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004774 /*
4775 * Setup driver NVRAM options.
4776 */
4777 qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
4778 "QLE81XX");
4779
4780 /* Use alternate WWN? */
4781 if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
4782 memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
4783 memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
4784 }
4785
4786 /* Prepare nodename */
4787 if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
4788 /*
4789 * Firmware will apply the following mask if the nodename was
4790 * not provided.
4791 */
4792 memcpy(icb->node_name, icb->port_name, WWN_SIZE);
4793 icb->node_name[0] &= 0xF0;
4794 }
4795
4796 /* Set host adapter parameters. */
4797 ha->flags.disable_risc_code_load = 0;
4798 ha->flags.enable_lip_reset = 0;
4799 ha->flags.enable_lip_full_login =
4800 le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
4801 ha->flags.enable_target_reset =
4802 le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
4803 ha->flags.enable_led_scheme = 0;
4804 ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
4805
4806 ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
4807 (BIT_6 | BIT_5 | BIT_4)) >> 4;
4808
4809 /* save HBA serial number */
4810 ha->serial0 = icb->port_name[5];
4811 ha->serial1 = icb->port_name[6];
4812 ha->serial2 = icb->port_name[7];
4813 memcpy(vha->node_name, icb->node_name, WWN_SIZE);
4814 memcpy(vha->port_name, icb->port_name, WWN_SIZE);
4815
4816 icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
4817
4818 ha->retry_count = le16_to_cpu(nv->login_retry_count);
4819
4820 /* Set minimum login_timeout to 4 seconds. */
4821 if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
4822 nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
4823 if (le16_to_cpu(nv->login_timeout) < 4)
4824 nv->login_timeout = __constant_cpu_to_le16(4);
4825 ha->login_timeout = le16_to_cpu(nv->login_timeout);
4826 icb->login_timeout = nv->login_timeout;
4827
4828 /* Set minimum RATOV to 100 tenths of a second. */
4829 ha->r_a_tov = 100;
4830
4831 ha->loop_reset_delay = nv->reset_delay;
4832
4833 /* Link Down Timeout = 0:
4834 *
4835 * When Port Down timer expires we will start returning
4836 * I/O's to OS with "DID_NO_CONNECT".
4837 *
4838 * Link Down Timeout != 0:
4839 *
4840 * The driver waits for the link to come up after link down
4841 * before returning I/Os to OS with "DID_NO_CONNECT".
4842 */
4843 if (le16_to_cpu(nv->link_down_timeout) == 0) {
4844 ha->loop_down_abort_time =
4845 (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
4846 } else {
4847 ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
4848 ha->loop_down_abort_time =
4849 (LOOP_DOWN_TIME - ha->link_down_timeout);
4850 }
4851
4852 /* Need enough time to try and get the port back. */
4853 ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
4854 if (qlport_down_retry)
4855 ha->port_down_retry_count = qlport_down_retry;
4856
4857 /* Set login_retry_count */
4858 ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
4859 if (ha->port_down_retry_count ==
4860 le16_to_cpu(nv->port_down_retry_count) &&
4861 ha->port_down_retry_count > 3)
4862 ha->login_retry_count = ha->port_down_retry_count;
4863 else if (ha->port_down_retry_count > (int)ha->login_retry_count)
4864 ha->login_retry_count = ha->port_down_retry_count;
4865 if (ql2xloginretrycount)
4866 ha->login_retry_count = ql2xloginretrycount;
4867
4868 /* Enable ZIO. */
4869 if (!vha->flags.init_done) {
4870 ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
4871 (BIT_3 | BIT_2 | BIT_1 | BIT_0);
4872 ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
4873 le16_to_cpu(icb->interrupt_delay_timer): 2;
4874 }
4875 icb->firmware_options_2 &= __constant_cpu_to_le32(
4876 ~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
4877 vha->flags.process_response_queue = 0;
4878 if (ha->zio_mode != QLA_ZIO_DISABLED) {
4879 ha->zio_mode = QLA_ZIO_MODE_6;
4880
4881 DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
4882 "(%d us).\n", vha->host_no, ha->zio_mode,
4883 ha->zio_timer * 100));
4884 qla_printk(KERN_INFO, ha,
4885 "ZIO mode %d enabled; timer delay (%d us).\n",
4886 ha->zio_mode, ha->zio_timer * 100);
4887
4888 icb->firmware_options_2 |= cpu_to_le32(
4889 (uint32_t)ha->zio_mode);
4890 icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
4891 vha->flags.process_response_queue = 1;
4892 }
4893
4894 if (rval) {
4895 DEBUG2_3(printk(KERN_WARNING
4896 "scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
4897 }
4898 return (rval);
4899}
4900
4901void
Andrew Vasquezae97c912010-02-18 10:07:28 -08004902qla81xx_update_fw_options(scsi_qla_host_t *vha)
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004903{
Andrew Vasquezae97c912010-02-18 10:07:28 -08004904 struct qla_hw_data *ha = vha->hw;
4905
4906 if (!ql2xetsenable)
4907 return;
4908
4909 /* Enable ETS Burst. */
4910 memset(ha->fw_options, 0, sizeof(ha->fw_options));
4911 ha->fw_options[2] |= BIT_9;
4912 qla2x00_set_fw_options(vha, ha->fw_options);
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08004913}
Sarang Radke09ff7012010-03-19 17:03:59 -07004914
4915/*
4916 * qla24xx_get_fcp_prio
4917 * Gets the fcp cmd priority value for the logged in port.
4918 * Looks for a match of the port descriptors within
4919 * each of the fcp prio config entries. If a match is found,
4920 * the tag (priority) value is returned.
4921 *
4922 * Input:
4923 * ha = adapter block po
4924 * fcport = port structure pointer.
4925 *
4926 * Return:
4927 * non-zero (if found)
4928 * 0 (if not found)
4929 *
4930 * Context:
4931 * Kernel context
4932 */
4933uint8_t
4934qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
4935{
4936 int i, entries;
4937 uint8_t pid_match, wwn_match;
4938 uint8_t priority;
4939 uint32_t pid1, pid2;
4940 uint64_t wwn1, wwn2;
4941 struct qla_fcp_prio_entry *pri_entry;
4942 struct qla_hw_data *ha = vha->hw;
4943
4944 if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled)
4945 return 0;
4946
4947 priority = 0;
4948 entries = ha->fcp_prio_cfg->num_entries;
4949 pri_entry = &ha->fcp_prio_cfg->entry[0];
4950
4951 for (i = 0; i < entries; i++) {
4952 pid_match = wwn_match = 0;
4953
4954 if (!(pri_entry->flags & FCP_PRIO_ENTRY_VALID)) {
4955 pri_entry++;
4956 continue;
4957 }
4958
4959 /* check source pid for a match */
4960 if (pri_entry->flags & FCP_PRIO_ENTRY_SPID_VALID) {
4961 pid1 = pri_entry->src_pid & INVALID_PORT_ID;
4962 pid2 = vha->d_id.b24 & INVALID_PORT_ID;
4963 if (pid1 == INVALID_PORT_ID)
4964 pid_match++;
4965 else if (pid1 == pid2)
4966 pid_match++;
4967 }
4968
4969 /* check destination pid for a match */
4970 if (pri_entry->flags & FCP_PRIO_ENTRY_DPID_VALID) {
4971 pid1 = pri_entry->dst_pid & INVALID_PORT_ID;
4972 pid2 = fcport->d_id.b24 & INVALID_PORT_ID;
4973 if (pid1 == INVALID_PORT_ID)
4974 pid_match++;
4975 else if (pid1 == pid2)
4976 pid_match++;
4977 }
4978
4979 /* check source WWN for a match */
4980 if (pri_entry->flags & FCP_PRIO_ENTRY_SWWN_VALID) {
4981 wwn1 = wwn_to_u64(vha->port_name);
4982 wwn2 = wwn_to_u64(pri_entry->src_wwpn);
4983 if (wwn2 == (uint64_t)-1)
4984 wwn_match++;
4985 else if (wwn1 == wwn2)
4986 wwn_match++;
4987 }
4988
4989 /* check destination WWN for a match */
4990 if (pri_entry->flags & FCP_PRIO_ENTRY_DWWN_VALID) {
4991 wwn1 = wwn_to_u64(fcport->port_name);
4992 wwn2 = wwn_to_u64(pri_entry->dst_wwpn);
4993 if (wwn2 == (uint64_t)-1)
4994 wwn_match++;
4995 else if (wwn1 == wwn2)
4996 wwn_match++;
4997 }
4998
4999 if (pid_match == 2 || wwn_match == 2) {
5000 /* Found a matching entry */
5001 if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
5002 priority = pri_entry->tag;
5003 break;
5004 }
5005
5006 pri_entry++;
5007 }
5008
5009 return priority;
5010}
5011
5012/*
5013 * qla24xx_update_fcport_fcp_prio
5014 * Activates fcp priority for the logged in fc port
5015 *
5016 * Input:
5017 * ha = adapter block pointer.
5018 * fcp = port structure pointer.
5019 *
5020 * Return:
5021 * QLA_SUCCESS or QLA_FUNCTION_FAILED
5022 *
5023 * Context:
5024 * Kernel context.
5025 */
5026int
5027qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *ha, fc_port_t *fcport)
5028{
5029 int ret;
5030 uint8_t priority;
5031 uint16_t mb[5];
5032
5033 if (atomic_read(&fcport->state) == FCS_UNCONFIGURED ||
5034 fcport->port_type != FCT_TARGET ||
5035 fcport->loop_id == FC_NO_LOOP_ID)
5036 return QLA_FUNCTION_FAILED;
5037
5038 priority = qla24xx_get_fcp_prio(ha, fcport);
5039 ret = qla24xx_set_fcp_prio(ha, fcport->loop_id, priority, mb);
5040 if (ret == QLA_SUCCESS)
5041 fcport->fcp_prio = priority;
5042 else
5043 DEBUG2(printk(KERN_WARNING
5044 "scsi(%ld): Unable to activate fcp priority, "
5045 " ret=0x%x\n", ha->host_no, ret));
5046
5047 return ret;
5048}
5049
5050/*
5051 * qla24xx_update_all_fcp_prio
5052 * Activates fcp priority for all the logged in ports
5053 *
5054 * Input:
5055 * ha = adapter block pointer.
5056 *
5057 * Return:
5058 * QLA_SUCCESS or QLA_FUNCTION_FAILED
5059 *
5060 * Context:
5061 * Kernel context.
5062 */
5063int
5064qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha)
5065{
5066 int ret;
5067 fc_port_t *fcport;
5068
5069 ret = QLA_FUNCTION_FAILED;
5070 /* We need to set priority for all logged in ports */
5071 list_for_each_entry(fcport, &vha->vp_fcports, list)
5072 ret = qla24xx_update_fcport_fcp_prio(vha, fcport);
5073
5074 return ret;
5075}