xref: /OK3568_Linux_fs/kernel/drivers/scsi/qla4xxx/ql4_mbx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * QLogic iSCSI HBA Driver
4*4882a593Smuzhiyun  * Copyright (c)  2003-2013 QLogic Corporation
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include <linux/ctype.h>
8*4882a593Smuzhiyun #include "ql4_def.h"
9*4882a593Smuzhiyun #include "ql4_glbl.h"
10*4882a593Smuzhiyun #include "ql4_dbg.h"
11*4882a593Smuzhiyun #include "ql4_inline.h"
12*4882a593Smuzhiyun #include "ql4_version.h"
13*4882a593Smuzhiyun 
qla4xxx_queue_mbox_cmd(struct scsi_qla_host * ha,uint32_t * mbx_cmd,int in_count)14*4882a593Smuzhiyun void qla4xxx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
15*4882a593Smuzhiyun 			    int in_count)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	int i;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	/* Load all mailbox registers, except mailbox 0. */
20*4882a593Smuzhiyun 	for (i = 1; i < in_count; i++)
21*4882a593Smuzhiyun 		writel(mbx_cmd[i], &ha->reg->mailbox[i]);
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	/* Wakeup firmware  */
24*4882a593Smuzhiyun 	writel(mbx_cmd[0], &ha->reg->mailbox[0]);
25*4882a593Smuzhiyun 	readl(&ha->reg->mailbox[0]);
26*4882a593Smuzhiyun 	writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
27*4882a593Smuzhiyun 	readl(&ha->reg->ctrl_status);
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun 
qla4xxx_process_mbox_intr(struct scsi_qla_host * ha,int out_count)30*4882a593Smuzhiyun void qla4xxx_process_mbox_intr(struct scsi_qla_host *ha, int out_count)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	int intr_status;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	intr_status = readl(&ha->reg->ctrl_status);
35*4882a593Smuzhiyun 	if (intr_status & INTR_PENDING) {
36*4882a593Smuzhiyun 		/*
37*4882a593Smuzhiyun 		 * Service the interrupt.
38*4882a593Smuzhiyun 		 * The ISR will save the mailbox status registers
39*4882a593Smuzhiyun 		 * to a temporary storage location in the adapter structure.
40*4882a593Smuzhiyun 		 */
41*4882a593Smuzhiyun 		ha->mbox_status_count = out_count;
42*4882a593Smuzhiyun 		ha->isp_ops->interrupt_service_routine(ha, intr_status);
43*4882a593Smuzhiyun 	}
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /**
47*4882a593Smuzhiyun  * qla4xxx_is_intr_poll_mode – Are we allowed to poll for interrupts?
48*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
49*4882a593Smuzhiyun  * returns: 1=polling mode, 0=non-polling mode
50*4882a593Smuzhiyun  **/
qla4xxx_is_intr_poll_mode(struct scsi_qla_host * ha)51*4882a593Smuzhiyun static int qla4xxx_is_intr_poll_mode(struct scsi_qla_host *ha)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	int rval = 1;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	if (is_qla8032(ha) || is_qla8042(ha)) {
56*4882a593Smuzhiyun 		if (test_bit(AF_IRQ_ATTACHED, &ha->flags) &&
57*4882a593Smuzhiyun 		    test_bit(AF_83XX_MBOX_INTR_ON, &ha->flags))
58*4882a593Smuzhiyun 			rval = 0;
59*4882a593Smuzhiyun 	} else {
60*4882a593Smuzhiyun 		if (test_bit(AF_IRQ_ATTACHED, &ha->flags) &&
61*4882a593Smuzhiyun 		    test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
62*4882a593Smuzhiyun 		    test_bit(AF_ONLINE, &ha->flags) &&
63*4882a593Smuzhiyun 		    !test_bit(AF_HA_REMOVAL, &ha->flags))
64*4882a593Smuzhiyun 			rval = 0;
65*4882a593Smuzhiyun 	}
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	return rval;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun /**
71*4882a593Smuzhiyun  * qla4xxx_mailbox_command - issues mailbox commands
72*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
73*4882a593Smuzhiyun  * @inCount: number of mailbox registers to load.
74*4882a593Smuzhiyun  * @outCount: number of mailbox registers to return.
75*4882a593Smuzhiyun  * @mbx_cmd: data pointer for mailbox in registers.
76*4882a593Smuzhiyun  * @mbx_sts: data pointer for mailbox out registers.
77*4882a593Smuzhiyun  *
78*4882a593Smuzhiyun  * This routine issue mailbox commands and waits for completion.
79*4882a593Smuzhiyun  * If outCount is 0, this routine completes successfully WITHOUT waiting
80*4882a593Smuzhiyun  * for the mailbox command to complete.
81*4882a593Smuzhiyun  **/
qla4xxx_mailbox_command(struct scsi_qla_host * ha,uint8_t inCount,uint8_t outCount,uint32_t * mbx_cmd,uint32_t * mbx_sts)82*4882a593Smuzhiyun int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount,
83*4882a593Smuzhiyun 			    uint8_t outCount, uint32_t *mbx_cmd,
84*4882a593Smuzhiyun 			    uint32_t *mbx_sts)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun 	int status = QLA_ERROR;
87*4882a593Smuzhiyun 	uint8_t i;
88*4882a593Smuzhiyun 	u_long wait_count;
89*4882a593Smuzhiyun 	unsigned long flags = 0;
90*4882a593Smuzhiyun 	uint32_t dev_state;
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* Make sure that pointers are valid */
93*4882a593Smuzhiyun 	if (!mbx_cmd || !mbx_sts) {
94*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts "
95*4882a593Smuzhiyun 			      "pointer\n", ha->host_no, __func__));
96*4882a593Smuzhiyun 		return status;
97*4882a593Smuzhiyun 	}
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
100*4882a593Smuzhiyun 		if (test_bit(AF_HA_REMOVAL, &ha->flags)) {
101*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: "
102*4882a593Smuzhiyun 					  "prematurely completing mbx cmd as "
103*4882a593Smuzhiyun 					  "adapter removal detected\n",
104*4882a593Smuzhiyun 					  ha->host_no, __func__));
105*4882a593Smuzhiyun 			return status;
106*4882a593Smuzhiyun 		}
107*4882a593Smuzhiyun 	}
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	if ((is_aer_supported(ha)) &&
110*4882a593Smuzhiyun 	    (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) {
111*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, "
112*4882a593Smuzhiyun 		    "timeout MBX Exiting.\n", ha->host_no, __func__));
113*4882a593Smuzhiyun 		return status;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	/* Mailbox code active */
117*4882a593Smuzhiyun 	wait_count = MBOX_TOV * 100;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	while (wait_count--) {
120*4882a593Smuzhiyun 		mutex_lock(&ha->mbox_sem);
121*4882a593Smuzhiyun 		if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) {
122*4882a593Smuzhiyun 			set_bit(AF_MBOX_COMMAND, &ha->flags);
123*4882a593Smuzhiyun 			mutex_unlock(&ha->mbox_sem);
124*4882a593Smuzhiyun 			break;
125*4882a593Smuzhiyun 		}
126*4882a593Smuzhiyun 		mutex_unlock(&ha->mbox_sem);
127*4882a593Smuzhiyun 		if (!wait_count) {
128*4882a593Smuzhiyun 			DEBUG2(printk("scsi%ld: %s: mbox_sem failed\n",
129*4882a593Smuzhiyun 				ha->host_no, __func__));
130*4882a593Smuzhiyun 			return status;
131*4882a593Smuzhiyun 		}
132*4882a593Smuzhiyun 		msleep(10);
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (is_qla80XX(ha)) {
136*4882a593Smuzhiyun 		if (test_bit(AF_FW_RECOVERY, &ha->flags)) {
137*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_WARNING, ha,
138*4882a593Smuzhiyun 					  "scsi%ld: %s: prematurely completing mbx cmd as firmware recovery detected\n",
139*4882a593Smuzhiyun 					  ha->host_no, __func__));
140*4882a593Smuzhiyun 			goto mbox_exit;
141*4882a593Smuzhiyun 		}
142*4882a593Smuzhiyun 		/* Do not send any mbx cmd if h/w is in failed state*/
143*4882a593Smuzhiyun 		ha->isp_ops->idc_lock(ha);
144*4882a593Smuzhiyun 		dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
145*4882a593Smuzhiyun 		ha->isp_ops->idc_unlock(ha);
146*4882a593Smuzhiyun 		if (dev_state == QLA8XXX_DEV_FAILED) {
147*4882a593Smuzhiyun 			ql4_printk(KERN_WARNING, ha,
148*4882a593Smuzhiyun 				   "scsi%ld: %s: H/W is in failed state, do not send any mailbox commands\n",
149*4882a593Smuzhiyun 				   ha->host_no, __func__);
150*4882a593Smuzhiyun 			goto mbox_exit;
151*4882a593Smuzhiyun 		}
152*4882a593Smuzhiyun 	}
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	ha->mbox_status_count = outCount;
157*4882a593Smuzhiyun 	for (i = 0; i < outCount; i++)
158*4882a593Smuzhiyun 		ha->mbox_status[i] = 0;
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* Queue the mailbox command to the firmware */
161*4882a593Smuzhiyun 	ha->isp_ops->queue_mailbox_command(ha, mbx_cmd, inCount);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	/* Wait for completion */
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	/*
168*4882a593Smuzhiyun 	 * If we don't want status, don't wait for the mailbox command to
169*4882a593Smuzhiyun 	 * complete.  For example, MBOX_CMD_RESET_FW doesn't return status,
170*4882a593Smuzhiyun 	 * you must poll the inbound Interrupt Mask for completion.
171*4882a593Smuzhiyun 	 */
172*4882a593Smuzhiyun 	if (outCount == 0) {
173*4882a593Smuzhiyun 		status = QLA_SUCCESS;
174*4882a593Smuzhiyun 		goto mbox_exit;
175*4882a593Smuzhiyun 	}
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	/*
178*4882a593Smuzhiyun 	 * Wait for completion: Poll or completion queue
179*4882a593Smuzhiyun 	 */
180*4882a593Smuzhiyun 	if (qla4xxx_is_intr_poll_mode(ha)) {
181*4882a593Smuzhiyun 		/* Poll for command to complete */
182*4882a593Smuzhiyun 		wait_count = jiffies + MBOX_TOV * HZ;
183*4882a593Smuzhiyun 		while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
184*4882a593Smuzhiyun 			if (time_after_eq(jiffies, wait_count))
185*4882a593Smuzhiyun 				break;
186*4882a593Smuzhiyun 			/*
187*4882a593Smuzhiyun 			 * Service the interrupt.
188*4882a593Smuzhiyun 			 * The ISR will save the mailbox status registers
189*4882a593Smuzhiyun 			 * to a temporary storage location in the adapter
190*4882a593Smuzhiyun 			 * structure.
191*4882a593Smuzhiyun 			 */
192*4882a593Smuzhiyun 			spin_lock_irqsave(&ha->hardware_lock, flags);
193*4882a593Smuzhiyun 			ha->isp_ops->process_mailbox_interrupt(ha, outCount);
194*4882a593Smuzhiyun 			spin_unlock_irqrestore(&ha->hardware_lock, flags);
195*4882a593Smuzhiyun 			msleep(10);
196*4882a593Smuzhiyun 		}
197*4882a593Smuzhiyun 	} else {
198*4882a593Smuzhiyun 		/* Do not poll for completion. Use completion queue */
199*4882a593Smuzhiyun 		set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
200*4882a593Smuzhiyun 		wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ);
201*4882a593Smuzhiyun 		clear_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags);
202*4882a593Smuzhiyun 	}
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* Check for mailbox timeout. */
205*4882a593Smuzhiyun 	if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
206*4882a593Smuzhiyun 		if (is_qla80XX(ha) &&
207*4882a593Smuzhiyun 		    test_bit(AF_FW_RECOVERY, &ha->flags)) {
208*4882a593Smuzhiyun 			DEBUG2(ql4_printk(KERN_INFO, ha,
209*4882a593Smuzhiyun 			    "scsi%ld: %s: prematurely completing mbx cmd as "
210*4882a593Smuzhiyun 			    "firmware recovery detected\n",
211*4882a593Smuzhiyun 			    ha->host_no, __func__));
212*4882a593Smuzhiyun 			goto mbox_exit;
213*4882a593Smuzhiyun 		}
214*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "scsi%ld: Mailbox Cmd 0x%08X timed out, Scheduling Adapter Reset\n",
215*4882a593Smuzhiyun 			   ha->host_no, mbx_cmd[0]);
216*4882a593Smuzhiyun 		ha->mailbox_timeout_count++;
217*4882a593Smuzhiyun 		mbx_sts[0] = (-1);
218*4882a593Smuzhiyun 		set_bit(DPC_RESET_HA, &ha->dpc_flags);
219*4882a593Smuzhiyun 		if (is_qla8022(ha)) {
220*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha,
221*4882a593Smuzhiyun 				   "disabling pause transmit on port 0 & 1.\n");
222*4882a593Smuzhiyun 			qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
223*4882a593Smuzhiyun 					CRB_NIU_XG_PAUSE_CTL_P0 |
224*4882a593Smuzhiyun 					CRB_NIU_XG_PAUSE_CTL_P1);
225*4882a593Smuzhiyun 		} else if (is_qla8032(ha) || is_qla8042(ha)) {
226*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, " %s: disabling pause transmit on port 0 & 1.\n",
227*4882a593Smuzhiyun 				   __func__);
228*4882a593Smuzhiyun 			qla4_83xx_disable_pause(ha);
229*4882a593Smuzhiyun 		}
230*4882a593Smuzhiyun 		goto mbox_exit;
231*4882a593Smuzhiyun 	}
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	/*
234*4882a593Smuzhiyun 	 * Copy the mailbox out registers to the caller's mailbox in/out
235*4882a593Smuzhiyun 	 * structure.
236*4882a593Smuzhiyun 	 */
237*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
238*4882a593Smuzhiyun 	for (i = 0; i < outCount; i++)
239*4882a593Smuzhiyun 		mbx_sts[i] = ha->mbox_status[i];
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	/* Set return status and error flags (if applicable). */
242*4882a593Smuzhiyun 	switch (ha->mbox_status[0]) {
243*4882a593Smuzhiyun 	case MBOX_STS_COMMAND_COMPLETE:
244*4882a593Smuzhiyun 		status = QLA_SUCCESS;
245*4882a593Smuzhiyun 		break;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	case MBOX_STS_INTERMEDIATE_COMPLETION:
248*4882a593Smuzhiyun 		status = QLA_SUCCESS;
249*4882a593Smuzhiyun 		break;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	case MBOX_STS_BUSY:
252*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
253*4882a593Smuzhiyun 			   ha->host_no, __func__, mbx_cmd[0]);
254*4882a593Smuzhiyun 		ha->mailbox_timeout_count++;
255*4882a593Smuzhiyun 		break;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	default:
258*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: FAILED, MBOX CMD = %08X, MBOX STS = %08X %08X %08X %08X %08X %08X %08X %08X\n",
259*4882a593Smuzhiyun 			   ha->host_no, __func__, mbx_cmd[0], mbx_sts[0],
260*4882a593Smuzhiyun 			   mbx_sts[1], mbx_sts[2], mbx_sts[3], mbx_sts[4],
261*4882a593Smuzhiyun 			   mbx_sts[5], mbx_sts[6], mbx_sts[7]);
262*4882a593Smuzhiyun 		break;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun mbox_exit:
267*4882a593Smuzhiyun 	mutex_lock(&ha->mbox_sem);
268*4882a593Smuzhiyun 	clear_bit(AF_MBOX_COMMAND, &ha->flags);
269*4882a593Smuzhiyun 	mutex_unlock(&ha->mbox_sem);
270*4882a593Smuzhiyun 	clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return status;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun /**
276*4882a593Smuzhiyun  * qla4xxx_get_minidump_template - Get the firmware template
277*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
278*4882a593Smuzhiyun  * @phys_addr: dma address for template
279*4882a593Smuzhiyun  *
280*4882a593Smuzhiyun  * Obtain the minidump template from firmware during initialization
281*4882a593Smuzhiyun  * as it may not be available when minidump is desired.
282*4882a593Smuzhiyun  **/
qla4xxx_get_minidump_template(struct scsi_qla_host * ha,dma_addr_t phys_addr)283*4882a593Smuzhiyun int qla4xxx_get_minidump_template(struct scsi_qla_host *ha,
284*4882a593Smuzhiyun 				  dma_addr_t phys_addr)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
287*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
288*4882a593Smuzhiyun 	int status;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
291*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_MINIDUMP;
294*4882a593Smuzhiyun 	mbox_cmd[1] = MINIDUMP_GET_TMPLT_SUBCOMMAND;
295*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(phys_addr);
296*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(phys_addr);
297*4882a593Smuzhiyun 	mbox_cmd[4] = ha->fw_dump_tmplt_size;
298*4882a593Smuzhiyun 	mbox_cmd[5] = 0;
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0],
301*4882a593Smuzhiyun 					 &mbox_sts[0]);
302*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
303*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
304*4882a593Smuzhiyun 				  "scsi%ld: %s: Cmd = %08X, mbx[0] = 0x%04x, mbx[1] = 0x%04x\n",
305*4882a593Smuzhiyun 				  ha->host_no, __func__, mbox_cmd[0],
306*4882a593Smuzhiyun 				  mbox_sts[0], mbox_sts[1]));
307*4882a593Smuzhiyun 	}
308*4882a593Smuzhiyun 	return status;
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun /**
312*4882a593Smuzhiyun  * qla4xxx_req_template_size - Get minidump template size from firmware.
313*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
314*4882a593Smuzhiyun  **/
qla4xxx_req_template_size(struct scsi_qla_host * ha)315*4882a593Smuzhiyun int qla4xxx_req_template_size(struct scsi_qla_host *ha)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
318*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
319*4882a593Smuzhiyun 	int status;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
322*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_MINIDUMP;
325*4882a593Smuzhiyun 	mbox_cmd[1] = MINIDUMP_GET_SIZE_SUBCOMMAND;
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 8, &mbox_cmd[0],
328*4882a593Smuzhiyun 					 &mbox_sts[0]);
329*4882a593Smuzhiyun 	if (status == QLA_SUCCESS) {
330*4882a593Smuzhiyun 		ha->fw_dump_tmplt_size = mbox_sts[1];
331*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
332*4882a593Smuzhiyun 				  "%s: sts[0]=0x%04x, template  size=0x%04x, size_cm_02=0x%04x, size_cm_04=0x%04x, size_cm_08=0x%04x, size_cm_10=0x%04x, size_cm_FF=0x%04x, version=0x%04x\n",
333*4882a593Smuzhiyun 				  __func__, mbox_sts[0], mbox_sts[1],
334*4882a593Smuzhiyun 				  mbox_sts[2], mbox_sts[3], mbox_sts[4],
335*4882a593Smuzhiyun 				  mbox_sts[5], mbox_sts[6], mbox_sts[7]));
336*4882a593Smuzhiyun 		if (ha->fw_dump_tmplt_size == 0)
337*4882a593Smuzhiyun 			status = QLA_ERROR;
338*4882a593Smuzhiyun 	} else {
339*4882a593Smuzhiyun 		ql4_printk(KERN_WARNING, ha,
340*4882a593Smuzhiyun 			   "%s: Error sts[0]=0x%04x, mbx[1]=0x%04x\n",
341*4882a593Smuzhiyun 			   __func__, mbox_sts[0], mbox_sts[1]);
342*4882a593Smuzhiyun 		status = QLA_ERROR;
343*4882a593Smuzhiyun 	}
344*4882a593Smuzhiyun 
345*4882a593Smuzhiyun 	return status;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun 
qla4xxx_mailbox_premature_completion(struct scsi_qla_host * ha)348*4882a593Smuzhiyun void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	set_bit(AF_FW_RECOVERY, &ha->flags);
351*4882a593Smuzhiyun 	ql4_printk(KERN_INFO, ha, "scsi%ld: %s: set FW RECOVERY!\n",
352*4882a593Smuzhiyun 	    ha->host_no, __func__);
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	if (test_bit(AF_MBOX_COMMAND, &ha->flags)) {
355*4882a593Smuzhiyun 		if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags)) {
356*4882a593Smuzhiyun 			complete(&ha->mbx_intr_comp);
357*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw "
358*4882a593Smuzhiyun 			    "recovery, doing premature completion of "
359*4882a593Smuzhiyun 			    "mbx cmd\n", ha->host_no, __func__);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		} else {
362*4882a593Smuzhiyun 			set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
363*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw "
364*4882a593Smuzhiyun 			    "recovery, doing premature completion of "
365*4882a593Smuzhiyun 			    "polling mbx cmd\n", ha->host_no, __func__);
366*4882a593Smuzhiyun 		}
367*4882a593Smuzhiyun 	}
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun static uint8_t
qla4xxx_set_ifcb(struct scsi_qla_host * ha,uint32_t * mbox_cmd,uint32_t * mbox_sts,dma_addr_t init_fw_cb_dma)371*4882a593Smuzhiyun qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
372*4882a593Smuzhiyun 		 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun 	memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
375*4882a593Smuzhiyun 	memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	if (is_qla8022(ha))
378*4882a593Smuzhiyun 		qla4_82xx_wr_32(ha, ha->nx_db_wr_ptr, 0);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
381*4882a593Smuzhiyun 	mbox_cmd[1] = 0;
382*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(init_fw_cb_dma);
383*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(init_fw_cb_dma);
384*4882a593Smuzhiyun 	mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) !=
387*4882a593Smuzhiyun 	    QLA_SUCCESS) {
388*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: "
389*4882a593Smuzhiyun 			      "MBOX_CMD_INITIALIZE_FIRMWARE"
390*4882a593Smuzhiyun 			      " failed w/ status %04X\n",
391*4882a593Smuzhiyun 			      ha->host_no, __func__, mbox_sts[0]));
392*4882a593Smuzhiyun 		return QLA_ERROR;
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 	return QLA_SUCCESS;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun uint8_t
qla4xxx_get_ifcb(struct scsi_qla_host * ha,uint32_t * mbox_cmd,uint32_t * mbox_sts,dma_addr_t init_fw_cb_dma)398*4882a593Smuzhiyun qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
399*4882a593Smuzhiyun 		 uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma)
400*4882a593Smuzhiyun {
401*4882a593Smuzhiyun 	memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
402*4882a593Smuzhiyun 	memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
403*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
404*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(init_fw_cb_dma);
405*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(init_fw_cb_dma);
406*4882a593Smuzhiyun 	mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, 5, 5, mbox_cmd, mbox_sts) !=
409*4882a593Smuzhiyun 	    QLA_SUCCESS) {
410*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: "
411*4882a593Smuzhiyun 			      "MBOX_CMD_GET_INIT_FW_CTRL_BLOCK"
412*4882a593Smuzhiyun 			      " failed w/ status %04X\n",
413*4882a593Smuzhiyun 			      ha->host_no, __func__, mbox_sts[0]));
414*4882a593Smuzhiyun 		return QLA_ERROR;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 	return QLA_SUCCESS;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun 
qla4xxx_set_ipaddr_state(uint8_t fw_ipaddr_state)419*4882a593Smuzhiyun uint8_t qla4xxx_set_ipaddr_state(uint8_t fw_ipaddr_state)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	uint8_t ipaddr_state;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	switch (fw_ipaddr_state) {
424*4882a593Smuzhiyun 	case IP_ADDRSTATE_UNCONFIGURED:
425*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_UNCONFIGURED;
426*4882a593Smuzhiyun 		break;
427*4882a593Smuzhiyun 	case IP_ADDRSTATE_INVALID:
428*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_INVALID;
429*4882a593Smuzhiyun 		break;
430*4882a593Smuzhiyun 	case IP_ADDRSTATE_ACQUIRING:
431*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_ACQUIRING;
432*4882a593Smuzhiyun 		break;
433*4882a593Smuzhiyun 	case IP_ADDRSTATE_TENTATIVE:
434*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_TENTATIVE;
435*4882a593Smuzhiyun 		break;
436*4882a593Smuzhiyun 	case IP_ADDRSTATE_DEPRICATED:
437*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_DEPRECATED;
438*4882a593Smuzhiyun 		break;
439*4882a593Smuzhiyun 	case IP_ADDRSTATE_PREFERRED:
440*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_VALID;
441*4882a593Smuzhiyun 		break;
442*4882a593Smuzhiyun 	case IP_ADDRSTATE_DISABLING:
443*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_DISABLING;
444*4882a593Smuzhiyun 		break;
445*4882a593Smuzhiyun 	default:
446*4882a593Smuzhiyun 		ipaddr_state = ISCSI_IPDDRESS_STATE_UNCONFIGURED;
447*4882a593Smuzhiyun 	}
448*4882a593Smuzhiyun 	return ipaddr_state;
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun static void
qla4xxx_update_local_ip(struct scsi_qla_host * ha,struct addr_ctrl_blk * init_fw_cb)452*4882a593Smuzhiyun qla4xxx_update_local_ip(struct scsi_qla_host *ha,
453*4882a593Smuzhiyun 			struct addr_ctrl_blk *init_fw_cb)
454*4882a593Smuzhiyun {
455*4882a593Smuzhiyun 	ha->ip_config.tcp_options = le16_to_cpu(init_fw_cb->ipv4_tcp_opts);
456*4882a593Smuzhiyun 	ha->ip_config.ipv4_options = le16_to_cpu(init_fw_cb->ipv4_ip_opts);
457*4882a593Smuzhiyun 	ha->ip_config.ipv4_addr_state =
458*4882a593Smuzhiyun 			qla4xxx_set_ipaddr_state(init_fw_cb->ipv4_addr_state);
459*4882a593Smuzhiyun 	ha->ip_config.eth_mtu_size =
460*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->eth_mtu_size);
461*4882a593Smuzhiyun 	ha->ip_config.ipv4_port = le16_to_cpu(init_fw_cb->ipv4_port);
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	if (ha->acb_version == ACB_SUPPORTED) {
464*4882a593Smuzhiyun 		ha->ip_config.ipv6_options = le16_to_cpu(init_fw_cb->ipv6_opts);
465*4882a593Smuzhiyun 		ha->ip_config.ipv6_addl_options =
466*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->ipv6_addtl_opts);
467*4882a593Smuzhiyun 		ha->ip_config.ipv6_tcp_options =
468*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->ipv6_tcp_opts);
469*4882a593Smuzhiyun 	}
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	/* Save IPv4 Address Info */
472*4882a593Smuzhiyun 	memcpy(ha->ip_config.ip_address, init_fw_cb->ipv4_addr,
473*4882a593Smuzhiyun 	       min(sizeof(ha->ip_config.ip_address),
474*4882a593Smuzhiyun 		   sizeof(init_fw_cb->ipv4_addr)));
475*4882a593Smuzhiyun 	memcpy(ha->ip_config.subnet_mask, init_fw_cb->ipv4_subnet,
476*4882a593Smuzhiyun 	       min(sizeof(ha->ip_config.subnet_mask),
477*4882a593Smuzhiyun 		   sizeof(init_fw_cb->ipv4_subnet)));
478*4882a593Smuzhiyun 	memcpy(ha->ip_config.gateway, init_fw_cb->ipv4_gw_addr,
479*4882a593Smuzhiyun 	       min(sizeof(ha->ip_config.gateway),
480*4882a593Smuzhiyun 		   sizeof(init_fw_cb->ipv4_gw_addr)));
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	ha->ip_config.ipv4_vlan_tag = be16_to_cpu(init_fw_cb->ipv4_vlan_tag);
483*4882a593Smuzhiyun 	ha->ip_config.control = init_fw_cb->control;
484*4882a593Smuzhiyun 	ha->ip_config.tcp_wsf = init_fw_cb->ipv4_tcp_wsf;
485*4882a593Smuzhiyun 	ha->ip_config.ipv4_tos = init_fw_cb->ipv4_tos;
486*4882a593Smuzhiyun 	ha->ip_config.ipv4_cache_id = init_fw_cb->ipv4_cacheid;
487*4882a593Smuzhiyun 	ha->ip_config.ipv4_alt_cid_len = init_fw_cb->ipv4_dhcp_alt_cid_len;
488*4882a593Smuzhiyun 	memcpy(ha->ip_config.ipv4_alt_cid, init_fw_cb->ipv4_dhcp_alt_cid,
489*4882a593Smuzhiyun 	       min(sizeof(ha->ip_config.ipv4_alt_cid),
490*4882a593Smuzhiyun 		   sizeof(init_fw_cb->ipv4_dhcp_alt_cid)));
491*4882a593Smuzhiyun 	ha->ip_config.ipv4_vid_len = init_fw_cb->ipv4_dhcp_vid_len;
492*4882a593Smuzhiyun 	memcpy(ha->ip_config.ipv4_vid, init_fw_cb->ipv4_dhcp_vid,
493*4882a593Smuzhiyun 	       min(sizeof(ha->ip_config.ipv4_vid),
494*4882a593Smuzhiyun 		   sizeof(init_fw_cb->ipv4_dhcp_vid)));
495*4882a593Smuzhiyun 	ha->ip_config.ipv4_ttl = init_fw_cb->ipv4_ttl;
496*4882a593Smuzhiyun 	ha->ip_config.def_timeout = le16_to_cpu(init_fw_cb->def_timeout);
497*4882a593Smuzhiyun 	ha->ip_config.abort_timer = init_fw_cb->abort_timer;
498*4882a593Smuzhiyun 	ha->ip_config.iscsi_options = le16_to_cpu(init_fw_cb->iscsi_opts);
499*4882a593Smuzhiyun 	ha->ip_config.iscsi_max_pdu_size =
500*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->iscsi_max_pdu_size);
501*4882a593Smuzhiyun 	ha->ip_config.iscsi_first_burst_len =
502*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->iscsi_fburst_len);
503*4882a593Smuzhiyun 	ha->ip_config.iscsi_max_outstnd_r2t =
504*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->iscsi_max_outstnd_r2t);
505*4882a593Smuzhiyun 	ha->ip_config.iscsi_max_burst_len =
506*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->iscsi_max_burst_len);
507*4882a593Smuzhiyun 	memcpy(ha->ip_config.iscsi_name, init_fw_cb->iscsi_name,
508*4882a593Smuzhiyun 	       min(sizeof(ha->ip_config.iscsi_name),
509*4882a593Smuzhiyun 		   sizeof(init_fw_cb->iscsi_name)));
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	if (is_ipv6_enabled(ha)) {
512*4882a593Smuzhiyun 		/* Save IPv6 Address */
513*4882a593Smuzhiyun 		ha->ip_config.ipv6_link_local_state =
514*4882a593Smuzhiyun 		  qla4xxx_set_ipaddr_state(init_fw_cb->ipv6_lnk_lcl_addr_state);
515*4882a593Smuzhiyun 		ha->ip_config.ipv6_addr0_state =
516*4882a593Smuzhiyun 			qla4xxx_set_ipaddr_state(init_fw_cb->ipv6_addr0_state);
517*4882a593Smuzhiyun 		ha->ip_config.ipv6_addr1_state =
518*4882a593Smuzhiyun 			qla4xxx_set_ipaddr_state(init_fw_cb->ipv6_addr1_state);
519*4882a593Smuzhiyun 
520*4882a593Smuzhiyun 		switch (le16_to_cpu(init_fw_cb->ipv6_dflt_rtr_state)) {
521*4882a593Smuzhiyun 		case IPV6_RTRSTATE_UNKNOWN:
522*4882a593Smuzhiyun 			ha->ip_config.ipv6_default_router_state =
523*4882a593Smuzhiyun 						ISCSI_ROUTER_STATE_UNKNOWN;
524*4882a593Smuzhiyun 			break;
525*4882a593Smuzhiyun 		case IPV6_RTRSTATE_MANUAL:
526*4882a593Smuzhiyun 			ha->ip_config.ipv6_default_router_state =
527*4882a593Smuzhiyun 						ISCSI_ROUTER_STATE_MANUAL;
528*4882a593Smuzhiyun 			break;
529*4882a593Smuzhiyun 		case IPV6_RTRSTATE_ADVERTISED:
530*4882a593Smuzhiyun 			ha->ip_config.ipv6_default_router_state =
531*4882a593Smuzhiyun 						ISCSI_ROUTER_STATE_ADVERTISED;
532*4882a593Smuzhiyun 			break;
533*4882a593Smuzhiyun 		case IPV6_RTRSTATE_STALE:
534*4882a593Smuzhiyun 			ha->ip_config.ipv6_default_router_state =
535*4882a593Smuzhiyun 						ISCSI_ROUTER_STATE_STALE;
536*4882a593Smuzhiyun 			break;
537*4882a593Smuzhiyun 		default:
538*4882a593Smuzhiyun 			ha->ip_config.ipv6_default_router_state =
539*4882a593Smuzhiyun 						ISCSI_ROUTER_STATE_UNKNOWN;
540*4882a593Smuzhiyun 		}
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 		ha->ip_config.ipv6_link_local_addr.in6_u.u6_addr8[0] = 0xFE;
543*4882a593Smuzhiyun 		ha->ip_config.ipv6_link_local_addr.in6_u.u6_addr8[1] = 0x80;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 		memcpy(&ha->ip_config.ipv6_link_local_addr.in6_u.u6_addr8[8],
546*4882a593Smuzhiyun 		       init_fw_cb->ipv6_if_id,
547*4882a593Smuzhiyun 		       min(sizeof(ha->ip_config.ipv6_link_local_addr)/2,
548*4882a593Smuzhiyun 			   sizeof(init_fw_cb->ipv6_if_id)));
549*4882a593Smuzhiyun 		memcpy(&ha->ip_config.ipv6_addr0, init_fw_cb->ipv6_addr0,
550*4882a593Smuzhiyun 		       min(sizeof(ha->ip_config.ipv6_addr0),
551*4882a593Smuzhiyun 			   sizeof(init_fw_cb->ipv6_addr0)));
552*4882a593Smuzhiyun 		memcpy(&ha->ip_config.ipv6_addr1, init_fw_cb->ipv6_addr1,
553*4882a593Smuzhiyun 		       min(sizeof(ha->ip_config.ipv6_addr1),
554*4882a593Smuzhiyun 			   sizeof(init_fw_cb->ipv6_addr1)));
555*4882a593Smuzhiyun 		memcpy(&ha->ip_config.ipv6_default_router_addr,
556*4882a593Smuzhiyun 		       init_fw_cb->ipv6_dflt_rtr_addr,
557*4882a593Smuzhiyun 		       min(sizeof(ha->ip_config.ipv6_default_router_addr),
558*4882a593Smuzhiyun 			   sizeof(init_fw_cb->ipv6_dflt_rtr_addr)));
559*4882a593Smuzhiyun 		ha->ip_config.ipv6_vlan_tag =
560*4882a593Smuzhiyun 				be16_to_cpu(init_fw_cb->ipv6_vlan_tag);
561*4882a593Smuzhiyun 		ha->ip_config.ipv6_port = le16_to_cpu(init_fw_cb->ipv6_port);
562*4882a593Smuzhiyun 		ha->ip_config.ipv6_cache_id = init_fw_cb->ipv6_cache_id;
563*4882a593Smuzhiyun 		ha->ip_config.ipv6_flow_lbl =
564*4882a593Smuzhiyun 				le16_to_cpu(init_fw_cb->ipv6_flow_lbl);
565*4882a593Smuzhiyun 		ha->ip_config.ipv6_traffic_class =
566*4882a593Smuzhiyun 				init_fw_cb->ipv6_traffic_class;
567*4882a593Smuzhiyun 		ha->ip_config.ipv6_hop_limit = init_fw_cb->ipv6_hop_limit;
568*4882a593Smuzhiyun 		ha->ip_config.ipv6_nd_reach_time =
569*4882a593Smuzhiyun 				le32_to_cpu(init_fw_cb->ipv6_nd_reach_time);
570*4882a593Smuzhiyun 		ha->ip_config.ipv6_nd_rexmit_timer =
571*4882a593Smuzhiyun 				le32_to_cpu(init_fw_cb->ipv6_nd_rexmit_timer);
572*4882a593Smuzhiyun 		ha->ip_config.ipv6_nd_stale_timeout =
573*4882a593Smuzhiyun 				le32_to_cpu(init_fw_cb->ipv6_nd_stale_timeout);
574*4882a593Smuzhiyun 		ha->ip_config.ipv6_dup_addr_detect_count =
575*4882a593Smuzhiyun 					init_fw_cb->ipv6_dup_addr_detect_count;
576*4882a593Smuzhiyun 		ha->ip_config.ipv6_gw_advrt_mtu =
577*4882a593Smuzhiyun 				le32_to_cpu(init_fw_cb->ipv6_gw_advrt_mtu);
578*4882a593Smuzhiyun 		ha->ip_config.ipv6_tcp_wsf = init_fw_cb->ipv6_tcp_wsf;
579*4882a593Smuzhiyun 	}
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun 
582*4882a593Smuzhiyun uint8_t
qla4xxx_update_local_ifcb(struct scsi_qla_host * ha,uint32_t * mbox_cmd,uint32_t * mbox_sts,struct addr_ctrl_blk * init_fw_cb,dma_addr_t init_fw_cb_dma)583*4882a593Smuzhiyun qla4xxx_update_local_ifcb(struct scsi_qla_host *ha,
584*4882a593Smuzhiyun 			  uint32_t *mbox_cmd,
585*4882a593Smuzhiyun 			  uint32_t *mbox_sts,
586*4882a593Smuzhiyun 			  struct addr_ctrl_blk  *init_fw_cb,
587*4882a593Smuzhiyun 			  dma_addr_t init_fw_cb_dma)
588*4882a593Smuzhiyun {
589*4882a593Smuzhiyun 	if (qla4xxx_get_ifcb(ha, mbox_cmd, mbox_sts, init_fw_cb_dma)
590*4882a593Smuzhiyun 	    != QLA_SUCCESS) {
591*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING
592*4882a593Smuzhiyun 			      "scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
593*4882a593Smuzhiyun 			      ha->host_no, __func__));
594*4882a593Smuzhiyun 		return QLA_ERROR;
595*4882a593Smuzhiyun 	}
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	DEBUG2(qla4xxx_dump_buffer(init_fw_cb, sizeof(struct addr_ctrl_blk)));
598*4882a593Smuzhiyun 
599*4882a593Smuzhiyun 	/* Save some info in adapter structure. */
600*4882a593Smuzhiyun 	ha->acb_version = init_fw_cb->acb_version;
601*4882a593Smuzhiyun 	ha->firmware_options = le16_to_cpu(init_fw_cb->fw_options);
602*4882a593Smuzhiyun 	ha->heartbeat_interval = init_fw_cb->hb_interval;
603*4882a593Smuzhiyun 	memcpy(ha->name_string, init_fw_cb->iscsi_name,
604*4882a593Smuzhiyun 		min(sizeof(ha->name_string),
605*4882a593Smuzhiyun 		sizeof(init_fw_cb->iscsi_name)));
606*4882a593Smuzhiyun 	ha->def_timeout = le16_to_cpu(init_fw_cb->def_timeout);
607*4882a593Smuzhiyun 	/*memcpy(ha->alias, init_fw_cb->Alias,
608*4882a593Smuzhiyun 	       min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/
609*4882a593Smuzhiyun 
610*4882a593Smuzhiyun 	qla4xxx_update_local_ip(ha, init_fw_cb);
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	return QLA_SUCCESS;
613*4882a593Smuzhiyun }
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun /**
616*4882a593Smuzhiyun  * qla4xxx_initialize_fw_cb - initializes firmware control block.
617*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
618*4882a593Smuzhiyun  **/
qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)619*4882a593Smuzhiyun int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	struct addr_ctrl_blk *init_fw_cb;
622*4882a593Smuzhiyun 	dma_addr_t init_fw_cb_dma;
623*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
624*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
625*4882a593Smuzhiyun 	int status = QLA_ERROR;
626*4882a593Smuzhiyun 
627*4882a593Smuzhiyun 	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
628*4882a593Smuzhiyun 					sizeof(struct addr_ctrl_blk),
629*4882a593Smuzhiyun 					&init_fw_cb_dma, GFP_KERNEL);
630*4882a593Smuzhiyun 	if (init_fw_cb == NULL) {
631*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
632*4882a593Smuzhiyun 			      ha->host_no, __func__));
633*4882a593Smuzhiyun 		goto exit_init_fw_cb_no_free;
634*4882a593Smuzhiyun 	}
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	/* Get Initialize Firmware Control Block. */
637*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
638*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=
641*4882a593Smuzhiyun 	    QLA_SUCCESS) {
642*4882a593Smuzhiyun 		goto exit_init_fw_cb;
643*4882a593Smuzhiyun 	}
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 	/* Fill in the request and response queue information. */
646*4882a593Smuzhiyun 	init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out);
647*4882a593Smuzhiyun 	init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in);
648*4882a593Smuzhiyun 	init_fw_cb->rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
649*4882a593Smuzhiyun 	init_fw_cb->compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
650*4882a593Smuzhiyun 	init_fw_cb->rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma));
651*4882a593Smuzhiyun 	init_fw_cb->rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma));
652*4882a593Smuzhiyun 	init_fw_cb->compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma));
653*4882a593Smuzhiyun 	init_fw_cb->compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma));
654*4882a593Smuzhiyun 	init_fw_cb->shdwreg_addr_lo = cpu_to_le32(LSDW(ha->shadow_regs_dma));
655*4882a593Smuzhiyun 	init_fw_cb->shdwreg_addr_hi = cpu_to_le32(MSDW(ha->shadow_regs_dma));
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun 	/* Set up required options. */
658*4882a593Smuzhiyun 	init_fw_cb->fw_options |=
659*4882a593Smuzhiyun 		__constant_cpu_to_le16(FWOPT_SESSION_MODE |
660*4882a593Smuzhiyun 				       FWOPT_INITIATOR_MODE);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	if (is_qla80XX(ha))
663*4882a593Smuzhiyun 		init_fw_cb->fw_options |=
664*4882a593Smuzhiyun 		    __constant_cpu_to_le16(FWOPT_ENABLE_CRBDB);
665*4882a593Smuzhiyun 
666*4882a593Smuzhiyun 	init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	init_fw_cb->add_fw_options = 0;
669*4882a593Smuzhiyun 	init_fw_cb->add_fw_options |=
670*4882a593Smuzhiyun 			__constant_cpu_to_le16(ADFWOPT_SERIALIZE_TASK_MGMT);
671*4882a593Smuzhiyun 	init_fw_cb->add_fw_options |=
672*4882a593Smuzhiyun 			__constant_cpu_to_le16(ADFWOPT_AUTOCONN_DISABLE);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)
675*4882a593Smuzhiyun 		!= QLA_SUCCESS) {
676*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING
677*4882a593Smuzhiyun 			      "scsi%ld: %s: Failed to set init_fw_ctrl_blk\n",
678*4882a593Smuzhiyun 			      ha->host_no, __func__));
679*4882a593Smuzhiyun 		goto exit_init_fw_cb;
680*4882a593Smuzhiyun 	}
681*4882a593Smuzhiyun 
682*4882a593Smuzhiyun 	if (qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0],
683*4882a593Smuzhiyun 		init_fw_cb, init_fw_cb_dma) != QLA_SUCCESS) {
684*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: Failed to update local ifcb\n",
685*4882a593Smuzhiyun 				ha->host_no, __func__));
686*4882a593Smuzhiyun 		goto exit_init_fw_cb;
687*4882a593Smuzhiyun 	}
688*4882a593Smuzhiyun 	status = QLA_SUCCESS;
689*4882a593Smuzhiyun 
690*4882a593Smuzhiyun exit_init_fw_cb:
691*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
692*4882a593Smuzhiyun 				init_fw_cb, init_fw_cb_dma);
693*4882a593Smuzhiyun exit_init_fw_cb_no_free:
694*4882a593Smuzhiyun 	return status;
695*4882a593Smuzhiyun }
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun /**
698*4882a593Smuzhiyun  * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP
699*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
700*4882a593Smuzhiyun  **/
qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)701*4882a593Smuzhiyun int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
702*4882a593Smuzhiyun {
703*4882a593Smuzhiyun 	struct addr_ctrl_blk *init_fw_cb;
704*4882a593Smuzhiyun 	dma_addr_t init_fw_cb_dma;
705*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
706*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
709*4882a593Smuzhiyun 					sizeof(struct addr_ctrl_blk),
710*4882a593Smuzhiyun 					&init_fw_cb_dma, GFP_KERNEL);
711*4882a593Smuzhiyun 	if (init_fw_cb == NULL) {
712*4882a593Smuzhiyun 		printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
713*4882a593Smuzhiyun 		       __func__);
714*4882a593Smuzhiyun 		return QLA_ERROR;
715*4882a593Smuzhiyun 	}
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	/* Get Initialize Firmware Control Block. */
718*4882a593Smuzhiyun 	if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) !=
719*4882a593Smuzhiyun 	    QLA_SUCCESS) {
720*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
721*4882a593Smuzhiyun 			      ha->host_no, __func__));
722*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev,
723*4882a593Smuzhiyun 				  sizeof(struct addr_ctrl_blk),
724*4882a593Smuzhiyun 				  init_fw_cb, init_fw_cb_dma);
725*4882a593Smuzhiyun 		return QLA_ERROR;
726*4882a593Smuzhiyun 	}
727*4882a593Smuzhiyun 
728*4882a593Smuzhiyun 	/* Save IP Address. */
729*4882a593Smuzhiyun 	qla4xxx_update_local_ip(ha, init_fw_cb);
730*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk),
731*4882a593Smuzhiyun 				init_fw_cb, init_fw_cb_dma);
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	return QLA_SUCCESS;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun /**
737*4882a593Smuzhiyun  * qla4xxx_get_firmware_state - gets firmware state of HBA
738*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
739*4882a593Smuzhiyun  **/
qla4xxx_get_firmware_state(struct scsi_qla_host * ha)740*4882a593Smuzhiyun int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
741*4882a593Smuzhiyun {
742*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
743*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
744*4882a593Smuzhiyun 
745*4882a593Smuzhiyun 	/* Get firmware version */
746*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
747*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_FW_STATE;
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 4, &mbox_cmd[0], &mbox_sts[0]) !=
752*4882a593Smuzhiyun 	    QLA_SUCCESS) {
753*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ "
754*4882a593Smuzhiyun 			      "status %04X\n", ha->host_no, __func__,
755*4882a593Smuzhiyun 			      mbox_sts[0]));
756*4882a593Smuzhiyun 		return QLA_ERROR;
757*4882a593Smuzhiyun 	}
758*4882a593Smuzhiyun 	ha->firmware_state = mbox_sts[1];
759*4882a593Smuzhiyun 	ha->board_id = mbox_sts[2];
760*4882a593Smuzhiyun 	ha->addl_fw_state = mbox_sts[3];
761*4882a593Smuzhiyun 	DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
762*4882a593Smuzhiyun 		      ha->host_no, __func__, ha->firmware_state);)
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	return QLA_SUCCESS;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun /**
768*4882a593Smuzhiyun  * qla4xxx_get_firmware_status - retrieves firmware status
769*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
770*4882a593Smuzhiyun  **/
qla4xxx_get_firmware_status(struct scsi_qla_host * ha)771*4882a593Smuzhiyun int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
774*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	/* Get firmware version */
777*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
778*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
779*4882a593Smuzhiyun 
780*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS;
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) !=
783*4882a593Smuzhiyun 	    QLA_SUCCESS) {
784*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ "
785*4882a593Smuzhiyun 			      "status %04X\n", ha->host_no, __func__,
786*4882a593Smuzhiyun 			      mbox_sts[0]));
787*4882a593Smuzhiyun 		return QLA_ERROR;
788*4882a593Smuzhiyun 	}
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	/* High-water mark of IOCBs */
791*4882a593Smuzhiyun 	ha->iocb_hiwat = mbox_sts[2];
792*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
793*4882a593Smuzhiyun 			  "%s: firmware IOCBs available = %d\n", __func__,
794*4882a593Smuzhiyun 			  ha->iocb_hiwat));
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun 	if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
797*4882a593Smuzhiyun 		ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun 	/* Ideally, we should not enter this code, as the # of firmware
800*4882a593Smuzhiyun 	 * IOCBs is hard-coded in the firmware. We set a default
801*4882a593Smuzhiyun 	 * iocb_hiwat here just in case */
802*4882a593Smuzhiyun 	if (ha->iocb_hiwat == 0) {
803*4882a593Smuzhiyun 		ha->iocb_hiwat = REQUEST_QUEUE_DEPTH / 4;
804*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,
805*4882a593Smuzhiyun 				  "%s: Setting IOCB's to = %d\n", __func__,
806*4882a593Smuzhiyun 				  ha->iocb_hiwat));
807*4882a593Smuzhiyun 	}
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	return QLA_SUCCESS;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun /*
813*4882a593Smuzhiyun  * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry
814*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
815*4882a593Smuzhiyun  * @fw_ddb_index: Firmware's device database index
816*4882a593Smuzhiyun  * @fw_ddb_entry: Pointer to firmware's device database entry structure
817*4882a593Smuzhiyun  * @num_valid_ddb_entries: Pointer to number of valid ddb entries
818*4882a593Smuzhiyun  * @next_ddb_index: Pointer to next valid device database index
819*4882a593Smuzhiyun  * @fw_ddb_device_state: Pointer to device state
820*4882a593Smuzhiyun  **/
qla4xxx_get_fwddb_entry(struct scsi_qla_host * ha,uint16_t fw_ddb_index,struct dev_db_entry * fw_ddb_entry,dma_addr_t fw_ddb_entry_dma,uint32_t * num_valid_ddb_entries,uint32_t * next_ddb_index,uint32_t * fw_ddb_device_state,uint32_t * conn_err_detail,uint16_t * tcp_source_port_num,uint16_t * connection_id)821*4882a593Smuzhiyun int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
822*4882a593Smuzhiyun 			    uint16_t fw_ddb_index,
823*4882a593Smuzhiyun 			    struct dev_db_entry *fw_ddb_entry,
824*4882a593Smuzhiyun 			    dma_addr_t fw_ddb_entry_dma,
825*4882a593Smuzhiyun 			    uint32_t *num_valid_ddb_entries,
826*4882a593Smuzhiyun 			    uint32_t *next_ddb_index,
827*4882a593Smuzhiyun 			    uint32_t *fw_ddb_device_state,
828*4882a593Smuzhiyun 			    uint32_t *conn_err_detail,
829*4882a593Smuzhiyun 			    uint16_t *tcp_source_port_num,
830*4882a593Smuzhiyun 			    uint16_t *connection_id)
831*4882a593Smuzhiyun {
832*4882a593Smuzhiyun 	int status = QLA_ERROR;
833*4882a593Smuzhiyun 	uint16_t options;
834*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
835*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
836*4882a593Smuzhiyun 
837*4882a593Smuzhiyun 	/* Make sure the device index is valid */
838*4882a593Smuzhiyun 	if (fw_ddb_index >= MAX_DDB_ENTRIES) {
839*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: ddb [%d] out of range.\n",
840*4882a593Smuzhiyun 			      ha->host_no, __func__, fw_ddb_index));
841*4882a593Smuzhiyun 		goto exit_get_fwddb;
842*4882a593Smuzhiyun 	}
843*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
844*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
845*4882a593Smuzhiyun 	if (fw_ddb_entry)
846*4882a593Smuzhiyun 		memset(fw_ddb_entry, 0, sizeof(struct dev_db_entry));
847*4882a593Smuzhiyun 
848*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
849*4882a593Smuzhiyun 	mbox_cmd[1] = (uint32_t) fw_ddb_index;
850*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
851*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
852*4882a593Smuzhiyun 	mbox_cmd[4] = sizeof(struct dev_db_entry);
853*4882a593Smuzhiyun 
854*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 7, &mbox_cmd[0], &mbox_sts[0]) ==
855*4882a593Smuzhiyun 	    QLA_ERROR) {
856*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed"
857*4882a593Smuzhiyun 			      " with status 0x%04X\n", ha->host_no, __func__,
858*4882a593Smuzhiyun 			      mbox_sts[0]));
859*4882a593Smuzhiyun 		goto exit_get_fwddb;
860*4882a593Smuzhiyun 	}
861*4882a593Smuzhiyun 	if (fw_ddb_index != mbox_sts[1]) {
862*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: ddb mismatch [%d] != [%d].\n",
863*4882a593Smuzhiyun 			      ha->host_no, __func__, fw_ddb_index,
864*4882a593Smuzhiyun 			      mbox_sts[1]));
865*4882a593Smuzhiyun 		goto exit_get_fwddb;
866*4882a593Smuzhiyun 	}
867*4882a593Smuzhiyun 	if (fw_ddb_entry) {
868*4882a593Smuzhiyun 		options = le16_to_cpu(fw_ddb_entry->options);
869*4882a593Smuzhiyun 		if (options & DDB_OPT_IPV6_DEVICE) {
870*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d "
871*4882a593Smuzhiyun 				"Next %d State %04x ConnErr %08x %pI6 "
872*4882a593Smuzhiyun 				":%04d \"%s\"\n", __func__, fw_ddb_index,
873*4882a593Smuzhiyun 				mbox_sts[0], mbox_sts[2], mbox_sts[3],
874*4882a593Smuzhiyun 				mbox_sts[4], mbox_sts[5],
875*4882a593Smuzhiyun 				fw_ddb_entry->ip_addr,
876*4882a593Smuzhiyun 				le16_to_cpu(fw_ddb_entry->port),
877*4882a593Smuzhiyun 				fw_ddb_entry->iscsi_name);
878*4882a593Smuzhiyun 		} else {
879*4882a593Smuzhiyun 			ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d "
880*4882a593Smuzhiyun 				"Next %d State %04x ConnErr %08x %pI4 "
881*4882a593Smuzhiyun 				":%04d \"%s\"\n", __func__, fw_ddb_index,
882*4882a593Smuzhiyun 				mbox_sts[0], mbox_sts[2], mbox_sts[3],
883*4882a593Smuzhiyun 				mbox_sts[4], mbox_sts[5],
884*4882a593Smuzhiyun 				fw_ddb_entry->ip_addr,
885*4882a593Smuzhiyun 				le16_to_cpu(fw_ddb_entry->port),
886*4882a593Smuzhiyun 				fw_ddb_entry->iscsi_name);
887*4882a593Smuzhiyun 		}
888*4882a593Smuzhiyun 	}
889*4882a593Smuzhiyun 	if (num_valid_ddb_entries)
890*4882a593Smuzhiyun 		*num_valid_ddb_entries = mbox_sts[2];
891*4882a593Smuzhiyun 	if (next_ddb_index)
892*4882a593Smuzhiyun 		*next_ddb_index = mbox_sts[3];
893*4882a593Smuzhiyun 	if (fw_ddb_device_state)
894*4882a593Smuzhiyun 		*fw_ddb_device_state = mbox_sts[4];
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	/*
897*4882a593Smuzhiyun 	 * RA: This mailbox has been changed to pass connection error and
898*4882a593Smuzhiyun 	 * details.  Its true for ISP4010 as per Version E - Not sure when it
899*4882a593Smuzhiyun 	 * was changed.	 Get the time2wait from the fw_dd_entry field :
900*4882a593Smuzhiyun 	 * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY
901*4882a593Smuzhiyun 	 * struct.
902*4882a593Smuzhiyun 	 */
903*4882a593Smuzhiyun 	if (conn_err_detail)
904*4882a593Smuzhiyun 		*conn_err_detail = mbox_sts[5];
905*4882a593Smuzhiyun 	if (tcp_source_port_num)
906*4882a593Smuzhiyun 		*tcp_source_port_num = (uint16_t) (mbox_sts[6] >> 16);
907*4882a593Smuzhiyun 	if (connection_id)
908*4882a593Smuzhiyun 		*connection_id = (uint16_t) mbox_sts[6] & 0x00FF;
909*4882a593Smuzhiyun 	status = QLA_SUCCESS;
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun exit_get_fwddb:
912*4882a593Smuzhiyun 	return status;
913*4882a593Smuzhiyun }
914*4882a593Smuzhiyun 
qla4xxx_conn_open(struct scsi_qla_host * ha,uint16_t fw_ddb_index)915*4882a593Smuzhiyun int qla4xxx_conn_open(struct scsi_qla_host *ha, uint16_t fw_ddb_index)
916*4882a593Smuzhiyun {
917*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
918*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
919*4882a593Smuzhiyun 	int status;
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
922*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_CONN_OPEN;
925*4882a593Smuzhiyun 	mbox_cmd[1] = fw_ddb_index;
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0],
928*4882a593Smuzhiyun 					 &mbox_sts[0]);
929*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
930*4882a593Smuzhiyun 			  "%s: status = %d mbx0 = 0x%x mbx1 = 0x%x\n",
931*4882a593Smuzhiyun 			  __func__, status, mbox_sts[0], mbox_sts[1]));
932*4882a593Smuzhiyun 	return status;
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun 
935*4882a593Smuzhiyun /**
936*4882a593Smuzhiyun  * qla4xxx_set_fwddb_entry - sets a ddb entry.
937*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
938*4882a593Smuzhiyun  * @fw_ddb_index: Firmware's device database index
939*4882a593Smuzhiyun  * @fw_ddb_entry_dma: dma address of ddb entry
940*4882a593Smuzhiyun  * @mbx_sts: mailbox 0 to be returned or NULL
941*4882a593Smuzhiyun  *
942*4882a593Smuzhiyun  * This routine initializes or updates the adapter's device database
943*4882a593Smuzhiyun  * entry for the specified device.
944*4882a593Smuzhiyun  **/
qla4xxx_set_ddb_entry(struct scsi_qla_host * ha,uint16_t fw_ddb_index,dma_addr_t fw_ddb_entry_dma,uint32_t * mbx_sts)945*4882a593Smuzhiyun int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
946*4882a593Smuzhiyun 			  dma_addr_t fw_ddb_entry_dma, uint32_t *mbx_sts)
947*4882a593Smuzhiyun {
948*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
949*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
950*4882a593Smuzhiyun 	int status;
951*4882a593Smuzhiyun 
952*4882a593Smuzhiyun 	/* Do not wait for completion. The firmware will send us an
953*4882a593Smuzhiyun 	 * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
954*4882a593Smuzhiyun 	 */
955*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
956*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY;
959*4882a593Smuzhiyun 	mbox_cmd[1] = (uint32_t) fw_ddb_index;
960*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
961*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
962*4882a593Smuzhiyun 	mbox_cmd[4] = sizeof(struct dev_db_entry);
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
965*4882a593Smuzhiyun 					 &mbox_sts[0]);
966*4882a593Smuzhiyun 	if (mbx_sts)
967*4882a593Smuzhiyun 		*mbx_sts = mbox_sts[0];
968*4882a593Smuzhiyun 	DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n",
969*4882a593Smuzhiyun 	    ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);)
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	return status;
972*4882a593Smuzhiyun }
973*4882a593Smuzhiyun 
qla4xxx_session_logout_ddb(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,int options)974*4882a593Smuzhiyun int qla4xxx_session_logout_ddb(struct scsi_qla_host *ha,
975*4882a593Smuzhiyun 			       struct ddb_entry *ddb_entry, int options)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun 	int status;
978*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
979*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
980*4882a593Smuzhiyun 
981*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
982*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
985*4882a593Smuzhiyun 	mbox_cmd[1] = ddb_entry->fw_ddb_index;
986*4882a593Smuzhiyun 	mbox_cmd[3] = options;
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0],
989*4882a593Smuzhiyun 					 &mbox_sts[0]);
990*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
991*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
992*4882a593Smuzhiyun 				  "%s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
993*4882a593Smuzhiyun 				  "failed sts %04X %04X", __func__,
994*4882a593Smuzhiyun 				  mbox_sts[0], mbox_sts[1]));
995*4882a593Smuzhiyun 		if ((mbox_sts[0] == MBOX_STS_COMMAND_ERROR) &&
996*4882a593Smuzhiyun 		    (mbox_sts[1] == DDB_NOT_LOGGED_IN)) {
997*4882a593Smuzhiyun 			set_bit(DDB_CONN_CLOSE_FAILURE, &ddb_entry->flags);
998*4882a593Smuzhiyun 		}
999*4882a593Smuzhiyun 	}
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	return status;
1002*4882a593Smuzhiyun }
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun /**
1005*4882a593Smuzhiyun  * qla4xxx_get_crash_record - retrieves crash record.
1006*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
1007*4882a593Smuzhiyun  *
1008*4882a593Smuzhiyun  * This routine retrieves a crash record from the QLA4010 after an 8002h aen.
1009*4882a593Smuzhiyun  **/
qla4xxx_get_crash_record(struct scsi_qla_host * ha)1010*4882a593Smuzhiyun void qla4xxx_get_crash_record(struct scsi_qla_host * ha)
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1013*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1014*4882a593Smuzhiyun 	struct crash_record *crash_record = NULL;
1015*4882a593Smuzhiyun 	dma_addr_t crash_record_dma = 0;
1016*4882a593Smuzhiyun 	uint32_t crash_record_size = 0;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1019*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_cmd));
1020*4882a593Smuzhiyun 
1021*4882a593Smuzhiyun 	/* Get size of crash record. */
1022*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
1025*4882a593Smuzhiyun 	    QLA_SUCCESS) {
1026*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n",
1027*4882a593Smuzhiyun 			      ha->host_no, __func__));
1028*4882a593Smuzhiyun 		goto exit_get_crash_record;
1029*4882a593Smuzhiyun 	}
1030*4882a593Smuzhiyun 	crash_record_size = mbox_sts[4];
1031*4882a593Smuzhiyun 	if (crash_record_size == 0) {
1032*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n",
1033*4882a593Smuzhiyun 			      ha->host_no, __func__));
1034*4882a593Smuzhiyun 		goto exit_get_crash_record;
1035*4882a593Smuzhiyun 	}
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 	/* Alloc Memory for Crash Record. */
1038*4882a593Smuzhiyun 	crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size,
1039*4882a593Smuzhiyun 					  &crash_record_dma, GFP_KERNEL);
1040*4882a593Smuzhiyun 	if (crash_record == NULL)
1041*4882a593Smuzhiyun 		goto exit_get_crash_record;
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	/* Get Crash Record. */
1044*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1045*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_cmd));
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
1048*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(crash_record_dma);
1049*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(crash_record_dma);
1050*4882a593Smuzhiyun 	mbox_cmd[4] = crash_record_size;
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
1053*4882a593Smuzhiyun 	    QLA_SUCCESS)
1054*4882a593Smuzhiyun 		goto exit_get_crash_record;
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun 	/* Dump Crash Record. */
1057*4882a593Smuzhiyun 
1058*4882a593Smuzhiyun exit_get_crash_record:
1059*4882a593Smuzhiyun 	if (crash_record)
1060*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, crash_record_size,
1061*4882a593Smuzhiyun 				  crash_record, crash_record_dma);
1062*4882a593Smuzhiyun }
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun /**
1065*4882a593Smuzhiyun  * qla4xxx_get_conn_event_log - retrieves connection event log
1066*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
1067*4882a593Smuzhiyun  **/
qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)1068*4882a593Smuzhiyun void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
1069*4882a593Smuzhiyun {
1070*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1071*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1072*4882a593Smuzhiyun 	struct conn_event_log_entry *event_log = NULL;
1073*4882a593Smuzhiyun 	dma_addr_t event_log_dma = 0;
1074*4882a593Smuzhiyun 	uint32_t event_log_size = 0;
1075*4882a593Smuzhiyun 	uint32_t num_valid_entries;
1076*4882a593Smuzhiyun 	uint32_t      oldest_entry = 0;
1077*4882a593Smuzhiyun 	uint32_t	max_event_log_entries;
1078*4882a593Smuzhiyun 	uint8_t		i;
1079*4882a593Smuzhiyun 
1080*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1081*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_cmd));
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun 	/* Get size of crash record. */
1084*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
1085*4882a593Smuzhiyun 
1086*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
1087*4882a593Smuzhiyun 	    QLA_SUCCESS)
1088*4882a593Smuzhiyun 		goto exit_get_event_log;
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	event_log_size = mbox_sts[4];
1091*4882a593Smuzhiyun 	if (event_log_size == 0)
1092*4882a593Smuzhiyun 		goto exit_get_event_log;
1093*4882a593Smuzhiyun 
1094*4882a593Smuzhiyun 	/* Alloc Memory for Crash Record. */
1095*4882a593Smuzhiyun 	event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size,
1096*4882a593Smuzhiyun 				       &event_log_dma, GFP_KERNEL);
1097*4882a593Smuzhiyun 	if (event_log == NULL)
1098*4882a593Smuzhiyun 		goto exit_get_event_log;
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	/* Get Crash Record. */
1101*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1102*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_cmd));
1103*4882a593Smuzhiyun 
1104*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
1105*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(event_log_dma);
1106*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(event_log_dma);
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) !=
1109*4882a593Smuzhiyun 	    QLA_SUCCESS) {
1110*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event "
1111*4882a593Smuzhiyun 			      "log!\n", ha->host_no, __func__));
1112*4882a593Smuzhiyun 		goto exit_get_event_log;
1113*4882a593Smuzhiyun 	}
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	/* Dump Event Log. */
1116*4882a593Smuzhiyun 	num_valid_entries = mbox_sts[1];
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	max_event_log_entries = event_log_size /
1119*4882a593Smuzhiyun 		sizeof(struct conn_event_log_entry);
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	if (num_valid_entries > max_event_log_entries)
1122*4882a593Smuzhiyun 		oldest_entry = num_valid_entries % max_event_log_entries;
1123*4882a593Smuzhiyun 
1124*4882a593Smuzhiyun 	DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n",
1125*4882a593Smuzhiyun 		      ha->host_no, num_valid_entries));
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 	if (ql4xextended_error_logging == 3) {
1128*4882a593Smuzhiyun 		if (oldest_entry == 0) {
1129*4882a593Smuzhiyun 			/* Circular Buffer has not wrapped around */
1130*4882a593Smuzhiyun 			for (i=0; i < num_valid_entries; i++) {
1131*4882a593Smuzhiyun 				qla4xxx_dump_buffer((uint8_t *)event_log+
1132*4882a593Smuzhiyun 						    (i*sizeof(*event_log)),
1133*4882a593Smuzhiyun 						    sizeof(*event_log));
1134*4882a593Smuzhiyun 			}
1135*4882a593Smuzhiyun 		}
1136*4882a593Smuzhiyun 		else {
1137*4882a593Smuzhiyun 			/* Circular Buffer has wrapped around -
1138*4882a593Smuzhiyun 			 * display accordingly*/
1139*4882a593Smuzhiyun 			for (i=oldest_entry; i < max_event_log_entries; i++) {
1140*4882a593Smuzhiyun 				qla4xxx_dump_buffer((uint8_t *)event_log+
1141*4882a593Smuzhiyun 						    (i*sizeof(*event_log)),
1142*4882a593Smuzhiyun 						    sizeof(*event_log));
1143*4882a593Smuzhiyun 			}
1144*4882a593Smuzhiyun 			for (i=0; i < oldest_entry; i++) {
1145*4882a593Smuzhiyun 				qla4xxx_dump_buffer((uint8_t *)event_log+
1146*4882a593Smuzhiyun 						    (i*sizeof(*event_log)),
1147*4882a593Smuzhiyun 						    sizeof(*event_log));
1148*4882a593Smuzhiyun 			}
1149*4882a593Smuzhiyun 		}
1150*4882a593Smuzhiyun 	}
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun exit_get_event_log:
1153*4882a593Smuzhiyun 	if (event_log)
1154*4882a593Smuzhiyun 		dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
1155*4882a593Smuzhiyun 				  event_log_dma);
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun 
1158*4882a593Smuzhiyun /**
1159*4882a593Smuzhiyun  * qla4xxx_abort_task - issues Abort Task
1160*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
1161*4882a593Smuzhiyun  * @srb: Pointer to srb entry
1162*4882a593Smuzhiyun  *
1163*4882a593Smuzhiyun  * This routine performs a LUN RESET on the specified target/lun.
1164*4882a593Smuzhiyun  * The caller must ensure that the ddb_entry and lun_entry pointers
1165*4882a593Smuzhiyun  * are valid before calling this routine.
1166*4882a593Smuzhiyun  **/
qla4xxx_abort_task(struct scsi_qla_host * ha,struct srb * srb)1167*4882a593Smuzhiyun int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1170*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1171*4882a593Smuzhiyun 	struct scsi_cmnd *cmd = srb->cmd;
1172*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1173*4882a593Smuzhiyun 	unsigned long flags = 0;
1174*4882a593Smuzhiyun 	uint32_t index;
1175*4882a593Smuzhiyun 
1176*4882a593Smuzhiyun 	/*
1177*4882a593Smuzhiyun 	 * Send abort task command to ISP, so that the ISP will return
1178*4882a593Smuzhiyun 	 * request with ABORT status
1179*4882a593Smuzhiyun 	 */
1180*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1181*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->hardware_lock, flags);
1184*4882a593Smuzhiyun 	index = (unsigned long)(unsigned char *)cmd->host_scribble;
1185*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	/* Firmware already posted completion on response queue */
1188*4882a593Smuzhiyun 	if (index == MAX_SRBS)
1189*4882a593Smuzhiyun 		return status;
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_ABORT_TASK;
1192*4882a593Smuzhiyun 	mbox_cmd[1] = srb->ddb->fw_ddb_index;
1193*4882a593Smuzhiyun 	mbox_cmd[2] = index;
1194*4882a593Smuzhiyun 	/* Immediate Command Enable */
1195*4882a593Smuzhiyun 	mbox_cmd[5] = 0x01;
1196*4882a593Smuzhiyun 
1197*4882a593Smuzhiyun 	qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0],
1198*4882a593Smuzhiyun 	    &mbox_sts[0]);
1199*4882a593Smuzhiyun 	if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) {
1200*4882a593Smuzhiyun 		status = QLA_ERROR;
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 		DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%llu: abort task FAILED: "
1203*4882a593Smuzhiyun 		    "mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n",
1204*4882a593Smuzhiyun 		    ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0],
1205*4882a593Smuzhiyun 		    mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4]));
1206*4882a593Smuzhiyun 	}
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	return status;
1209*4882a593Smuzhiyun }
1210*4882a593Smuzhiyun 
1211*4882a593Smuzhiyun /**
1212*4882a593Smuzhiyun  * qla4xxx_reset_lun - issues LUN Reset
1213*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
1214*4882a593Smuzhiyun  * @ddb_entry: Pointer to device database entry
1215*4882a593Smuzhiyun  * @lun: lun number
1216*4882a593Smuzhiyun  *
1217*4882a593Smuzhiyun  * This routine performs a LUN RESET on the specified target/lun.
1218*4882a593Smuzhiyun  * The caller must ensure that the ddb_entry and lun_entry pointers
1219*4882a593Smuzhiyun  * are valid before calling this routine.
1220*4882a593Smuzhiyun  **/
qla4xxx_reset_lun(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,uint64_t lun)1221*4882a593Smuzhiyun int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
1222*4882a593Smuzhiyun 		      uint64_t lun)
1223*4882a593Smuzhiyun {
1224*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1225*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1226*4882a593Smuzhiyun 	uint32_t scsi_lun[2];
1227*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1228*4882a593Smuzhiyun 
1229*4882a593Smuzhiyun 	DEBUG2(printk("scsi%ld:%d:%llu: lun reset issued\n", ha->host_no,
1230*4882a593Smuzhiyun 		      ddb_entry->fw_ddb_index, lun));
1231*4882a593Smuzhiyun 
1232*4882a593Smuzhiyun 	/*
1233*4882a593Smuzhiyun 	 * Send lun reset command to ISP, so that the ISP will return all
1234*4882a593Smuzhiyun 	 * outstanding requests with RESET status
1235*4882a593Smuzhiyun 	 */
1236*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1237*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1238*4882a593Smuzhiyun 	int_to_scsilun(lun, (struct scsi_lun *) scsi_lun);
1239*4882a593Smuzhiyun 
1240*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_LUN_RESET;
1241*4882a593Smuzhiyun 	mbox_cmd[1] = ddb_entry->fw_ddb_index;
1242*4882a593Smuzhiyun 	/* FW expects LUN bytes 0-3 in Incoming Mailbox 2
1243*4882a593Smuzhiyun 	 * (LUN byte 0 is LSByte, byte 3 is MSByte) */
1244*4882a593Smuzhiyun 	mbox_cmd[2] = cpu_to_le32(scsi_lun[0]);
1245*4882a593Smuzhiyun 	/* FW expects LUN bytes 4-7 in Incoming Mailbox 3
1246*4882a593Smuzhiyun 	 * (LUN byte 4 is LSByte, byte 7 is MSByte) */
1247*4882a593Smuzhiyun 	mbox_cmd[3] = cpu_to_le32(scsi_lun[1]);
1248*4882a593Smuzhiyun 	mbox_cmd[5] = 0x01;	/* Immediate Command Enable */
1249*4882a593Smuzhiyun 
1250*4882a593Smuzhiyun 	qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]);
1251*4882a593Smuzhiyun 	if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
1252*4882a593Smuzhiyun 	    mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
1253*4882a593Smuzhiyun 		status = QLA_ERROR;
1254*4882a593Smuzhiyun 
1255*4882a593Smuzhiyun 	return status;
1256*4882a593Smuzhiyun }
1257*4882a593Smuzhiyun 
1258*4882a593Smuzhiyun /**
1259*4882a593Smuzhiyun  * qla4xxx_reset_target - issues target Reset
1260*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
1261*4882a593Smuzhiyun  * @ddb_entry: Pointer to device database entry
1262*4882a593Smuzhiyun  *
1263*4882a593Smuzhiyun  * This routine performs a TARGET RESET on the specified target.
1264*4882a593Smuzhiyun  * The caller must ensure that the ddb_entry pointers
1265*4882a593Smuzhiyun  * are valid before calling this routine.
1266*4882a593Smuzhiyun  **/
qla4xxx_reset_target(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry)1267*4882a593Smuzhiyun int qla4xxx_reset_target(struct scsi_qla_host *ha,
1268*4882a593Smuzhiyun 			 struct ddb_entry *ddb_entry)
1269*4882a593Smuzhiyun {
1270*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1271*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1272*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun 	DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no,
1275*4882a593Smuzhiyun 		      ddb_entry->fw_ddb_index));
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	/*
1278*4882a593Smuzhiyun 	 * Send target reset command to ISP, so that the ISP will return all
1279*4882a593Smuzhiyun 	 * outstanding requests with RESET status
1280*4882a593Smuzhiyun 	 */
1281*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1282*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET;
1285*4882a593Smuzhiyun 	mbox_cmd[1] = ddb_entry->fw_ddb_index;
1286*4882a593Smuzhiyun 	mbox_cmd[5] = 0x01;	/* Immediate Command Enable */
1287*4882a593Smuzhiyun 
1288*4882a593Smuzhiyun 	qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
1289*4882a593Smuzhiyun 				&mbox_sts[0]);
1290*4882a593Smuzhiyun 	if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
1291*4882a593Smuzhiyun 	    mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
1292*4882a593Smuzhiyun 		status = QLA_ERROR;
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	return status;
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun 
qla4xxx_get_flash(struct scsi_qla_host * ha,dma_addr_t dma_addr,uint32_t offset,uint32_t len)1297*4882a593Smuzhiyun int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
1298*4882a593Smuzhiyun 		      uint32_t offset, uint32_t len)
1299*4882a593Smuzhiyun {
1300*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1301*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1304*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1305*4882a593Smuzhiyun 
1306*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_READ_FLASH;
1307*4882a593Smuzhiyun 	mbox_cmd[1] = LSDW(dma_addr);
1308*4882a593Smuzhiyun 	mbox_cmd[2] = MSDW(dma_addr);
1309*4882a593Smuzhiyun 	mbox_cmd[3] = offset;
1310*4882a593Smuzhiyun 	mbox_cmd[4] = len;
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) !=
1313*4882a593Smuzhiyun 	    QLA_SUCCESS) {
1314*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ "
1315*4882a593Smuzhiyun 		    "status %04X %04X, offset %08x, len %08x\n", ha->host_no,
1316*4882a593Smuzhiyun 		    __func__, mbox_sts[0], mbox_sts[1], offset, len));
1317*4882a593Smuzhiyun 		return QLA_ERROR;
1318*4882a593Smuzhiyun 	}
1319*4882a593Smuzhiyun 	return QLA_SUCCESS;
1320*4882a593Smuzhiyun }
1321*4882a593Smuzhiyun 
1322*4882a593Smuzhiyun /**
1323*4882a593Smuzhiyun  * qla4xxx_about_firmware - gets FW, iscsi draft and boot loader version
1324*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
1325*4882a593Smuzhiyun  *
1326*4882a593Smuzhiyun  * Retrieves the FW version, iSCSI draft version & bootloader version of HBA.
1327*4882a593Smuzhiyun  * Mailboxes 2 & 3 may hold an address for data. Make sure that we write 0 to
1328*4882a593Smuzhiyun  * those mailboxes, if unused.
1329*4882a593Smuzhiyun  **/
qla4xxx_about_firmware(struct scsi_qla_host * ha)1330*4882a593Smuzhiyun int qla4xxx_about_firmware(struct scsi_qla_host *ha)
1331*4882a593Smuzhiyun {
1332*4882a593Smuzhiyun 	struct about_fw_info *about_fw = NULL;
1333*4882a593Smuzhiyun 	dma_addr_t about_fw_dma;
1334*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1335*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1336*4882a593Smuzhiyun 	int status = QLA_ERROR;
1337*4882a593Smuzhiyun 
1338*4882a593Smuzhiyun 	about_fw = dma_alloc_coherent(&ha->pdev->dev,
1339*4882a593Smuzhiyun 				      sizeof(struct about_fw_info),
1340*4882a593Smuzhiyun 				      &about_fw_dma, GFP_KERNEL);
1341*4882a593Smuzhiyun 	if (!about_fw) {
1342*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Unable to alloc memory "
1343*4882a593Smuzhiyun 				  "for about_fw\n", __func__));
1344*4882a593Smuzhiyun 		return status;
1345*4882a593Smuzhiyun 	}
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1348*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1349*4882a593Smuzhiyun 
1350*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
1351*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(about_fw_dma);
1352*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(about_fw_dma);
1353*4882a593Smuzhiyun 	mbox_cmd[4] = sizeof(struct about_fw_info);
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
1356*4882a593Smuzhiyun 					 &mbox_cmd[0], &mbox_sts[0]);
1357*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1358*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_ABOUT_FW "
1359*4882a593Smuzhiyun 				  "failed w/ status %04X\n", __func__,
1360*4882a593Smuzhiyun 				  mbox_sts[0]));
1361*4882a593Smuzhiyun 		goto exit_about_fw;
1362*4882a593Smuzhiyun 	}
1363*4882a593Smuzhiyun 
1364*4882a593Smuzhiyun 	/* Save version information. */
1365*4882a593Smuzhiyun 	ha->fw_info.fw_major = le16_to_cpu(about_fw->fw_major);
1366*4882a593Smuzhiyun 	ha->fw_info.fw_minor = le16_to_cpu(about_fw->fw_minor);
1367*4882a593Smuzhiyun 	ha->fw_info.fw_patch = le16_to_cpu(about_fw->fw_patch);
1368*4882a593Smuzhiyun 	ha->fw_info.fw_build = le16_to_cpu(about_fw->fw_build);
1369*4882a593Smuzhiyun 	memcpy(ha->fw_info.fw_build_date, about_fw->fw_build_date,
1370*4882a593Smuzhiyun 	       sizeof(about_fw->fw_build_date));
1371*4882a593Smuzhiyun 	memcpy(ha->fw_info.fw_build_time, about_fw->fw_build_time,
1372*4882a593Smuzhiyun 	       sizeof(about_fw->fw_build_time));
1373*4882a593Smuzhiyun 	strcpy((char *)ha->fw_info.fw_build_user,
1374*4882a593Smuzhiyun 	       skip_spaces((char *)about_fw->fw_build_user));
1375*4882a593Smuzhiyun 	ha->fw_info.fw_load_source = le16_to_cpu(about_fw->fw_load_source);
1376*4882a593Smuzhiyun 	ha->fw_info.iscsi_major = le16_to_cpu(about_fw->iscsi_major);
1377*4882a593Smuzhiyun 	ha->fw_info.iscsi_minor = le16_to_cpu(about_fw->iscsi_minor);
1378*4882a593Smuzhiyun 	ha->fw_info.bootload_major = le16_to_cpu(about_fw->bootload_major);
1379*4882a593Smuzhiyun 	ha->fw_info.bootload_minor = le16_to_cpu(about_fw->bootload_minor);
1380*4882a593Smuzhiyun 	ha->fw_info.bootload_patch = le16_to_cpu(about_fw->bootload_patch);
1381*4882a593Smuzhiyun 	ha->fw_info.bootload_build = le16_to_cpu(about_fw->bootload_build);
1382*4882a593Smuzhiyun 	strcpy((char *)ha->fw_info.extended_timestamp,
1383*4882a593Smuzhiyun 	       skip_spaces((char *)about_fw->extended_timestamp));
1384*4882a593Smuzhiyun 
1385*4882a593Smuzhiyun 	ha->fw_uptime_secs = le32_to_cpu(mbox_sts[5]);
1386*4882a593Smuzhiyun 	ha->fw_uptime_msecs = le32_to_cpu(mbox_sts[6]);
1387*4882a593Smuzhiyun 	status = QLA_SUCCESS;
1388*4882a593Smuzhiyun 
1389*4882a593Smuzhiyun exit_about_fw:
1390*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(struct about_fw_info),
1391*4882a593Smuzhiyun 			  about_fw, about_fw_dma);
1392*4882a593Smuzhiyun 	return status;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun 
qla4xxx_get_default_ddb(struct scsi_qla_host * ha,uint32_t options,dma_addr_t dma_addr)1395*4882a593Smuzhiyun int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options,
1396*4882a593Smuzhiyun 			    dma_addr_t dma_addr)
1397*4882a593Smuzhiyun {
1398*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1399*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1400*4882a593Smuzhiyun 
1401*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1402*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1403*4882a593Smuzhiyun 
1404*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS;
1405*4882a593Smuzhiyun 	mbox_cmd[1] = options;
1406*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(dma_addr);
1407*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(dma_addr);
1408*4882a593Smuzhiyun 
1409*4882a593Smuzhiyun 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) !=
1410*4882a593Smuzhiyun 	    QLA_SUCCESS) {
1411*4882a593Smuzhiyun 		DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
1412*4882a593Smuzhiyun 		     ha->host_no, __func__, mbox_sts[0]));
1413*4882a593Smuzhiyun 		return QLA_ERROR;
1414*4882a593Smuzhiyun 	}
1415*4882a593Smuzhiyun 	return QLA_SUCCESS;
1416*4882a593Smuzhiyun }
1417*4882a593Smuzhiyun 
qla4xxx_req_ddb_entry(struct scsi_qla_host * ha,uint32_t ddb_index,uint32_t * mbx_sts)1418*4882a593Smuzhiyun int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index,
1419*4882a593Smuzhiyun 			  uint32_t *mbx_sts)
1420*4882a593Smuzhiyun {
1421*4882a593Smuzhiyun 	int status;
1422*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1423*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1424*4882a593Smuzhiyun 
1425*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1426*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1427*4882a593Smuzhiyun 
1428*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY;
1429*4882a593Smuzhiyun 	mbox_cmd[1] = ddb_index;
1430*4882a593Smuzhiyun 
1431*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
1432*4882a593Smuzhiyun 					 &mbox_sts[0]);
1433*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1434*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n",
1435*4882a593Smuzhiyun 				   __func__, mbox_sts[0]));
1436*4882a593Smuzhiyun 	}
1437*4882a593Smuzhiyun 
1438*4882a593Smuzhiyun 	*mbx_sts = mbox_sts[0];
1439*4882a593Smuzhiyun 	return status;
1440*4882a593Smuzhiyun }
1441*4882a593Smuzhiyun 
qla4xxx_clear_ddb_entry(struct scsi_qla_host * ha,uint32_t ddb_index)1442*4882a593Smuzhiyun int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index)
1443*4882a593Smuzhiyun {
1444*4882a593Smuzhiyun 	int status;
1445*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1446*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1449*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1450*4882a593Smuzhiyun 
1451*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
1452*4882a593Smuzhiyun 	mbox_cmd[1] = ddb_index;
1453*4882a593Smuzhiyun 
1454*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 2, 1, &mbox_cmd[0],
1455*4882a593Smuzhiyun 					 &mbox_sts[0]);
1456*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1457*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n",
1458*4882a593Smuzhiyun 				   __func__, mbox_sts[0]));
1459*4882a593Smuzhiyun 	}
1460*4882a593Smuzhiyun 
1461*4882a593Smuzhiyun 	return status;
1462*4882a593Smuzhiyun }
1463*4882a593Smuzhiyun 
qla4xxx_set_flash(struct scsi_qla_host * ha,dma_addr_t dma_addr,uint32_t offset,uint32_t length,uint32_t options)1464*4882a593Smuzhiyun int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr,
1465*4882a593Smuzhiyun 		      uint32_t offset, uint32_t length, uint32_t options)
1466*4882a593Smuzhiyun {
1467*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1468*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1469*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1470*4882a593Smuzhiyun 
1471*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1472*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1473*4882a593Smuzhiyun 
1474*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_WRITE_FLASH;
1475*4882a593Smuzhiyun 	mbox_cmd[1] = LSDW(dma_addr);
1476*4882a593Smuzhiyun 	mbox_cmd[2] = MSDW(dma_addr);
1477*4882a593Smuzhiyun 	mbox_cmd[3] = offset;
1478*4882a593Smuzhiyun 	mbox_cmd[4] = length;
1479*4882a593Smuzhiyun 	mbox_cmd[5] = options;
1480*4882a593Smuzhiyun 
1481*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 6, 2, &mbox_cmd[0], &mbox_sts[0]);
1482*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1483*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_WRITE_FLASH "
1484*4882a593Smuzhiyun 				  "failed w/ status %04X, mbx1 %04X\n",
1485*4882a593Smuzhiyun 				  __func__, mbox_sts[0], mbox_sts[1]));
1486*4882a593Smuzhiyun 	}
1487*4882a593Smuzhiyun 	return status;
1488*4882a593Smuzhiyun }
1489*4882a593Smuzhiyun 
qla4xxx_bootdb_by_index(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,dma_addr_t fw_ddb_entry_dma,uint16_t ddb_index)1490*4882a593Smuzhiyun int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha,
1491*4882a593Smuzhiyun 			    struct dev_db_entry *fw_ddb_entry,
1492*4882a593Smuzhiyun 			    dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index)
1493*4882a593Smuzhiyun {
1494*4882a593Smuzhiyun 	uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO;
1495*4882a593Smuzhiyun 	uint32_t dev_db_end_offset;
1496*4882a593Smuzhiyun 	int status = QLA_ERROR;
1497*4882a593Smuzhiyun 
1498*4882a593Smuzhiyun 	memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
1499*4882a593Smuzhiyun 
1500*4882a593Smuzhiyun 	dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry));
1501*4882a593Smuzhiyun 	dev_db_end_offset = FLASH_OFFSET_DB_END;
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	if (dev_db_start_offset > dev_db_end_offset) {
1504*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
1505*4882a593Smuzhiyun 				  "%s:Invalid DDB index %d", __func__,
1506*4882a593Smuzhiyun 				  ddb_index));
1507*4882a593Smuzhiyun 		goto exit_bootdb_failed;
1508*4882a593Smuzhiyun 	}
1509*4882a593Smuzhiyun 
1510*4882a593Smuzhiyun 	if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
1511*4882a593Smuzhiyun 			      sizeof(*fw_ddb_entry)) != QLA_SUCCESS) {
1512*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash"
1513*4882a593Smuzhiyun 			   "failed\n", ha->host_no, __func__);
1514*4882a593Smuzhiyun 		goto exit_bootdb_failed;
1515*4882a593Smuzhiyun 	}
1516*4882a593Smuzhiyun 
1517*4882a593Smuzhiyun 	if (fw_ddb_entry->cookie == DDB_VALID_COOKIE)
1518*4882a593Smuzhiyun 		status = QLA_SUCCESS;
1519*4882a593Smuzhiyun 
1520*4882a593Smuzhiyun exit_bootdb_failed:
1521*4882a593Smuzhiyun 	return status;
1522*4882a593Smuzhiyun }
1523*4882a593Smuzhiyun 
qla4xxx_flashdb_by_index(struct scsi_qla_host * ha,struct dev_db_entry * fw_ddb_entry,dma_addr_t fw_ddb_entry_dma,uint16_t ddb_index)1524*4882a593Smuzhiyun int qla4xxx_flashdb_by_index(struct scsi_qla_host *ha,
1525*4882a593Smuzhiyun 			     struct dev_db_entry *fw_ddb_entry,
1526*4882a593Smuzhiyun 			     dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index)
1527*4882a593Smuzhiyun {
1528*4882a593Smuzhiyun 	uint32_t dev_db_start_offset;
1529*4882a593Smuzhiyun 	uint32_t dev_db_end_offset;
1530*4882a593Smuzhiyun 	int status = QLA_ERROR;
1531*4882a593Smuzhiyun 
1532*4882a593Smuzhiyun 	memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry));
1533*4882a593Smuzhiyun 
1534*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
1535*4882a593Smuzhiyun 		dev_db_start_offset = FLASH_OFFSET_DB_INFO;
1536*4882a593Smuzhiyun 		dev_db_end_offset = FLASH_OFFSET_DB_END;
1537*4882a593Smuzhiyun 	} else {
1538*4882a593Smuzhiyun 		dev_db_start_offset = FLASH_RAW_ACCESS_ADDR +
1539*4882a593Smuzhiyun 				      (ha->hw.flt_region_ddb << 2);
1540*4882a593Smuzhiyun 		/* flt_ddb_size is DDB table size for both ports
1541*4882a593Smuzhiyun 		 * so divide it by 2 to calculate the offset for second port
1542*4882a593Smuzhiyun 		 */
1543*4882a593Smuzhiyun 		if (ha->port_num == 1)
1544*4882a593Smuzhiyun 			dev_db_start_offset += (ha->hw.flt_ddb_size / 2);
1545*4882a593Smuzhiyun 
1546*4882a593Smuzhiyun 		dev_db_end_offset = dev_db_start_offset +
1547*4882a593Smuzhiyun 				    (ha->hw.flt_ddb_size / 2);
1548*4882a593Smuzhiyun 	}
1549*4882a593Smuzhiyun 
1550*4882a593Smuzhiyun 	dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry));
1551*4882a593Smuzhiyun 
1552*4882a593Smuzhiyun 	if (dev_db_start_offset > dev_db_end_offset) {
1553*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
1554*4882a593Smuzhiyun 				  "%s:Invalid DDB index %d", __func__,
1555*4882a593Smuzhiyun 				  ddb_index));
1556*4882a593Smuzhiyun 		goto exit_fdb_failed;
1557*4882a593Smuzhiyun 	}
1558*4882a593Smuzhiyun 
1559*4882a593Smuzhiyun 	if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset,
1560*4882a593Smuzhiyun 			      sizeof(*fw_ddb_entry)) != QLA_SUCCESS) {
1561*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash failed\n",
1562*4882a593Smuzhiyun 			   ha->host_no, __func__);
1563*4882a593Smuzhiyun 		goto exit_fdb_failed;
1564*4882a593Smuzhiyun 	}
1565*4882a593Smuzhiyun 
1566*4882a593Smuzhiyun 	if (fw_ddb_entry->cookie == DDB_VALID_COOKIE)
1567*4882a593Smuzhiyun 		status = QLA_SUCCESS;
1568*4882a593Smuzhiyun 
1569*4882a593Smuzhiyun exit_fdb_failed:
1570*4882a593Smuzhiyun 	return status;
1571*4882a593Smuzhiyun }
1572*4882a593Smuzhiyun 
qla4xxx_get_chap(struct scsi_qla_host * ha,char * username,char * password,uint16_t idx)1573*4882a593Smuzhiyun int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password,
1574*4882a593Smuzhiyun 		     uint16_t idx)
1575*4882a593Smuzhiyun {
1576*4882a593Smuzhiyun 	int ret = 0;
1577*4882a593Smuzhiyun 	int rval = QLA_ERROR;
1578*4882a593Smuzhiyun 	uint32_t offset = 0, chap_size;
1579*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table;
1580*4882a593Smuzhiyun 	dma_addr_t chap_dma;
1581*4882a593Smuzhiyun 
1582*4882a593Smuzhiyun 	chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
1583*4882a593Smuzhiyun 	if (chap_table == NULL)
1584*4882a593Smuzhiyun 		return -ENOMEM;
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	chap_size = sizeof(struct ql4_chap_table);
1587*4882a593Smuzhiyun 
1588*4882a593Smuzhiyun 	if (is_qla40XX(ha))
1589*4882a593Smuzhiyun 		offset = FLASH_CHAP_OFFSET | (idx * chap_size);
1590*4882a593Smuzhiyun 	else {
1591*4882a593Smuzhiyun 		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
1592*4882a593Smuzhiyun 		/* flt_chap_size is CHAP table size for both ports
1593*4882a593Smuzhiyun 		 * so divide it by 2 to calculate the offset for second port
1594*4882a593Smuzhiyun 		 */
1595*4882a593Smuzhiyun 		if (ha->port_num == 1)
1596*4882a593Smuzhiyun 			offset += (ha->hw.flt_chap_size / 2);
1597*4882a593Smuzhiyun 		offset += (idx * chap_size);
1598*4882a593Smuzhiyun 	}
1599*4882a593Smuzhiyun 
1600*4882a593Smuzhiyun 	rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size);
1601*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS) {
1602*4882a593Smuzhiyun 		ret = -EINVAL;
1603*4882a593Smuzhiyun 		goto exit_get_chap;
1604*4882a593Smuzhiyun 	}
1605*4882a593Smuzhiyun 
1606*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n",
1607*4882a593Smuzhiyun 		__le16_to_cpu(chap_table->cookie)));
1608*4882a593Smuzhiyun 
1609*4882a593Smuzhiyun 	if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) {
1610*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "No valid chap entry found\n");
1611*4882a593Smuzhiyun 		goto exit_get_chap;
1612*4882a593Smuzhiyun 	}
1613*4882a593Smuzhiyun 
1614*4882a593Smuzhiyun 	strlcpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN);
1615*4882a593Smuzhiyun 	strlcpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN);
1616*4882a593Smuzhiyun 	chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
1617*4882a593Smuzhiyun 
1618*4882a593Smuzhiyun exit_get_chap:
1619*4882a593Smuzhiyun 	dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
1620*4882a593Smuzhiyun 	return ret;
1621*4882a593Smuzhiyun }
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun /**
1624*4882a593Smuzhiyun  * qla4xxx_set_chap - Make a chap entry at the given index
1625*4882a593Smuzhiyun  * @ha: pointer to adapter structure
1626*4882a593Smuzhiyun  * @username: CHAP username to set
1627*4882a593Smuzhiyun  * @password: CHAP password to set
1628*4882a593Smuzhiyun  * @idx: CHAP index at which to make the entry
1629*4882a593Smuzhiyun  * @bidi: type of chap entry (chap_in or chap_out)
1630*4882a593Smuzhiyun  *
1631*4882a593Smuzhiyun  * Create chap entry at the given index with the information provided.
1632*4882a593Smuzhiyun  *
1633*4882a593Smuzhiyun  * Note: Caller should acquire the chap lock before getting here.
1634*4882a593Smuzhiyun  **/
qla4xxx_set_chap(struct scsi_qla_host * ha,char * username,char * password,uint16_t idx,int bidi)1635*4882a593Smuzhiyun int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, char *password,
1636*4882a593Smuzhiyun 		     uint16_t idx, int bidi)
1637*4882a593Smuzhiyun {
1638*4882a593Smuzhiyun 	int ret = 0;
1639*4882a593Smuzhiyun 	int rval = QLA_ERROR;
1640*4882a593Smuzhiyun 	uint32_t offset = 0;
1641*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table;
1642*4882a593Smuzhiyun 	uint32_t chap_size = 0;
1643*4882a593Smuzhiyun 	dma_addr_t chap_dma;
1644*4882a593Smuzhiyun 
1645*4882a593Smuzhiyun 	chap_table = dma_pool_zalloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma);
1646*4882a593Smuzhiyun 	if (chap_table == NULL) {
1647*4882a593Smuzhiyun 		ret =  -ENOMEM;
1648*4882a593Smuzhiyun 		goto exit_set_chap;
1649*4882a593Smuzhiyun 	}
1650*4882a593Smuzhiyun 
1651*4882a593Smuzhiyun 	if (bidi)
1652*4882a593Smuzhiyun 		chap_table->flags |= BIT_6; /* peer */
1653*4882a593Smuzhiyun 	else
1654*4882a593Smuzhiyun 		chap_table->flags |= BIT_7; /* local */
1655*4882a593Smuzhiyun 	chap_table->secret_len = strlen(password);
1656*4882a593Smuzhiyun 	strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN - 1);
1657*4882a593Smuzhiyun 	strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN - 1);
1658*4882a593Smuzhiyun 	chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE);
1659*4882a593Smuzhiyun 
1660*4882a593Smuzhiyun 	if (is_qla40XX(ha)) {
1661*4882a593Smuzhiyun 		chap_size = MAX_CHAP_ENTRIES_40XX * sizeof(*chap_table);
1662*4882a593Smuzhiyun 		offset = FLASH_CHAP_OFFSET;
1663*4882a593Smuzhiyun 	} else { /* Single region contains CHAP info for both ports which is
1664*4882a593Smuzhiyun 		  * divided into half for each port.
1665*4882a593Smuzhiyun 		  */
1666*4882a593Smuzhiyun 		chap_size = ha->hw.flt_chap_size / 2;
1667*4882a593Smuzhiyun 		offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2);
1668*4882a593Smuzhiyun 		if (ha->port_num == 1)
1669*4882a593Smuzhiyun 			offset += chap_size;
1670*4882a593Smuzhiyun 	}
1671*4882a593Smuzhiyun 
1672*4882a593Smuzhiyun 	offset += (idx * sizeof(struct ql4_chap_table));
1673*4882a593Smuzhiyun 	rval = qla4xxx_set_flash(ha, chap_dma, offset,
1674*4882a593Smuzhiyun 				sizeof(struct ql4_chap_table),
1675*4882a593Smuzhiyun 				FLASH_OPT_RMW_COMMIT);
1676*4882a593Smuzhiyun 
1677*4882a593Smuzhiyun 	if (rval == QLA_SUCCESS && ha->chap_list) {
1678*4882a593Smuzhiyun 		/* Update ha chap_list cache */
1679*4882a593Smuzhiyun 		memcpy((struct ql4_chap_table *)ha->chap_list + idx,
1680*4882a593Smuzhiyun 		       chap_table, sizeof(struct ql4_chap_table));
1681*4882a593Smuzhiyun 	}
1682*4882a593Smuzhiyun 	dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma);
1683*4882a593Smuzhiyun 	if (rval != QLA_SUCCESS)
1684*4882a593Smuzhiyun 		ret =  -EINVAL;
1685*4882a593Smuzhiyun 
1686*4882a593Smuzhiyun exit_set_chap:
1687*4882a593Smuzhiyun 	return ret;
1688*4882a593Smuzhiyun }
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun 
qla4xxx_get_uni_chap_at_index(struct scsi_qla_host * ha,char * username,char * password,uint16_t chap_index)1691*4882a593Smuzhiyun int qla4xxx_get_uni_chap_at_index(struct scsi_qla_host *ha, char *username,
1692*4882a593Smuzhiyun 				  char *password, uint16_t chap_index)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun 	int rval = QLA_ERROR;
1695*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table = NULL;
1696*4882a593Smuzhiyun 	int max_chap_entries;
1697*4882a593Smuzhiyun 
1698*4882a593Smuzhiyun 	if (!ha->chap_list) {
1699*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
1700*4882a593Smuzhiyun 		rval = QLA_ERROR;
1701*4882a593Smuzhiyun 		goto exit_uni_chap;
1702*4882a593Smuzhiyun 	}
1703*4882a593Smuzhiyun 
1704*4882a593Smuzhiyun 	if (!username || !password) {
1705*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "No memory for username & secret\n");
1706*4882a593Smuzhiyun 		rval = QLA_ERROR;
1707*4882a593Smuzhiyun 		goto exit_uni_chap;
1708*4882a593Smuzhiyun 	}
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun 	if (is_qla80XX(ha))
1711*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
1712*4882a593Smuzhiyun 				   sizeof(struct ql4_chap_table);
1713*4882a593Smuzhiyun 	else
1714*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
1715*4882a593Smuzhiyun 
1716*4882a593Smuzhiyun 	if (chap_index > max_chap_entries) {
1717*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Invalid Chap index\n");
1718*4882a593Smuzhiyun 		rval = QLA_ERROR;
1719*4882a593Smuzhiyun 		goto exit_uni_chap;
1720*4882a593Smuzhiyun 	}
1721*4882a593Smuzhiyun 
1722*4882a593Smuzhiyun 	mutex_lock(&ha->chap_sem);
1723*4882a593Smuzhiyun 	chap_table = (struct ql4_chap_table *)ha->chap_list + chap_index;
1724*4882a593Smuzhiyun 	if (chap_table->cookie != __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
1725*4882a593Smuzhiyun 		rval = QLA_ERROR;
1726*4882a593Smuzhiyun 		goto exit_unlock_uni_chap;
1727*4882a593Smuzhiyun 	}
1728*4882a593Smuzhiyun 
1729*4882a593Smuzhiyun 	if (!(chap_table->flags & BIT_7)) {
1730*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Unidirectional entry not set\n");
1731*4882a593Smuzhiyun 		rval = QLA_ERROR;
1732*4882a593Smuzhiyun 		goto exit_unlock_uni_chap;
1733*4882a593Smuzhiyun 	}
1734*4882a593Smuzhiyun 
1735*4882a593Smuzhiyun 	strlcpy(password, chap_table->secret, MAX_CHAP_SECRET_LEN);
1736*4882a593Smuzhiyun 	strlcpy(username, chap_table->name, MAX_CHAP_NAME_LEN);
1737*4882a593Smuzhiyun 
1738*4882a593Smuzhiyun 	rval = QLA_SUCCESS;
1739*4882a593Smuzhiyun 
1740*4882a593Smuzhiyun exit_unlock_uni_chap:
1741*4882a593Smuzhiyun 	mutex_unlock(&ha->chap_sem);
1742*4882a593Smuzhiyun exit_uni_chap:
1743*4882a593Smuzhiyun 	return rval;
1744*4882a593Smuzhiyun }
1745*4882a593Smuzhiyun 
1746*4882a593Smuzhiyun /**
1747*4882a593Smuzhiyun  * qla4xxx_get_chap_index - Get chap index given username and secret
1748*4882a593Smuzhiyun  * @ha: pointer to adapter structure
1749*4882a593Smuzhiyun  * @username: CHAP username to be searched
1750*4882a593Smuzhiyun  * @password: CHAP password to be searched
1751*4882a593Smuzhiyun  * @bidi: Is this a BIDI CHAP
1752*4882a593Smuzhiyun  * @chap_index: CHAP index to be returned
1753*4882a593Smuzhiyun  *
1754*4882a593Smuzhiyun  * Match the username and password in the chap_list, return the index if a
1755*4882a593Smuzhiyun  * match is found. If a match is not found then add the entry in FLASH and
1756*4882a593Smuzhiyun  * return the index at which entry is written in the FLASH.
1757*4882a593Smuzhiyun  **/
qla4xxx_get_chap_index(struct scsi_qla_host * ha,char * username,char * password,int bidi,uint16_t * chap_index)1758*4882a593Smuzhiyun int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username,
1759*4882a593Smuzhiyun 			   char *password, int bidi, uint16_t *chap_index)
1760*4882a593Smuzhiyun {
1761*4882a593Smuzhiyun 	int i, rval;
1762*4882a593Smuzhiyun 	int free_index = -1;
1763*4882a593Smuzhiyun 	int found_index = 0;
1764*4882a593Smuzhiyun 	int max_chap_entries = 0;
1765*4882a593Smuzhiyun 	struct ql4_chap_table *chap_table;
1766*4882a593Smuzhiyun 
1767*4882a593Smuzhiyun 	if (is_qla80XX(ha))
1768*4882a593Smuzhiyun 		max_chap_entries = (ha->hw.flt_chap_size / 2) /
1769*4882a593Smuzhiyun 						sizeof(struct ql4_chap_table);
1770*4882a593Smuzhiyun 	else
1771*4882a593Smuzhiyun 		max_chap_entries = MAX_CHAP_ENTRIES_40XX;
1772*4882a593Smuzhiyun 
1773*4882a593Smuzhiyun 	if (!ha->chap_list) {
1774*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n");
1775*4882a593Smuzhiyun 		return QLA_ERROR;
1776*4882a593Smuzhiyun 	}
1777*4882a593Smuzhiyun 
1778*4882a593Smuzhiyun 	if (!username || !password) {
1779*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "Do not have username and psw\n");
1780*4882a593Smuzhiyun 		return QLA_ERROR;
1781*4882a593Smuzhiyun 	}
1782*4882a593Smuzhiyun 
1783*4882a593Smuzhiyun 	mutex_lock(&ha->chap_sem);
1784*4882a593Smuzhiyun 	for (i = 0; i < max_chap_entries; i++) {
1785*4882a593Smuzhiyun 		chap_table = (struct ql4_chap_table *)ha->chap_list + i;
1786*4882a593Smuzhiyun 		if (chap_table->cookie !=
1787*4882a593Smuzhiyun 		    __constant_cpu_to_le16(CHAP_VALID_COOKIE)) {
1788*4882a593Smuzhiyun 			if (i > MAX_RESRV_CHAP_IDX && free_index == -1)
1789*4882a593Smuzhiyun 				free_index = i;
1790*4882a593Smuzhiyun 			continue;
1791*4882a593Smuzhiyun 		}
1792*4882a593Smuzhiyun 		if (bidi) {
1793*4882a593Smuzhiyun 			if (chap_table->flags & BIT_7)
1794*4882a593Smuzhiyun 				continue;
1795*4882a593Smuzhiyun 		} else {
1796*4882a593Smuzhiyun 			if (chap_table->flags & BIT_6)
1797*4882a593Smuzhiyun 				continue;
1798*4882a593Smuzhiyun 		}
1799*4882a593Smuzhiyun 		if (!strncmp(chap_table->secret, password,
1800*4882a593Smuzhiyun 			     MAX_CHAP_SECRET_LEN) &&
1801*4882a593Smuzhiyun 		    !strncmp(chap_table->name, username,
1802*4882a593Smuzhiyun 			     MAX_CHAP_NAME_LEN)) {
1803*4882a593Smuzhiyun 			*chap_index = i;
1804*4882a593Smuzhiyun 			found_index = 1;
1805*4882a593Smuzhiyun 			break;
1806*4882a593Smuzhiyun 		}
1807*4882a593Smuzhiyun 	}
1808*4882a593Smuzhiyun 
1809*4882a593Smuzhiyun 	/* If chap entry is not present and a free index is available then
1810*4882a593Smuzhiyun 	 * write the entry in flash
1811*4882a593Smuzhiyun 	 */
1812*4882a593Smuzhiyun 	if (!found_index && free_index != -1) {
1813*4882a593Smuzhiyun 		rval = qla4xxx_set_chap(ha, username, password,
1814*4882a593Smuzhiyun 					free_index, bidi);
1815*4882a593Smuzhiyun 		if (!rval) {
1816*4882a593Smuzhiyun 			*chap_index = free_index;
1817*4882a593Smuzhiyun 			found_index = 1;
1818*4882a593Smuzhiyun 		}
1819*4882a593Smuzhiyun 	}
1820*4882a593Smuzhiyun 
1821*4882a593Smuzhiyun 	mutex_unlock(&ha->chap_sem);
1822*4882a593Smuzhiyun 
1823*4882a593Smuzhiyun 	if (found_index)
1824*4882a593Smuzhiyun 		return QLA_SUCCESS;
1825*4882a593Smuzhiyun 	return QLA_ERROR;
1826*4882a593Smuzhiyun }
1827*4882a593Smuzhiyun 
qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,uint16_t fw_ddb_index,uint16_t connection_id,uint16_t option)1828*4882a593Smuzhiyun int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha,
1829*4882a593Smuzhiyun 				   uint16_t fw_ddb_index,
1830*4882a593Smuzhiyun 				   uint16_t connection_id,
1831*4882a593Smuzhiyun 				   uint16_t option)
1832*4882a593Smuzhiyun {
1833*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1834*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1835*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1836*4882a593Smuzhiyun 
1837*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1838*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
1841*4882a593Smuzhiyun 	mbox_cmd[1] = fw_ddb_index;
1842*4882a593Smuzhiyun 	mbox_cmd[2] = connection_id;
1843*4882a593Smuzhiyun 	mbox_cmd[3] = option;
1844*4882a593Smuzhiyun 
1845*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]);
1846*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1847*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_CONN_CLOSE "
1848*4882a593Smuzhiyun 				  "option %04x failed w/ status %04X %04X\n",
1849*4882a593Smuzhiyun 				  __func__, option, mbox_sts[0], mbox_sts[1]));
1850*4882a593Smuzhiyun 	}
1851*4882a593Smuzhiyun 	return status;
1852*4882a593Smuzhiyun }
1853*4882a593Smuzhiyun 
1854*4882a593Smuzhiyun /**
1855*4882a593Smuzhiyun  * qla4_84xx_extend_idc_tmo - Extend IDC Timeout.
1856*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
1857*4882a593Smuzhiyun  * @ext_tmo: idc timeout value
1858*4882a593Smuzhiyun  *
1859*4882a593Smuzhiyun  * Requests firmware to extend the idc timeout value.
1860*4882a593Smuzhiyun  **/
qla4_84xx_extend_idc_tmo(struct scsi_qla_host * ha,uint32_t ext_tmo)1861*4882a593Smuzhiyun static int qla4_84xx_extend_idc_tmo(struct scsi_qla_host *ha, uint32_t ext_tmo)
1862*4882a593Smuzhiyun {
1863*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1864*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1865*4882a593Smuzhiyun 	int status;
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1868*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1869*4882a593Smuzhiyun 	ext_tmo &= 0xf;
1870*4882a593Smuzhiyun 
1871*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_IDC_TIME_EXTEND;
1872*4882a593Smuzhiyun 	mbox_cmd[1] = ((ha->idc_info.request_desc & 0xfffff0ff) |
1873*4882a593Smuzhiyun 		       (ext_tmo << 8));		/* new timeout */
1874*4882a593Smuzhiyun 	mbox_cmd[2] = ha->idc_info.info1;
1875*4882a593Smuzhiyun 	mbox_cmd[3] = ha->idc_info.info2;
1876*4882a593Smuzhiyun 	mbox_cmd[4] = ha->idc_info.info3;
1877*4882a593Smuzhiyun 
1878*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
1879*4882a593Smuzhiyun 					 mbox_cmd, mbox_sts);
1880*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1881*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
1882*4882a593Smuzhiyun 				  "scsi%ld: %s: failed status %04X\n",
1883*4882a593Smuzhiyun 				  ha->host_no, __func__, mbox_sts[0]));
1884*4882a593Smuzhiyun 		return QLA_ERROR;
1885*4882a593Smuzhiyun 	} else {
1886*4882a593Smuzhiyun 		ql4_printk(KERN_INFO, ha, "%s: IDC timeout extended by %d secs\n",
1887*4882a593Smuzhiyun 			   __func__, ext_tmo);
1888*4882a593Smuzhiyun 	}
1889*4882a593Smuzhiyun 
1890*4882a593Smuzhiyun 	return QLA_SUCCESS;
1891*4882a593Smuzhiyun }
1892*4882a593Smuzhiyun 
qla4xxx_disable_acb(struct scsi_qla_host * ha)1893*4882a593Smuzhiyun int qla4xxx_disable_acb(struct scsi_qla_host *ha)
1894*4882a593Smuzhiyun {
1895*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1896*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1897*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1898*4882a593Smuzhiyun 
1899*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1900*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1901*4882a593Smuzhiyun 
1902*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_DISABLE_ACB;
1903*4882a593Smuzhiyun 
1904*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 8, 5, &mbox_cmd[0], &mbox_sts[0]);
1905*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1906*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_DISABLE_ACB "
1907*4882a593Smuzhiyun 				  "failed w/ status %04X %04X %04X", __func__,
1908*4882a593Smuzhiyun 				  mbox_sts[0], mbox_sts[1], mbox_sts[2]));
1909*4882a593Smuzhiyun 	} else {
1910*4882a593Smuzhiyun 		if (is_qla8042(ha) &&
1911*4882a593Smuzhiyun 		    test_bit(DPC_POST_IDC_ACK, &ha->dpc_flags) &&
1912*4882a593Smuzhiyun 		    (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE)) {
1913*4882a593Smuzhiyun 			/*
1914*4882a593Smuzhiyun 			 * Disable ACB mailbox command takes time to complete
1915*4882a593Smuzhiyun 			 * based on the total number of targets connected.
1916*4882a593Smuzhiyun 			 * For 512 targets, it took approximately 5 secs to
1917*4882a593Smuzhiyun 			 * complete. Setting the timeout value to 8, with the 3
1918*4882a593Smuzhiyun 			 * secs buffer.
1919*4882a593Smuzhiyun 			 */
1920*4882a593Smuzhiyun 			qla4_84xx_extend_idc_tmo(ha, IDC_EXTEND_TOV);
1921*4882a593Smuzhiyun 			if (!wait_for_completion_timeout(&ha->disable_acb_comp,
1922*4882a593Smuzhiyun 							 IDC_EXTEND_TOV * HZ)) {
1923*4882a593Smuzhiyun 				ql4_printk(KERN_WARNING, ha, "%s: Disable ACB Completion not received\n",
1924*4882a593Smuzhiyun 					   __func__);
1925*4882a593Smuzhiyun 			}
1926*4882a593Smuzhiyun 		}
1927*4882a593Smuzhiyun 	}
1928*4882a593Smuzhiyun 	return status;
1929*4882a593Smuzhiyun }
1930*4882a593Smuzhiyun 
qla4xxx_get_acb(struct scsi_qla_host * ha,dma_addr_t acb_dma,uint32_t acb_type,uint32_t len)1931*4882a593Smuzhiyun int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t acb_dma,
1932*4882a593Smuzhiyun 		    uint32_t acb_type, uint32_t len)
1933*4882a593Smuzhiyun {
1934*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
1935*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
1936*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
1939*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_ACB;
1942*4882a593Smuzhiyun 	mbox_cmd[1] = acb_type;
1943*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(acb_dma);
1944*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(acb_dma);
1945*4882a593Smuzhiyun 	mbox_cmd[4] = len;
1946*4882a593Smuzhiyun 
1947*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]);
1948*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1949*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_GET_ACB "
1950*4882a593Smuzhiyun 				  "failed w/ status %04X\n", __func__,
1951*4882a593Smuzhiyun 				  mbox_sts[0]));
1952*4882a593Smuzhiyun 	}
1953*4882a593Smuzhiyun 	return status;
1954*4882a593Smuzhiyun }
1955*4882a593Smuzhiyun 
qla4xxx_set_acb(struct scsi_qla_host * ha,uint32_t * mbox_cmd,uint32_t * mbox_sts,dma_addr_t acb_dma)1956*4882a593Smuzhiyun int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
1957*4882a593Smuzhiyun 		    uint32_t *mbox_sts, dma_addr_t acb_dma)
1958*4882a593Smuzhiyun {
1959*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1960*4882a593Smuzhiyun 
1961*4882a593Smuzhiyun 	memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
1962*4882a593Smuzhiyun 	memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
1963*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_SET_ACB;
1964*4882a593Smuzhiyun 	mbox_cmd[1] = 0; /* Primary ACB */
1965*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(acb_dma);
1966*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(acb_dma);
1967*4882a593Smuzhiyun 	mbox_cmd[4] = sizeof(struct addr_ctrl_blk);
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]);
1970*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
1971*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,  "%s: MBOX_CMD_SET_ACB "
1972*4882a593Smuzhiyun 				  "failed w/ status %04X\n", __func__,
1973*4882a593Smuzhiyun 				  mbox_sts[0]));
1974*4882a593Smuzhiyun 	}
1975*4882a593Smuzhiyun 	return status;
1976*4882a593Smuzhiyun }
1977*4882a593Smuzhiyun 
qla4xxx_set_param_ddbentry(struct scsi_qla_host * ha,struct ddb_entry * ddb_entry,struct iscsi_cls_conn * cls_conn,uint32_t * mbx_sts)1978*4882a593Smuzhiyun int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha,
1979*4882a593Smuzhiyun 			       struct ddb_entry *ddb_entry,
1980*4882a593Smuzhiyun 			       struct iscsi_cls_conn *cls_conn,
1981*4882a593Smuzhiyun 			       uint32_t *mbx_sts)
1982*4882a593Smuzhiyun {
1983*4882a593Smuzhiyun 	struct dev_db_entry *fw_ddb_entry;
1984*4882a593Smuzhiyun 	struct iscsi_conn *conn;
1985*4882a593Smuzhiyun 	struct iscsi_session *sess;
1986*4882a593Smuzhiyun 	struct qla_conn *qla_conn;
1987*4882a593Smuzhiyun 	struct sockaddr *dst_addr;
1988*4882a593Smuzhiyun 	dma_addr_t fw_ddb_entry_dma;
1989*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
1990*4882a593Smuzhiyun 	int rval = 0;
1991*4882a593Smuzhiyun 	struct sockaddr_in *addr;
1992*4882a593Smuzhiyun 	struct sockaddr_in6 *addr6;
1993*4882a593Smuzhiyun 	char *ip;
1994*4882a593Smuzhiyun 	uint16_t iscsi_opts = 0;
1995*4882a593Smuzhiyun 	uint32_t options = 0;
1996*4882a593Smuzhiyun 	uint16_t idx, *ptid;
1997*4882a593Smuzhiyun 
1998*4882a593Smuzhiyun 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
1999*4882a593Smuzhiyun 					  &fw_ddb_entry_dma, GFP_KERNEL);
2000*4882a593Smuzhiyun 	if (!fw_ddb_entry) {
2001*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha,
2002*4882a593Smuzhiyun 				  "%s: Unable to allocate dma buffer.\n",
2003*4882a593Smuzhiyun 				  __func__));
2004*4882a593Smuzhiyun 		rval = -ENOMEM;
2005*4882a593Smuzhiyun 		goto exit_set_param_no_free;
2006*4882a593Smuzhiyun 	}
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	conn = cls_conn->dd_data;
2009*4882a593Smuzhiyun 	qla_conn = conn->dd_data;
2010*4882a593Smuzhiyun 	sess = conn->session;
2011*4882a593Smuzhiyun 	dst_addr = (struct sockaddr *)&qla_conn->qla_ep->dst_addr;
2012*4882a593Smuzhiyun 
2013*4882a593Smuzhiyun 	if (dst_addr->sa_family == AF_INET6)
2014*4882a593Smuzhiyun 		options |= IPV6_DEFAULT_DDB_ENTRY;
2015*4882a593Smuzhiyun 
2016*4882a593Smuzhiyun 	status = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma);
2017*4882a593Smuzhiyun 	if (status == QLA_ERROR) {
2018*4882a593Smuzhiyun 		rval = -EINVAL;
2019*4882a593Smuzhiyun 		goto exit_set_param;
2020*4882a593Smuzhiyun 	}
2021*4882a593Smuzhiyun 
2022*4882a593Smuzhiyun 	ptid = (uint16_t *)&fw_ddb_entry->isid[1];
2023*4882a593Smuzhiyun 	*ptid = cpu_to_le16((uint16_t)ddb_entry->sess->target_id);
2024*4882a593Smuzhiyun 
2025*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha, "ISID [%pmR]\n", fw_ddb_entry->isid));
2026*4882a593Smuzhiyun 
2027*4882a593Smuzhiyun 	iscsi_opts = le16_to_cpu(fw_ddb_entry->iscsi_options);
2028*4882a593Smuzhiyun 	memset(fw_ddb_entry->iscsi_alias, 0, sizeof(fw_ddb_entry->iscsi_alias));
2029*4882a593Smuzhiyun 
2030*4882a593Smuzhiyun 	memset(fw_ddb_entry->iscsi_name, 0, sizeof(fw_ddb_entry->iscsi_name));
2031*4882a593Smuzhiyun 
2032*4882a593Smuzhiyun 	if (sess->targetname != NULL) {
2033*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->iscsi_name, sess->targetname,
2034*4882a593Smuzhiyun 		       min(strlen(sess->targetname),
2035*4882a593Smuzhiyun 		       sizeof(fw_ddb_entry->iscsi_name)));
2036*4882a593Smuzhiyun 	}
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun 	memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr));
2039*4882a593Smuzhiyun 	memset(fw_ddb_entry->tgt_addr, 0, sizeof(fw_ddb_entry->tgt_addr));
2040*4882a593Smuzhiyun 
2041*4882a593Smuzhiyun 	fw_ddb_entry->options =  DDB_OPT_TARGET | DDB_OPT_AUTO_SENDTGTS_DISABLE;
2042*4882a593Smuzhiyun 
2043*4882a593Smuzhiyun 	if (dst_addr->sa_family == AF_INET) {
2044*4882a593Smuzhiyun 		addr = (struct sockaddr_in *)dst_addr;
2045*4882a593Smuzhiyun 		ip = (char *)&addr->sin_addr;
2046*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->ip_addr, ip, IP_ADDR_LEN);
2047*4882a593Smuzhiyun 		fw_ddb_entry->port = cpu_to_le16(ntohs(addr->sin_port));
2048*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
2049*4882a593Smuzhiyun 				  "%s: Destination Address [%pI4]: index [%d]\n",
2050*4882a593Smuzhiyun 				   __func__, fw_ddb_entry->ip_addr,
2051*4882a593Smuzhiyun 				  ddb_entry->fw_ddb_index));
2052*4882a593Smuzhiyun 	} else if (dst_addr->sa_family == AF_INET6) {
2053*4882a593Smuzhiyun 		addr6 = (struct sockaddr_in6 *)dst_addr;
2054*4882a593Smuzhiyun 		ip = (char *)&addr6->sin6_addr;
2055*4882a593Smuzhiyun 		memcpy(fw_ddb_entry->ip_addr, ip, IPv6_ADDR_LEN);
2056*4882a593Smuzhiyun 		fw_ddb_entry->port = cpu_to_le16(ntohs(addr6->sin6_port));
2057*4882a593Smuzhiyun 		fw_ddb_entry->options |= DDB_OPT_IPV6_DEVICE;
2058*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_INFO, ha,
2059*4882a593Smuzhiyun 				  "%s: Destination Address [%pI6]: index [%d]\n",
2060*4882a593Smuzhiyun 				   __func__, fw_ddb_entry->ip_addr,
2061*4882a593Smuzhiyun 				  ddb_entry->fw_ddb_index));
2062*4882a593Smuzhiyun 	} else {
2063*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha,
2064*4882a593Smuzhiyun 			   "%s: Failed to get IP Address\n",
2065*4882a593Smuzhiyun 			   __func__);
2066*4882a593Smuzhiyun 		rval = -EINVAL;
2067*4882a593Smuzhiyun 		goto exit_set_param;
2068*4882a593Smuzhiyun 	}
2069*4882a593Smuzhiyun 
2070*4882a593Smuzhiyun 	/* CHAP */
2071*4882a593Smuzhiyun 	if (sess->username != NULL && sess->password != NULL) {
2072*4882a593Smuzhiyun 		if (strlen(sess->username) && strlen(sess->password)) {
2073*4882a593Smuzhiyun 			iscsi_opts |= BIT_7;
2074*4882a593Smuzhiyun 
2075*4882a593Smuzhiyun 			rval = qla4xxx_get_chap_index(ha, sess->username,
2076*4882a593Smuzhiyun 						sess->password,
2077*4882a593Smuzhiyun 						LOCAL_CHAP, &idx);
2078*4882a593Smuzhiyun 			if (rval)
2079*4882a593Smuzhiyun 				goto exit_set_param;
2080*4882a593Smuzhiyun 
2081*4882a593Smuzhiyun 			fw_ddb_entry->chap_tbl_idx = cpu_to_le16(idx);
2082*4882a593Smuzhiyun 		}
2083*4882a593Smuzhiyun 	}
2084*4882a593Smuzhiyun 
2085*4882a593Smuzhiyun 	if (sess->username_in != NULL && sess->password_in != NULL) {
2086*4882a593Smuzhiyun 		/* Check if BIDI CHAP */
2087*4882a593Smuzhiyun 		if (strlen(sess->username_in) && strlen(sess->password_in)) {
2088*4882a593Smuzhiyun 			iscsi_opts |= BIT_4;
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun 			rval = qla4xxx_get_chap_index(ha, sess->username_in,
2091*4882a593Smuzhiyun 						      sess->password_in,
2092*4882a593Smuzhiyun 						      BIDI_CHAP, &idx);
2093*4882a593Smuzhiyun 			if (rval)
2094*4882a593Smuzhiyun 				goto exit_set_param;
2095*4882a593Smuzhiyun 		}
2096*4882a593Smuzhiyun 	}
2097*4882a593Smuzhiyun 
2098*4882a593Smuzhiyun 	if (sess->initial_r2t_en)
2099*4882a593Smuzhiyun 		iscsi_opts |= BIT_10;
2100*4882a593Smuzhiyun 
2101*4882a593Smuzhiyun 	if (sess->imm_data_en)
2102*4882a593Smuzhiyun 		iscsi_opts |= BIT_11;
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun 	fw_ddb_entry->iscsi_options = cpu_to_le16(iscsi_opts);
2105*4882a593Smuzhiyun 
2106*4882a593Smuzhiyun 	if (conn->max_recv_dlength)
2107*4882a593Smuzhiyun 		fw_ddb_entry->iscsi_max_rcv_data_seg_len =
2108*4882a593Smuzhiyun 		  __constant_cpu_to_le16((conn->max_recv_dlength / BYTE_UNITS));
2109*4882a593Smuzhiyun 
2110*4882a593Smuzhiyun 	if (sess->max_r2t)
2111*4882a593Smuzhiyun 		fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t);
2112*4882a593Smuzhiyun 
2113*4882a593Smuzhiyun 	if (sess->first_burst)
2114*4882a593Smuzhiyun 		fw_ddb_entry->iscsi_first_burst_len =
2115*4882a593Smuzhiyun 		       __constant_cpu_to_le16((sess->first_burst / BYTE_UNITS));
2116*4882a593Smuzhiyun 
2117*4882a593Smuzhiyun 	if (sess->max_burst)
2118*4882a593Smuzhiyun 		fw_ddb_entry->iscsi_max_burst_len =
2119*4882a593Smuzhiyun 			__constant_cpu_to_le16((sess->max_burst / BYTE_UNITS));
2120*4882a593Smuzhiyun 
2121*4882a593Smuzhiyun 	if (sess->time2wait)
2122*4882a593Smuzhiyun 		fw_ddb_entry->iscsi_def_time2wait =
2123*4882a593Smuzhiyun 			cpu_to_le16(sess->time2wait);
2124*4882a593Smuzhiyun 
2125*4882a593Smuzhiyun 	if (sess->time2retain)
2126*4882a593Smuzhiyun 		fw_ddb_entry->iscsi_def_time2retain =
2127*4882a593Smuzhiyun 			cpu_to_le16(sess->time2retain);
2128*4882a593Smuzhiyun 
2129*4882a593Smuzhiyun 	status = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index,
2130*4882a593Smuzhiyun 				       fw_ddb_entry_dma, mbx_sts);
2131*4882a593Smuzhiyun 
2132*4882a593Smuzhiyun 	if (status != QLA_SUCCESS)
2133*4882a593Smuzhiyun 		rval = -EINVAL;
2134*4882a593Smuzhiyun exit_set_param:
2135*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
2136*4882a593Smuzhiyun 			  fw_ddb_entry, fw_ddb_entry_dma);
2137*4882a593Smuzhiyun exit_set_param_no_free:
2138*4882a593Smuzhiyun 	return rval;
2139*4882a593Smuzhiyun }
2140*4882a593Smuzhiyun 
qla4xxx_get_mgmt_data(struct scsi_qla_host * ha,uint16_t fw_ddb_index,uint16_t stats_size,dma_addr_t stats_dma)2141*4882a593Smuzhiyun int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index,
2142*4882a593Smuzhiyun 			  uint16_t stats_size, dma_addr_t stats_dma)
2143*4882a593Smuzhiyun {
2144*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
2145*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2146*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun 	memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT);
2149*4882a593Smuzhiyun 	memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT);
2150*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_MANAGEMENT_DATA;
2151*4882a593Smuzhiyun 	mbox_cmd[1] = fw_ddb_index;
2152*4882a593Smuzhiyun 	mbox_cmd[2] = LSDW(stats_dma);
2153*4882a593Smuzhiyun 	mbox_cmd[3] = MSDW(stats_dma);
2154*4882a593Smuzhiyun 	mbox_cmd[4] = stats_size;
2155*4882a593Smuzhiyun 
2156*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 5, 1, &mbox_cmd[0], &mbox_sts[0]);
2157*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
2158*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,
2159*4882a593Smuzhiyun 				  "%s: MBOX_CMD_GET_MANAGEMENT_DATA "
2160*4882a593Smuzhiyun 				  "failed w/ status %04X\n", __func__,
2161*4882a593Smuzhiyun 				  mbox_sts[0]));
2162*4882a593Smuzhiyun 	}
2163*4882a593Smuzhiyun 	return status;
2164*4882a593Smuzhiyun }
2165*4882a593Smuzhiyun 
qla4xxx_get_ip_state(struct scsi_qla_host * ha,uint32_t acb_idx,uint32_t ip_idx,uint32_t * sts)2166*4882a593Smuzhiyun int qla4xxx_get_ip_state(struct scsi_qla_host *ha, uint32_t acb_idx,
2167*4882a593Smuzhiyun 			 uint32_t ip_idx, uint32_t *sts)
2168*4882a593Smuzhiyun {
2169*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2170*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2171*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
2172*4882a593Smuzhiyun 
2173*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2174*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2175*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_IP_ADDR_STATE;
2176*4882a593Smuzhiyun 	mbox_cmd[1] = acb_idx;
2177*4882a593Smuzhiyun 	mbox_cmd[2] = ip_idx;
2178*4882a593Smuzhiyun 
2179*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, 3, 8, &mbox_cmd[0], &mbox_sts[0]);
2180*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
2181*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_WARNING, ha,  "%s: "
2182*4882a593Smuzhiyun 				  "MBOX_CMD_GET_IP_ADDR_STATE failed w/ "
2183*4882a593Smuzhiyun 				  "status %04X\n", __func__, mbox_sts[0]));
2184*4882a593Smuzhiyun 	}
2185*4882a593Smuzhiyun 	memcpy(sts, mbox_sts, sizeof(mbox_sts));
2186*4882a593Smuzhiyun 	return status;
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun 
qla4xxx_get_nvram(struct scsi_qla_host * ha,dma_addr_t nvram_dma,uint32_t offset,uint32_t size)2189*4882a593Smuzhiyun int qla4xxx_get_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma,
2190*4882a593Smuzhiyun 		      uint32_t offset, uint32_t size)
2191*4882a593Smuzhiyun {
2192*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
2193*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2194*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2195*4882a593Smuzhiyun 
2196*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2197*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2198*4882a593Smuzhiyun 
2199*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_NVRAM;
2200*4882a593Smuzhiyun 	mbox_cmd[1] = LSDW(nvram_dma);
2201*4882a593Smuzhiyun 	mbox_cmd[2] = MSDW(nvram_dma);
2202*4882a593Smuzhiyun 	mbox_cmd[3] = offset;
2203*4882a593Smuzhiyun 	mbox_cmd[4] = size;
2204*4882a593Smuzhiyun 
2205*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
2206*4882a593Smuzhiyun 					 &mbox_sts[0]);
2207*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
2208*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
2209*4882a593Smuzhiyun 				  "status %04X\n", ha->host_no, __func__,
2210*4882a593Smuzhiyun 				  mbox_sts[0]));
2211*4882a593Smuzhiyun 	}
2212*4882a593Smuzhiyun 	return status;
2213*4882a593Smuzhiyun }
2214*4882a593Smuzhiyun 
qla4xxx_set_nvram(struct scsi_qla_host * ha,dma_addr_t nvram_dma,uint32_t offset,uint32_t size)2215*4882a593Smuzhiyun int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma,
2216*4882a593Smuzhiyun 		      uint32_t offset, uint32_t size)
2217*4882a593Smuzhiyun {
2218*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
2219*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2220*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2221*4882a593Smuzhiyun 
2222*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2223*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_SET_NVRAM;
2226*4882a593Smuzhiyun 	mbox_cmd[1] = LSDW(nvram_dma);
2227*4882a593Smuzhiyun 	mbox_cmd[2] = MSDW(nvram_dma);
2228*4882a593Smuzhiyun 	mbox_cmd[3] = offset;
2229*4882a593Smuzhiyun 	mbox_cmd[4] = size;
2230*4882a593Smuzhiyun 
2231*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
2232*4882a593Smuzhiyun 					 &mbox_sts[0]);
2233*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
2234*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
2235*4882a593Smuzhiyun 				  "status %04X\n", ha->host_no, __func__,
2236*4882a593Smuzhiyun 				  mbox_sts[0]));
2237*4882a593Smuzhiyun 	}
2238*4882a593Smuzhiyun 	return status;
2239*4882a593Smuzhiyun }
2240*4882a593Smuzhiyun 
qla4xxx_restore_factory_defaults(struct scsi_qla_host * ha,uint32_t region,uint32_t field0,uint32_t field1)2241*4882a593Smuzhiyun int qla4xxx_restore_factory_defaults(struct scsi_qla_host *ha,
2242*4882a593Smuzhiyun 				     uint32_t region, uint32_t field0,
2243*4882a593Smuzhiyun 				     uint32_t field1)
2244*4882a593Smuzhiyun {
2245*4882a593Smuzhiyun 	int status = QLA_SUCCESS;
2246*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2247*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2248*4882a593Smuzhiyun 
2249*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2250*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2251*4882a593Smuzhiyun 
2252*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_RESTORE_FACTORY_DEFAULTS;
2253*4882a593Smuzhiyun 	mbox_cmd[3] = region;
2254*4882a593Smuzhiyun 	mbox_cmd[4] = field0;
2255*4882a593Smuzhiyun 	mbox_cmd[5] = field1;
2256*4882a593Smuzhiyun 
2257*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0],
2258*4882a593Smuzhiyun 					 &mbox_sts[0]);
2259*4882a593Smuzhiyun 	if (status != QLA_SUCCESS) {
2260*4882a593Smuzhiyun 		DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed "
2261*4882a593Smuzhiyun 				  "status %04X\n", ha->host_no, __func__,
2262*4882a593Smuzhiyun 				  mbox_sts[0]));
2263*4882a593Smuzhiyun 	}
2264*4882a593Smuzhiyun 	return status;
2265*4882a593Smuzhiyun }
2266*4882a593Smuzhiyun 
2267*4882a593Smuzhiyun /**
2268*4882a593Smuzhiyun  * qla4_8xxx_set_param - set driver version in firmware.
2269*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
2270*4882a593Smuzhiyun  * @param: Parameter to set i.e driver version
2271*4882a593Smuzhiyun  **/
qla4_8xxx_set_param(struct scsi_qla_host * ha,int param)2272*4882a593Smuzhiyun int qla4_8xxx_set_param(struct scsi_qla_host *ha, int param)
2273*4882a593Smuzhiyun {
2274*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2275*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2276*4882a593Smuzhiyun 	uint32_t status;
2277*4882a593Smuzhiyun 
2278*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2279*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2280*4882a593Smuzhiyun 
2281*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_SET_PARAM;
2282*4882a593Smuzhiyun 	if (param == SET_DRVR_VERSION) {
2283*4882a593Smuzhiyun 		mbox_cmd[1] = SET_DRVR_VERSION;
2284*4882a593Smuzhiyun 		strncpy((char *)&mbox_cmd[2], QLA4XXX_DRIVER_VERSION,
2285*4882a593Smuzhiyun 			MAX_DRVR_VER_LEN - 1);
2286*4882a593Smuzhiyun 	} else {
2287*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: invalid parameter 0x%x\n",
2288*4882a593Smuzhiyun 			   __func__, param);
2289*4882a593Smuzhiyun 		status = QLA_ERROR;
2290*4882a593Smuzhiyun 		goto exit_set_param;
2291*4882a593Smuzhiyun 	}
2292*4882a593Smuzhiyun 
2293*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, mbox_cmd,
2294*4882a593Smuzhiyun 					 mbox_sts);
2295*4882a593Smuzhiyun 	if (status == QLA_ERROR)
2296*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n",
2297*4882a593Smuzhiyun 			   __func__, mbox_sts[0]);
2298*4882a593Smuzhiyun 
2299*4882a593Smuzhiyun exit_set_param:
2300*4882a593Smuzhiyun 	return status;
2301*4882a593Smuzhiyun }
2302*4882a593Smuzhiyun 
2303*4882a593Smuzhiyun /**
2304*4882a593Smuzhiyun  * qla4_83xx_post_idc_ack - post IDC ACK
2305*4882a593Smuzhiyun  * @ha: Pointer to host adapter structure.
2306*4882a593Smuzhiyun  *
2307*4882a593Smuzhiyun  * Posts IDC ACK for IDC Request Notification AEN.
2308*4882a593Smuzhiyun  **/
qla4_83xx_post_idc_ack(struct scsi_qla_host * ha)2309*4882a593Smuzhiyun int qla4_83xx_post_idc_ack(struct scsi_qla_host *ha)
2310*4882a593Smuzhiyun {
2311*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2312*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2313*4882a593Smuzhiyun 	int status;
2314*4882a593Smuzhiyun 
2315*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2316*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2317*4882a593Smuzhiyun 
2318*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_IDC_ACK;
2319*4882a593Smuzhiyun 	mbox_cmd[1] = ha->idc_info.request_desc;
2320*4882a593Smuzhiyun 	mbox_cmd[2] = ha->idc_info.info1;
2321*4882a593Smuzhiyun 	mbox_cmd[3] = ha->idc_info.info2;
2322*4882a593Smuzhiyun 	mbox_cmd[4] = ha->idc_info.info3;
2323*4882a593Smuzhiyun 
2324*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
2325*4882a593Smuzhiyun 					 mbox_cmd, mbox_sts);
2326*4882a593Smuzhiyun 	if (status == QLA_ERROR)
2327*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", __func__,
2328*4882a593Smuzhiyun 			   mbox_sts[0]);
2329*4882a593Smuzhiyun 	else
2330*4882a593Smuzhiyun 	       ql4_printk(KERN_INFO, ha, "%s: IDC ACK posted\n", __func__);
2331*4882a593Smuzhiyun 
2332*4882a593Smuzhiyun 	return status;
2333*4882a593Smuzhiyun }
2334*4882a593Smuzhiyun 
qla4_84xx_config_acb(struct scsi_qla_host * ha,int acb_config)2335*4882a593Smuzhiyun int qla4_84xx_config_acb(struct scsi_qla_host *ha, int acb_config)
2336*4882a593Smuzhiyun {
2337*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2338*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2339*4882a593Smuzhiyun 	struct addr_ctrl_blk *acb = NULL;
2340*4882a593Smuzhiyun 	uint32_t acb_len = sizeof(struct addr_ctrl_blk);
2341*4882a593Smuzhiyun 	int rval = QLA_SUCCESS;
2342*4882a593Smuzhiyun 	dma_addr_t acb_dma;
2343*4882a593Smuzhiyun 
2344*4882a593Smuzhiyun 	acb = dma_alloc_coherent(&ha->pdev->dev,
2345*4882a593Smuzhiyun 				 sizeof(struct addr_ctrl_blk),
2346*4882a593Smuzhiyun 				 &acb_dma, GFP_KERNEL);
2347*4882a593Smuzhiyun 	if (!acb) {
2348*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", __func__);
2349*4882a593Smuzhiyun 		rval = QLA_ERROR;
2350*4882a593Smuzhiyun 		goto exit_config_acb;
2351*4882a593Smuzhiyun 	}
2352*4882a593Smuzhiyun 	memset(acb, 0, acb_len);
2353*4882a593Smuzhiyun 
2354*4882a593Smuzhiyun 	switch (acb_config) {
2355*4882a593Smuzhiyun 	case ACB_CONFIG_DISABLE:
2356*4882a593Smuzhiyun 		rval = qla4xxx_get_acb(ha, acb_dma, 0, acb_len);
2357*4882a593Smuzhiyun 		if (rval != QLA_SUCCESS)
2358*4882a593Smuzhiyun 			goto exit_free_acb;
2359*4882a593Smuzhiyun 
2360*4882a593Smuzhiyun 		rval = qla4xxx_disable_acb(ha);
2361*4882a593Smuzhiyun 		if (rval != QLA_SUCCESS)
2362*4882a593Smuzhiyun 			goto exit_free_acb;
2363*4882a593Smuzhiyun 
2364*4882a593Smuzhiyun 		if (!ha->saved_acb)
2365*4882a593Smuzhiyun 			ha->saved_acb = kzalloc(acb_len, GFP_KERNEL);
2366*4882a593Smuzhiyun 
2367*4882a593Smuzhiyun 		if (!ha->saved_acb) {
2368*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n",
2369*4882a593Smuzhiyun 				   __func__);
2370*4882a593Smuzhiyun 			rval = QLA_ERROR;
2371*4882a593Smuzhiyun 			goto exit_free_acb;
2372*4882a593Smuzhiyun 		}
2373*4882a593Smuzhiyun 		memcpy(ha->saved_acb, acb, acb_len);
2374*4882a593Smuzhiyun 		break;
2375*4882a593Smuzhiyun 	case ACB_CONFIG_SET:
2376*4882a593Smuzhiyun 
2377*4882a593Smuzhiyun 		if (!ha->saved_acb) {
2378*4882a593Smuzhiyun 			ql4_printk(KERN_ERR, ha, "%s: Can't set ACB, Saved ACB not available\n",
2379*4882a593Smuzhiyun 				   __func__);
2380*4882a593Smuzhiyun 			rval = QLA_ERROR;
2381*4882a593Smuzhiyun 			goto exit_free_acb;
2382*4882a593Smuzhiyun 		}
2383*4882a593Smuzhiyun 
2384*4882a593Smuzhiyun 		memcpy(acb, ha->saved_acb, acb_len);
2385*4882a593Smuzhiyun 
2386*4882a593Smuzhiyun 		rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma);
2387*4882a593Smuzhiyun 		if (rval != QLA_SUCCESS)
2388*4882a593Smuzhiyun 			goto exit_free_acb;
2389*4882a593Smuzhiyun 
2390*4882a593Smuzhiyun 		break;
2391*4882a593Smuzhiyun 	default:
2392*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: Invalid ACB Configuration\n",
2393*4882a593Smuzhiyun 			   __func__);
2394*4882a593Smuzhiyun 	}
2395*4882a593Smuzhiyun 
2396*4882a593Smuzhiyun exit_free_acb:
2397*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), acb,
2398*4882a593Smuzhiyun 			  acb_dma);
2399*4882a593Smuzhiyun exit_config_acb:
2400*4882a593Smuzhiyun 	if ((acb_config == ACB_CONFIG_SET) && ha->saved_acb) {
2401*4882a593Smuzhiyun 		kfree(ha->saved_acb);
2402*4882a593Smuzhiyun 		ha->saved_acb = NULL;
2403*4882a593Smuzhiyun 	}
2404*4882a593Smuzhiyun 	DEBUG2(ql4_printk(KERN_INFO, ha,
2405*4882a593Smuzhiyun 			  "%s %s\n", __func__,
2406*4882a593Smuzhiyun 			  rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED"));
2407*4882a593Smuzhiyun 	return rval;
2408*4882a593Smuzhiyun }
2409*4882a593Smuzhiyun 
qla4_83xx_get_port_config(struct scsi_qla_host * ha,uint32_t * config)2410*4882a593Smuzhiyun int qla4_83xx_get_port_config(struct scsi_qla_host *ha, uint32_t *config)
2411*4882a593Smuzhiyun {
2412*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2413*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2414*4882a593Smuzhiyun 	int status;
2415*4882a593Smuzhiyun 
2416*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2417*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2418*4882a593Smuzhiyun 
2419*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_GET_PORT_CONFIG;
2420*4882a593Smuzhiyun 
2421*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
2422*4882a593Smuzhiyun 					 mbox_cmd, mbox_sts);
2423*4882a593Smuzhiyun 	if (status == QLA_SUCCESS)
2424*4882a593Smuzhiyun 		*config = mbox_sts[1];
2425*4882a593Smuzhiyun 	else
2426*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", __func__,
2427*4882a593Smuzhiyun 			   mbox_sts[0]);
2428*4882a593Smuzhiyun 
2429*4882a593Smuzhiyun 	return status;
2430*4882a593Smuzhiyun }
2431*4882a593Smuzhiyun 
qla4_83xx_set_port_config(struct scsi_qla_host * ha,uint32_t * config)2432*4882a593Smuzhiyun int qla4_83xx_set_port_config(struct scsi_qla_host *ha, uint32_t *config)
2433*4882a593Smuzhiyun {
2434*4882a593Smuzhiyun 	uint32_t mbox_cmd[MBOX_REG_COUNT];
2435*4882a593Smuzhiyun 	uint32_t mbox_sts[MBOX_REG_COUNT];
2436*4882a593Smuzhiyun 	int status;
2437*4882a593Smuzhiyun 
2438*4882a593Smuzhiyun 	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
2439*4882a593Smuzhiyun 	memset(&mbox_sts, 0, sizeof(mbox_sts));
2440*4882a593Smuzhiyun 
2441*4882a593Smuzhiyun 	mbox_cmd[0] = MBOX_CMD_SET_PORT_CONFIG;
2442*4882a593Smuzhiyun 	mbox_cmd[1] = *config;
2443*4882a593Smuzhiyun 
2444*4882a593Smuzhiyun 	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT,
2445*4882a593Smuzhiyun 				mbox_cmd, mbox_sts);
2446*4882a593Smuzhiyun 	if (status != QLA_SUCCESS)
2447*4882a593Smuzhiyun 		ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", __func__,
2448*4882a593Smuzhiyun 			   mbox_sts[0]);
2449*4882a593Smuzhiyun 
2450*4882a593Smuzhiyun 	return status;
2451*4882a593Smuzhiyun }
2452