blob: 44df0b752adfd3f21a2eefdd6a5b86697c24f7db [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"
8
Andrew Vasquez05236a02007-09-20 14:07:37 -07009#include <linux/delay.h>
Andrew Vasquezdf7baa52006-10-13 09:33:39 -070010#include <scsi/scsi_tcq.h>
Giridhar Malavali9a069e12010-01-12 13:02:47 -080011#include <scsi/scsi_bsg_fc.h>
Andrew Vasquezdf7baa52006-10-13 09:33:39 -070012
Linus Torvalds1da177e2005-04-16 15:20:36 -070013static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
Anirban Chakraborty73208df2008-12-09 16:45:39 -080014static void qla2x00_process_completed_request(struct scsi_qla_host *,
15 struct req_que *, uint32_t);
16static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -070017static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
Anirban Chakraborty73208df2008-12-09 16:45:39 -080018static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
19 sts_entry_t *);
Andrew Vasquez9a853f72005-07-06 10:31:27 -070020
Linus Torvalds1da177e2005-04-16 15:20:36 -070021/**
22 * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
23 * @irq:
24 * @dev_id: SCSI driver HA context
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 *
26 * Called by system whenever the host adapter generates an interrupt.
27 *
28 * Returns handled flag.
29 */
30irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +010031qla2100_intr_handler(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070032{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080033 scsi_qla_host_t *vha;
34 struct qla_hw_data *ha;
Andrew Vasquez3d716442005-07-06 10:30:26 -070035 struct device_reg_2xxx __iomem *reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 unsigned long iter;
Seokmann Ju14e660e2007-09-20 14:07:36 -070038 uint16_t hccr;
Andrew Vasquez9a853f72005-07-06 10:31:27 -070039 uint16_t mb[4];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080040 struct rsp_que *rsp;
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -070041 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080043 rsp = (struct rsp_que *) dev_id;
44 if (!rsp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070045 printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080046 "%s(): NULL response queue pointer\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047 return (IRQ_NONE);
48 }
49
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080050 ha = rsp->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -070051 reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 status = 0;
53
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -070054 spin_lock_irqsave(&ha->hardware_lock, flags);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -070055 vha = pci_get_drvdata(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 for (iter = 50; iter--; ) {
Seokmann Ju14e660e2007-09-20 14:07:36 -070057 hccr = RD_REG_WORD(&reg->hccr);
58 if (hccr & HCCR_RISC_PAUSE) {
59 if (pci_channel_offline(ha->pdev))
60 break;
61
62 /*
63 * Issue a "HARD" reset in order for the RISC interrupt
64 * bit to be cleared. Schedule a big hammmer to get
65 * out of the RISC PAUSED state.
66 */
67 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
68 RD_REG_WORD(&reg->hccr);
69
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080070 ha->isp_ops->fw_dump(vha, 1);
71 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Seokmann Ju14e660e2007-09-20 14:07:36 -070072 break;
73 } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 break;
75
76 if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
77 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
78 RD_REG_WORD(&reg->hccr);
79
80 /* Get mailbox data. */
Andrew Vasquez9a853f72005-07-06 10:31:27 -070081 mb[0] = RD_MAILBOX_REG(ha, reg, 0);
82 if (mb[0] > 0x3fff && mb[0] < 0x8000) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080083 qla2x00_mbx_completion(vha, mb[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 status |= MBX_INTERRUPT;
Andrew Vasquez9a853f72005-07-06 10:31:27 -070085 } else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
86 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
87 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
88 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
Anirban Chakraborty73208df2008-12-09 16:45:39 -080089 qla2x00_async_event(vha, rsp, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 } else {
91 /*EMPTY*/
92 DEBUG2(printk("scsi(%ld): Unrecognized "
Andrew Vasquez9a853f72005-07-06 10:31:27 -070093 "interrupt type (%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080094 vha->host_no, mb[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 }
96 /* Release mailbox registers. */
97 WRT_REG_WORD(&reg->semaphore, 0);
98 RD_REG_WORD(&reg->semaphore);
99 } else {
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800100 qla2x00_process_response_queue(rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
102 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
103 RD_REG_WORD(&reg->hccr);
104 }
105 }
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -0700106 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
109 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -0800111 complete(&ha->mbx_intr_comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 }
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 return (IRQ_HANDLED);
115}
116
117/**
118 * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
119 * @irq:
120 * @dev_id: SCSI driver HA context
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 *
122 * Called by system whenever the host adapter generates an interrupt.
123 *
124 * Returns handled flag.
125 */
126irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100127qla2300_intr_handler(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800129 scsi_qla_host_t *vha;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700130 struct device_reg_2xxx __iomem *reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 unsigned long iter;
133 uint32_t stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 uint16_t hccr;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700135 uint16_t mb[4];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800136 struct rsp_que *rsp;
137 struct qla_hw_data *ha;
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -0700138 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800140 rsp = (struct rsp_que *) dev_id;
141 if (!rsp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800143 "%s(): NULL response queue pointer\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144 return (IRQ_NONE);
145 }
146
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800147 ha = rsp->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700148 reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 status = 0;
150
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -0700151 spin_lock_irqsave(&ha->hardware_lock, flags);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -0700152 vha = pci_get_drvdata(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 for (iter = 50; iter--; ) {
154 stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
155 if (stat & HSR_RISC_PAUSED) {
Andrew Vasquez85880802009-12-15 21:29:46 -0800156 if (unlikely(pci_channel_offline(ha->pdev)))
Seokmann Ju14e660e2007-09-20 14:07:36 -0700157 break;
158
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 hccr = RD_REG_WORD(&reg->hccr);
160 if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
Andrew Vasquez07f31802006-12-13 19:20:31 -0800161 qla_printk(KERN_INFO, ha, "Parity error -- "
162 "HCCR=%x, Dumping firmware!\n", hccr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 else
Andrew Vasquez07f31802006-12-13 19:20:31 -0800164 qla_printk(KERN_INFO, ha, "RISC paused -- "
165 "HCCR=%x, Dumping firmware!\n", hccr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166
167 /*
168 * Issue a "HARD" reset in order for the RISC
169 * interrupt bit to be cleared. Schedule a big
170 * hammmer to get out of the RISC PAUSED state.
171 */
172 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
173 RD_REG_WORD(&reg->hccr);
Andrew Vasquez07f31802006-12-13 19:20:31 -0800174
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800175 ha->isp_ops->fw_dump(vha, 1);
176 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 break;
178 } else if ((stat & HSR_RISC_INT) == 0)
179 break;
180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 switch (stat & 0xff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 case 0x1:
183 case 0x2:
184 case 0x10:
185 case 0x11:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800186 qla2x00_mbx_completion(vha, MSW(stat));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 status |= MBX_INTERRUPT;
188
189 /* Release mailbox registers. */
190 WRT_REG_WORD(&reg->semaphore, 0);
191 break;
192 case 0x12:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700193 mb[0] = MSW(stat);
194 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
195 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
196 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800197 qla2x00_async_event(vha, rsp, mb);
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700198 break;
199 case 0x13:
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800200 qla2x00_process_response_queue(rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 break;
202 case 0x15:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700203 mb[0] = MBA_CMPLT_1_16BIT;
204 mb[1] = MSW(stat);
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800205 qla2x00_async_event(vha, rsp, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 break;
207 case 0x16:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700208 mb[0] = MBA_SCSI_COMPLETION;
209 mb[1] = MSW(stat);
210 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800211 qla2x00_async_event(vha, rsp, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 break;
213 default:
214 DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700215 "(%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800216 vha->host_no, stat & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 break;
218 }
219 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
220 RD_REG_WORD_RELAXED(&reg->hccr);
221 }
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -0700222 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
225 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -0800227 complete(&ha->mbx_intr_comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 }
229
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 return (IRQ_HANDLED);
231}
232
233/**
234 * qla2x00_mbx_completion() - Process mailbox command completions.
235 * @ha: SCSI driver HA context
236 * @mb0: Mailbox0 register
237 */
238static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800239qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240{
241 uint16_t cnt;
242 uint16_t __iomem *wptr;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800243 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700244 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
246 /* Load return mailbox registers. */
247 ha->flags.mbox_int = 1;
248 ha->mailbox_out[0] = mb0;
249 wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);
250
251 for (cnt = 1; cnt < ha->mbx_count; cnt++) {
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700252 if (IS_QLA2200(ha) && cnt == 8)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
254 if (cnt == 4 || cnt == 5)
255 ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
256 else
257 ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700258
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 wptr++;
260 }
261
262 if (ha->mcp) {
263 DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800264 __func__, vha->host_no, ha->mcp->mb[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 } else {
266 DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800267 __func__, vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 }
269}
270
Andrew Vasquez8a659572009-02-08 20:50:12 -0800271static void
272qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
273{
274 static char *event[] =
275 { "Complete", "Request Notification", "Time Extension" };
276 int rval;
277 struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
278 uint16_t __iomem *wptr;
279 uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
280
281 /* Seed data -- mailbox1 -> mailbox7. */
282 wptr = (uint16_t __iomem *)&reg24->mailbox1;
283 for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
284 mb[cnt] = RD_REG_WORD(wptr);
285
286 DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
287 "%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no,
288 event[aen & 0xff],
289 mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6]));
290
291 /* Acknowledgement needed? [Notify && non-zero timeout]. */
292 timeout = (descr >> 8) & 0xf;
293 if (aen != MBA_IDC_NOTIFY || !timeout)
294 return;
295
296 DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
297 "ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout));
298
299 rval = qla2x00_post_idc_ack_work(vha, mb);
300 if (rval != QLA_SUCCESS)
301 qla_printk(KERN_WARNING, vha->hw,
302 "IDC failed to post ACK.\n");
303}
304
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305/**
306 * qla2x00_async_event() - Process aynchronous events.
307 * @ha: SCSI driver HA context
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700308 * @mb: Mailbox registers (0 - 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 */
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700310void
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800311qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700313#define LS_UNKNOWN 2
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800314 static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 char *link_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 uint16_t handle_cnt;
Andrew Vasquezbdab23d2009-10-13 15:16:46 -0700317 uint16_t cnt, mbx;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 uint32_t handles[5];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800319 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700320 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Andrew Vasquezbdab23d2009-10-13 15:16:46 -0700321 struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 uint32_t rscn_entry, host_pid;
323 uint8_t rscn_queue_index;
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700324 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 /* Setup to process RIO completion. */
327 handle_cnt = 0;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800328 if (IS_QLA81XX(ha))
329 goto skip_rio;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330 switch (mb[0]) {
331 case MBA_SCSI_COMPLETION:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700332 handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 handle_cnt = 1;
334 break;
335 case MBA_CMPLT_1_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700336 handles[0] = mb[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 handle_cnt = 1;
338 mb[0] = MBA_SCSI_COMPLETION;
339 break;
340 case MBA_CMPLT_2_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700341 handles[0] = mb[1];
342 handles[1] = mb[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343 handle_cnt = 2;
344 mb[0] = MBA_SCSI_COMPLETION;
345 break;
346 case MBA_CMPLT_3_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700347 handles[0] = mb[1];
348 handles[1] = mb[2];
349 handles[2] = mb[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350 handle_cnt = 3;
351 mb[0] = MBA_SCSI_COMPLETION;
352 break;
353 case MBA_CMPLT_4_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700354 handles[0] = mb[1];
355 handles[1] = mb[2];
356 handles[2] = mb[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
358 handle_cnt = 4;
359 mb[0] = MBA_SCSI_COMPLETION;
360 break;
361 case MBA_CMPLT_5_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700362 handles[0] = mb[1];
363 handles[1] = mb[2];
364 handles[2] = mb[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
366 handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
367 handle_cnt = 5;
368 mb[0] = MBA_SCSI_COMPLETION;
369 break;
370 case MBA_CMPLT_2_32BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700371 handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 handles[1] = le32_to_cpu(
373 ((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) |
374 RD_MAILBOX_REG(ha, reg, 6));
375 handle_cnt = 2;
376 mb[0] = MBA_SCSI_COMPLETION;
377 break;
378 default:
379 break;
380 }
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800381skip_rio:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 switch (mb[0]) {
383 case MBA_SCSI_COMPLETION: /* Fast Post */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800384 if (!vha->flags.online)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 break;
386
387 for (cnt = 0; cnt < handle_cnt; cnt++)
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800388 qla2x00_process_completed_request(vha, rsp->req,
389 handles[cnt]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 break;
391
392 case MBA_RESET: /* Reset */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800393 DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n",
394 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800396 set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 break;
398
399 case MBA_SYSTEM_ERR: /* System Error */
Andrew Vasquezbdab23d2009-10-13 15:16:46 -0700400 mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox7) : 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700401 qla_printk(KERN_INFO, ha,
Andrew Vasquezbdab23d2009-10-13 15:16:46 -0700402 "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
403 "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800405 ha->isp_ops->fw_dump(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406
Andrew Vasqueze4289242007-07-19 15:05:56 -0700407 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700408 if (mb[1] == 0 && mb[2] == 0) {
409 qla_printk(KERN_ERR, ha,
410 "Unrecoverable Hardware Error: adapter "
411 "marked OFFLINE!\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800412 vha->flags.online = 0;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700413 } else
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800414 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700415 } else if (mb[1] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 qla_printk(KERN_INFO, ha,
417 "Unrecoverable Hardware Error: adapter marked "
418 "OFFLINE!\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800419 vha->flags.online = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420 } else
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800421 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700422 break;
423
424 case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */
Andrew Vasquezbdab23d2009-10-13 15:16:46 -0700425 DEBUG2(printk("scsi(%ld): ISP Request Transfer Error (%x).\n",
426 vha->host_no, mb[1]));
427 qla_printk(KERN_WARNING, ha,
428 "ISP Request Transfer Error (%x).\n", mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800430 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431 break;
432
433 case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */
434 DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800435 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
437
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800438 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 break;
440
441 case MBA_WAKEUP_THRES: /* Request Queue Wake-up */
442 DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800443 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 break;
445
446 case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800447 DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", vha->host_no,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 mb[1]));
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -0700449 qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800451 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
452 atomic_set(&vha->loop_state, LOOP_DOWN);
453 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
454 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 }
456
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800457 if (vha->vp_idx) {
458 atomic_set(&vha->vp_state, VP_FAILED);
459 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700460 }
461
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800462 set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
463 set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800465 vha->flags.management_server_logged_in = 0;
466 qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 break;
468
469 case MBA_LOOP_UP: /* Loop Up Event */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
471 link_speed = link_speeds[0];
Andrew Vasquezd8b45212006-10-02 12:00:43 -0700472 ha->link_data_rate = PORT_SPEED_1GB;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 } else {
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700474 link_speed = link_speeds[LS_UNKNOWN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 if (mb[1] < 5)
476 link_speed = link_speeds[mb[1]];
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800477 else if (mb[1] == 0x13)
478 link_speed = link_speeds[5];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 ha->link_data_rate = mb[1];
480 }
481
482 DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800483 vha->host_no, link_speed));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
485 link_speed);
486
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800487 vha->flags.management_server_logged_in = 0;
488 qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 break;
490
491 case MBA_LOOP_DOWN: /* Loop Down Event */
Andrew Vasquezbdab23d2009-10-13 15:16:46 -0700492 mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700493 DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
Andrew Vasquezbdab23d2009-10-13 15:16:46 -0700494 "(%x %x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3],
495 mbx));
496 qla_printk(KERN_INFO, ha,
497 "LOOP DOWN detected (%x %x %x %x).\n", mb[1], mb[2], mb[3],
498 mbx);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800500 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
501 atomic_set(&vha->loop_state, LOOP_DOWN);
502 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
503 vha->device_flags |= DFLG_NO_CABLE;
504 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 }
506
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800507 if (vha->vp_idx) {
508 atomic_set(&vha->vp_state, VP_FAILED);
509 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700510 }
511
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800512 vha->flags.management_server_logged_in = 0;
Andrew Vasquezd8b45212006-10-02 12:00:43 -0700513 ha->link_data_rate = PORT_SPEED_UNKNOWN;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800514 qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 break;
516
517 case MBA_LIP_RESET: /* LIP reset occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800519 vha->host_no, mb[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 qla_printk(KERN_INFO, ha,
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -0700521 "LIP reset occurred (%x).\n", mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800523 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
524 atomic_set(&vha->loop_state, LOOP_DOWN);
525 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
526 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 }
528
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800529 if (vha->vp_idx) {
530 atomic_set(&vha->vp_state, VP_FAILED);
531 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700532 }
533
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800534 set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 ha->operating_mode = LOOP;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800537 vha->flags.management_server_logged_in = 0;
538 qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 break;
540
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800541 /* case MBA_DCBX_COMPLETE: */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 case MBA_POINT_TO_POINT: /* Point-to-Point */
543 if (IS_QLA2100(ha))
544 break;
545
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800546 if (IS_QLA81XX(ha))
547 DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
548 "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
549 else
550 DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
551 "received.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552
553 /*
554 * Until there's a transition from loop down to loop up, treat
555 * this as loop down only.
556 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800557 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
558 atomic_set(&vha->loop_state, LOOP_DOWN);
559 if (!atomic_read(&vha->loop_down_timer))
560 atomic_set(&vha->loop_down_timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 LOOP_DOWN_TIME);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800562 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 }
564
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800565 if (vha->vp_idx) {
566 atomic_set(&vha->vp_state, VP_FAILED);
567 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700568 }
569
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800570 if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
571 set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
572
573 set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
574 set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
Andrew Vasquez4346b142006-12-13 19:20:28 -0800575
576 ha->flags.gpsc_supported = 1;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800577 vha->flags.management_server_logged_in = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 break;
579
580 case MBA_CHG_IN_CONNECTION: /* Change in connection mode */
581 if (IS_QLA2100(ha))
582 break;
583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection "
585 "received.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800586 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 qla_printk(KERN_INFO, ha,
588 "Configuration change detected: value=%x.\n", mb[1]);
589
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800590 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
591 atomic_set(&vha->loop_state, LOOP_DOWN);
592 if (!atomic_read(&vha->loop_down_timer))
593 atomic_set(&vha->loop_down_timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594 LOOP_DOWN_TIME);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800595 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 }
597
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800598 if (vha->vp_idx) {
599 atomic_set(&vha->vp_state, VP_FAILED);
600 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700601 }
602
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800603 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
604 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 break;
606
607 case MBA_PORT_UPDATE: /* Port database update */
Santosh Vernekar55903b92009-07-31 15:09:25 -0700608 /*
609 * Handle only global and vn-port update events
610 *
611 * Relevant inputs:
612 * mb[1] = N_Port handle of changed port
613 * OR 0xffff for global event
614 * mb[2] = New login state
615 * 7 = Port logged out
616 * mb[3] = LSB is vp_idx, 0xff = all vps
617 *
618 * Skip processing if:
619 * Event is global, vp_idx is NOT all vps,
620 * vp_idx does not match
621 * Event is not global, vp_idx does not match
622 */
Andrew Vasquez12cec63e42010-03-19 16:59:17 -0700623 if (IS_QLA2XXX_MIDTYPE(ha) &&
624 ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
625 (mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
626 break;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800627
Andrew Vasquez9764ff82009-07-31 15:09:24 -0700628 /* Global event -- port logout or port unavailable. */
629 if (mb[1] == 0xffff && mb[2] == 0x7) {
630 DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
631 vha->host_no));
632 DEBUG(printk(KERN_INFO
633 "scsi(%ld): Port unavailable %04x %04x %04x.\n",
634 vha->host_no, mb[1], mb[2], mb[3]));
635
636 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
637 atomic_set(&vha->loop_state, LOOP_DOWN);
638 atomic_set(&vha->loop_down_timer,
639 LOOP_DOWN_TIME);
640 vha->device_flags |= DFLG_NO_CABLE;
641 qla2x00_mark_all_devices_lost(vha, 1);
642 }
643
644 if (vha->vp_idx) {
645 atomic_set(&vha->vp_state, VP_FAILED);
646 fc_vport_set_state(vha->fc_vport,
647 FC_VPORT_FAILED);
Santosh Vernekarfaadc5e2009-07-31 15:09:26 -0700648 qla2x00_mark_all_devices_lost(vha, 1);
Andrew Vasquez9764ff82009-07-31 15:09:24 -0700649 }
650
651 vha->flags.management_server_logged_in = 0;
652 ha->link_data_rate = PORT_SPEED_UNKNOWN;
653 break;
654 }
655
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656 /*
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -0700657 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 * event etc. earlier indicating loop is down) then process
659 * it. Otherwise ignore it and Wait for RSCN to come in.
660 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800661 atomic_set(&vha->loop_down_timer, 0);
662 if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
663 atomic_read(&vha->loop_state) != LOOP_DEAD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800665 "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700666 mb[2], mb[3]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 break;
668 }
669
670 DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800671 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 DEBUG(printk(KERN_INFO
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700673 "scsi(%ld): Port database changed %04x %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800674 vha->host_no, mb[1], mb[2], mb[3]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
676 /*
677 * Mark all devices as missing so we will login again.
678 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800679 atomic_set(&vha->loop_state, LOOP_UP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800681 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800683 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800685 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
686 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 break;
688
689 case MBA_RSCN_UPDATE: /* State Change Registration */
Seokmann Ju3c397402008-05-19 14:25:39 -0700690 /* Check if the Vport has issued a SCR */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800691 if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
Seokmann Ju3c397402008-05-19 14:25:39 -0700692 break;
693 /* Only handle SCNs for our Vport index. */
Andrew Vasquez0d6e61b2009-08-25 11:36:19 -0700694 if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
Seokmann Ju3c397402008-05-19 14:25:39 -0700695 break;
Andrew Vasquez0d6e61b2009-08-25 11:36:19 -0700696
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800698 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 DEBUG(printk(KERN_INFO
Shyam Sundarf4a8dbc2007-11-12 10:30:59 -0800700 "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800701 vha->host_no, mb[1], mb[2], mb[3]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Ravi Anand59d72d82008-09-11 21:22:53 -0700703 rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800704 host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
705 | vha->d_id.b.al_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 if (rscn_entry == host_pid) {
707 DEBUG(printk(KERN_INFO
708 "scsi(%ld): Ignoring RSCN update to local host "
709 "port ID (%06x)\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800710 vha->host_no, host_pid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 break;
712 }
713
Ravi Anand59d72d82008-09-11 21:22:53 -0700714 /* Ignore reserved bits from RSCN-payload. */
715 rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800716 rscn_queue_index = vha->rscn_in_ptr + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 if (rscn_queue_index == MAX_RSCN_COUNT)
718 rscn_queue_index = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800719 if (rscn_queue_index != vha->rscn_out_ptr) {
720 vha->rscn_queue[vha->rscn_in_ptr] = rscn_entry;
721 vha->rscn_in_ptr = rscn_queue_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800723 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 }
725
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800726 atomic_set(&vha->loop_state, LOOP_UPDATE);
727 atomic_set(&vha->loop_down_timer, 0);
728 vha->flags.management_server_logged_in = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800730 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
731 set_bit(RSCN_UPDATE, &vha->dpc_flags);
732 qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 break;
734
735 /* case MBA_RIO_RESPONSE: */
736 case MBA_ZIO_RESPONSE:
Andrew Vasquez3fd67cd2009-01-05 11:18:07 -0800737 DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800738 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739
Andrew Vasqueze4289242007-07-19 15:05:56 -0700740 if (IS_FWI2_CAPABLE(ha))
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -0700741 qla24xx_process_response_queue(vha, rsp);
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -0700742 else
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800743 qla2x00_process_response_queue(rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 break;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700745
746 case MBA_DISCARD_RND_FRAME:
747 DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800748 "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700749 break;
Andrew Vasquez45ebeb52006-08-01 13:48:14 -0700750
751 case MBA_TRACE_NOTIFICATION:
752 DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800753 vha->host_no, mb[1], mb[2]));
Andrew Vasquez45ebeb52006-08-01 13:48:14 -0700754 break;
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700755
756 case MBA_ISP84XX_ALERT:
757 DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800758 "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700759
760 spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
761 switch (mb[1]) {
762 case A84_PANIC_RECOVERY:
763 qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery "
764 "%04x %04x\n", mb[2], mb[3]);
765 break;
766 case A84_OP_LOGIN_COMPLETE:
767 ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
768 DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
769 "firmware version %x\n", ha->cs84xx->op_fw_version));
770 break;
771 case A84_DIAG_LOGIN_COMPLETE:
772 ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
773 DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
774 "diagnostic firmware version %x\n",
775 ha->cs84xx->diag_fw_version));
776 break;
777 case A84_GOLD_LOGIN_COMPLETE:
778 ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
779 ha->cs84xx->fw_update = 1;
780 DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold "
781 "firmware version %x\n",
782 ha->cs84xx->gold_fw_version));
783 break;
784 default:
785 qla_printk(KERN_ERR, ha,
786 "Alert 84xx: Invalid Alert %04x %04x %04x\n",
787 mb[1], mb[2], mb[3]);
788 }
789 spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
790 break;
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800791 case MBA_DCBX_START:
792 DEBUG2(printk("scsi(%ld): DCBX Started -- %04x %04x %04x\n",
793 vha->host_no, mb[1], mb[2], mb[3]));
794 break;
795 case MBA_DCBX_PARAM_UPDATE:
796 DEBUG2(printk("scsi(%ld): DCBX Parameters Updated -- "
797 "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
798 break;
799 case MBA_FCF_CONF_ERR:
800 DEBUG2(printk("scsi(%ld): FCF Configuration Error -- "
801 "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
802 break;
803 case MBA_IDC_COMPLETE:
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800804 case MBA_IDC_NOTIFY:
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800805 case MBA_IDC_TIME_EXT:
Andrew Vasquez8a659572009-02-08 20:50:12 -0800806 qla81xx_idc_event(vha, mb[0], mb[1]);
Andrew Vasquez3a03eb72009-01-05 11:18:11 -0800807 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700809
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800810 if (!vha->vp_idx && ha->num_vhosts)
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800811 qla2x00_alert_all_vps(rsp, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812}
813
814/**
815 * qla2x00_process_completed_request() - Process a Fast Post response.
816 * @ha: SCSI driver HA context
817 * @index: SRB index
818 */
819static void
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800820qla2x00_process_completed_request(struct scsi_qla_host *vha,
821 struct req_que *req, uint32_t index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
823 srb_t *sp;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800824 struct qla_hw_data *ha = vha->hw;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
826 /* Validate handle. */
827 if (index >= MAX_OUTSTANDING_COMMANDS) {
828 DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800829 vha->host_no, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 qla_printk(KERN_WARNING, ha,
831 "Invalid SCSI completion handle %d.\n", index);
832
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800833 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 return;
835 }
836
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800837 sp = req->outstanding_cmds[index];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (sp) {
839 /* Free outstanding command slot. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800840 req->outstanding_cmds[index] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 /* Save ISP completion status */
843 sp->cmd->result = DID_OK << 16;
Anirban Chakraborty73208df2008-12-09 16:45:39 -0800844 qla2x00_sp_compl(ha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 } else {
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -0700846 DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
847 " handle(%d)\n", vha->host_no, req->id, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 qla_printk(KERN_WARNING, ha,
849 "Invalid ISP SCSI completion handle\n");
850
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800851 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 }
853}
854
Andrew Vasquezac280b62009-08-20 11:06:05 -0700855static srb_t *
856qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
857 struct req_que *req, void *iocb)
858{
859 struct qla_hw_data *ha = vha->hw;
860 sts_entry_t *pkt = iocb;
861 srb_t *sp = NULL;
862 uint16_t index;
863
864 index = LSW(pkt->handle);
865 if (index >= MAX_OUTSTANDING_COMMANDS) {
866 qla_printk(KERN_WARNING, ha,
867 "%s: Invalid completion handle (%x).\n", func, index);
868 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
869 goto done;
870 }
871 sp = req->outstanding_cmds[index];
872 if (!sp) {
873 qla_printk(KERN_WARNING, ha,
874 "%s: Invalid completion handle (%x) -- timed-out.\n", func,
875 index);
876 return sp;
877 }
878 if (sp->handle != index) {
879 qla_printk(KERN_WARNING, ha,
880 "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle,
881 index);
882 return NULL;
883 }
Giridhar Malavali9a069e12010-01-12 13:02:47 -0800884
Andrew Vasquezac280b62009-08-20 11:06:05 -0700885 req->outstanding_cmds[index] = NULL;
Giridhar Malavali9a069e12010-01-12 13:02:47 -0800886
Andrew Vasquezac280b62009-08-20 11:06:05 -0700887done:
888 return sp;
889}
890
891static void
892qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
893 struct mbx_entry *mbx)
894{
895 const char func[] = "MBX-IOCB";
896 const char *type;
897 struct qla_hw_data *ha = vha->hw;
898 fc_port_t *fcport;
899 srb_t *sp;
900 struct srb_logio *lio;
901 uint16_t data[2];
902
903 sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
904 if (!sp)
905 return;
906
907 type = NULL;
908 lio = sp->ctx;
909 switch (lio->ctx.type) {
910 case SRB_LOGIN_CMD:
911 type = "login";
912 break;
913 case SRB_LOGOUT_CMD:
914 type = "logout";
915 break;
916 default:
917 qla_printk(KERN_WARNING, ha,
918 "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
919 lio->ctx.type);
920 return;
921 }
922
923 del_timer(&lio->ctx.timer);
924 fcport = sp->fcport;
925
926 data[0] = data[1] = 0;
927 if (mbx->entry_status) {
928 DEBUG2(printk(KERN_WARNING
929 "scsi(%ld:%x): Async-%s error entry - entry-status=%x "
930 "status=%x state-flag=%x status-flags=%x.\n",
931 fcport->vha->host_no, sp->handle, type,
932 mbx->entry_status, le16_to_cpu(mbx->status),
933 le16_to_cpu(mbx->state_flags),
934 le16_to_cpu(mbx->status_flags)));
935 DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
936
937 data[0] = MBS_COMMAND_ERROR;
938 data[1] = lio->flags & SRB_LOGIN_RETRIED ?
939 QLA_LOGIO_LOGIN_RETRIED: 0;
940 goto done_post_logio_done_work;
941 }
942
943 if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
944 DEBUG2(printk(KERN_DEBUG
945 "scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
946 fcport->vha->host_no, sp->handle, type,
947 le16_to_cpu(mbx->mb1)));
948
949 data[0] = MBS_COMMAND_COMPLETE;
950 if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1)
Santosh Vernekar8474f3a2009-08-25 11:36:16 -0700951 fcport->flags |= FCF_FCP2_DEVICE;
Andrew Vasquezac280b62009-08-20 11:06:05 -0700952
953 goto done_post_logio_done_work;
954 }
955
956 data[0] = le16_to_cpu(mbx->mb0);
957 switch (data[0]) {
958 case MBS_PORT_ID_USED:
959 data[1] = le16_to_cpu(mbx->mb1);
960 break;
961 case MBS_LOOP_ID_USED:
962 break;
963 default:
964 data[0] = MBS_COMMAND_ERROR;
965 data[1] = lio->flags & SRB_LOGIN_RETRIED ?
966 QLA_LOGIO_LOGIN_RETRIED: 0;
967 break;
968 }
969
970 DEBUG2(printk(KERN_WARNING
971 "scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
972 "mb6=%x mb7=%x.\n",
973 fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status),
974 le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
975 le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
976 le16_to_cpu(mbx->mb7)));
977
978done_post_logio_done_work:
979 lio->ctx.type == SRB_LOGIN_CMD ?
980 qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
981 qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
982
983 lio->ctx.free(sp);
984}
985
986static void
Giridhar Malavali9a069e12010-01-12 13:02:47 -0800987qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
988 struct sts_entry_24xx *pkt, int iocb_type)
989{
990 const char func[] = "ELS_CT_IOCB";
991 const char *type;
992 struct qla_hw_data *ha = vha->hw;
993 srb_t *sp;
994 struct srb_bsg *sp_bsg;
995 struct fc_bsg_job *bsg_job;
996 uint16_t comp_status;
997 uint32_t fw_status[3];
998 uint8_t* fw_sts_ptr;
999
1000 sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
1001 if (!sp)
1002 return;
1003 sp_bsg = (struct srb_bsg*)sp->ctx;
1004 bsg_job = sp_bsg->bsg_job;
1005
1006 type = NULL;
1007 switch (sp_bsg->ctx.type) {
1008 case SRB_ELS_CMD_RPT:
1009 case SRB_ELS_CMD_HST:
1010 type = "els";
1011 break;
1012 case SRB_CT_CMD:
1013 type = "ct pass-through";
1014 break;
1015 default:
1016 qla_printk(KERN_WARNING, ha,
1017 "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
1018 sp_bsg->ctx.type);
1019 return;
1020 }
1021
1022 comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
1023 fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1);
1024 fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2);
1025
1026 /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
1027 * fc payload to the caller
1028 */
1029 bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
1030 bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
1031
1032 if (comp_status != CS_COMPLETE) {
1033 if (comp_status == CS_DATA_UNDERRUN) {
1034 bsg_job->reply->result = DID_OK << 16;
1035 bsg_job->reply->reply_payload_rcv_len =
1036 le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count);
1037
1038 DEBUG2(qla_printk(KERN_WARNING, ha,
1039 "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
1040 "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
1041 vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2],
1042 le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count)));
1043 fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
1044 memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
1045 }
1046 else {
1047 DEBUG2(qla_printk(KERN_WARNING, ha,
1048 "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
1049 "error subcode 1=0x%x error subcode 2=0x%x.\n",
1050 vha->host_no, sp->handle, type, comp_status,
1051 le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1),
1052 le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2)));
1053 bsg_job->reply->result = DID_ERROR << 16;
1054 bsg_job->reply->reply_payload_rcv_len = 0;
1055 fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
1056 memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
1057 }
1058 DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt)));
1059 }
1060 else {
1061 bsg_job->reply->result = DID_OK << 16;;
1062 bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
1063 bsg_job->reply_len = 0;
1064 }
1065
1066 dma_unmap_sg(&ha->pdev->dev,
1067 bsg_job->request_payload.sg_list,
1068 bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
1069 dma_unmap_sg(&ha->pdev->dev,
1070 bsg_job->reply_payload.sg_list,
1071 bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE);
1072 if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) ||
1073 (sp_bsg->ctx.type == SRB_CT_CMD))
1074 kfree(sp->fcport);
1075 kfree(sp->ctx);
1076 mempool_free(sp, ha->srb_mempool);
1077 bsg_job->job_done(bsg_job);
1078}
1079
1080static void
Andrew Vasquezac280b62009-08-20 11:06:05 -07001081qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
1082 struct logio_entry_24xx *logio)
1083{
1084 const char func[] = "LOGIO-IOCB";
1085 const char *type;
1086 struct qla_hw_data *ha = vha->hw;
1087 fc_port_t *fcport;
1088 srb_t *sp;
1089 struct srb_logio *lio;
1090 uint16_t data[2];
1091 uint32_t iop[2];
1092
1093 sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
1094 if (!sp)
1095 return;
1096
1097 type = NULL;
1098 lio = sp->ctx;
1099 switch (lio->ctx.type) {
1100 case SRB_LOGIN_CMD:
1101 type = "login";
1102 break;
1103 case SRB_LOGOUT_CMD:
1104 type = "logout";
1105 break;
1106 default:
1107 qla_printk(KERN_WARNING, ha,
1108 "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
1109 lio->ctx.type);
1110 return;
1111 }
1112
1113 del_timer(&lio->ctx.timer);
1114 fcport = sp->fcport;
1115
1116 data[0] = data[1] = 0;
1117 if (logio->entry_status) {
1118 DEBUG2(printk(KERN_WARNING
1119 "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
1120 fcport->vha->host_no, sp->handle, type,
1121 logio->entry_status));
1122 DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
1123
1124 data[0] = MBS_COMMAND_ERROR;
1125 data[1] = lio->flags & SRB_LOGIN_RETRIED ?
1126 QLA_LOGIO_LOGIN_RETRIED: 0;
1127 goto done_post_logio_done_work;
1128 }
1129
1130 if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
1131 DEBUG2(printk(KERN_DEBUG
1132 "scsi(%ld:%x): Async-%s complete - iop0=%x.\n",
1133 fcport->vha->host_no, sp->handle, type,
1134 le32_to_cpu(logio->io_parameter[0])));
1135
1136 data[0] = MBS_COMMAND_COMPLETE;
1137 if (lio->ctx.type == SRB_LOGOUT_CMD)
1138 goto done_post_logio_done_work;
1139
1140 iop[0] = le32_to_cpu(logio->io_parameter[0]);
1141 if (iop[0] & BIT_4) {
1142 fcport->port_type = FCT_TARGET;
1143 if (iop[0] & BIT_8)
Santosh Vernekar8474f3a2009-08-25 11:36:16 -07001144 fcport->flags |= FCF_FCP2_DEVICE;
Andrew Vasquezac280b62009-08-20 11:06:05 -07001145 }
1146 if (iop[0] & BIT_5)
1147 fcport->port_type = FCT_INITIATOR;
1148 if (logio->io_parameter[7] || logio->io_parameter[8])
1149 fcport->supported_classes |= FC_COS_CLASS2;
1150 if (logio->io_parameter[9] || logio->io_parameter[10])
1151 fcport->supported_classes |= FC_COS_CLASS3;
1152
1153 goto done_post_logio_done_work;
1154 }
1155
1156 iop[0] = le32_to_cpu(logio->io_parameter[0]);
1157 iop[1] = le32_to_cpu(logio->io_parameter[1]);
1158 switch (iop[0]) {
1159 case LSC_SCODE_PORTID_USED:
1160 data[0] = MBS_PORT_ID_USED;
1161 data[1] = LSW(iop[1]);
1162 break;
1163 case LSC_SCODE_NPORT_USED:
1164 data[0] = MBS_LOOP_ID_USED;
1165 break;
1166 case LSC_SCODE_CMD_FAILED:
1167 if ((iop[1] & 0xff) == 0x05) {
1168 data[0] = MBS_NOT_LOGGED_IN;
1169 break;
1170 }
1171 /* Fall through. */
1172 default:
1173 data[0] = MBS_COMMAND_ERROR;
1174 data[1] = lio->flags & SRB_LOGIN_RETRIED ?
1175 QLA_LOGIO_LOGIN_RETRIED: 0;
1176 break;
1177 }
1178
1179 DEBUG2(printk(KERN_WARNING
1180 "scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n",
1181 fcport->vha->host_no, sp->handle, type,
1182 le16_to_cpu(logio->comp_status),
1183 le32_to_cpu(logio->io_parameter[0]),
1184 le32_to_cpu(logio->io_parameter[1])));
1185
1186done_post_logio_done_work:
1187 lio->ctx.type == SRB_LOGIN_CMD ?
1188 qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
1189 qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
1190
1191 lio->ctx.free(sp);
1192}
1193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194/**
1195 * qla2x00_process_response_queue() - Process response queue entries.
1196 * @ha: SCSI driver HA context
1197 */
1198void
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001199qla2x00_process_response_queue(struct rsp_que *rsp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200{
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001201 struct scsi_qla_host *vha;
1202 struct qla_hw_data *ha = rsp->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -07001203 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 sts_entry_t *pkt;
1205 uint16_t handle_cnt;
1206 uint16_t cnt;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001207
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001208 vha = pci_get_drvdata(ha->pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001210 if (!vha->flags.online)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return;
1212
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001213 while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
1214 pkt = (sts_entry_t *)rsp->ring_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001216 rsp->ring_index++;
1217 if (rsp->ring_index == rsp->length) {
1218 rsp->ring_index = 0;
1219 rsp->ring_ptr = rsp->ring;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001221 rsp->ring_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 }
1223
1224 if (pkt->entry_status != 0) {
1225 DEBUG3(printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001226 "scsi(%ld): Process error entry.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001228 qla2x00_error_entry(vha, rsp, pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
1230 wmb();
1231 continue;
1232 }
1233
1234 switch (pkt->entry_type) {
1235 case STATUS_TYPE:
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001236 qla2x00_status_entry(vha, rsp, pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237 break;
1238 case STATUS_TYPE_21:
1239 handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
1240 for (cnt = 0; cnt < handle_cnt; cnt++) {
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001241 qla2x00_process_completed_request(vha, rsp->req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 ((sts21_entry_t *)pkt)->handle[cnt]);
1243 }
1244 break;
1245 case STATUS_TYPE_22:
1246 handle_cnt = ((sts22_entry_t *)pkt)->handle_count;
1247 for (cnt = 0; cnt < handle_cnt; cnt++) {
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001248 qla2x00_process_completed_request(vha, rsp->req,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 ((sts22_entry_t *)pkt)->handle[cnt]);
1250 }
1251 break;
1252 case STATUS_CONT_TYPE:
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001253 qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 break;
Andrew Vasquezac280b62009-08-20 11:06:05 -07001255 case MBX_IOCB_TYPE:
1256 qla2x00_mbx_iocb_entry(vha, rsp->req,
1257 (struct mbx_entry *)pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 default:
1259 /* Type Not Supported. */
1260 DEBUG4(printk(KERN_WARNING
1261 "scsi(%ld): Received unknown response pkt type %x "
1262 "entry status=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001263 vha->host_no, pkt->entry_type, pkt->entry_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 break;
1265 }
1266 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
1267 wmb();
1268 }
1269
1270 /* Adjust ring index */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001271 WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272}
1273
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001274static inline void
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001275qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
1276 struct rsp_que *rsp)
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001277{
1278 struct scsi_cmnd *cp = sp->cmd;
1279
1280 if (sense_len >= SCSI_SENSE_BUFFERSIZE)
1281 sense_len = SCSI_SENSE_BUFFERSIZE;
1282
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001283 sp->request_sense_length = sense_len;
1284 sp->request_sense_ptr = cp->sense_buffer;
1285 if (sp->request_sense_length > 32)
1286 sense_len = 32;
1287
1288 memcpy(cp->sense_buffer, sense_data, sense_len);
1289
1290 sp->request_sense_ptr += sense_len;
1291 sp->request_sense_length -= sense_len;
1292 if (sp->request_sense_length != 0)
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001293 rsp->status_srb = sp;
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001294
1295 DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001296 "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
Andrew Vasquez19851f12008-08-13 21:37:00 -07001297 cp->device->channel, cp->device->id, cp->device->lun, cp,
1298 cp->serial_number));
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001299 if (sense_len)
Shyam Sundarddb9b122009-03-24 09:08:10 -07001300 DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001301}
1302
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303/**
1304 * qla2x00_status_entry() - Process a Status IOCB entry.
1305 * @ha: SCSI driver HA context
1306 * @pkt: Entry pointer
1307 */
1308static void
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001309qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001311 srb_t *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312 fc_port_t *fcport;
1313 struct scsi_cmnd *cp;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001314 sts_entry_t *sts;
1315 struct sts_entry_24xx *sts24;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316 uint16_t comp_status;
1317 uint16_t scsi_status;
1318 uint8_t lscsi_status;
1319 int32_t resid;
Ravi Ananded17c71b52006-05-17 15:08:55 -07001320 uint32_t sense_len, rsp_info_len, resid_len, fw_resid_len;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001321 uint8_t *rsp_info, *sense_data;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001322 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001323 uint32_t handle;
1324 uint16_t que;
1325 struct req_que *req;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001326
1327 sts = (sts_entry_t *) pkt;
1328 sts24 = (struct sts_entry_24xx *) pkt;
Andrew Vasqueze4289242007-07-19 15:05:56 -07001329 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001330 comp_status = le16_to_cpu(sts24->comp_status);
1331 scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
1332 } else {
1333 comp_status = le16_to_cpu(sts->comp_status);
1334 scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
1335 }
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001336 handle = (uint32_t) LSW(sts->handle);
1337 que = MSW(sts->handle);
1338 req = ha->req_q_map[que];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 /* Fast path completion. */
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001340 if (comp_status == CS_COMPLETE && scsi_status == 0) {
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001341 qla2x00_process_completed_request(vha, req, handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342
1343 return;
1344 }
1345
1346 /* Validate handle. */
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001347 if (handle < MAX_OUTSTANDING_COMMANDS) {
1348 sp = req->outstanding_cmds[handle];
1349 req->outstanding_cmds[handle] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 } else
1351 sp = NULL;
1352
1353 if (sp == NULL) {
1354 DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001355 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n");
1357
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001358 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1359 qla2xxx_wake_dpc(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 return;
1361 }
1362 cp = sp->cmd;
1363 if (cp == NULL) {
1364 DEBUG2(printk("scsi(%ld): Command already returned back to OS "
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001365 "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 qla_printk(KERN_WARNING, ha,
1367 "Command is NULL: already returned to OS (sp=%p)\n", sp);
1368
1369 return;
1370 }
1371
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001372 lscsi_status = scsi_status & STATUS_MASK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373
bdf79622005-04-17 15:06:53 -05001374 fcport = sp->fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375
Ravi Ananded17c71b52006-05-17 15:08:55 -07001376 sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
Andrew Vasqueze4289242007-07-19 15:05:56 -07001377 if (IS_FWI2_CAPABLE(ha)) {
Lalit Chandivade0f00a202009-10-13 15:16:52 -07001378 if (scsi_status & SS_SENSE_LEN_VALID)
1379 sense_len = le32_to_cpu(sts24->sense_len);
1380 if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
1381 rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
1382 if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
1383 resid_len = le32_to_cpu(sts24->rsp_residual_count);
1384 if (comp_status == CS_DATA_UNDERRUN)
1385 fw_resid_len = le32_to_cpu(sts24->residual_len);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001386 rsp_info = sts24->data;
1387 sense_data = sts24->data;
1388 host_to_fcp_swap(sts24->data, sizeof(sts24->data));
1389 } else {
Lalit Chandivade0f00a202009-10-13 15:16:52 -07001390 if (scsi_status & SS_SENSE_LEN_VALID)
1391 sense_len = le16_to_cpu(sts->req_sense_length);
1392 if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
1393 rsp_info_len = le16_to_cpu(sts->rsp_info_len);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001394 resid_len = le32_to_cpu(sts->residual_length);
1395 rsp_info = sts->rsp_info;
1396 sense_data = sts->req_sense_data;
1397 }
1398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 /* Check for any FCP transport errors. */
1400 if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001401 /* Sense data lies beyond any FCP RESPONSE data. */
Andrew Vasqueze4289242007-07-19 15:05:56 -07001402 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001403 sense_data += rsp_info_len;
1404 if (rsp_info_len > 3 && rsp_info[3]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001405 DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
1406 "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001407 "retrying command\n", vha->host_no,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001408 cp->device->channel, cp->device->id,
1409 cp->device->lun, rsp_info_len, rsp_info[0],
1410 rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4],
1411 rsp_info[5], rsp_info[6], rsp_info[7]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412
1413 cp->result = DID_BUS_BUSY << 16;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001414 qla2x00_sp_compl(ha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 return;
1416 }
1417 }
1418
Andrew Vasquez3e8ce322008-02-28 14:06:10 -08001419 /* Check for overrun. */
1420 if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
1421 scsi_status & SS_RESIDUAL_OVER)
1422 comp_status = CS_DATA_OVERRUN;
1423
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 /*
1425 * Based on Host and scsi status generate status code for Linux
1426 */
1427 switch (comp_status) {
1428 case CS_COMPLETE:
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001429 case CS_QUEUE_FULL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001430 if (scsi_status == 0) {
1431 cp->result = DID_OK << 16;
1432 break;
1433 }
1434 if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001435 resid = resid_len;
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001436 scsi_set_resid(cp, resid);
Andrew Vasquez0da69df2005-12-06 10:58:06 -08001437
1438 if (!lscsi_status &&
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001439 ((unsigned)(scsi_bufflen(cp) - resid) <
Andrew Vasquez0da69df2005-12-06 10:58:06 -08001440 cp->underflow)) {
1441 qla_printk(KERN_INFO, ha,
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001442 "scsi(%ld:%d:%d:%d): Mid-layer underflow "
1443 "detected (%x of %x bytes)...returning "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001444 "error status.\n", vha->host_no,
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001445 cp->device->channel, cp->device->id,
1446 cp->device->lun, resid,
1447 scsi_bufflen(cp));
Andrew Vasquez0da69df2005-12-06 10:58:06 -08001448
1449 cp->result = DID_ERROR << 16;
1450 break;
1451 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 cp->result = DID_OK << 16 | lscsi_status;
1454
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001455 if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
1456 DEBUG2(printk(KERN_INFO
1457 "scsi(%ld): QUEUE FULL status detected "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001458 "0x%x-0x%x.\n", vha->host_no, comp_status,
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001459 scsi_status));
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001460 break;
1461 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 if (lscsi_status != SS_CHECK_CONDITION)
1463 break;
1464
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +09001465 memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 if (!(scsi_status & SS_SENSE_LEN_VALID))
1467 break;
1468
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001469 qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 break;
1471
1472 case CS_DATA_UNDERRUN:
Lalit Chandivade0f00a202009-10-13 15:16:52 -07001473 DEBUG2(printk(KERN_INFO
1474 "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x. "
1475 "resid=0x%x fw_resid=0x%x cdb=0x%x os_underflow=0x%x\n",
1476 vha->host_no, cp->device->id, cp->device->lun, comp_status,
1477 scsi_status, resid_len, fw_resid_len, cp->cmnd[0],
1478 cp->underflow));
1479
Ravi Ananded17c71b52006-05-17 15:08:55 -07001480 /* Use F/W calculated residual length. */
Lalit Chandivade0f00a202009-10-13 15:16:52 -07001481 resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
1482 scsi_set_resid(cp, resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 if (scsi_status & SS_RESIDUAL_UNDER) {
Lalit Chandivade0f00a202009-10-13 15:16:52 -07001484 if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
1485 DEBUG2(printk(
1486 "scsi(%ld:%d:%d:%d) Dropped frame(s) "
1487 "detected (%x of %x bytes)...residual "
1488 "length mismatch...retrying command.\n",
1489 vha->host_no, cp->device->channel,
1490 cp->device->id, cp->device->lun, resid,
1491 scsi_bufflen(cp)));
andrew.vasquez@qlogic.come038a1be2006-01-13 17:04:59 -08001492
Lalit Chandivade0f00a202009-10-13 15:16:52 -07001493 cp->result = DID_ERROR << 16 | lscsi_status;
1494 break;
1495 }
1496
1497 if (!lscsi_status &&
1498 ((unsigned)(scsi_bufflen(cp) - resid) <
1499 cp->underflow)) {
1500 qla_printk(KERN_INFO, ha,
1501 "scsi(%ld:%d:%d:%d): Mid-layer underflow "
1502 "detected (%x of %x bytes)...returning "
1503 "error status.\n", vha->host_no,
1504 cp->device->channel, cp->device->id,
1505 cp->device->lun, resid, scsi_bufflen(cp));
1506
1507 cp->result = DID_ERROR << 16;
1508 break;
1509 }
1510 } else if (!lscsi_status) {
1511 DEBUG2(printk(
1512 "scsi(%ld:%d:%d:%d) Dropped frame(s) detected "
1513 "(%x of %x bytes)...firmware reported underrun..."
1514 "retrying command.\n", vha->host_no,
1515 cp->device->channel, cp->device->id,
1516 cp->device->lun, resid, scsi_bufflen(cp)));
1517
1518 cp->result = DID_ERROR << 16;
1519 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001520 }
1521
Lalit Chandivade0f00a202009-10-13 15:16:52 -07001522 cp->result = DID_OK << 16 | lscsi_status;
1523
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 /*
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001525 * Check to see if SCSI Status is non zero. If so report SCSI
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 * Status.
1527 */
1528 if (lscsi_status != 0) {
Andrew Vasquezffec28a2007-01-29 10:22:27 -08001529 if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
1530 DEBUG2(printk(KERN_INFO
1531 "scsi(%ld): QUEUE FULL status detected "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001532 "0x%x-0x%x.\n", vha->host_no, comp_status,
Andrew Vasquezffec28a2007-01-29 10:22:27 -08001533 scsi_status));
Andrew Vasquezffec28a2007-01-29 10:22:27 -08001534 break;
1535 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536 if (lscsi_status != SS_CHECK_CONDITION)
1537 break;
1538
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +09001539 memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 if (!(scsi_status & SS_SENSE_LEN_VALID))
1541 break;
1542
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001543 qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 }
1545 break;
1546
1547 case CS_DATA_OVERRUN:
1548 DEBUG2(printk(KERN_INFO
1549 "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001550 vha->host_no, cp->device->id, cp->device->lun, comp_status,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001551 scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 DEBUG2(printk(KERN_INFO
1553 "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1554 cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
1555 cp->cmnd[4], cp->cmnd[5]));
1556 DEBUG2(printk(KERN_INFO
1557 "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR "
1558 "status!\n",
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001559 cp->serial_number, scsi_bufflen(cp), resid_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001560
1561 cp->result = DID_ERROR << 16;
1562 break;
1563
1564 case CS_PORT_LOGGED_OUT:
1565 case CS_PORT_CONFIG_CHG:
1566 case CS_PORT_BUSY:
1567 case CS_INCOMPLETE:
1568 case CS_PORT_UNAVAILABLE:
1569 /*
1570 * If the port is in Target Down state, return all IOs for this
1571 * Target with DID_NO_CONNECT ELSE Queue the IOs in the
1572 * retry_queue.
1573 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001574 DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
1575 "pid=%ld, compl status=0x%x, port state=0x%x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001576 vha->host_no, cp->device->id, cp->device->lun,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001577 cp->serial_number, comp_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001578 atomic_read(&fcport->state)));
1579
Mike Christie056a4482008-08-19 18:45:29 -05001580 /*
1581 * We are going to have the fc class block the rport
1582 * while we try to recover so instruct the mid layer
1583 * to requeue until the class decides how to handle this.
1584 */
1585 cp->result = DID_TRANSPORT_DISRUPTED << 16;
Andrew Vasqueza7a28502008-08-13 21:36:57 -07001586 if (atomic_read(&fcport->state) == FCS_ONLINE)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001587 qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001588 break;
1589
1590 case CS_RESET:
1591 DEBUG2(printk(KERN_INFO
1592 "scsi(%ld): RESET status detected 0x%x-0x%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001593 vha->host_no, comp_status, scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001594
f4f051e2005-04-17 15:02:26 -05001595 cp->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001596 break;
1597
1598 case CS_ABORTED:
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001599 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 * hv2.19.12 - DID_ABORT does not retry the request if we
1601 * aborted this request then abort otherwise it must be a
1602 * reset.
1603 */
1604 DEBUG2(printk(KERN_INFO
1605 "scsi(%ld): ABORT status detected 0x%x-0x%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001606 vha->host_no, comp_status, scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607
1608 cp->result = DID_RESET << 16;
1609 break;
1610
1611 case CS_TIMEOUT:
Mike Christie056a4482008-08-19 18:45:29 -05001612 /*
1613 * We are going to have the fc class block the rport
1614 * while we try to recover so instruct the mid layer
1615 * to requeue until the class decides how to handle this.
1616 */
1617 cp->result = DID_TRANSPORT_DISRUPTED << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618
Andrew Vasqueze4289242007-07-19 15:05:56 -07001619 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001620 DEBUG2(printk(KERN_INFO
1621 "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001622 "0x%x-0x%x\n", vha->host_no, cp->device->channel,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001623 cp->device->id, cp->device->lun, comp_status,
1624 scsi_status));
1625 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626 }
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001627 DEBUG2(printk(KERN_INFO
1628 "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001629 "sflags=%x.\n", vha->host_no, cp->device->channel,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001630 cp->device->id, cp->device->lun, comp_status, scsi_status,
1631 le16_to_cpu(sts->status_flags)));
1632
1633 /* Check to see if logout occurred. */
1634 if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001635 qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636 break;
1637
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638 default:
1639 DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001640 "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641 qla_printk(KERN_INFO, ha,
1642 "Unknown status detected 0x%x-0x%x.\n",
1643 comp_status, scsi_status);
1644
1645 cp->result = DID_ERROR << 16;
1646 break;
1647 }
1648
1649 /* Place command on done queue. */
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001650 if (rsp->status_srb == NULL)
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001651 qla2x00_sp_compl(ha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652}
1653
1654/**
1655 * qla2x00_status_cont_entry() - Process a Status Continuations entry.
1656 * @ha: SCSI driver HA context
1657 * @pkt: Entry pointer
1658 *
1659 * Extended sense data.
1660 */
1661static void
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001662qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663{
1664 uint8_t sense_sz = 0;
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001665 struct qla_hw_data *ha = rsp->hw;
1666 srb_t *sp = rsp->status_srb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001667 struct scsi_cmnd *cp;
1668
1669 if (sp != NULL && sp->request_sense_length != 0) {
1670 cp = sp->cmd;
1671 if (cp == NULL) {
1672 DEBUG2(printk("%s(): Cmd already returned back to OS "
Andrew Vasquez75bc4192006-05-17 15:09:22 -07001673 "sp=%p.\n", __func__, sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 qla_printk(KERN_INFO, ha,
1675 "cmd is NULL: already returned to OS (sp=%p)\n",
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001676 sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001677
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001678 rsp->status_srb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679 return;
1680 }
1681
1682 if (sp->request_sense_length > sizeof(pkt->data)) {
1683 sense_sz = sizeof(pkt->data);
1684 } else {
1685 sense_sz = sp->request_sense_length;
1686 }
1687
1688 /* Move sense data. */
Andrew Vasqueze4289242007-07-19 15:05:56 -07001689 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001690 host_to_fcp_swap(pkt->data, sizeof(pkt->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691 memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
1692 DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
1693
1694 sp->request_sense_ptr += sense_sz;
1695 sp->request_sense_length -= sense_sz;
1696
1697 /* Place command on done queue. */
1698 if (sp->request_sense_length == 0) {
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001699 rsp->status_srb = NULL;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001700 qla2x00_sp_compl(ha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701 }
1702 }
1703}
1704
1705/**
1706 * qla2x00_error_entry() - Process an error entry.
1707 * @ha: SCSI driver HA context
1708 * @pkt: Entry pointer
1709 */
1710static void
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001711qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001712{
1713 srb_t *sp;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001714 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001715 uint32_t handle = LSW(pkt->handle);
1716 uint16_t que = MSW(pkt->handle);
1717 struct req_que *req = ha->req_q_map[que];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001718#if defined(QL_DEBUG_LEVEL_2)
1719 if (pkt->entry_status & RF_INV_E_ORDER)
1720 qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
1721 else if (pkt->entry_status & RF_INV_E_COUNT)
1722 qla_printk(KERN_ERR, ha, "%s: Invalid Entry Count\n", __func__);
1723 else if (pkt->entry_status & RF_INV_E_PARAM)
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001724 qla_printk(KERN_ERR, ha,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001725 "%s: Invalid Entry Parameter\n", __func__);
1726 else if (pkt->entry_status & RF_INV_E_TYPE)
1727 qla_printk(KERN_ERR, ha, "%s: Invalid Entry Type\n", __func__);
1728 else if (pkt->entry_status & RF_BUSY)
1729 qla_printk(KERN_ERR, ha, "%s: Busy\n", __func__);
1730 else
1731 qla_printk(KERN_ERR, ha, "%s: UNKNOWN flag error\n", __func__);
1732#endif
1733
1734 /* Validate handle. */
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001735 if (handle < MAX_OUTSTANDING_COMMANDS)
1736 sp = req->outstanding_cmds[handle];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737 else
1738 sp = NULL;
1739
1740 if (sp) {
1741 /* Free outstanding command slot. */
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001742 req->outstanding_cmds[handle] = NULL;
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001743
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 /* Bad payload or header */
1745 if (pkt->entry_status &
1746 (RF_INV_E_ORDER | RF_INV_E_COUNT |
1747 RF_INV_E_PARAM | RF_INV_E_TYPE)) {
1748 sp->cmd->result = DID_ERROR << 16;
1749 } else if (pkt->entry_status & RF_BUSY) {
1750 sp->cmd->result = DID_BUS_BUSY << 16;
1751 } else {
1752 sp->cmd->result = DID_ERROR << 16;
1753 }
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001754 qla2x00_sp_compl(ha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001755
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001756 } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
1757 COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001759 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001760 qla_printk(KERN_WARNING, ha,
1761 "Error entry - invalid handle\n");
1762
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001763 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1764 qla2xxx_wake_dpc(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 }
1766}
1767
1768/**
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001769 * qla24xx_mbx_completion() - Process mailbox command completions.
1770 * @ha: SCSI driver HA context
1771 * @mb0: Mailbox0 register
1772 */
1773static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001774qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001775{
1776 uint16_t cnt;
1777 uint16_t __iomem *wptr;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001778 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001779 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1780
1781 /* Load return mailbox registers. */
1782 ha->flags.mbox_int = 1;
1783 ha->mailbox_out[0] = mb0;
1784 wptr = (uint16_t __iomem *)&reg->mailbox1;
1785
1786 for (cnt = 1; cnt < ha->mbx_count; cnt++) {
1787 ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
1788 wptr++;
1789 }
1790
1791 if (ha->mcp) {
1792 DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001793 __func__, vha->host_no, ha->mcp->mb[0]));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001794 } else {
1795 DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001796 __func__, vha->host_no));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001797 }
1798}
1799
1800/**
1801 * qla24xx_process_response_queue() - Process response queue entries.
1802 * @ha: SCSI driver HA context
1803 */
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001804void qla24xx_process_response_queue(struct scsi_qla_host *vha,
1805 struct rsp_que *rsp)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001806{
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001807 struct sts_entry_24xx *pkt;
1808
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001809 if (!vha->flags.online)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001810 return;
1811
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001812 while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
1813 pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001814
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001815 rsp->ring_index++;
1816 if (rsp->ring_index == rsp->length) {
1817 rsp->ring_index = 0;
1818 rsp->ring_ptr = rsp->ring;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001819 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001820 rsp->ring_ptr++;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001821 }
1822
1823 if (pkt->entry_status != 0) {
1824 DEBUG3(printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001825 "scsi(%ld): Process error entry.\n", vha->host_no));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001826
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001827 qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001828 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
1829 wmb();
1830 continue;
1831 }
1832
1833 switch (pkt->entry_type) {
1834 case STATUS_TYPE:
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001835 qla2x00_status_entry(vha, rsp, pkt);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001836 break;
1837 case STATUS_CONT_TYPE:
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001838 qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001839 break;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001840 case VP_RPT_ID_IOCB_TYPE:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001841 qla24xx_report_id_acquisition(vha,
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001842 (struct vp_rpt_id_entry_24xx *)pkt);
1843 break;
Andrew Vasquezac280b62009-08-20 11:06:05 -07001844 case LOGINOUT_PORT_IOCB_TYPE:
1845 qla24xx_logio_entry(vha, rsp->req,
1846 (struct logio_entry_24xx *)pkt);
1847 break;
Giridhar Malavali9a069e12010-01-12 13:02:47 -08001848 case CT_IOCB_TYPE:
1849 qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
1850 clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
1851 break;
1852 case ELS_IOCB_TYPE:
1853 qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
1854 break;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001855 default:
1856 /* Type Not Supported. */
1857 DEBUG4(printk(KERN_WARNING
1858 "scsi(%ld): Received unknown response pkt type %x "
1859 "entry status=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001860 vha->host_no, pkt->entry_type, pkt->entry_status));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001861 break;
1862 }
1863 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
1864 wmb();
1865 }
1866
1867 /* Adjust ring index */
Andrew Vasquez08029992009-03-24 09:07:55 -07001868 WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001869}
1870
Andrew Vasquez05236a02007-09-20 14:07:37 -07001871static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001872qla2xxx_check_risc_status(scsi_qla_host_t *vha)
Andrew Vasquez05236a02007-09-20 14:07:37 -07001873{
1874 int rval;
1875 uint32_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001876 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez05236a02007-09-20 14:07:37 -07001877 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1878
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08001879 if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
Andrew Vasquez05236a02007-09-20 14:07:37 -07001880 return;
1881
1882 rval = QLA_SUCCESS;
1883 WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
1884 RD_REG_DWORD(&reg->iobase_addr);
1885 WRT_REG_DWORD(&reg->iobase_window, 0x0001);
1886 for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
1887 rval == QLA_SUCCESS; cnt--) {
1888 if (cnt) {
1889 WRT_REG_DWORD(&reg->iobase_window, 0x0001);
1890 udelay(10);
1891 } else
1892 rval = QLA_FUNCTION_TIMEOUT;
1893 }
1894 if (rval == QLA_SUCCESS)
1895 goto next_test;
1896
1897 WRT_REG_DWORD(&reg->iobase_window, 0x0003);
1898 for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
1899 rval == QLA_SUCCESS; cnt--) {
1900 if (cnt) {
1901 WRT_REG_DWORD(&reg->iobase_window, 0x0003);
1902 udelay(10);
1903 } else
1904 rval = QLA_FUNCTION_TIMEOUT;
1905 }
1906 if (rval != QLA_SUCCESS)
1907 goto done;
1908
1909next_test:
1910 if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
1911 qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
1912
1913done:
1914 WRT_REG_DWORD(&reg->iobase_window, 0x0000);
1915 RD_REG_DWORD(&reg->iobase_window);
1916}
1917
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001918/**
1919 * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
1920 * @irq:
1921 * @dev_id: SCSI driver HA context
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001922 *
1923 * Called by system whenever the host adapter generates an interrupt.
1924 *
1925 * Returns handled flag.
1926 */
1927irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01001928qla24xx_intr_handler(int irq, void *dev_id)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001929{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001930 scsi_qla_host_t *vha;
1931 struct qla_hw_data *ha;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001932 struct device_reg_24xx __iomem *reg;
1933 int status;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001934 unsigned long iter;
1935 uint32_t stat;
1936 uint32_t hccr;
1937 uint16_t mb[4];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001938 struct rsp_que *rsp;
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -07001939 unsigned long flags;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001940
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001941 rsp = (struct rsp_que *) dev_id;
1942 if (!rsp) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001943 printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001944 "%s(): NULL response queue pointer\n", __func__);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001945 return IRQ_NONE;
1946 }
1947
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001948 ha = rsp->hw;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001949 reg = &ha->iobase->isp24;
1950 status = 0;
1951
Andrew Vasquez85880802009-12-15 21:29:46 -08001952 if (unlikely(pci_channel_offline(ha->pdev)))
1953 return IRQ_HANDLED;
1954
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -07001955 spin_lock_irqsave(&ha->hardware_lock, flags);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001956 vha = pci_get_drvdata(ha->pdev);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001957 for (iter = 50; iter--; ) {
1958 stat = RD_REG_DWORD(&reg->host_status);
1959 if (stat & HSRX_RISC_PAUSED) {
Andrew Vasquez85880802009-12-15 21:29:46 -08001960 if (unlikely(pci_channel_offline(ha->pdev)))
Seokmann Ju14e660e2007-09-20 14:07:36 -07001961 break;
1962
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001963 hccr = RD_REG_DWORD(&reg->hccr);
1964
1965 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
1966 "Dumping firmware!\n", hccr);
Andrew Vasquez05236a02007-09-20 14:07:37 -07001967
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001968 qla2xxx_check_risc_status(vha);
Andrew Vasquez05236a02007-09-20 14:07:37 -07001969
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001970 ha->isp_ops->fw_dump(vha, 1);
1971 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001972 break;
1973 } else if ((stat & HSRX_RISC_INT) == 0)
1974 break;
1975
1976 switch (stat & 0xff) {
1977 case 0x1:
1978 case 0x2:
1979 case 0x10:
1980 case 0x11:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001981 qla24xx_mbx_completion(vha, MSW(stat));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001982 status |= MBX_INTERRUPT;
1983
1984 break;
1985 case 0x12:
1986 mb[0] = MSW(stat);
1987 mb[1] = RD_REG_WORD(&reg->mailbox1);
1988 mb[2] = RD_REG_WORD(&reg->mailbox2);
1989 mb[3] = RD_REG_WORD(&reg->mailbox3);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001990 qla2x00_async_event(vha, rsp, mb);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001991 break;
1992 case 0x13:
Anirban Chakraborty73208df2008-12-09 16:45:39 -08001993 case 0x14:
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07001994 qla24xx_process_response_queue(vha, rsp);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001995 break;
1996 default:
1997 DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
1998 "(%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001999 vha->host_no, stat & 0xff));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07002000 break;
2001 }
2002 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2003 RD_REG_DWORD_RELAXED(&reg->hccr);
2004 }
Anirban Chakraborty43fac4d2009-06-10 13:55:11 -07002005 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07002006
2007 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
2008 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07002009 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -08002010 complete(&ha->mbx_intr_comp);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07002011 }
2012
2013 return IRQ_HANDLED;
2014}
2015
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002016static irqreturn_t
2017qla24xx_msix_rsp_q(int irq, void *dev_id)
2018{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002019 struct qla_hw_data *ha;
2020 struct rsp_que *rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002021 struct device_reg_24xx __iomem *reg;
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002022 struct scsi_qla_host *vha;
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002023 unsigned long flags;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002024
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002025 rsp = (struct rsp_que *) dev_id;
2026 if (!rsp) {
2027 printk(KERN_INFO
2028 "%s(): NULL response queue pointer\n", __func__);
2029 return IRQ_NONE;
2030 }
2031 ha = rsp->hw;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002032 reg = &ha->iobase->isp24;
2033
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002034 spin_lock_irqsave(&ha->hardware_lock, flags);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002035
Anirban Chakrabortya67093d2010-02-04 14:17:59 -08002036 vha = pci_get_drvdata(ha->pdev);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002037 qla24xx_process_response_queue(vha, rsp);
Anirban Chakraborty31557542009-12-02 10:36:55 -08002038 if (!ha->flags.disable_msix_handshake) {
Anirban Chakrabortyeb941142009-08-04 16:12:13 -07002039 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2040 RD_REG_DWORD_RELAXED(&reg->hccr);
2041 }
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002042 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002043
2044 return IRQ_HANDLED;
2045}
2046
2047static irqreturn_t
Anirban Chakraborty68ca9492009-04-06 22:33:41 -07002048qla25xx_msix_rsp_q(int irq, void *dev_id)
2049{
2050 struct qla_hw_data *ha;
2051 struct rsp_que *rsp;
Anirban Chakraborty31557542009-12-02 10:36:55 -08002052 struct device_reg_24xx __iomem *reg;
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002053 unsigned long flags;
Anirban Chakraborty68ca9492009-04-06 22:33:41 -07002054
2055 rsp = (struct rsp_que *) dev_id;
2056 if (!rsp) {
2057 printk(KERN_INFO
2058 "%s(): NULL response queue pointer\n", __func__);
2059 return IRQ_NONE;
2060 }
2061 ha = rsp->hw;
2062
Anirban Chakraborty31557542009-12-02 10:36:55 -08002063 /* Clear the interrupt, if enabled, for this response queue */
2064 if (rsp->options & ~BIT_6) {
2065 reg = &ha->iobase->isp24;
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002066 spin_lock_irqsave(&ha->hardware_lock, flags);
Anirban Chakraborty31557542009-12-02 10:36:55 -08002067 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2068 RD_REG_DWORD_RELAXED(&reg->hccr);
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002069 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Anirban Chakraborty31557542009-12-02 10:36:55 -08002070 }
Anirban Chakraborty68ca9492009-04-06 22:33:41 -07002071 queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);
2072
2073 return IRQ_HANDLED;
2074}
2075
2076static irqreturn_t
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002077qla24xx_msix_default(int irq, void *dev_id)
2078{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002079 scsi_qla_host_t *vha;
2080 struct qla_hw_data *ha;
2081 struct rsp_que *rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002082 struct device_reg_24xx __iomem *reg;
2083 int status;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002084 uint32_t stat;
2085 uint32_t hccr;
2086 uint16_t mb[4];
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002087 unsigned long flags;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002088
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002089 rsp = (struct rsp_que *) dev_id;
2090 if (!rsp) {
2091 DEBUG(printk(
2092 "%s(): NULL response queue pointer\n", __func__));
2093 return IRQ_NONE;
2094 }
2095 ha = rsp->hw;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002096 reg = &ha->iobase->isp24;
2097 status = 0;
2098
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002099 spin_lock_irqsave(&ha->hardware_lock, flags);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002100 vha = pci_get_drvdata(ha->pdev);
Andrew Vasquez87f27012007-09-20 14:07:49 -07002101 do {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002102 stat = RD_REG_DWORD(&reg->host_status);
2103 if (stat & HSRX_RISC_PAUSED) {
Andrew Vasquez85880802009-12-15 21:29:46 -08002104 if (unlikely(pci_channel_offline(ha->pdev)))
Seokmann Ju14e660e2007-09-20 14:07:36 -07002105 break;
2106
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002107 hccr = RD_REG_DWORD(&reg->hccr);
2108
2109 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
2110 "Dumping firmware!\n", hccr);
Andrew Vasquez05236a02007-09-20 14:07:37 -07002111
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002112 qla2xxx_check_risc_status(vha);
Andrew Vasquez05236a02007-09-20 14:07:37 -07002113
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002114 ha->isp_ops->fw_dump(vha, 1);
2115 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002116 break;
2117 } else if ((stat & HSRX_RISC_INT) == 0)
2118 break;
2119
2120 switch (stat & 0xff) {
2121 case 0x1:
2122 case 0x2:
2123 case 0x10:
2124 case 0x11:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002125 qla24xx_mbx_completion(vha, MSW(stat));
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002126 status |= MBX_INTERRUPT;
2127
2128 break;
2129 case 0x12:
2130 mb[0] = MSW(stat);
2131 mb[1] = RD_REG_WORD(&reg->mailbox1);
2132 mb[2] = RD_REG_WORD(&reg->mailbox2);
2133 mb[3] = RD_REG_WORD(&reg->mailbox3);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002134 qla2x00_async_event(vha, rsp, mb);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002135 break;
2136 case 0x13:
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002137 case 0x14:
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002138 qla24xx_process_response_queue(vha, rsp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002139 break;
2140 default:
2141 DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
2142 "(%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002143 vha->host_no, stat & 0xff));
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002144 break;
2145 }
2146 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
Andrew Vasquez87f27012007-09-20 14:07:49 -07002147 } while (0);
Xiaotian Feng0f19bc62010-01-29 18:09:30 +08002148 spin_unlock_irqrestore(&ha->hardware_lock, flags);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002149
2150 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
2151 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002152 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -08002153 complete(&ha->mbx_intr_comp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002154 }
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002155 return IRQ_HANDLED;
2156}
2157
2158/* Interrupt handling helpers. */
2159
2160struct qla_init_msix_entry {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002161 const char *name;
Jeff Garzik476834c2007-05-23 14:41:44 -07002162 irq_handler_t handler;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002163};
2164
Anirban Chakraborty68ca9492009-04-06 22:33:41 -07002165static struct qla_init_msix_entry msix_entries[3] = {
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002166 { "qla2xxx (default)", qla24xx_msix_default },
2167 { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
Anirban Chakraborty68ca9492009-04-06 22:33:41 -07002168 { "qla2xxx (multiq)", qla25xx_msix_rsp_q },
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002169};
2170
2171static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002172qla24xx_disable_msix(struct qla_hw_data *ha)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002173{
2174 int i;
2175 struct qla_msix_entry *qentry;
2176
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002177 for (i = 0; i < ha->msix_count; i++) {
2178 qentry = &ha->msix_entries[i];
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002179 if (qentry->have_irq)
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002180 free_irq(qentry->vector, qentry->rsp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002181 }
2182 pci_disable_msix(ha->pdev);
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002183 kfree(ha->msix_entries);
2184 ha->msix_entries = NULL;
2185 ha->flags.msix_enabled = 0;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002186}
2187
2188static int
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002189qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002190{
Lalit Chandivadead038fa2009-01-22 09:45:33 -08002191#define MIN_MSIX_COUNT 2
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002192 int i, ret;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002193 struct msix_entry *entries;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002194 struct qla_msix_entry *qentry;
2195
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002196 entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
2197 GFP_KERNEL);
2198 if (!entries)
2199 return -ENOMEM;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002200
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002201 for (i = 0; i < ha->msix_count; i++)
2202 entries[i].entry = i;
2203
2204 ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002205 if (ret) {
Lalit Chandivadead038fa2009-01-22 09:45:33 -08002206 if (ret < MIN_MSIX_COUNT)
2207 goto msix_failed;
2208
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002209 qla_printk(KERN_WARNING, ha,
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002210 "MSI-X: Failed to enable support -- %d/%d\n"
2211 " Retry with %d vectors\n", ha->msix_count, ret, ret);
2212 ha->msix_count = ret;
2213 ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
2214 if (ret) {
Lalit Chandivadead038fa2009-01-22 09:45:33 -08002215msix_failed:
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002216 qla_printk(KERN_WARNING, ha, "MSI-X: Failed to enable"
2217 " support, giving up -- %d/%d\n",
2218 ha->msix_count, ret);
2219 goto msix_out;
2220 }
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002221 ha->max_rsp_queues = ha->msix_count - 1;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002222 }
2223 ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
2224 ha->msix_count, GFP_KERNEL);
2225 if (!ha->msix_entries) {
2226 ret = -ENOMEM;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002227 goto msix_out;
2228 }
2229 ha->flags.msix_enabled = 1;
2230
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002231 for (i = 0; i < ha->msix_count; i++) {
2232 qentry = &ha->msix_entries[i];
2233 qentry->vector = entries[i].vector;
2234 qentry->entry = entries[i].entry;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002235 qentry->have_irq = 0;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002236 qentry->rsp = NULL;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002237 }
2238
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002239 /* Enable MSI-X vectors for the base queue */
2240 for (i = 0; i < 2; i++) {
2241 qentry = &ha->msix_entries[i];
2242 ret = request_irq(qentry->vector, msix_entries[i].handler,
2243 0, msix_entries[i].name, rsp);
2244 if (ret) {
2245 qla_printk(KERN_WARNING, ha,
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002246 "MSI-X: Unable to register handler -- %x/%d.\n",
2247 qentry->vector, ret);
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002248 qla24xx_disable_msix(ha);
2249 ha->mqenable = 0;
2250 goto msix_out;
2251 }
2252 qentry->have_irq = 1;
2253 qentry->rsp = rsp;
2254 rsp->msix = qentry;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002255 }
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002256
2257 /* Enable MSI-X vector for response queue update for queue 0 */
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002258 if (ha->mqiobase && (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002259 ha->mqenable = 1;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002260
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002261msix_out:
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002262 kfree(entries);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002263 return ret;
2264}
2265
2266int
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002267qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002268{
2269 int ret;
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002270 device_reg_t __iomem *reg = ha->iobase;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002271
2272 /* If possible, enable MSI-X. */
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08002273 if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
Ben Hutchings6377a7a2010-03-19 16:59:19 -07002274 !IS_QLA8432(ha) && !IS_QLA8001(ha))
2275 goto skip_msi;
2276
2277 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
2278 (ha->pdev->subsystem_device == 0x7040 ||
2279 ha->pdev->subsystem_device == 0x7041 ||
2280 ha->pdev->subsystem_device == 0x1705)) {
2281 DEBUG2(qla_printk(KERN_WARNING, ha,
2282 "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X,0x%X).\n",
2283 ha->pdev->subsystem_vendor,
2284 ha->pdev->subsystem_device));
2285 goto skip_msi;
2286 }
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002287
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002288 if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
2289 !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002290 DEBUG2(qla_printk(KERN_WARNING, ha,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002291 "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
2292 ha->pdev->revision, ha->fw_attributes));
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002293 goto skip_msix;
2294 }
2295
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002296 ret = qla24xx_enable_msix(ha, rsp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002297 if (!ret) {
2298 DEBUG2(qla_printk(KERN_INFO, ha,
2299 "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
2300 ha->fw_attributes));
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002301 goto clear_risc_ints;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002302 }
2303 qla_printk(KERN_WARNING, ha,
2304 "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
2305skip_msix:
Andrew Vasquezcbedb602007-05-07 07:43:02 -07002306
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08002307 if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
2308 !IS_QLA8001(ha))
Andrew Vasquezcbedb602007-05-07 07:43:02 -07002309 goto skip_msi;
2310
2311 ret = pci_enable_msi(ha->pdev);
2312 if (!ret) {
2313 DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
2314 ha->flags.msi_enabled = 1;
2315 }
2316skip_msi:
2317
Andrew Vasquezfd34f552007-07-19 15:06:00 -07002318 ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
Giridhar Malavalid1b1bef2009-03-24 09:08:13 -07002319 IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002320 if (ret) {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002321 qla_printk(KERN_WARNING, ha,
2322 "Failed to reserve interrupt %d already in use.\n",
2323 ha->pdev->irq);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002324 goto fail;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002325 }
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002326 ha->flags.inta_enabled = 1;
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002327clear_risc_ints:
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002328
Andrew Vasquez3a03eb72009-01-05 11:18:11 -08002329 /*
2330 * FIXME: Noted that 8014s were being dropped during NK testing.
2331 * Timing deltas during MSI-X/INTa transitions?
2332 */
2333 if (IS_QLA81XX(ha))
2334 goto fail;
Andrew Vasquezc6952482008-04-03 13:13:17 -07002335 spin_lock_irq(&ha->hardware_lock);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002336 if (IS_FWI2_CAPABLE(ha)) {
2337 WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
2338 WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
2339 } else {
2340 WRT_REG_WORD(&reg->isp.semaphore, 0);
2341 WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
2342 WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_HOST_INT);
2343 }
Andrew Vasquezc6952482008-04-03 13:13:17 -07002344 spin_unlock_irq(&ha->hardware_lock);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08002345
2346fail:
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002347 return ret;
2348}
2349
2350void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002351qla2x00_free_irqs(scsi_qla_host_t *vha)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002352{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002353 struct qla_hw_data *ha = vha->hw;
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002354 struct rsp_que *rsp = ha->rsp_q_map[0];
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002355
2356 if (ha->flags.msix_enabled)
2357 qla24xx_disable_msix(ha);
Joe Carnuccio90a86fc2010-01-12 13:02:46 -08002358 else if (ha->flags.msi_enabled) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002359 free_irq(ha->pdev->irq, rsp);
Andrew Vasquezcbedb602007-05-07 07:43:02 -07002360 pci_disable_msi(ha->pdev);
Joe Carnuccio90a86fc2010-01-12 13:02:46 -08002361 } else
2362 free_irq(ha->pdev->irq, rsp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08002363}
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08002364
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002365
2366int qla25xx_request_irq(struct rsp_que *rsp)
2367{
2368 struct qla_hw_data *ha = rsp->hw;
Anirban Chakraborty2afa19a2009-04-06 22:33:40 -07002369 struct qla_init_msix_entry *intr = &msix_entries[2];
Anirban Chakraborty73208df2008-12-09 16:45:39 -08002370 struct qla_msix_entry *msix = rsp->msix;
2371 int ret;
2372
2373 ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp);
2374 if (ret) {
2375 qla_printk(KERN_WARNING, ha,
2376 "MSI-X: Unable to register handler -- %x/%d.\n",
2377 msix->vector, ret);
2378 return ret;
2379 }
2380 msix->have_irq = 1;
2381 msix->rsp = rsp;
2382 return ret;
2383}