| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * QLogic iSCSI HBA Driver | 
 | 3 |  * Copyright (c)  2003-2006 QLogic Corporation | 
 | 4 |  * | 
 | 5 |  * See LICENSE.qla4xxx for copyright and licensing details. | 
 | 6 |  */ | 
 | 7 |  | 
 | 8 | #include "ql4_def.h" | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 9 | #include "ql4_glbl.h" | 
 | 10 | #include "ql4_dbg.h" | 
 | 11 | #include "ql4_inline.h" | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 12 |  | 
 | 13 |  | 
 | 14 | /** | 
 | 15 |  * qla4xxx_mailbox_command - issues mailbox commands | 
 | 16 |  * @ha: Pointer to host adapter structure. | 
 | 17 |  * @inCount: number of mailbox registers to load. | 
 | 18 |  * @outCount: number of mailbox registers to return. | 
 | 19 |  * @mbx_cmd: data pointer for mailbox in registers. | 
 | 20 |  * @mbx_sts: data pointer for mailbox out registers. | 
 | 21 |  * | 
 | 22 |  * This routine sssue mailbox commands and waits for completion. | 
 | 23 |  * If outCount is 0, this routine completes successfully WITHOUT waiting | 
 | 24 |  * for the mailbox command to complete. | 
 | 25 |  **/ | 
| Adrian Bunk | 4797547 | 2007-04-26 00:35:16 -0700 | [diff] [blame] | 26 | static int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, | 
 | 27 | 				   uint8_t outCount, uint32_t *mbx_cmd, | 
 | 28 | 				   uint32_t *mbx_sts) | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 29 | { | 
 | 30 | 	int status = QLA_ERROR; | 
 | 31 | 	uint8_t i; | 
 | 32 | 	u_long wait_count; | 
 | 33 | 	uint32_t intr_status; | 
 | 34 | 	unsigned long flags = 0; | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 35 |  | 
 | 36 | 	/* Make sure that pointers are valid */ | 
 | 37 | 	if (!mbx_cmd || !mbx_sts) { | 
 | 38 | 		DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts " | 
 | 39 | 			      "pointer\n", ha->host_no, __func__)); | 
| David C Somayajulu | 477ffb9 | 2007-01-22 12:26:11 -0800 | [diff] [blame] | 40 | 		return status; | 
 | 41 | 	} | 
 | 42 | 	/* Mailbox code active */ | 
 | 43 | 	wait_count = MBOX_TOV * 100; | 
 | 44 |  | 
 | 45 | 	while (wait_count--) { | 
 | 46 | 		mutex_lock(&ha->mbox_sem); | 
 | 47 | 		if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) { | 
 | 48 | 			set_bit(AF_MBOX_COMMAND, &ha->flags); | 
 | 49 | 			mutex_unlock(&ha->mbox_sem); | 
 | 50 | 			break; | 
 | 51 | 		} | 
 | 52 | 		mutex_unlock(&ha->mbox_sem); | 
 | 53 | 		if (!wait_count) { | 
 | 54 | 			DEBUG2(printk("scsi%ld: %s: mbox_sem failed\n", | 
 | 55 | 				ha->host_no, __func__)); | 
 | 56 | 			return status; | 
 | 57 | 		} | 
 | 58 | 		msleep(10); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 59 | 	} | 
 | 60 |  | 
 | 61 | 	/* To prevent overwriting mailbox registers for a command that has | 
 | 62 | 	 * not yet been serviced, check to see if a previously issued | 
 | 63 | 	 * mailbox command is interrupting. | 
 | 64 | 	 * ----------------------------------------------------------------- | 
 | 65 | 	 */ | 
 | 66 | 	spin_lock_irqsave(&ha->hardware_lock, flags); | 
 | 67 | 	intr_status = readl(&ha->reg->ctrl_status); | 
 | 68 | 	if (intr_status & CSR_SCSI_PROCESSOR_INTR) { | 
 | 69 | 		/* Service existing interrupt */ | 
 | 70 | 		qla4xxx_interrupt_service_routine(ha, intr_status); | 
 | 71 | 		clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | 
 | 72 | 	} | 
 | 73 |  | 
 | 74 | 	/* Send the mailbox command to the firmware */ | 
 | 75 | 	ha->mbox_status_count = outCount; | 
 | 76 | 	for (i = 0; i < outCount; i++) | 
 | 77 | 		ha->mbox_status[i] = 0; | 
 | 78 |  | 
 | 79 | 	/* Load all mailbox registers, except mailbox 0. */ | 
 | 80 | 	for (i = 1; i < inCount; i++) | 
 | 81 | 		writel(mbx_cmd[i], &ha->reg->mailbox[i]); | 
 | 82 |  | 
 | 83 | 	/* Wakeup firmware  */ | 
 | 84 | 	writel(mbx_cmd[0], &ha->reg->mailbox[0]); | 
 | 85 | 	readl(&ha->reg->mailbox[0]); | 
 | 86 | 	writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status); | 
 | 87 | 	readl(&ha->reg->ctrl_status); | 
 | 88 | 	spin_unlock_irqrestore(&ha->hardware_lock, flags); | 
 | 89 |  | 
 | 90 | 	/* Wait for completion */ | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 91 |  | 
 | 92 | 	/* | 
 | 93 | 	 * If we don't want status, don't wait for the mailbox command to | 
 | 94 | 	 * complete.  For example, MBOX_CMD_RESET_FW doesn't return status, | 
 | 95 | 	 * you must poll the inbound Interrupt Mask for completion. | 
 | 96 | 	 */ | 
 | 97 | 	if (outCount == 0) { | 
 | 98 | 		status = QLA_SUCCESS; | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 99 | 		goto mbox_exit; | 
 | 100 | 	} | 
 | 101 | 	/* Wait for command to complete */ | 
 | 102 | 	wait_count = jiffies + MBOX_TOV * HZ; | 
 | 103 | 	while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { | 
 | 104 | 		if (time_after_eq(jiffies, wait_count)) | 
 | 105 | 			break; | 
 | 106 |  | 
 | 107 | 		spin_lock_irqsave(&ha->hardware_lock, flags); | 
 | 108 | 		intr_status = readl(&ha->reg->ctrl_status); | 
 | 109 | 		if (intr_status & INTR_PENDING) { | 
 | 110 | 			/* | 
 | 111 | 			 * Service the interrupt. | 
 | 112 | 			 * The ISR will save the mailbox status registers | 
 | 113 | 			 * to a temporary storage location in the adapter | 
 | 114 | 			 * structure. | 
 | 115 | 			 */ | 
 | 116 | 			ha->mbox_status_count = outCount; | 
 | 117 | 			qla4xxx_interrupt_service_routine(ha, intr_status); | 
 | 118 | 		} | 
 | 119 | 		spin_unlock_irqrestore(&ha->hardware_lock, flags); | 
 | 120 | 		msleep(10); | 
 | 121 | 	} | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 122 |  | 
 | 123 | 	/* Check for mailbox timeout. */ | 
 | 124 | 	if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { | 
 | 125 | 		DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...," | 
 | 126 | 			      " Scheduling Adapter Reset\n", ha->host_no, | 
 | 127 | 			      mbx_cmd[0])); | 
 | 128 | 		ha->mailbox_timeout_count++; | 
 | 129 | 		mbx_sts[0] = (-1); | 
 | 130 | 		set_bit(DPC_RESET_HA, &ha->dpc_flags); | 
 | 131 | 		goto mbox_exit; | 
 | 132 | 	} | 
 | 133 |  | 
 | 134 | 	/* | 
 | 135 | 	 * Copy the mailbox out registers to the caller's mailbox in/out | 
 | 136 | 	 * structure. | 
 | 137 | 	 */ | 
 | 138 | 	spin_lock_irqsave(&ha->hardware_lock, flags); | 
 | 139 | 	for (i = 0; i < outCount; i++) | 
 | 140 | 		mbx_sts[i] = ha->mbox_status[i]; | 
 | 141 |  | 
 | 142 | 	/* Set return status and error flags (if applicable). */ | 
 | 143 | 	switch (ha->mbox_status[0]) { | 
 | 144 | 	case MBOX_STS_COMMAND_COMPLETE: | 
 | 145 | 		status = QLA_SUCCESS; | 
 | 146 | 		break; | 
 | 147 |  | 
 | 148 | 	case MBOX_STS_INTERMEDIATE_COMPLETION: | 
 | 149 | 		status = QLA_SUCCESS; | 
 | 150 | 		break; | 
 | 151 |  | 
 | 152 | 	case MBOX_STS_BUSY: | 
 | 153 | 		DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n", | 
 | 154 | 			       ha->host_no, __func__, mbx_cmd[0])); | 
 | 155 | 		ha->mailbox_timeout_count++; | 
 | 156 | 		break; | 
 | 157 |  | 
 | 158 | 	default: | 
 | 159 | 		DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, " | 
 | 160 | 			      "sts = %08X ****\n", ha->host_no, __func__, | 
 | 161 | 			      mbx_cmd[0], mbx_sts[0])); | 
 | 162 | 		break; | 
 | 163 | 	} | 
 | 164 | 	spin_unlock_irqrestore(&ha->hardware_lock, flags); | 
 | 165 |  | 
 | 166 | mbox_exit: | 
| David C Somayajulu | 477ffb9 | 2007-01-22 12:26:11 -0800 | [diff] [blame] | 167 | 	mutex_lock(&ha->mbox_sem); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 168 | 	clear_bit(AF_MBOX_COMMAND, &ha->flags); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 169 | 	mutex_unlock(&ha->mbox_sem); | 
| David C Somayajulu | 477ffb9 | 2007-01-22 12:26:11 -0800 | [diff] [blame] | 170 | 	clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 171 |  | 
 | 172 | 	return status; | 
 | 173 | } | 
 | 174 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 175 | /** | 
 | 176 |  * qla4xxx_initialize_fw_cb - initializes firmware control block. | 
 | 177 |  * @ha: Pointer to host adapter structure. | 
 | 178 |  **/ | 
 | 179 | int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) | 
 | 180 | { | 
 | 181 | 	struct init_fw_ctrl_blk *init_fw_cb; | 
 | 182 | 	dma_addr_t init_fw_cb_dma; | 
 | 183 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 184 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 185 | 	int status = QLA_ERROR; | 
 | 186 |  | 
 | 187 | 	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, | 
 | 188 | 					sizeof(struct init_fw_ctrl_blk), | 
 | 189 | 					&init_fw_cb_dma, GFP_KERNEL); | 
 | 190 | 	if (init_fw_cb == NULL) { | 
 | 191 | 		DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", | 
 | 192 | 			      ha->host_no, __func__)); | 
 | 193 | 		return 10; | 
 | 194 | 	} | 
 | 195 | 	memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); | 
 | 196 |  | 
 | 197 | 	/* Get Initialize Firmware Control Block. */ | 
 | 198 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 199 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 200 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 201 | 	mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; | 
 | 202 | 	mbox_cmd[2] = LSDW(init_fw_cb_dma); | 
 | 203 | 	mbox_cmd[3] = MSDW(init_fw_cb_dma); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 204 | 	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); | 
 | 205 |  | 
 | 206 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 207 | 	    QLA_SUCCESS) { | 
 | 208 | 		dma_free_coherent(&ha->pdev->dev, | 
 | 209 | 				  sizeof(struct init_fw_ctrl_blk), | 
 | 210 | 				  init_fw_cb, init_fw_cb_dma); | 
 | 211 | 		return status; | 
 | 212 | 	} | 
 | 213 |  | 
 | 214 | 	/* Initialize request and response queues. */ | 
 | 215 | 	qla4xxx_init_rings(ha); | 
 | 216 |  | 
 | 217 | 	/* Fill in the request and response queue information. */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 218 | 	init_fw_cb->pri.rqq_consumer_idx = cpu_to_le16(ha->request_out); | 
 | 219 | 	init_fw_cb->pri.compq_producer_idx = cpu_to_le16(ha->response_in); | 
 | 220 | 	init_fw_cb->pri.rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); | 
 | 221 | 	init_fw_cb->pri.compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); | 
 | 222 | 	init_fw_cb->pri.rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma)); | 
 | 223 | 	init_fw_cb->pri.rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma)); | 
 | 224 | 	init_fw_cb->pri.compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma)); | 
 | 225 | 	init_fw_cb->pri.compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma)); | 
 | 226 | 	init_fw_cb->pri.shdwreg_addr_lo = | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 227 | 		cpu_to_le32(LSDW(ha->shadow_regs_dma)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 228 | 	init_fw_cb->pri.shdwreg_addr_hi = | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 229 | 		cpu_to_le32(MSDW(ha->shadow_regs_dma)); | 
 | 230 |  | 
 | 231 | 	/* Set up required options. */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 232 | 	init_fw_cb->pri.fw_options |= | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 233 | 		__constant_cpu_to_le16(FWOPT_SESSION_MODE | | 
 | 234 | 				       FWOPT_INITIATOR_MODE); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 235 | 	init_fw_cb->pri.fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 236 |  | 
 | 237 | 	/* Save some info in adapter structure. */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 238 | 	ha->firmware_options = le16_to_cpu(init_fw_cb->pri.fw_options); | 
 | 239 | 	ha->tcp_options = le16_to_cpu(init_fw_cb->pri.ipv4_tcp_opts); | 
 | 240 | 	ha->heartbeat_interval = init_fw_cb->pri.hb_interval; | 
 | 241 | 	memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr, | 
 | 242 | 	       min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr))); | 
 | 243 | 	memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet, | 
 | 244 | 	       min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet))); | 
 | 245 | 	memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr, | 
 | 246 | 	       min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr))); | 
 | 247 | 	memcpy(ha->name_string, init_fw_cb->pri.iscsi_name, | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 248 | 	       min(sizeof(ha->name_string), | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 249 | 		   sizeof(init_fw_cb->pri.iscsi_name))); | 
 | 250 | 	/*memcpy(ha->alias, init_fw_cb->Alias, | 
 | 251 | 	       min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 252 |  | 
 | 253 | 	/* Save Command Line Paramater info */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 254 | 	ha->port_down_retry_count = le16_to_cpu(init_fw_cb->pri.conn_ka_timeout); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 255 | 	ha->discovery_wait = ql4xdiscoverywait; | 
 | 256 |  | 
 | 257 | 	/* Send Initialize Firmware Control Block. */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 258 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 259 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
 | 260 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 261 | 	mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; | 
 | 262 | 	mbox_cmd[1] = 0; | 
 | 263 | 	mbox_cmd[2] = LSDW(init_fw_cb_dma); | 
 | 264 | 	mbox_cmd[3] = MSDW(init_fw_cb_dma); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 265 | 	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); | 
 | 266 |  | 
 | 267 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) == | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 268 | 	    QLA_SUCCESS) | 
 | 269 | 		status = QLA_SUCCESS; | 
 | 270 | 	 else { | 
 | 271 | 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE " | 
 | 272 | 			      "failed w/ status %04X\n", ha->host_no, __func__, | 
 | 273 | 			      mbox_sts[0])); | 
 | 274 | 	} | 
 | 275 | 	dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), | 
 | 276 | 			  init_fw_cb, init_fw_cb_dma); | 
 | 277 |  | 
 | 278 | 	return status; | 
 | 279 | } | 
 | 280 |  | 
 | 281 | /** | 
 | 282 |  * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP | 
 | 283 |  * @ha: Pointer to host adapter structure. | 
 | 284 |  **/ | 
 | 285 | int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) | 
 | 286 | { | 
 | 287 | 	struct init_fw_ctrl_blk *init_fw_cb; | 
 | 288 | 	dma_addr_t init_fw_cb_dma; | 
 | 289 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 290 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 291 |  | 
 | 292 | 	init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, | 
 | 293 | 					sizeof(struct init_fw_ctrl_blk), | 
 | 294 | 					&init_fw_cb_dma, GFP_KERNEL); | 
 | 295 | 	if (init_fw_cb == NULL) { | 
 | 296 | 		printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, | 
 | 297 | 		       __func__); | 
 | 298 | 		return 10; | 
 | 299 | 	} | 
 | 300 |  | 
 | 301 | 	/* Get Initialize Firmware Control Block. */ | 
 | 302 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 303 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 304 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 305 | 	memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk)); | 
 | 306 | 	mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; | 
 | 307 | 	mbox_cmd[2] = LSDW(init_fw_cb_dma); | 
 | 308 | 	mbox_cmd[3] = MSDW(init_fw_cb_dma); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 309 | 	mbox_cmd[4] = sizeof(struct init_fw_ctrl_blk); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 310 |  | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 311 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 312 | 	    QLA_SUCCESS) { | 
 | 313 | 		DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", | 
 | 314 | 			      ha->host_no, __func__)); | 
 | 315 | 		dma_free_coherent(&ha->pdev->dev, | 
 | 316 | 				  sizeof(struct init_fw_ctrl_blk), | 
 | 317 | 				  init_fw_cb, init_fw_cb_dma); | 
 | 318 | 		return QLA_ERROR; | 
 | 319 | 	} | 
 | 320 |  | 
 | 321 | 	/* Save IP Address. */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 322 | 	memcpy(ha->ip_address, init_fw_cb->pri.ipv4_addr, | 
 | 323 | 	       min(sizeof(ha->ip_address), sizeof(init_fw_cb->pri.ipv4_addr))); | 
 | 324 | 	memcpy(ha->subnet_mask, init_fw_cb->pri.ipv4_subnet, | 
 | 325 | 	       min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->pri.ipv4_subnet))); | 
 | 326 | 	memcpy(ha->gateway, init_fw_cb->pri.ipv4_gw_addr, | 
 | 327 | 	       min(sizeof(ha->gateway), sizeof(init_fw_cb->pri.ipv4_gw_addr))); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 328 |  | 
 | 329 | 	dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk), | 
 | 330 | 			  init_fw_cb, init_fw_cb_dma); | 
 | 331 |  | 
 | 332 | 	return QLA_SUCCESS; | 
 | 333 | } | 
 | 334 |  | 
 | 335 | /** | 
 | 336 |  * qla4xxx_get_firmware_state - gets firmware state of HBA | 
 | 337 |  * @ha: Pointer to host adapter structure. | 
 | 338 |  **/ | 
 | 339 | int qla4xxx_get_firmware_state(struct scsi_qla_host * ha) | 
 | 340 | { | 
 | 341 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 342 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 343 |  | 
 | 344 | 	/* Get firmware version */ | 
 | 345 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 346 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 347 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 348 | 	mbox_cmd[0] = MBOX_CMD_GET_FW_STATE; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 349 |  | 
 | 350 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 4, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 351 | 	    QLA_SUCCESS) { | 
 | 352 | 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ " | 
 | 353 | 			      "status %04X\n", ha->host_no, __func__, | 
 | 354 | 			      mbox_sts[0])); | 
 | 355 | 		return QLA_ERROR; | 
 | 356 | 	} | 
 | 357 | 	ha->firmware_state = mbox_sts[1]; | 
 | 358 | 	ha->board_id = mbox_sts[2]; | 
 | 359 | 	ha->addl_fw_state = mbox_sts[3]; | 
 | 360 | 	DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n", | 
 | 361 | 		      ha->host_no, __func__, ha->firmware_state);) | 
 | 362 |  | 
 | 363 | 		return QLA_SUCCESS; | 
 | 364 | } | 
 | 365 |  | 
 | 366 | /** | 
 | 367 |  * qla4xxx_get_firmware_status - retrieves firmware status | 
 | 368 |  * @ha: Pointer to host adapter structure. | 
 | 369 |  **/ | 
 | 370 | int qla4xxx_get_firmware_status(struct scsi_qla_host * ha) | 
 | 371 | { | 
 | 372 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 373 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 374 |  | 
 | 375 | 	/* Get firmware version */ | 
 | 376 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 377 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 378 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 379 | 	mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 380 |  | 
 | 381 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 382 | 	    QLA_SUCCESS) { | 
 | 383 | 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ " | 
 | 384 | 			      "status %04X\n", ha->host_no, __func__, | 
 | 385 | 			      mbox_sts[0])); | 
 | 386 | 		return QLA_ERROR; | 
 | 387 | 	} | 
 | 388 |  | 
 | 389 | 	/* High-water mark of IOCBs */ | 
 | 390 | 	ha->iocb_hiwat = mbox_sts[2]; | 
 | 391 | 	if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION) | 
 | 392 | 		ha->iocb_hiwat -= IOCB_HIWAT_CUSHION; | 
 | 393 | 	else | 
 | 394 | 		dev_info(&ha->pdev->dev, "WARNING!!!  You have less than %d " | 
 | 395 | 			   "firmare IOCBs available (%d).\n", | 
 | 396 | 			   IOCB_HIWAT_CUSHION, ha->iocb_hiwat); | 
 | 397 |  | 
 | 398 | 	return QLA_SUCCESS; | 
 | 399 | } | 
 | 400 |  | 
 | 401 | /** | 
 | 402 |  * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry | 
 | 403 |  * @ha: Pointer to host adapter structure. | 
 | 404 |  * @fw_ddb_index: Firmware's device database index | 
 | 405 |  * @fw_ddb_entry: Pointer to firmware's device database entry structure | 
 | 406 |  * @num_valid_ddb_entries: Pointer to number of valid ddb entries | 
 | 407 |  * @next_ddb_index: Pointer to next valid device database index | 
 | 408 |  * @fw_ddb_device_state: Pointer to device state | 
 | 409 |  **/ | 
 | 410 | int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, | 
 | 411 | 			    uint16_t fw_ddb_index, | 
 | 412 | 			    struct dev_db_entry *fw_ddb_entry, | 
 | 413 | 			    dma_addr_t fw_ddb_entry_dma, | 
 | 414 | 			    uint32_t *num_valid_ddb_entries, | 
 | 415 | 			    uint32_t *next_ddb_index, | 
 | 416 | 			    uint32_t *fw_ddb_device_state, | 
 | 417 | 			    uint32_t *conn_err_detail, | 
 | 418 | 			    uint16_t *tcp_source_port_num, | 
 | 419 | 			    uint16_t *connection_id) | 
 | 420 | { | 
 | 421 | 	int status = QLA_ERROR; | 
 | 422 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 423 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 424 |  | 
 | 425 | 	/* Make sure the device index is valid */ | 
 | 426 | 	if (fw_ddb_index >= MAX_DDB_ENTRIES) { | 
 | 427 | 		DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n", | 
 | 428 | 			      ha->host_no, __func__, fw_ddb_index)); | 
 | 429 | 		goto exit_get_fwddb; | 
 | 430 | 	} | 
 | 431 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 432 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 433 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 434 | 	mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY; | 
 | 435 | 	mbox_cmd[1] = (uint32_t) fw_ddb_index; | 
 | 436 | 	mbox_cmd[2] = LSDW(fw_ddb_entry_dma); | 
 | 437 | 	mbox_cmd[3] = MSDW(fw_ddb_entry_dma); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 438 | 	mbox_cmd[4] = sizeof(struct dev_db_entry); | 
 | 439 |  | 
 | 440 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 7, &mbox_cmd[0], &mbox_sts[0]) == | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 441 | 	    QLA_ERROR) { | 
 | 442 | 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed" | 
 | 443 | 			      " with status 0x%04X\n", ha->host_no, __func__, | 
 | 444 | 			      mbox_sts[0])); | 
 | 445 | 		goto exit_get_fwddb; | 
 | 446 | 	} | 
 | 447 | 	if (fw_ddb_index != mbox_sts[1]) { | 
 | 448 | 		DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n", | 
 | 449 | 			      ha->host_no, __func__, fw_ddb_index, | 
 | 450 | 			      mbox_sts[1])); | 
 | 451 | 		goto exit_get_fwddb; | 
 | 452 | 	} | 
 | 453 | 	if (fw_ddb_entry) { | 
 | 454 | 		dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d " | 
 | 455 | 			   "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n", | 
 | 456 | 			   fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3], | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 457 | 			   mbox_sts[4], mbox_sts[5], fw_ddb_entry->ip_addr[0], | 
 | 458 | 			   fw_ddb_entry->ip_addr[1], fw_ddb_entry->ip_addr[2], | 
 | 459 | 			   fw_ddb_entry->ip_addr[3], | 
 | 460 | 			   le16_to_cpu(fw_ddb_entry->port), | 
 | 461 | 			   fw_ddb_entry->iscsi_name); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 462 | 	} | 
 | 463 | 	if (num_valid_ddb_entries) | 
 | 464 | 		*num_valid_ddb_entries = mbox_sts[2]; | 
 | 465 | 	if (next_ddb_index) | 
 | 466 | 		*next_ddb_index = mbox_sts[3]; | 
 | 467 | 	if (fw_ddb_device_state) | 
 | 468 | 		*fw_ddb_device_state = mbox_sts[4]; | 
 | 469 |  | 
 | 470 | 	/* | 
 | 471 | 	 * RA: This mailbox has been changed to pass connection error and | 
 | 472 | 	 * details.  Its true for ISP4010 as per Version E - Not sure when it | 
 | 473 | 	 * was changed.	 Get the time2wait from the fw_dd_entry field : | 
 | 474 | 	 * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY | 
 | 475 | 	 * struct. | 
 | 476 | 	 */ | 
 | 477 | 	if (conn_err_detail) | 
 | 478 | 		*conn_err_detail = mbox_sts[5]; | 
 | 479 | 	if (tcp_source_port_num) | 
 | 480 | 		*tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16; | 
 | 481 | 	if (connection_id) | 
 | 482 | 		*connection_id = (uint16_t) mbox_sts[6] & 0x00FF; | 
 | 483 | 	status = QLA_SUCCESS; | 
 | 484 |  | 
 | 485 | exit_get_fwddb: | 
 | 486 | 	return status; | 
 | 487 | } | 
 | 488 |  | 
 | 489 | /** | 
 | 490 |  * qla4xxx_set_fwddb_entry - sets a ddb entry. | 
 | 491 |  * @ha: Pointer to host adapter structure. | 
 | 492 |  * @fw_ddb_index: Firmware's device database index | 
 | 493 |  * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL. | 
 | 494 |  * | 
 | 495 |  * This routine initializes or updates the adapter's device database | 
 | 496 |  * entry for the specified device. It also triggers a login for the | 
 | 497 |  * specified device. Therefore, it may also be used as a secondary | 
 | 498 |  * login routine when a NULL pointer is specified for the fw_ddb_entry. | 
 | 499 |  **/ | 
 | 500 | int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, | 
 | 501 | 			  dma_addr_t fw_ddb_entry_dma) | 
 | 502 | { | 
 | 503 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 504 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 505 |  | 
 | 506 | 	/* Do not wait for completion. The firmware will send us an | 
 | 507 | 	 * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. | 
 | 508 | 	 */ | 
 | 509 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 510 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
 | 511 |  | 
 | 512 | 	mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY; | 
 | 513 | 	mbox_cmd[1] = (uint32_t) fw_ddb_index; | 
 | 514 | 	mbox_cmd[2] = LSDW(fw_ddb_entry_dma); | 
 | 515 | 	mbox_cmd[3] = MSDW(fw_ddb_entry_dma); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 516 | 	mbox_cmd[4] = sizeof(struct dev_db_entry); | 
 | 517 |  | 
 | 518 | 	return qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 519 | } | 
 | 520 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 521 | /** | 
 | 522 |  * qla4xxx_get_crash_record - retrieves crash record. | 
 | 523 |  * @ha: Pointer to host adapter structure. | 
 | 524 |  * | 
 | 525 |  * This routine retrieves a crash record from the QLA4010 after an 8002h aen. | 
 | 526 |  **/ | 
 | 527 | void qla4xxx_get_crash_record(struct scsi_qla_host * ha) | 
 | 528 | { | 
 | 529 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 530 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 531 | 	struct crash_record *crash_record = NULL; | 
 | 532 | 	dma_addr_t crash_record_dma = 0; | 
 | 533 | 	uint32_t crash_record_size = 0; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 534 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 535 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 536 | 	memset(&mbox_sts, 0, sizeof(mbox_cmd)); | 
 | 537 |  | 
 | 538 | 	/* Get size of crash record. */ | 
 | 539 | 	mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 540 |  | 
 | 541 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 542 | 	    QLA_SUCCESS) { | 
 | 543 | 		DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n", | 
 | 544 | 			      ha->host_no, __func__)); | 
 | 545 | 		goto exit_get_crash_record; | 
 | 546 | 	} | 
 | 547 | 	crash_record_size = mbox_sts[4]; | 
 | 548 | 	if (crash_record_size == 0) { | 
 | 549 | 		DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n", | 
 | 550 | 			      ha->host_no, __func__)); | 
 | 551 | 		goto exit_get_crash_record; | 
 | 552 | 	} | 
 | 553 |  | 
 | 554 | 	/* Alloc Memory for Crash Record. */ | 
 | 555 | 	crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size, | 
 | 556 | 					  &crash_record_dma, GFP_KERNEL); | 
 | 557 | 	if (crash_record == NULL) | 
 | 558 | 		goto exit_get_crash_record; | 
 | 559 |  | 
 | 560 | 	/* Get Crash Record. */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 561 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 562 | 	memset(&mbox_sts, 0, sizeof(mbox_cmd)); | 
 | 563 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 564 | 	mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; | 
 | 565 | 	mbox_cmd[2] = LSDW(crash_record_dma); | 
 | 566 | 	mbox_cmd[3] = MSDW(crash_record_dma); | 
 | 567 | 	mbox_cmd[4] = crash_record_size; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 568 |  | 
 | 569 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 570 | 	    QLA_SUCCESS) | 
 | 571 | 		goto exit_get_crash_record; | 
 | 572 |  | 
 | 573 | 	/* Dump Crash Record. */ | 
 | 574 |  | 
 | 575 | exit_get_crash_record: | 
 | 576 | 	if (crash_record) | 
 | 577 | 		dma_free_coherent(&ha->pdev->dev, crash_record_size, | 
 | 578 | 				  crash_record, crash_record_dma); | 
 | 579 | } | 
 | 580 |  | 
 | 581 | /** | 
 | 582 |  * qla4xxx_get_conn_event_log - retrieves connection event log | 
 | 583 |  * @ha: Pointer to host adapter structure. | 
 | 584 |  **/ | 
 | 585 | void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) | 
 | 586 | { | 
 | 587 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 588 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 589 | 	struct conn_event_log_entry *event_log = NULL; | 
 | 590 | 	dma_addr_t event_log_dma = 0; | 
 | 591 | 	uint32_t event_log_size = 0; | 
 | 592 | 	uint32_t num_valid_entries; | 
 | 593 | 	uint32_t      oldest_entry = 0; | 
 | 594 | 	uint32_t	max_event_log_entries; | 
 | 595 | 	uint8_t		i; | 
 | 596 |  | 
 | 597 |  | 
 | 598 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 599 | 	memset(&mbox_sts, 0, sizeof(mbox_cmd)); | 
 | 600 |  | 
 | 601 | 	/* Get size of crash record. */ | 
 | 602 | 	mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 603 |  | 
 | 604 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 605 | 	    QLA_SUCCESS) | 
 | 606 | 		goto exit_get_event_log; | 
 | 607 |  | 
 | 608 | 	event_log_size = mbox_sts[4]; | 
 | 609 | 	if (event_log_size == 0) | 
 | 610 | 		goto exit_get_event_log; | 
 | 611 |  | 
 | 612 | 	/* Alloc Memory for Crash Record. */ | 
 | 613 | 	event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size, | 
 | 614 | 				       &event_log_dma, GFP_KERNEL); | 
 | 615 | 	if (event_log == NULL) | 
 | 616 | 		goto exit_get_event_log; | 
 | 617 |  | 
 | 618 | 	/* Get Crash Record. */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 619 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 620 | 	memset(&mbox_sts, 0, sizeof(mbox_cmd)); | 
 | 621 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 622 | 	mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; | 
 | 623 | 	mbox_cmd[2] = LSDW(event_log_dma); | 
 | 624 | 	mbox_cmd[3] = MSDW(event_log_dma); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 625 |  | 
 | 626 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 627 | 	    QLA_SUCCESS) { | 
 | 628 | 		DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event " | 
 | 629 | 			      "log!\n", ha->host_no, __func__)); | 
 | 630 | 		goto exit_get_event_log; | 
 | 631 | 	} | 
 | 632 |  | 
 | 633 | 	/* Dump Event Log. */ | 
 | 634 | 	num_valid_entries = mbox_sts[1]; | 
 | 635 |  | 
 | 636 | 	max_event_log_entries = event_log_size / | 
 | 637 | 		sizeof(struct conn_event_log_entry); | 
 | 638 |  | 
 | 639 | 	if (num_valid_entries > max_event_log_entries) | 
 | 640 | 		oldest_entry = num_valid_entries % max_event_log_entries; | 
 | 641 |  | 
 | 642 | 	DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", | 
 | 643 | 		      ha->host_no, num_valid_entries)); | 
 | 644 |  | 
| Andrew Vasquez | 11010fe | 2006-10-06 09:54:59 -0700 | [diff] [blame] | 645 | 	if (ql4xextended_error_logging == 3) { | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 646 | 		if (oldest_entry == 0) { | 
 | 647 | 			/* Circular Buffer has not wrapped around */ | 
 | 648 | 			for (i=0; i < num_valid_entries; i++) { | 
 | 649 | 				qla4xxx_dump_buffer((uint8_t *)event_log+ | 
 | 650 | 						    (i*sizeof(*event_log)), | 
 | 651 | 						    sizeof(*event_log)); | 
 | 652 | 			} | 
 | 653 | 		} | 
 | 654 | 		else { | 
 | 655 | 			/* Circular Buffer has wrapped around - | 
 | 656 | 			 * display accordingly*/ | 
 | 657 | 			for (i=oldest_entry; i < max_event_log_entries; i++) { | 
 | 658 | 				qla4xxx_dump_buffer((uint8_t *)event_log+ | 
 | 659 | 						    (i*sizeof(*event_log)), | 
 | 660 | 						    sizeof(*event_log)); | 
 | 661 | 			} | 
 | 662 | 			for (i=0; i < oldest_entry; i++) { | 
 | 663 | 				qla4xxx_dump_buffer((uint8_t *)event_log+ | 
 | 664 | 						    (i*sizeof(*event_log)), | 
 | 665 | 						    sizeof(*event_log)); | 
 | 666 | 			} | 
 | 667 | 		} | 
 | 668 | 	} | 
 | 669 |  | 
 | 670 | exit_get_event_log: | 
 | 671 | 	if (event_log) | 
 | 672 | 		dma_free_coherent(&ha->pdev->dev, event_log_size, event_log, | 
 | 673 | 				  event_log_dma); | 
 | 674 | } | 
 | 675 |  | 
 | 676 | /** | 
 | 677 |  * qla4xxx_reset_lun - issues LUN Reset | 
 | 678 |  * @ha: Pointer to host adapter structure. | 
 | 679 |  * @db_entry: Pointer to device database entry | 
 | 680 |  * @un_entry: Pointer to lun entry structure | 
 | 681 |  * | 
 | 682 |  * This routine performs a LUN RESET on the specified target/lun. | 
 | 683 |  * The caller must ensure that the ddb_entry and lun_entry pointers | 
 | 684 |  * are valid before calling this routine. | 
 | 685 |  **/ | 
 | 686 | int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, | 
 | 687 | 		      int lun) | 
 | 688 | { | 
 | 689 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 690 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 691 | 	int status = QLA_SUCCESS; | 
 | 692 |  | 
 | 693 | 	DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no, | 
 | 694 | 		      ddb_entry->os_target_id, lun)); | 
 | 695 |  | 
 | 696 | 	/* | 
 | 697 | 	 * Send lun reset command to ISP, so that the ISP will return all | 
 | 698 | 	 * outstanding requests with RESET status | 
 | 699 | 	 */ | 
 | 700 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 701 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 702 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 703 | 	mbox_cmd[0] = MBOX_CMD_LUN_RESET; | 
 | 704 | 	mbox_cmd[1] = ddb_entry->fw_ddb_index; | 
 | 705 | 	mbox_cmd[2] = lun << 8; | 
 | 706 | 	mbox_cmd[5] = 0x01;	/* Immediate Command Enable */ | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 707 |  | 
 | 708 | 	qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 709 | 	if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && | 
 | 710 | 	    mbox_sts[0] != MBOX_STS_COMMAND_ERROR) | 
 | 711 | 		status = QLA_ERROR; | 
 | 712 |  | 
 | 713 | 	return status; | 
 | 714 | } | 
 | 715 |  | 
| Mike Christie | ce54503 | 2008-02-29 18:25:20 -0600 | [diff] [blame] | 716 | /** | 
 | 717 |  * qla4xxx_reset_target - issues target Reset | 
 | 718 |  * @ha: Pointer to host adapter structure. | 
 | 719 |  * @db_entry: Pointer to device database entry | 
 | 720 |  * @un_entry: Pointer to lun entry structure | 
 | 721 |  * | 
 | 722 |  * This routine performs a TARGET RESET on the specified target. | 
 | 723 |  * The caller must ensure that the ddb_entry pointers | 
 | 724 |  * are valid before calling this routine. | 
 | 725 |  **/ | 
 | 726 | int qla4xxx_reset_target(struct scsi_qla_host *ha, | 
 | 727 | 			 struct ddb_entry *ddb_entry) | 
 | 728 | { | 
 | 729 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 730 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 731 | 	int status = QLA_SUCCESS; | 
 | 732 |  | 
 | 733 | 	DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, | 
 | 734 | 		      ddb_entry->os_target_id)); | 
 | 735 |  | 
 | 736 | 	/* | 
 | 737 | 	 * Send target reset command to ISP, so that the ISP will return all | 
 | 738 | 	 * outstanding requests with RESET status | 
 | 739 | 	 */ | 
 | 740 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 741 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
 | 742 |  | 
 | 743 | 	mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET; | 
 | 744 | 	mbox_cmd[1] = ddb_entry->fw_ddb_index; | 
 | 745 | 	mbox_cmd[5] = 0x01;	/* Immediate Command Enable */ | 
 | 746 |  | 
 | 747 | 	qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], | 
 | 748 | 				&mbox_sts[0]); | 
 | 749 | 	if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && | 
 | 750 | 	    mbox_sts[0] != MBOX_STS_COMMAND_ERROR) | 
 | 751 | 		status = QLA_ERROR; | 
 | 752 |  | 
 | 753 | 	return status; | 
 | 754 | } | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 755 |  | 
 | 756 | int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, | 
 | 757 | 		      uint32_t offset, uint32_t len) | 
 | 758 | { | 
 | 759 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 760 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 761 |  | 
 | 762 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 763 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 764 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 765 | 	mbox_cmd[0] = MBOX_CMD_READ_FLASH; | 
 | 766 | 	mbox_cmd[1] = LSDW(dma_addr); | 
 | 767 | 	mbox_cmd[2] = MSDW(dma_addr); | 
 | 768 | 	mbox_cmd[3] = offset; | 
 | 769 | 	mbox_cmd[4] = len; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 770 |  | 
 | 771 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 772 | 	    QLA_SUCCESS) { | 
 | 773 | 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ " | 
 | 774 | 		    "status %04X %04X, offset %08x, len %08x\n", ha->host_no, | 
 | 775 | 		    __func__, mbox_sts[0], mbox_sts[1], offset, len)); | 
 | 776 | 		return QLA_ERROR; | 
 | 777 | 	} | 
 | 778 | 	return QLA_SUCCESS; | 
 | 779 | } | 
 | 780 |  | 
 | 781 | /** | 
 | 782 |  * qla4xxx_get_fw_version - gets firmware version | 
 | 783 |  * @ha: Pointer to host adapter structure. | 
 | 784 |  * | 
 | 785 |  * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may | 
 | 786 |  * hold an address for data.  Make sure that we write 0 to those mailboxes, | 
 | 787 |  * if unused. | 
 | 788 |  **/ | 
 | 789 | int qla4xxx_get_fw_version(struct scsi_qla_host * ha) | 
 | 790 | { | 
 | 791 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 792 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 793 |  | 
 | 794 | 	/* Get firmware version. */ | 
 | 795 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 796 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 797 |  | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 798 | 	mbox_cmd[0] = MBOX_CMD_ABOUT_FW; | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 799 |  | 
 | 800 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 801 | 	    QLA_SUCCESS) { | 
 | 802 | 		DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ " | 
 | 803 | 		    "status %04X\n", ha->host_no, __func__, mbox_sts[0])); | 
 | 804 | 		return QLA_ERROR; | 
 | 805 | 	} | 
 | 806 |  | 
 | 807 | 	/* Save firmware version information. */ | 
 | 808 | 	ha->firmware_version[0] = mbox_sts[1]; | 
 | 809 | 	ha->firmware_version[1] = mbox_sts[2]; | 
 | 810 | 	ha->patch_number = mbox_sts[3]; | 
 | 811 | 	ha->build_number = mbox_sts[4]; | 
 | 812 |  | 
 | 813 | 	return QLA_SUCCESS; | 
 | 814 | } | 
 | 815 |  | 
| Adrian Bunk | 4797547 | 2007-04-26 00:35:16 -0700 | [diff] [blame] | 816 | static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, | 
 | 817 | 				   dma_addr_t dma_addr) | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 818 | { | 
 | 819 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 820 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 821 |  | 
 | 822 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 823 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
 | 824 |  | 
 | 825 | 	mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS; | 
 | 826 | 	mbox_cmd[2] = LSDW(dma_addr); | 
 | 827 | 	mbox_cmd[3] = MSDW(dma_addr); | 
 | 828 |  | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 829 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 830 | 	    QLA_SUCCESS) { | 
 | 831 | 		DEBUG2(printk("scsi%ld: %s: failed status %04X\n", | 
 | 832 | 		     ha->host_no, __func__, mbox_sts[0])); | 
 | 833 | 		return QLA_ERROR; | 
 | 834 | 	} | 
 | 835 | 	return QLA_SUCCESS; | 
 | 836 | } | 
 | 837 |  | 
| Adrian Bunk | 4797547 | 2007-04-26 00:35:16 -0700 | [diff] [blame] | 838 | static int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t *ddb_index) | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 839 | { | 
 | 840 | 	uint32_t mbox_cmd[MBOX_REG_COUNT]; | 
 | 841 | 	uint32_t mbox_sts[MBOX_REG_COUNT]; | 
 | 842 |  | 
 | 843 | 	memset(&mbox_cmd, 0, sizeof(mbox_cmd)); | 
 | 844 | 	memset(&mbox_sts, 0, sizeof(mbox_sts)); | 
 | 845 |  | 
 | 846 | 	mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY; | 
 | 847 | 	mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES; | 
 | 848 |  | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 849 | 	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) != | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 850 | 	    QLA_SUCCESS) { | 
 | 851 | 		if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) { | 
 | 852 | 			*ddb_index = mbox_sts[2]; | 
 | 853 | 		} else { | 
 | 854 | 			DEBUG2(printk("scsi%ld: %s: failed status %04X\n", | 
 | 855 | 			     ha->host_no, __func__, mbox_sts[0])); | 
 | 856 | 			return QLA_ERROR; | 
 | 857 | 		} | 
 | 858 | 	} else { | 
 | 859 | 		*ddb_index = MAX_PRST_DEV_DB_ENTRIES; | 
 | 860 | 	} | 
 | 861 |  | 
 | 862 | 	return QLA_SUCCESS; | 
 | 863 | } | 
 | 864 |  | 
 | 865 |  | 
 | 866 | int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port) | 
 | 867 | { | 
 | 868 | 	struct dev_db_entry *fw_ddb_entry; | 
 | 869 | 	dma_addr_t fw_ddb_entry_dma; | 
 | 870 | 	uint32_t ddb_index; | 
 | 871 | 	int ret_val = QLA_SUCCESS; | 
 | 872 |  | 
 | 873 |  | 
 | 874 | 	fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, | 
 | 875 | 					  sizeof(*fw_ddb_entry), | 
 | 876 | 					  &fw_ddb_entry_dma, GFP_KERNEL); | 
 | 877 | 	if (!fw_ddb_entry) { | 
 | 878 | 		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", | 
 | 879 | 			      ha->host_no, __func__)); | 
 | 880 | 		ret_val = QLA_ERROR; | 
 | 881 | 		goto qla4xxx_send_tgts_exit; | 
 | 882 | 	} | 
 | 883 |  | 
 | 884 | 	ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma); | 
 | 885 | 	if (ret_val != QLA_SUCCESS) | 
 | 886 | 		goto qla4xxx_send_tgts_exit; | 
 | 887 |  | 
 | 888 | 	ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index); | 
 | 889 | 	if (ret_val != QLA_SUCCESS) | 
 | 890 | 		goto qla4xxx_send_tgts_exit; | 
 | 891 |  | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 892 | 	memset(fw_ddb_entry->iscsi_alias, 0, | 
 | 893 | 	       sizeof(fw_ddb_entry->iscsi_alias)); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 894 |  | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 895 | 	memset(fw_ddb_entry->iscsi_name, 0, | 
 | 896 | 	       sizeof(fw_ddb_entry->iscsi_name)); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 897 |  | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 898 | 	memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr)); | 
 | 899 | 	memset(fw_ddb_entry->tgt_addr, 0, | 
 | 900 | 	       sizeof(fw_ddb_entry->tgt_addr)); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 901 |  | 
 | 902 | 	fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET); | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 903 | 	fw_ddb_entry->port = cpu_to_le16(ntohs(port)); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 904 |  | 
| David C Somayajulu | c0e344c | 2007-05-23 18:03:27 -0700 | [diff] [blame] | 905 | 	fw_ddb_entry->ip_addr[0] = *ip; | 
 | 906 | 	fw_ddb_entry->ip_addr[1] = *(ip + 1); | 
 | 907 | 	fw_ddb_entry->ip_addr[2] = *(ip + 2); | 
 | 908 | 	fw_ddb_entry->ip_addr[3] = *(ip + 3); | 
| David Somayajulu | afaf5a2 | 2006-09-19 10:28:00 -0700 | [diff] [blame] | 909 |  | 
 | 910 | 	ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma); | 
 | 911 |  | 
 | 912 | qla4xxx_send_tgts_exit: | 
 | 913 | 	dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), | 
 | 914 | 			  fw_ddb_entry, fw_ddb_entry_dma); | 
 | 915 | 	return ret_val; | 
 | 916 | } | 
 | 917 |  |