blob: 89d327117aa8fc7946542c5337933d8c8a65ddd0 [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>
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -070013static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
Andrew Vasquez9a853f72005-07-06 10:31:27 -070014static void qla2x00_status_entry(scsi_qla_host_t *, void *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070015static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
16static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080017static struct scsi_qla_host *qla2x00_get_rsp_host(struct rsp_que *);
Andrew Vasquez9a853f72005-07-06 10:31:27 -070018
Linus Torvalds1da177e2005-04-16 15:20:36 -070019/**
20 * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
21 * @irq:
22 * @dev_id: SCSI driver HA context
Linus Torvalds1da177e2005-04-16 15:20:36 -070023 *
24 * Called by system whenever the host adapter generates an interrupt.
25 *
26 * Returns handled flag.
27 */
28irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +010029qla2100_intr_handler(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070030{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080031 scsi_qla_host_t *vha;
32 struct qla_hw_data *ha;
Andrew Vasquez3d716442005-07-06 10:30:26 -070033 struct device_reg_2xxx __iomem *reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -070034 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -070035 unsigned long iter;
Seokmann Ju14e660e2007-09-20 14:07:36 -070036 uint16_t hccr;
Andrew Vasquez9a853f72005-07-06 10:31:27 -070037 uint16_t mb[4];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080038 struct rsp_que *rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080040 rsp = (struct rsp_que *) dev_id;
41 if (!rsp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080043 "%s(): NULL response queue pointer\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 return (IRQ_NONE);
45 }
46
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080047 ha = rsp->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -070048 reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 status = 0;
50
Andrew Vasquezc6952482008-04-03 13:13:17 -070051 spin_lock(&ha->hardware_lock);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080052 vha = qla2x00_get_rsp_host(rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 for (iter = 50; iter--; ) {
Seokmann Ju14e660e2007-09-20 14:07:36 -070054 hccr = RD_REG_WORD(&reg->hccr);
55 if (hccr & HCCR_RISC_PAUSE) {
56 if (pci_channel_offline(ha->pdev))
57 break;
58
59 /*
60 * Issue a "HARD" reset in order for the RISC interrupt
61 * bit to be cleared. Schedule a big hammmer to get
62 * out of the RISC PAUSED state.
63 */
64 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
65 RD_REG_WORD(&reg->hccr);
66
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080067 ha->isp_ops->fw_dump(vha, 1);
68 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Seokmann Ju14e660e2007-09-20 14:07:36 -070069 break;
70 } else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 break;
72
73 if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
74 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
75 RD_REG_WORD(&reg->hccr);
76
77 /* Get mailbox data. */
Andrew Vasquez9a853f72005-07-06 10:31:27 -070078 mb[0] = RD_MAILBOX_REG(ha, reg, 0);
79 if (mb[0] > 0x3fff && mb[0] < 0x8000) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080080 qla2x00_mbx_completion(vha, mb[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 status |= MBX_INTERRUPT;
Andrew Vasquez9a853f72005-07-06 10:31:27 -070082 } else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
83 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
84 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
85 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080086 qla2x00_async_event(vha, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 } else {
88 /*EMPTY*/
89 DEBUG2(printk("scsi(%ld): Unrecognized "
Andrew Vasquez9a853f72005-07-06 10:31:27 -070090 "interrupt type (%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080091 vha->host_no, mb[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 }
93 /* Release mailbox registers. */
94 WRT_REG_WORD(&reg->semaphore, 0);
95 RD_REG_WORD(&reg->semaphore);
96 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -080097 qla2x00_process_response_queue(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
99 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
100 RD_REG_WORD(&reg->hccr);
101 }
102 }
Andrew Vasquezc6952482008-04-03 13:13:17 -0700103 spin_unlock(&ha->hardware_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
106 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -0800108 complete(&ha->mbx_intr_comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 }
110
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 return (IRQ_HANDLED);
112}
113
114/**
115 * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
116 * @irq:
117 * @dev_id: SCSI driver HA context
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 *
119 * Called by system whenever the host adapter generates an interrupt.
120 *
121 * Returns handled flag.
122 */
123irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +0100124qla2300_intr_handler(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800126 scsi_qla_host_t *vha;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700127 struct device_reg_2xxx __iomem *reg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 unsigned long iter;
130 uint32_t stat;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131 uint16_t hccr;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700132 uint16_t mb[4];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800133 struct rsp_que *rsp;
134 struct qla_hw_data *ha;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800136 rsp = (struct rsp_que *) dev_id;
137 if (!rsp) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800139 "%s(): NULL response queue pointer\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 return (IRQ_NONE);
141 }
142
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800143 ha = rsp->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700144 reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145 status = 0;
146
Andrew Vasquezc6952482008-04-03 13:13:17 -0700147 spin_lock(&ha->hardware_lock);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800148 vha = qla2x00_get_rsp_host(rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 for (iter = 50; iter--; ) {
150 stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
151 if (stat & HSR_RISC_PAUSED) {
Seokmann Ju14e660e2007-09-20 14:07:36 -0700152 if (pci_channel_offline(ha->pdev))
153 break;
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 hccr = RD_REG_WORD(&reg->hccr);
156 if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
Andrew Vasquez07f31802006-12-13 19:20:31 -0800157 qla_printk(KERN_INFO, ha, "Parity error -- "
158 "HCCR=%x, Dumping firmware!\n", hccr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 else
Andrew Vasquez07f31802006-12-13 19:20:31 -0800160 qla_printk(KERN_INFO, ha, "RISC paused -- "
161 "HCCR=%x, Dumping firmware!\n", hccr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
163 /*
164 * Issue a "HARD" reset in order for the RISC
165 * interrupt bit to be cleared. Schedule a big
166 * hammmer to get out of the RISC PAUSED state.
167 */
168 WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
169 RD_REG_WORD(&reg->hccr);
Andrew Vasquez07f31802006-12-13 19:20:31 -0800170
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800171 ha->isp_ops->fw_dump(vha, 1);
172 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 break;
174 } else if ((stat & HSR_RISC_INT) == 0)
175 break;
176
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 switch (stat & 0xff) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 case 0x1:
179 case 0x2:
180 case 0x10:
181 case 0x11:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800182 qla2x00_mbx_completion(vha, MSW(stat));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 status |= MBX_INTERRUPT;
184
185 /* Release mailbox registers. */
186 WRT_REG_WORD(&reg->semaphore, 0);
187 break;
188 case 0x12:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700189 mb[0] = MSW(stat);
190 mb[1] = RD_MAILBOX_REG(ha, reg, 1);
191 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
192 mb[3] = RD_MAILBOX_REG(ha, reg, 3);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800193 qla2x00_async_event(vha, mb);
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700194 break;
195 case 0x13:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800196 qla2x00_process_response_queue(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 break;
198 case 0x15:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700199 mb[0] = MBA_CMPLT_1_16BIT;
200 mb[1] = MSW(stat);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800201 qla2x00_async_event(vha, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 break;
203 case 0x16:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700204 mb[0] = MBA_SCSI_COMPLETION;
205 mb[1] = MSW(stat);
206 mb[2] = RD_MAILBOX_REG(ha, reg, 2);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800207 qla2x00_async_event(vha, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 break;
209 default:
210 DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700211 "(%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800212 vha->host_no, stat & 0xff));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 break;
214 }
215 WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
216 RD_REG_WORD_RELAXED(&reg->hccr);
217 }
Andrew Vasquezc6952482008-04-03 13:13:17 -0700218 spin_unlock(&ha->hardware_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
221 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -0800223 complete(&ha->mbx_intr_comp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 }
225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 return (IRQ_HANDLED);
227}
228
229/**
230 * qla2x00_mbx_completion() - Process mailbox command completions.
231 * @ha: SCSI driver HA context
232 * @mb0: Mailbox0 register
233 */
234static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800235qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236{
237 uint16_t cnt;
238 uint16_t __iomem *wptr;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800239 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700240 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241
242 /* Load return mailbox registers. */
243 ha->flags.mbox_int = 1;
244 ha->mailbox_out[0] = mb0;
245 wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);
246
247 for (cnt = 1; cnt < ha->mbx_count; cnt++) {
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700248 if (IS_QLA2200(ha) && cnt == 8)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
250 if (cnt == 4 || cnt == 5)
251 ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
252 else
253 ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -0700254
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 wptr++;
256 }
257
258 if (ha->mcp) {
259 DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800260 __func__, vha->host_no, ha->mcp->mb[0]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 } else {
262 DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800263 __func__, vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 }
265}
266
267/**
268 * qla2x00_async_event() - Process aynchronous events.
269 * @ha: SCSI driver HA context
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700270 * @mb: Mailbox registers (0 - 3)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 */
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700272void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800273qla2x00_async_event(scsi_qla_host_t *vha, uint16_t *mb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274{
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700275#define LS_UNKNOWN 2
Andrew Vasquezc3a2f0d2007-07-19 20:37:34 -0700276 static char *link_speeds[5] = { "1", "2", "?", "4", "8" };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 char *link_speed;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 uint16_t handle_cnt;
279 uint16_t cnt;
280 uint32_t handles[5];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800281 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700282 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 uint32_t rscn_entry, host_pid;
284 uint8_t rscn_queue_index;
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700285 unsigned long flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
287 /* Setup to process RIO completion. */
288 handle_cnt = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 switch (mb[0]) {
290 case MBA_SCSI_COMPLETION:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700291 handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292 handle_cnt = 1;
293 break;
294 case MBA_CMPLT_1_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700295 handles[0] = mb[1];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 handle_cnt = 1;
297 mb[0] = MBA_SCSI_COMPLETION;
298 break;
299 case MBA_CMPLT_2_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700300 handles[0] = mb[1];
301 handles[1] = mb[2];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 handle_cnt = 2;
303 mb[0] = MBA_SCSI_COMPLETION;
304 break;
305 case MBA_CMPLT_3_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700306 handles[0] = mb[1];
307 handles[1] = mb[2];
308 handles[2] = mb[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 handle_cnt = 3;
310 mb[0] = MBA_SCSI_COMPLETION;
311 break;
312 case MBA_CMPLT_4_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700313 handles[0] = mb[1];
314 handles[1] = mb[2];
315 handles[2] = mb[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
317 handle_cnt = 4;
318 mb[0] = MBA_SCSI_COMPLETION;
319 break;
320 case MBA_CMPLT_5_16BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700321 handles[0] = mb[1];
322 handles[1] = mb[2];
323 handles[2] = mb[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
325 handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
326 handle_cnt = 5;
327 mb[0] = MBA_SCSI_COMPLETION;
328 break;
329 case MBA_CMPLT_2_32BIT:
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700330 handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331 handles[1] = le32_to_cpu(
332 ((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) |
333 RD_MAILBOX_REG(ha, reg, 6));
334 handle_cnt = 2;
335 mb[0] = MBA_SCSI_COMPLETION;
336 break;
337 default:
338 break;
339 }
340
341 switch (mb[0]) {
342 case MBA_SCSI_COMPLETION: /* Fast Post */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800343 if (!vha->flags.online)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 break;
345
346 for (cnt = 0; cnt < handle_cnt; cnt++)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800347 qla2x00_process_completed_request(vha, handles[cnt]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 break;
349
350 case MBA_RESET: /* Reset */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800351 DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n",
352 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800354 set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 break;
356
357 case MBA_SYSTEM_ERR: /* System Error */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 qla_printk(KERN_INFO, ha,
359 "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
360 mb[1], mb[2], mb[3]);
361
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800362 qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]);
363 ha->isp_ops->fw_dump(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
Andrew Vasqueze4289242007-07-19 15:05:56 -0700365 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700366 if (mb[1] == 0 && mb[2] == 0) {
367 qla_printk(KERN_ERR, ha,
368 "Unrecoverable Hardware Error: adapter "
369 "marked OFFLINE!\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800370 vha->flags.online = 0;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700371 } else
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800372 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700373 } else if (mb[1] == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 qla_printk(KERN_INFO, ha,
375 "Unrecoverable Hardware Error: adapter marked "
376 "OFFLINE!\n");
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800377 vha->flags.online = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378 } else
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800379 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 break;
381
382 case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */
383 DEBUG2(printk("scsi(%ld): ISP Request Transfer Error.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800384 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");
386
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800387 qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]);
388 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 break;
390
391 case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */
392 DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800393 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
395
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800396 qla2x00_post_hwe_work(vha, mb[0], mb[1], mb[2], mb[3]);
397 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 break;
399
400 case MBA_WAKEUP_THRES: /* Request Queue Wake-up */
401 DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800402 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 break;
404
405 case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800406 DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", vha->host_no,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 mb[1]));
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -0700408 qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800410 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
411 atomic_set(&vha->loop_state, LOOP_DOWN);
412 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
413 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 }
415
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800416 if (vha->vp_idx) {
417 atomic_set(&vha->vp_state, VP_FAILED);
418 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700419 }
420
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800421 set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
422 set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800424 vha->flags.management_server_logged_in = 0;
425 qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 break;
427
428 case MBA_LOOP_UP: /* Loop Up Event */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
430 link_speed = link_speeds[0];
Andrew Vasquezd8b45212006-10-02 12:00:43 -0700431 ha->link_data_rate = PORT_SPEED_1GB;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 } else {
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700433 link_speed = link_speeds[LS_UNKNOWN];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434 if (mb[1] < 5)
435 link_speed = link_speeds[mb[1]];
436 ha->link_data_rate = mb[1];
437 }
438
439 DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800440 vha->host_no, link_speed));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441 qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
442 link_speed);
443
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800444 vha->flags.management_server_logged_in = 0;
445 qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446 break;
447
448 case MBA_LOOP_DOWN: /* Loop Down Event */
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700449 DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800450 "(%x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3]));
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700451 qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n",
452 mb[1], mb[2], mb[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800454 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
455 atomic_set(&vha->loop_state, LOOP_DOWN);
456 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
457 vha->device_flags |= DFLG_NO_CABLE;
458 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 }
460
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800461 if (vha->vp_idx) {
462 atomic_set(&vha->vp_state, VP_FAILED);
463 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700464 }
465
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800466 vha->flags.management_server_logged_in = 0;
Andrew Vasquezd8b45212006-10-02 12:00:43 -0700467 ha->link_data_rate = PORT_SPEED_UNKNOWN;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800468 qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 break;
470
471 case MBA_LIP_RESET: /* LIP reset occurred */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800473 vha->host_no, mb[1]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474 qla_printk(KERN_INFO, ha,
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -0700475 "LIP reset occurred (%x).\n", mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800477 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
478 atomic_set(&vha->loop_state, LOOP_DOWN);
479 atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
480 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
482
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800483 if (vha->vp_idx) {
484 atomic_set(&vha->vp_state, VP_FAILED);
485 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700486 }
487
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800488 set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
490 ha->operating_mode = LOOP;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800491 vha->flags.management_server_logged_in = 0;
492 qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 break;
494
495 case MBA_POINT_TO_POINT: /* Point-to-Point */
496 if (IS_QLA2100(ha))
497 break;
498
499 DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE received.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800500 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 /*
503 * Until there's a transition from loop down to loop up, treat
504 * this as loop down only.
505 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800506 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
507 atomic_set(&vha->loop_state, LOOP_DOWN);
508 if (!atomic_read(&vha->loop_down_timer))
509 atomic_set(&vha->loop_down_timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 LOOP_DOWN_TIME);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800511 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 }
513
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800514 if (vha->vp_idx) {
515 atomic_set(&vha->vp_state, VP_FAILED);
516 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700517 }
518
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800519 if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
520 set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
521
522 set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
523 set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
Andrew Vasquez4346b142006-12-13 19:20:28 -0800524
525 ha->flags.gpsc_supported = 1;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800526 vha->flags.management_server_logged_in = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 break;
528
529 case MBA_CHG_IN_CONNECTION: /* Change in connection mode */
530 if (IS_QLA2100(ha))
531 break;
532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection "
534 "received.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800535 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 qla_printk(KERN_INFO, ha,
537 "Configuration change detected: value=%x.\n", mb[1]);
538
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800539 if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
540 atomic_set(&vha->loop_state, LOOP_DOWN);
541 if (!atomic_read(&vha->loop_down_timer))
542 atomic_set(&vha->loop_down_timer,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 LOOP_DOWN_TIME);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800544 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
546
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800547 if (vha->vp_idx) {
548 atomic_set(&vha->vp_state, VP_FAILED);
549 fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700550 }
551
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800552 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
553 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 break;
555
556 case MBA_PORT_UPDATE: /* Port database update */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 /*
Bjorn Helgaascc3ef7b2008-09-11 21:22:51 -0700558 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 * event etc. earlier indicating loop is down) then process
560 * it. Otherwise ignore it and Wait for RSCN to come in.
561 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800562 atomic_set(&vha->loop_down_timer, 0);
563 if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
564 atomic_read(&vha->loop_state) != LOOP_DEAD) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800566 "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700567 mb[2], mb[3]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 break;
569 }
570
571 DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800572 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 DEBUG(printk(KERN_INFO
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700574 "scsi(%ld): Port database changed %04x %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800575 vha->host_no, mb[1], mb[2], mb[3]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577 /*
578 * Mark all devices as missing so we will login again.
579 */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800580 atomic_set(&vha->loop_state, LOOP_UP);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800582 qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800584 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800586 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
587 set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 break;
589
590 case MBA_RSCN_UPDATE: /* State Change Registration */
Seokmann Ju3c397402008-05-19 14:25:39 -0700591 /* Check if the Vport has issued a SCR */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800592 if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
Seokmann Ju3c397402008-05-19 14:25:39 -0700593 break;
594 /* Only handle SCNs for our Vport index. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800595 if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff))
Seokmann Ju3c397402008-05-19 14:25:39 -0700596 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800598 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 DEBUG(printk(KERN_INFO
Shyam Sundarf4a8dbc2007-11-12 10:30:59 -0800600 "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800601 vha->host_no, mb[1], mb[2], mb[3]));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
Ravi Anand59d72d82008-09-11 21:22:53 -0700603 rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800604 host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
605 | vha->d_id.b.al_pa;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (rscn_entry == host_pid) {
607 DEBUG(printk(KERN_INFO
608 "scsi(%ld): Ignoring RSCN update to local host "
609 "port ID (%06x)\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800610 vha->host_no, host_pid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 break;
612 }
613
Ravi Anand59d72d82008-09-11 21:22:53 -0700614 /* Ignore reserved bits from RSCN-payload. */
615 rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800616 rscn_queue_index = vha->rscn_in_ptr + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 if (rscn_queue_index == MAX_RSCN_COUNT)
618 rscn_queue_index = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800619 if (rscn_queue_index != vha->rscn_out_ptr) {
620 vha->rscn_queue[vha->rscn_in_ptr] = rscn_entry;
621 vha->rscn_in_ptr = rscn_queue_index;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800623 vha->flags.rscn_queue_overflow = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624 }
625
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800626 atomic_set(&vha->loop_state, LOOP_UPDATE);
627 atomic_set(&vha->loop_down_timer, 0);
628 vha->flags.management_server_logged_in = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800630 set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
631 set_bit(RSCN_UPDATE, &vha->dpc_flags);
632 qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633 break;
634
635 /* case MBA_RIO_RESPONSE: */
636 case MBA_ZIO_RESPONSE:
637 DEBUG2(printk("scsi(%ld): [R|Z]IO update completion.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800638 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 DEBUG(printk(KERN_INFO
640 "scsi(%ld): [R|Z]IO update completion.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800641 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642
Andrew Vasqueze4289242007-07-19 15:05:56 -0700643 if (IS_FWI2_CAPABLE(ha))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800644 qla24xx_process_response_queue(vha);
Andrew Vasquez4fdfefe2005-10-27 11:09:48 -0700645 else
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800646 qla2x00_process_response_queue(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 break;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700648
649 case MBA_DISCARD_RND_FRAME:
650 DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800651 "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700652 break;
Andrew Vasquez45ebeb52006-08-01 13:48:14 -0700653
654 case MBA_TRACE_NOTIFICATION:
655 DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800656 vha->host_no, mb[1], mb[2]));
Andrew Vasquez45ebeb52006-08-01 13:48:14 -0700657 break;
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700658
659 case MBA_ISP84XX_ALERT:
660 DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800661 "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
Harihara Kadayam4d4df192008-04-03 13:13:26 -0700662
663 spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
664 switch (mb[1]) {
665 case A84_PANIC_RECOVERY:
666 qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery "
667 "%04x %04x\n", mb[2], mb[3]);
668 break;
669 case A84_OP_LOGIN_COMPLETE:
670 ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
671 DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
672 "firmware version %x\n", ha->cs84xx->op_fw_version));
673 break;
674 case A84_DIAG_LOGIN_COMPLETE:
675 ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
676 DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
677 "diagnostic firmware version %x\n",
678 ha->cs84xx->diag_fw_version));
679 break;
680 case A84_GOLD_LOGIN_COMPLETE:
681 ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
682 ha->cs84xx->fw_update = 1;
683 DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold "
684 "firmware version %x\n",
685 ha->cs84xx->gold_fw_version));
686 break;
687 default:
688 qla_printk(KERN_ERR, ha,
689 "Alert 84xx: Invalid Alert %04x %04x %04x\n",
690 mb[1], mb[2], mb[3]);
691 }
692 spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
693 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700695
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800696 if (!vha->vp_idx && ha->num_vhosts)
Seokmann Ju2c3dfe32007-07-05 13:16:51 -0700697 qla2x00_alert_all_vps(ha, mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698}
699
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700700static void
701qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
702{
703 fc_port_t *fcport = data;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800704 struct qla_hw_data *ha = fcport->vha->hw;
705 if (ha->req->max_q_depth <= sdev->queue_depth)
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700706 return;
707
708 if (sdev->ordered_tags)
709 scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
710 sdev->queue_depth + 1);
711 else
712 scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
713 sdev->queue_depth + 1);
714
715 fcport->last_ramp_up = jiffies;
716
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800717 DEBUG2(qla_printk(KERN_INFO, ha,
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700718 "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800719 fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700720 sdev->queue_depth));
721}
722
723static void
724qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
725{
726 fc_port_t *fcport = data;
727
728 if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
729 return;
730
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800731 DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700732 "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800733 fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700734 sdev->queue_depth));
735}
736
737static inline void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800738qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, srb_t *sp)
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700739{
740 fc_port_t *fcport;
741 struct scsi_device *sdev;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800742 struct qla_hw_data *ha = vha->hw;
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700743
744 sdev = sp->cmd->device;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800745 if (sdev->queue_depth >= ha->req->max_q_depth)
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700746 return;
747
748 fcport = sp->fcport;
749 if (time_before(jiffies,
750 fcport->last_ramp_up + ql2xqfullrampup * HZ))
751 return;
752 if (time_before(jiffies,
753 fcport->last_queue_full + ql2xqfullrampup * HZ))
754 return;
755
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700756 starget_for_each_device(sdev->sdev_target, fcport,
757 qla2x00_adjust_sdev_qdepth_up);
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700758}
759
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760/**
761 * qla2x00_process_completed_request() - Process a Fast Post response.
762 * @ha: SCSI driver HA context
763 * @index: SRB index
764 */
765static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800766qla2x00_process_completed_request(struct scsi_qla_host *vha, uint32_t index)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767{
768 srb_t *sp;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800769 struct qla_hw_data *ha = vha->hw;
770 struct req_que *req = ha->req;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 /* Validate handle. */
773 if (index >= MAX_OUTSTANDING_COMMANDS) {
774 DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800775 vha->host_no, index));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700776 qla_printk(KERN_WARNING, ha,
777 "Invalid SCSI completion handle %d.\n", index);
778
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800779 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return;
781 }
782
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800783 sp = req->outstanding_cmds[index];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 if (sp) {
785 /* Free outstanding command slot. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800786 req->outstanding_cmds[index] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788 CMD_COMPL_STATUS(sp->cmd) = 0L;
789 CMD_SCSI_STATUS(sp->cmd) = 0L;
790
791 /* Save ISP completion status */
792 sp->cmd->result = DID_OK << 16;
Andrew Vasquezdf7baa52006-10-13 09:33:39 -0700793
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800794 qla2x00_ramp_up_queue_depth(vha, sp);
795 qla2x00_sp_compl(vha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 } else {
797 DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800798 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 qla_printk(KERN_WARNING, ha,
800 "Invalid ISP SCSI completion handle\n");
801
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800802 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 }
804}
805
806/**
807 * qla2x00_process_response_queue() - Process response queue entries.
808 * @ha: SCSI driver HA context
809 */
810void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800811qla2x00_process_response_queue(struct scsi_qla_host *vha)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800813 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez3d716442005-07-06 10:30:26 -0700814 struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815 sts_entry_t *pkt;
816 uint16_t handle_cnt;
817 uint16_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800818 struct rsp_que *rsp = ha->rsp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800820 if (!vha->flags.online)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 return;
822
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800823 while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
824 pkt = (sts_entry_t *)rsp->ring_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800826 rsp->ring_index++;
827 if (rsp->ring_index == rsp->length) {
828 rsp->ring_index = 0;
829 rsp->ring_ptr = rsp->ring;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800831 rsp->ring_ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 }
833
834 if (pkt->entry_status != 0) {
835 DEBUG3(printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800836 "scsi(%ld): Process error entry.\n", vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800838 qla2x00_error_entry(vha, pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
840 wmb();
841 continue;
842 }
843
844 switch (pkt->entry_type) {
845 case STATUS_TYPE:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800846 qla2x00_status_entry(vha, pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 break;
848 case STATUS_TYPE_21:
849 handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
850 for (cnt = 0; cnt < handle_cnt; cnt++) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800851 qla2x00_process_completed_request(vha,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 ((sts21_entry_t *)pkt)->handle[cnt]);
853 }
854 break;
855 case STATUS_TYPE_22:
856 handle_cnt = ((sts22_entry_t *)pkt)->handle_count;
857 for (cnt = 0; cnt < handle_cnt; cnt++) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800858 qla2x00_process_completed_request(vha,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859 ((sts22_entry_t *)pkt)->handle[cnt]);
860 }
861 break;
862 case STATUS_CONT_TYPE:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800863 qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 default:
866 /* Type Not Supported. */
867 DEBUG4(printk(KERN_WARNING
868 "scsi(%ld): Received unknown response pkt type %x "
869 "entry status=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800870 vha->host_no, pkt->entry_type, pkt->entry_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 break;
872 }
873 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
874 wmb();
875 }
876
877 /* Adjust ring index */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800878 WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879}
880
Andrew Vasquez4733fcb2008-01-17 09:02:07 -0800881static inline void
882qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
883{
884 struct scsi_cmnd *cp = sp->cmd;
885
886 if (sense_len >= SCSI_SENSE_BUFFERSIZE)
887 sense_len = SCSI_SENSE_BUFFERSIZE;
888
889 CMD_ACTUAL_SNSLEN(cp) = sense_len;
890 sp->request_sense_length = sense_len;
891 sp->request_sense_ptr = cp->sense_buffer;
892 if (sp->request_sense_length > 32)
893 sense_len = 32;
894
895 memcpy(cp->sense_buffer, sense_data, sense_len);
896
897 sp->request_sense_ptr += sense_len;
898 sp->request_sense_length -= sense_len;
899 if (sp->request_sense_length != 0)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800900 sp->fcport->vha->status_srb = sp;
Andrew Vasquez4733fcb2008-01-17 09:02:07 -0800901
902 DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800903 "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
Andrew Vasquez19851f12008-08-13 21:37:00 -0700904 cp->device->channel, cp->device->id, cp->device->lun, cp,
905 cp->serial_number));
Andrew Vasquez4733fcb2008-01-17 09:02:07 -0800906 if (sense_len)
907 DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
908 CMD_ACTUAL_SNSLEN(cp)));
909}
910
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911/**
912 * qla2x00_status_entry() - Process a Status IOCB entry.
913 * @ha: SCSI driver HA context
914 * @pkt: Entry pointer
915 */
916static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800917qla2x00_status_entry(scsi_qla_host_t *vha, void *pkt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 srb_t *sp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 fc_port_t *fcport;
921 struct scsi_cmnd *cp;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700922 sts_entry_t *sts;
923 struct sts_entry_24xx *sts24;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924 uint16_t comp_status;
925 uint16_t scsi_status;
926 uint8_t lscsi_status;
927 int32_t resid;
Ravi Ananded17c712006-05-17 15:08:55 -0700928 uint32_t sense_len, rsp_info_len, resid_len, fw_resid_len;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700929 uint8_t *rsp_info, *sense_data;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800930 struct qla_hw_data *ha = vha->hw;
931 struct req_que *req = ha->req;
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700932
933 sts = (sts_entry_t *) pkt;
934 sts24 = (struct sts_entry_24xx *) pkt;
Andrew Vasqueze4289242007-07-19 15:05:56 -0700935 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700936 comp_status = le16_to_cpu(sts24->comp_status);
937 scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
938 } else {
939 comp_status = le16_to_cpu(sts->comp_status);
940 scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
941 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942
943 /* Fast path completion. */
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700944 if (comp_status == CS_COMPLETE && scsi_status == 0) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800945 qla2x00_process_completed_request(vha, sts->handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700946
947 return;
948 }
949
950 /* Validate handle. */
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700951 if (sts->handle < MAX_OUTSTANDING_COMMANDS) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800952 sp = req->outstanding_cmds[sts->handle];
953 req->outstanding_cmds[sts->handle] = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 } else
955 sp = NULL;
956
957 if (sp == NULL) {
958 DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800959 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n");
961
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800962 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
963 qla2xxx_wake_dpc(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return;
965 }
966 cp = sp->cmd;
967 if (cp == NULL) {
968 DEBUG2(printk("scsi(%ld): Command already returned back to OS "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -0800969 "pkt->handle=%d sp=%p.\n", vha->host_no, sts->handle, sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 qla_printk(KERN_WARNING, ha,
971 "Command is NULL: already returned to OS (sp=%p)\n", sp);
972
973 return;
974 }
975
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700976 lscsi_status = scsi_status & STATUS_MASK;
977 CMD_ENTRY_STATUS(cp) = sts->entry_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 CMD_COMPL_STATUS(cp) = comp_status;
979 CMD_SCSI_STATUS(cp) = scsi_status;
980
bdf79622005-04-17 15:06:53 -0500981 fcport = sp->fcport;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Ravi Ananded17c712006-05-17 15:08:55 -0700983 sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
Andrew Vasqueze4289242007-07-19 15:05:56 -0700984 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700985 sense_len = le32_to_cpu(sts24->sense_len);
986 rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
987 resid_len = le32_to_cpu(sts24->rsp_residual_count);
Ravi Ananded17c712006-05-17 15:08:55 -0700988 fw_resid_len = le32_to_cpu(sts24->residual_len);
Andrew Vasquez9a853f72005-07-06 10:31:27 -0700989 rsp_info = sts24->data;
990 sense_data = sts24->data;
991 host_to_fcp_swap(sts24->data, sizeof(sts24->data));
992 } else {
993 sense_len = le16_to_cpu(sts->req_sense_length);
994 rsp_info_len = le16_to_cpu(sts->rsp_info_len);
995 resid_len = le32_to_cpu(sts->residual_length);
996 rsp_info = sts->rsp_info;
997 sense_data = sts->req_sense_data;
998 }
999
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 /* Check for any FCP transport errors. */
1001 if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001002 /* Sense data lies beyond any FCP RESPONSE data. */
Andrew Vasqueze4289242007-07-19 15:05:56 -07001003 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001004 sense_data += rsp_info_len;
1005 if (rsp_info_len > 3 && rsp_info[3]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
1007 "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001008 "retrying command\n", vha->host_no,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001009 cp->device->channel, cp->device->id,
1010 cp->device->lun, rsp_info_len, rsp_info[0],
1011 rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4],
1012 rsp_info[5], rsp_info[6], rsp_info[7]));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
1014 cp->result = DID_BUS_BUSY << 16;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001015 qla2x00_sp_compl(vha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016 return;
1017 }
1018 }
1019
Andrew Vasquez3e8ce322008-02-28 14:06:10 -08001020 /* Check for overrun. */
1021 if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
1022 scsi_status & SS_RESIDUAL_OVER)
1023 comp_status = CS_DATA_OVERRUN;
1024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 /*
1026 * Based on Host and scsi status generate status code for Linux
1027 */
1028 switch (comp_status) {
1029 case CS_COMPLETE:
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001030 case CS_QUEUE_FULL:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (scsi_status == 0) {
1032 cp->result = DID_OK << 16;
1033 break;
1034 }
1035 if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001036 resid = resid_len;
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001037 scsi_set_resid(cp, resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 CMD_RESID_LEN(cp) = resid;
Andrew Vasquez0da69df2005-12-06 10:58:06 -08001039
1040 if (!lscsi_status &&
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001041 ((unsigned)(scsi_bufflen(cp) - resid) <
Andrew Vasquez0da69df2005-12-06 10:58:06 -08001042 cp->underflow)) {
1043 qla_printk(KERN_INFO, ha,
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001044 "scsi(%ld:%d:%d:%d): Mid-layer underflow "
1045 "detected (%x of %x bytes)...returning "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001046 "error status.\n", vha->host_no,
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001047 cp->device->channel, cp->device->id,
1048 cp->device->lun, resid,
1049 scsi_bufflen(cp));
Andrew Vasquez0da69df2005-12-06 10:58:06 -08001050
1051 cp->result = DID_ERROR << 16;
1052 break;
1053 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 cp->result = DID_OK << 16 | lscsi_status;
1056
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001057 if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
1058 DEBUG2(printk(KERN_INFO
1059 "scsi(%ld): QUEUE FULL status detected "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001060 "0x%x-0x%x.\n", vha->host_no, comp_status,
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001061 scsi_status));
1062
1063 /* Adjust queue depth for all luns on the port. */
1064 fcport->last_queue_full = jiffies;
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001065 starget_for_each_device(cp->device->sdev_target,
1066 fcport, qla2x00_adjust_sdev_qdepth_down);
Andrew Vasquezdf7baa52006-10-13 09:33:39 -07001067 break;
1068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 if (lscsi_status != SS_CHECK_CONDITION)
1070 break;
1071
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +09001072 memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 if (!(scsi_status & SS_SENSE_LEN_VALID))
1074 break;
1075
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001076 qla2x00_handle_sense(sp, sense_data, sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 break;
1078
1079 case CS_DATA_UNDERRUN:
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001080 resid = resid_len;
Ravi Ananded17c712006-05-17 15:08:55 -07001081 /* Use F/W calculated residual length. */
Andrew Vasquez6acf8192007-10-19 15:59:18 -07001082 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez2d136932008-09-11 21:22:52 -07001083 if (!(scsi_status & SS_RESIDUAL_UNDER)) {
1084 lscsi_status = 0;
1085 } else if (resid != fw_resid_len) {
Andrew Vasquez6acf8192007-10-19 15:59:18 -07001086 scsi_status &= ~SS_RESIDUAL_UNDER;
1087 lscsi_status = 0;
1088 }
Ravi Ananded17c712006-05-17 15:08:55 -07001089 resid = fw_resid_len;
Andrew Vasquez6acf8192007-10-19 15:59:18 -07001090 }
Ravi Ananded17c712006-05-17 15:08:55 -07001091
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 if (scsi_status & SS_RESIDUAL_UNDER) {
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001093 scsi_set_resid(cp, resid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 CMD_RESID_LEN(cp) = resid;
andrew.vasquez@qlogic.come038a1b2006-01-13 17:04:59 -08001095 } else {
1096 DEBUG2(printk(KERN_INFO
1097 "scsi(%ld:%d:%d) UNDERRUN status detected "
Ravi Ananded17c712006-05-17 15:08:55 -07001098 "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001099 "os_underflow=0x%x\n", vha->host_no,
Ravi Ananded17c712006-05-17 15:08:55 -07001100 cp->device->id, cp->device->lun, comp_status,
1101 scsi_status, resid_len, resid, cp->cmnd[0],
1102 cp->underflow));
andrew.vasquez@qlogic.come038a1b2006-01-13 17:04:59 -08001103
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
1105
1106 /*
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001107 * Check to see if SCSI Status is non zero. If so report SCSI
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 * Status.
1109 */
1110 if (lscsi_status != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 cp->result = DID_OK << 16 | lscsi_status;
1112
Andrew Vasquezffec28a2007-01-29 10:22:27 -08001113 if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
1114 DEBUG2(printk(KERN_INFO
1115 "scsi(%ld): QUEUE FULL status detected "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001116 "0x%x-0x%x.\n", vha->host_no, comp_status,
Andrew Vasquezffec28a2007-01-29 10:22:27 -08001117 scsi_status));
1118
1119 /*
1120 * Adjust queue depth for all luns on the
1121 * port.
1122 */
1123 fcport->last_queue_full = jiffies;
1124 starget_for_each_device(
1125 cp->device->sdev_target, fcport,
1126 qla2x00_adjust_sdev_qdepth_down);
1127 break;
1128 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (lscsi_status != SS_CHECK_CONDITION)
1130 break;
1131
FUJITA Tomonorib80ca4f2008-01-13 15:46:13 +09001132 memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 if (!(scsi_status & SS_SENSE_LEN_VALID))
1134 break;
1135
Andrew Vasquez4733fcb2008-01-17 09:02:07 -08001136 qla2x00_handle_sense(sp, sense_data, sense_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 } else {
1138 /*
1139 * If RISC reports underrun and target does not report
1140 * it then we must have a lost frame, so tell upper
1141 * layer to retry it by reporting a bus busy.
1142 */
1143 if (!(scsi_status & SS_RESIDUAL_UNDER)) {
1144 DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001145 "frame(s) detected (%x of %x bytes)..."
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001146 "retrying command.\n",
1147 vha->host_no, cp->device->channel,
1148 cp->device->id, cp->device->lun, resid,
1149 scsi_bufflen(cp)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
1151 cp->result = DID_BUS_BUSY << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 break;
1153 }
1154
1155 /* Handle mid-layer underflow */
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001156 if ((unsigned)(scsi_bufflen(cp) - resid) <
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 cp->underflow) {
1158 qla_printk(KERN_INFO, ha,
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001159 "scsi(%ld:%d:%d:%d): Mid-layer underflow "
1160 "detected (%x of %x bytes)...returning "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001161 "error status.\n", vha->host_no,
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001162 cp->device->channel, cp->device->id,
1163 cp->device->lun, resid,
1164 scsi_bufflen(cp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 cp->result = DID_ERROR << 16;
1167 break;
1168 }
1169
1170 /* Everybody online, looking good... */
1171 cp->result = DID_OK << 16;
1172 }
1173 break;
1174
1175 case CS_DATA_OVERRUN:
1176 DEBUG2(printk(KERN_INFO
1177 "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001178 vha->host_no, cp->device->id, cp->device->lun, comp_status,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001179 scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 DEBUG2(printk(KERN_INFO
1181 "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
1182 cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
1183 cp->cmnd[4], cp->cmnd[5]));
1184 DEBUG2(printk(KERN_INFO
1185 "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR "
1186 "status!\n",
FUJITA Tomonori385d70b2007-05-26 01:55:38 +09001187 cp->serial_number, scsi_bufflen(cp), resid_len));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
1189 cp->result = DID_ERROR << 16;
1190 break;
1191
1192 case CS_PORT_LOGGED_OUT:
1193 case CS_PORT_CONFIG_CHG:
1194 case CS_PORT_BUSY:
1195 case CS_INCOMPLETE:
1196 case CS_PORT_UNAVAILABLE:
1197 /*
1198 * If the port is in Target Down state, return all IOs for this
1199 * Target with DID_NO_CONNECT ELSE Queue the IOs in the
1200 * retry_queue.
1201 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
1203 "pid=%ld, compl status=0x%x, port state=0x%x\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001204 vha->host_no, cp->device->id, cp->device->lun,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001205 cp->serial_number, comp_status,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206 atomic_read(&fcport->state)));
1207
Mike Christie056a4482008-08-19 18:45:29 -05001208 /*
1209 * We are going to have the fc class block the rport
1210 * while we try to recover so instruct the mid layer
1211 * to requeue until the class decides how to handle this.
1212 */
1213 cp->result = DID_TRANSPORT_DISRUPTED << 16;
Andrew Vasqueza7a28502008-08-13 21:36:57 -07001214 if (atomic_read(&fcport->state) == FCS_ONLINE)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001215 qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001216 break;
1217
1218 case CS_RESET:
1219 DEBUG2(printk(KERN_INFO
1220 "scsi(%ld): RESET status detected 0x%x-0x%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001221 vha->host_no, comp_status, scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222
f4f051e2005-04-17 15:02:26 -05001223 cp->result = DID_RESET << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 break;
1225
1226 case CS_ABORTED:
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001227 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228 * hv2.19.12 - DID_ABORT does not retry the request if we
1229 * aborted this request then abort otherwise it must be a
1230 * reset.
1231 */
1232 DEBUG2(printk(KERN_INFO
1233 "scsi(%ld): ABORT status detected 0x%x-0x%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001234 vha->host_no, comp_status, scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
1236 cp->result = DID_RESET << 16;
1237 break;
1238
1239 case CS_TIMEOUT:
Mike Christie056a4482008-08-19 18:45:29 -05001240 /*
1241 * We are going to have the fc class block the rport
1242 * while we try to recover so instruct the mid layer
1243 * to requeue until the class decides how to handle this.
1244 */
1245 cp->result = DID_TRANSPORT_DISRUPTED << 16;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246
Andrew Vasqueze4289242007-07-19 15:05:56 -07001247 if (IS_FWI2_CAPABLE(ha)) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001248 DEBUG2(printk(KERN_INFO
1249 "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001250 "0x%x-0x%x\n", vha->host_no, cp->device->channel,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001251 cp->device->id, cp->device->lun, comp_status,
1252 scsi_status));
1253 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 }
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001255 DEBUG2(printk(KERN_INFO
1256 "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001257 "sflags=%x.\n", vha->host_no, cp->device->channel,
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001258 cp->device->id, cp->device->lun, comp_status, scsi_status,
1259 le16_to_cpu(sts->status_flags)));
1260
1261 /* Check to see if logout occurred. */
1262 if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001263 qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 break;
1265
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 default:
1267 DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001268 "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269 qla_printk(KERN_INFO, ha,
1270 "Unknown status detected 0x%x-0x%x.\n",
1271 comp_status, scsi_status);
1272
1273 cp->result = DID_ERROR << 16;
1274 break;
1275 }
1276
1277 /* Place command on done queue. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001278 if (vha->status_srb == NULL)
1279 qla2x00_sp_compl(vha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280}
1281
1282/**
1283 * qla2x00_status_cont_entry() - Process a Status Continuations entry.
1284 * @ha: SCSI driver HA context
1285 * @pkt: Entry pointer
1286 *
1287 * Extended sense data.
1288 */
1289static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001290qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291{
1292 uint8_t sense_sz = 0;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001293 struct qla_hw_data *ha = vha->hw;
1294 srb_t *sp = vha->status_srb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 struct scsi_cmnd *cp;
1296
1297 if (sp != NULL && sp->request_sense_length != 0) {
1298 cp = sp->cmd;
1299 if (cp == NULL) {
1300 DEBUG2(printk("%s(): Cmd already returned back to OS "
Andrew Vasquez75bc4192006-05-17 15:09:22 -07001301 "sp=%p.\n", __func__, sp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001302 qla_printk(KERN_INFO, ha,
1303 "cmd is NULL: already returned to OS (sp=%p)\n",
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001304 sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001306 vha->status_srb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 return;
1308 }
1309
1310 if (sp->request_sense_length > sizeof(pkt->data)) {
1311 sense_sz = sizeof(pkt->data);
1312 } else {
1313 sense_sz = sp->request_sense_length;
1314 }
1315
1316 /* Move sense data. */
Andrew Vasqueze4289242007-07-19 15:05:56 -07001317 if (IS_FWI2_CAPABLE(ha))
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001318 host_to_fcp_swap(pkt->data, sizeof(pkt->data));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
1320 DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
1321
1322 sp->request_sense_ptr += sense_sz;
1323 sp->request_sense_length -= sense_sz;
1324
1325 /* Place command on done queue. */
1326 if (sp->request_sense_length == 0) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001327 vha->status_srb = NULL;
1328 qla2x00_sp_compl(vha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 }
1330 }
1331}
1332
1333/**
1334 * qla2x00_error_entry() - Process an error entry.
1335 * @ha: SCSI driver HA context
1336 * @pkt: Entry pointer
1337 */
1338static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001339qla2x00_error_entry(scsi_qla_host_t *vha, sts_entry_t *pkt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340{
1341 srb_t *sp;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001342 struct qla_hw_data *ha = vha->hw;
1343 struct req_que *req = ha->req;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344#if defined(QL_DEBUG_LEVEL_2)
1345 if (pkt->entry_status & RF_INV_E_ORDER)
1346 qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
1347 else if (pkt->entry_status & RF_INV_E_COUNT)
1348 qla_printk(KERN_ERR, ha, "%s: Invalid Entry Count\n", __func__);
1349 else if (pkt->entry_status & RF_INV_E_PARAM)
Andrew Vasquezfa2a1ce2005-07-06 10:32:07 -07001350 qla_printk(KERN_ERR, ha,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 "%s: Invalid Entry Parameter\n", __func__);
1352 else if (pkt->entry_status & RF_INV_E_TYPE)
1353 qla_printk(KERN_ERR, ha, "%s: Invalid Entry Type\n", __func__);
1354 else if (pkt->entry_status & RF_BUSY)
1355 qla_printk(KERN_ERR, ha, "%s: Busy\n", __func__);
1356 else
1357 qla_printk(KERN_ERR, ha, "%s: UNKNOWN flag error\n", __func__);
1358#endif
1359
1360 /* Validate handle. */
1361 if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001362 sp = req->outstanding_cmds[pkt->handle];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363 else
1364 sp = NULL;
1365
1366 if (sp) {
1367 /* Free outstanding command slot. */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001368 req->outstanding_cmds[pkt->handle] = NULL;
Andrew Vasquez 354d6b22005-04-23 02:47:27 -04001369
Linus Torvalds1da177e2005-04-16 15:20:36 -07001370 /* Bad payload or header */
1371 if (pkt->entry_status &
1372 (RF_INV_E_ORDER | RF_INV_E_COUNT |
1373 RF_INV_E_PARAM | RF_INV_E_TYPE)) {
1374 sp->cmd->result = DID_ERROR << 16;
1375 } else if (pkt->entry_status & RF_BUSY) {
1376 sp->cmd->result = DID_BUS_BUSY << 16;
1377 } else {
1378 sp->cmd->result = DID_ERROR << 16;
1379 }
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001380 qla2x00_sp_compl(vha, sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001382 } else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
1383 COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001384 DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001385 vha->host_no));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386 qla_printk(KERN_WARNING, ha,
1387 "Error entry - invalid handle\n");
1388
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001389 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1390 qla2xxx_wake_dpc(vha);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 }
1392}
1393
1394/**
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001395 * qla24xx_mbx_completion() - Process mailbox command completions.
1396 * @ha: SCSI driver HA context
1397 * @mb0: Mailbox0 register
1398 */
1399static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001400qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001401{
1402 uint16_t cnt;
1403 uint16_t __iomem *wptr;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001404 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001405 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1406
1407 /* Load return mailbox registers. */
1408 ha->flags.mbox_int = 1;
1409 ha->mailbox_out[0] = mb0;
1410 wptr = (uint16_t __iomem *)&reg->mailbox1;
1411
1412 for (cnt = 1; cnt < ha->mbx_count; cnt++) {
1413 ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
1414 wptr++;
1415 }
1416
1417 if (ha->mcp) {
1418 DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001419 __func__, vha->host_no, ha->mcp->mb[0]));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001420 } else {
1421 DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001422 __func__, vha->host_no));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001423 }
1424}
1425
1426/**
1427 * qla24xx_process_response_queue() - Process response queue entries.
1428 * @ha: SCSI driver HA context
1429 */
1430void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001431qla24xx_process_response_queue(struct scsi_qla_host *vha)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001432{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001433 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001434 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1435 struct sts_entry_24xx *pkt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001436 struct rsp_que *rsp = ha->rsp;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001437
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001438 if (!vha->flags.online)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001439 return;
1440
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001441 while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
1442 pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001443
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001444 rsp->ring_index++;
1445 if (rsp->ring_index == rsp->length) {
1446 rsp->ring_index = 0;
1447 rsp->ring_ptr = rsp->ring;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001448 } else {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001449 rsp->ring_ptr++;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001450 }
1451
1452 if (pkt->entry_status != 0) {
1453 DEBUG3(printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001454 "scsi(%ld): Process error entry.\n", vha->host_no));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001455
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001456 qla2x00_error_entry(vha, (sts_entry_t *) pkt);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001457 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
1458 wmb();
1459 continue;
1460 }
1461
1462 switch (pkt->entry_type) {
1463 case STATUS_TYPE:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001464 qla2x00_status_entry(vha, pkt);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001465 break;
1466 case STATUS_CONT_TYPE:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001467 qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001468 break;
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001469 case VP_RPT_ID_IOCB_TYPE:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001470 qla24xx_report_id_acquisition(vha,
Seokmann Ju2c3dfe32007-07-05 13:16:51 -07001471 (struct vp_rpt_id_entry_24xx *)pkt);
1472 break;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001473 default:
1474 /* Type Not Supported. */
1475 DEBUG4(printk(KERN_WARNING
1476 "scsi(%ld): Received unknown response pkt type %x "
1477 "entry status=%x.\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001478 vha->host_no, pkt->entry_type, pkt->entry_status));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001479 break;
1480 }
1481 ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
1482 wmb();
1483 }
1484
1485 /* Adjust ring index */
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001486 WRT_REG_DWORD(&reg->rsp_q_out, rsp->ring_index);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001487}
1488
Andrew Vasquez05236a02007-09-20 14:07:37 -07001489static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001490qla2xxx_check_risc_status(scsi_qla_host_t *vha)
Andrew Vasquez05236a02007-09-20 14:07:37 -07001491{
1492 int rval;
1493 uint32_t cnt;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001494 struct qla_hw_data *ha = vha->hw;
Andrew Vasquez05236a02007-09-20 14:07:37 -07001495 struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1496
1497 if (!IS_QLA25XX(ha))
1498 return;
1499
1500 rval = QLA_SUCCESS;
1501 WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
1502 RD_REG_DWORD(&reg->iobase_addr);
1503 WRT_REG_DWORD(&reg->iobase_window, 0x0001);
1504 for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
1505 rval == QLA_SUCCESS; cnt--) {
1506 if (cnt) {
1507 WRT_REG_DWORD(&reg->iobase_window, 0x0001);
1508 udelay(10);
1509 } else
1510 rval = QLA_FUNCTION_TIMEOUT;
1511 }
1512 if (rval == QLA_SUCCESS)
1513 goto next_test;
1514
1515 WRT_REG_DWORD(&reg->iobase_window, 0x0003);
1516 for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
1517 rval == QLA_SUCCESS; cnt--) {
1518 if (cnt) {
1519 WRT_REG_DWORD(&reg->iobase_window, 0x0003);
1520 udelay(10);
1521 } else
1522 rval = QLA_FUNCTION_TIMEOUT;
1523 }
1524 if (rval != QLA_SUCCESS)
1525 goto done;
1526
1527next_test:
1528 if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
1529 qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");
1530
1531done:
1532 WRT_REG_DWORD(&reg->iobase_window, 0x0000);
1533 RD_REG_DWORD(&reg->iobase_window);
1534}
1535
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001536/**
1537 * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
1538 * @irq:
1539 * @dev_id: SCSI driver HA context
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001540 *
1541 * Called by system whenever the host adapter generates an interrupt.
1542 *
1543 * Returns handled flag.
1544 */
1545irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01001546qla24xx_intr_handler(int irq, void *dev_id)
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001547{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001548 scsi_qla_host_t *vha;
1549 struct qla_hw_data *ha;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001550 struct device_reg_24xx __iomem *reg;
1551 int status;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001552 unsigned long iter;
1553 uint32_t stat;
1554 uint32_t hccr;
1555 uint16_t mb[4];
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001556 struct rsp_que *rsp;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001557
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001558 rsp = (struct rsp_que *) dev_id;
1559 if (!rsp) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001560 printk(KERN_INFO
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001561 "%s(): NULL response queue pointer\n", __func__);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001562 return IRQ_NONE;
1563 }
1564
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001565 ha = rsp->hw;
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001566 reg = &ha->iobase->isp24;
1567 status = 0;
1568
Andrew Vasquezc6952482008-04-03 13:13:17 -07001569 spin_lock(&ha->hardware_lock);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001570 vha = qla2x00_get_rsp_host(rsp);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001571 for (iter = 50; iter--; ) {
1572 stat = RD_REG_DWORD(&reg->host_status);
1573 if (stat & HSRX_RISC_PAUSED) {
Seokmann Ju14e660e2007-09-20 14:07:36 -07001574 if (pci_channel_offline(ha->pdev))
1575 break;
1576
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -07001577 if (ha->hw_event_pause_errors == 0)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001578 qla2x00_post_hwe_work(vha, HW_EVENT_PARITY_ERR,
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -07001579 0, MSW(stat), LSW(stat));
1580 else if (ha->hw_event_pause_errors < 0xffffffff)
1581 ha->hw_event_pause_errors++;
1582
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001583 hccr = RD_REG_DWORD(&reg->hccr);
1584
1585 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
1586 "Dumping firmware!\n", hccr);
Andrew Vasquez05236a02007-09-20 14:07:37 -07001587
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001588 qla2xxx_check_risc_status(vha);
Andrew Vasquez05236a02007-09-20 14:07:37 -07001589
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001590 ha->isp_ops->fw_dump(vha, 1);
1591 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001592 break;
1593 } else if ((stat & HSRX_RISC_INT) == 0)
1594 break;
1595
1596 switch (stat & 0xff) {
1597 case 0x1:
1598 case 0x2:
1599 case 0x10:
1600 case 0x11:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001601 qla24xx_mbx_completion(vha, MSW(stat));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001602 status |= MBX_INTERRUPT;
1603
1604 break;
1605 case 0x12:
1606 mb[0] = MSW(stat);
1607 mb[1] = RD_REG_WORD(&reg->mailbox1);
1608 mb[2] = RD_REG_WORD(&reg->mailbox2);
1609 mb[3] = RD_REG_WORD(&reg->mailbox3);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001610 qla2x00_async_event(vha, mb);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001611 break;
1612 case 0x13:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001613 qla24xx_process_response_queue(vha);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001614 break;
1615 default:
1616 DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
1617 "(%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001618 vha->host_no, stat & 0xff));
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001619 break;
1620 }
1621 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
1622 RD_REG_DWORD_RELAXED(&reg->hccr);
1623 }
Andrew Vasquezc6952482008-04-03 13:13:17 -07001624 spin_unlock(&ha->hardware_lock);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001625
1626 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
1627 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001628 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -08001629 complete(&ha->mbx_intr_comp);
Andrew Vasquez9a853f72005-07-06 10:31:27 -07001630 }
1631
1632 return IRQ_HANDLED;
1633}
1634
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001635static irqreturn_t
1636qla24xx_msix_rsp_q(int irq, void *dev_id)
1637{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001638 scsi_qla_host_t *vha;
1639 struct qla_hw_data *ha;
1640 struct rsp_que *rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001641 struct device_reg_24xx __iomem *reg;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001642
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001643 rsp = (struct rsp_que *) dev_id;
1644 if (!rsp) {
1645 printk(KERN_INFO
1646 "%s(): NULL response queue pointer\n", __func__);
1647 return IRQ_NONE;
1648 }
1649 ha = rsp->hw;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001650 reg = &ha->iobase->isp24;
1651
Andrew Vasquez0e973a22008-05-12 22:21:09 -07001652 spin_lock_irq(&ha->hardware_lock);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001653
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001654 vha = qla2x00_get_rsp_host(rsp);
1655 qla24xx_process_response_queue(vha);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001656 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001657
Andrew Vasquez0e973a22008-05-12 22:21:09 -07001658 spin_unlock_irq(&ha->hardware_lock);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001659
1660 return IRQ_HANDLED;
1661}
1662
1663static irqreturn_t
1664qla24xx_msix_default(int irq, void *dev_id)
1665{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001666 scsi_qla_host_t *vha;
1667 struct qla_hw_data *ha;
1668 struct rsp_que *rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001669 struct device_reg_24xx __iomem *reg;
1670 int status;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001671 uint32_t stat;
1672 uint32_t hccr;
1673 uint16_t mb[4];
1674
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001675 rsp = (struct rsp_que *) dev_id;
1676 if (!rsp) {
1677 DEBUG(printk(
1678 "%s(): NULL response queue pointer\n", __func__));
1679 return IRQ_NONE;
1680 }
1681 ha = rsp->hw;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001682 reg = &ha->iobase->isp24;
1683 status = 0;
1684
Andrew Vasquez0e973a22008-05-12 22:21:09 -07001685 spin_lock_irq(&ha->hardware_lock);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001686 vha = qla2x00_get_rsp_host(rsp);
Andrew Vasquez87f27012007-09-20 14:07:49 -07001687 do {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001688 stat = RD_REG_DWORD(&reg->host_status);
1689 if (stat & HSRX_RISC_PAUSED) {
Seokmann Ju14e660e2007-09-20 14:07:36 -07001690 if (pci_channel_offline(ha->pdev))
1691 break;
1692
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -07001693 if (ha->hw_event_pause_errors == 0)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001694 qla2x00_post_hwe_work(vha, HW_EVENT_PARITY_ERR,
Andrew Vasquezcb8dacb2008-04-03 13:13:19 -07001695 0, MSW(stat), LSW(stat));
1696 else if (ha->hw_event_pause_errors < 0xffffffff)
1697 ha->hw_event_pause_errors++;
1698
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001699 hccr = RD_REG_DWORD(&reg->hccr);
1700
1701 qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
1702 "Dumping firmware!\n", hccr);
Andrew Vasquez05236a02007-09-20 14:07:37 -07001703
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001704 qla2xxx_check_risc_status(vha);
Andrew Vasquez05236a02007-09-20 14:07:37 -07001705
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001706 ha->isp_ops->fw_dump(vha, 1);
1707 set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001708 break;
1709 } else if ((stat & HSRX_RISC_INT) == 0)
1710 break;
1711
1712 switch (stat & 0xff) {
1713 case 0x1:
1714 case 0x2:
1715 case 0x10:
1716 case 0x11:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001717 qla24xx_mbx_completion(vha, MSW(stat));
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001718 status |= MBX_INTERRUPT;
1719
1720 break;
1721 case 0x12:
1722 mb[0] = MSW(stat);
1723 mb[1] = RD_REG_WORD(&reg->mailbox1);
1724 mb[2] = RD_REG_WORD(&reg->mailbox2);
1725 mb[3] = RD_REG_WORD(&reg->mailbox3);
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001726 qla2x00_async_event(vha, mb);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001727 break;
1728 case 0x13:
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001729 qla24xx_process_response_queue(vha);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001730 break;
1731 default:
1732 DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
1733 "(%d).\n",
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001734 vha->host_no, stat & 0xff));
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001735 break;
1736 }
1737 WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
Andrew Vasquez87f27012007-09-20 14:07:49 -07001738 } while (0);
Andrew Vasquez0e973a22008-05-12 22:21:09 -07001739 spin_unlock_irq(&ha->hardware_lock);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001740
1741 if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
1742 (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001743 set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
Marcus Barrow0b05a1f2008-01-17 09:02:13 -08001744 complete(&ha->mbx_intr_comp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001745 }
1746
1747 return IRQ_HANDLED;
1748}
1749
1750/* Interrupt handling helpers. */
1751
1752struct qla_init_msix_entry {
1753 uint16_t entry;
1754 uint16_t index;
1755 const char *name;
Jeff Garzik476834c2007-05-23 14:41:44 -07001756 irq_handler_t handler;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001757};
1758
1759static struct qla_init_msix_entry imsix_entries[QLA_MSIX_ENTRIES] = {
1760 { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT,
1761 "qla2xxx (default)", qla24xx_msix_default },
1762
1763 { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q,
1764 "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
1765};
1766
1767static void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001768qla24xx_disable_msix(struct qla_hw_data *ha)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001769{
1770 int i;
1771 struct qla_msix_entry *qentry;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001772 struct rsp_que *rsp = ha->rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001773
1774 for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
1775 qentry = &ha->msix_entries[imsix_entries[i].index];
1776 if (qentry->have_irq)
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001777 free_irq(qentry->msix_vector, rsp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001778 }
1779 pci_disable_msix(ha->pdev);
1780}
1781
1782static int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001783qla24xx_enable_msix(struct qla_hw_data *ha)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001784{
1785 int i, ret;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001786 struct rsp_que *rsp = ha->rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001787 struct msix_entry entries[QLA_MSIX_ENTRIES];
1788 struct qla_msix_entry *qentry;
1789
1790 for (i = 0; i < QLA_MSIX_ENTRIES; i++)
1791 entries[i].entry = imsix_entries[i].entry;
1792
1793 ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries));
1794 if (ret) {
1795 qla_printk(KERN_WARNING, ha,
1796 "MSI-X: Failed to enable support -- %d/%d\n",
1797 QLA_MSIX_ENTRIES, ret);
1798 goto msix_out;
1799 }
1800 ha->flags.msix_enabled = 1;
1801
1802 for (i = 0; i < QLA_MSIX_ENTRIES; i++) {
1803 qentry = &ha->msix_entries[imsix_entries[i].index];
1804 qentry->msix_vector = entries[i].vector;
1805 qentry->msix_entry = entries[i].entry;
1806 qentry->have_irq = 0;
1807 ret = request_irq(qentry->msix_vector,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001808 imsix_entries[i].handler, 0, imsix_entries[i].name, rsp);
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001809 if (ret) {
1810 qla_printk(KERN_WARNING, ha,
1811 "MSI-X: Unable to register handler -- %x/%d.\n",
1812 imsix_entries[i].index, ret);
1813 qla24xx_disable_msix(ha);
1814 goto msix_out;
1815 }
1816 qentry->have_irq = 1;
1817 }
1818
1819msix_out:
1820 return ret;
1821}
1822
1823int
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001824qla2x00_request_irqs(struct qla_hw_data *ha)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001825{
1826 int ret;
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001827 device_reg_t __iomem *reg = ha->iobase;
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001828 struct rsp_que *rsp = ha->rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001829
1830 /* If possible, enable MSI-X. */
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001831 if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001832 goto skip_msix;
1833
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001834 if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
1835 !QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001836 DEBUG2(qla_printk(KERN_WARNING, ha,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001837 "MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
1838 ha->pdev->revision, ha->fw_attributes));
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001839
1840 goto skip_msix;
1841 }
1842
Andrew Vasquezda7429f2008-01-17 09:02:11 -08001843 if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
1844 (ha->pdev->subsystem_device == 0x7040 ||
1845 ha->pdev->subsystem_device == 0x7041 ||
1846 ha->pdev->subsystem_device == 0x1705)) {
1847 DEBUG2(qla_printk(KERN_WARNING, ha,
1848 "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n",
1849 ha->pdev->subsystem_vendor,
1850 ha->pdev->subsystem_device));
1851
1852 goto skip_msi;
1853 }
1854
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001855 ret = qla24xx_enable_msix(ha);
1856 if (!ret) {
1857 DEBUG2(qla_printk(KERN_INFO, ha,
1858 "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
1859 ha->fw_attributes));
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001860 goto clear_risc_ints;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001861 }
1862 qla_printk(KERN_WARNING, ha,
1863 "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
1864skip_msix:
Andrew Vasquezcbedb602007-05-07 07:43:02 -07001865
Harihara Kadayam4d4df192008-04-03 13:13:26 -07001866 if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
Andrew Vasquezcbedb602007-05-07 07:43:02 -07001867 goto skip_msi;
1868
1869 ret = pci_enable_msi(ha->pdev);
1870 if (!ret) {
1871 DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
1872 ha->flags.msi_enabled = 1;
1873 }
1874skip_msi:
1875
Andrew Vasquezfd34f552007-07-19 15:06:00 -07001876 ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001877 IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001878 if (ret) {
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001879 qla_printk(KERN_WARNING, ha,
1880 "Failed to reserve interrupt %d already in use.\n",
1881 ha->pdev->irq);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001882 goto fail;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001883 }
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001884 ha->flags.inta_enabled = 1;
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001885clear_risc_ints:
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001886
Andrew Vasquezc6952482008-04-03 13:13:17 -07001887 spin_lock_irq(&ha->hardware_lock);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001888 if (IS_FWI2_CAPABLE(ha)) {
1889 WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
1890 WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
1891 } else {
1892 WRT_REG_WORD(&reg->isp.semaphore, 0);
1893 WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
1894 WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_HOST_INT);
1895 }
Andrew Vasquezc6952482008-04-03 13:13:17 -07001896 spin_unlock_irq(&ha->hardware_lock);
Andrew Vasquez963b0fd2008-01-31 12:33:50 -08001897
1898fail:
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001899 return ret;
1900}
1901
1902void
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001903qla2x00_free_irqs(scsi_qla_host_t *vha)
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001904{
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001905 struct qla_hw_data *ha = vha->hw;
1906 struct rsp_que *rsp = ha->rsp;
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001907
1908 if (ha->flags.msix_enabled)
1909 qla24xx_disable_msix(ha);
Andrew Vasquezcbedb602007-05-07 07:43:02 -07001910 else if (ha->flags.inta_enabled) {
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001911 free_irq(ha->pdev->irq, rsp);
Andrew Vasquezcbedb602007-05-07 07:43:02 -07001912 pci_disable_msi(ha->pdev);
1913 }
Andrew Vasqueza8488ab2007-01-29 10:22:19 -08001914}
Anirban Chakrabortye315cd22008-11-06 10:40:51 -08001915
1916static struct scsi_qla_host *
1917qla2x00_get_rsp_host(struct rsp_que *rsp)
1918{
1919 srb_t *sp;
1920 struct qla_hw_data *ha = rsp->hw;
1921 struct scsi_qla_host *vha = NULL;
1922 struct sts_entry_24xx *pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
1923
1924 if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) {
1925 sp = ha->req->outstanding_cmds[pkt->handle];
1926 if (sp)
1927 vha = sp->vha;
1928 }
1929 if (!vha)
1930 /* Invalid entry, handle it in base queue */
1931 vha = pci_get_drvdata(ha->pdev);
1932
1933 return vha;
1934}