brintos

brintos / linux-shallow public Read only

0
0
Text · 44.7 KiB · cf52258 Raw
1622 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * QLogic iSCSI HBA Driver4 * Copyright (c)  2003-2013 QLogic Corporation5 */6 7#include "ql4_def.h"8#include "ql4_glbl.h"9#include "ql4_dbg.h"10#include "ql4_inline.h"11 12/**13 * qla4xxx_copy_sense - copy sense data	into cmd sense buffer14 * @ha: Pointer to host adapter structure.15 * @sts_entry: Pointer to status entry structure.16 * @srb: Pointer to srb structure.17 **/18static void qla4xxx_copy_sense(struct scsi_qla_host *ha,19                               struct status_entry *sts_entry,20                               struct srb *srb)21{22	struct scsi_cmnd *cmd = srb->cmd;23	uint16_t sense_len;24 25	memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);26	sense_len = le16_to_cpu(sts_entry->senseDataByteCnt);27	if (sense_len == 0) {28		DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d:%llu: %s:"29				  " sense len 0\n", ha->host_no,30				  cmd->device->channel, cmd->device->id,31				  cmd->device->lun, __func__));32		ha->status_srb = NULL;33		return;34	}35	/* Save total available sense length,36	 * not to exceed cmd's sense buffer size */37	sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE);38	srb->req_sense_ptr = cmd->sense_buffer;39	srb->req_sense_len = sense_len;40 41	/* Copy sense from sts_entry pkt */42	sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN);43	memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len);44 45	DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%llu: %s: sense key = %x, "46		"ASL= %02x, ASC/ASCQ = %02x/%02x\n", ha->host_no,47		cmd->device->channel, cmd->device->id,48		cmd->device->lun, __func__,49		sts_entry->senseData[2] & 0x0f,50		sts_entry->senseData[7],51		sts_entry->senseData[12],52		sts_entry->senseData[13]));53 54	DEBUG5(qla4xxx_dump_buffer(cmd->sense_buffer, sense_len));55	srb->flags |= SRB_GOT_SENSE;56 57	/* Update srb, in case a sts_cont pkt follows */58	srb->req_sense_ptr += sense_len;59	srb->req_sense_len -= sense_len;60	if (srb->req_sense_len != 0)61		ha->status_srb = srb;62	else63		ha->status_srb = NULL;64}65 66/**67 * qla4xxx_status_cont_entry - Process a Status Continuations entry.68 * @ha: SCSI driver HA context69 * @sts_cont: Entry pointer70 *71 * Extended sense data.72 */73static void74qla4xxx_status_cont_entry(struct scsi_qla_host *ha,75			  struct status_cont_entry *sts_cont)76{77	struct srb *srb = ha->status_srb;78	struct scsi_cmnd *cmd;79	uint16_t sense_len;80 81	if (srb == NULL)82		return;83 84	cmd = srb->cmd;85	if (cmd == NULL) {86		DEBUG2(printk(KERN_INFO "scsi%ld: %s: Cmd already returned "87			"back to OS srb=%p srb->state:%d\n", ha->host_no,88			__func__, srb, srb->state));89		ha->status_srb = NULL;90		return;91	}92 93	/* Copy sense data. */94	sense_len = min_t(uint16_t, srb->req_sense_len,95			  IOCB_MAX_EXT_SENSEDATA_LEN);96	memcpy(srb->req_sense_ptr, sts_cont->ext_sense_data, sense_len);97	DEBUG5(qla4xxx_dump_buffer(srb->req_sense_ptr, sense_len));98 99	srb->req_sense_ptr += sense_len;100	srb->req_sense_len -= sense_len;101 102	/* Place command on done queue. */103	if (srb->req_sense_len == 0) {104		kref_put(&srb->srb_ref, qla4xxx_srb_compl);105		ha->status_srb = NULL;106	}107}108 109/**110 * qla4xxx_status_entry - processes status IOCBs111 * @ha: Pointer to host adapter structure.112 * @sts_entry: Pointer to status entry structure.113 **/114static void qla4xxx_status_entry(struct scsi_qla_host *ha,115				 struct status_entry *sts_entry)116{117	uint8_t scsi_status;118	struct scsi_cmnd *cmd;119	struct srb *srb;120	struct ddb_entry *ddb_entry;121	uint32_t residual;122 123	srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));124	if (!srb) {125		ql4_printk(KERN_WARNING, ha, "%s invalid status entry: "126			   "handle=0x%0x, srb=%p\n", __func__,127			   sts_entry->handle, srb);128		if (is_qla80XX(ha))129			set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags);130		else131			set_bit(DPC_RESET_HA, &ha->dpc_flags);132		return;133	}134 135	cmd = srb->cmd;136	if (cmd == NULL) {137		DEBUG2(printk("scsi%ld: %s: Command already returned back to "138			      "OS pkt->handle=%d srb=%p srb->state:%d\n",139			      ha->host_no, __func__, sts_entry->handle,140			      srb, srb->state));141		ql4_printk(KERN_WARNING, ha, "Command is NULL:"142		    " already returned to OS (srb=%p)\n", srb);143		return;144	}145 146	ddb_entry = srb->ddb;147	if (ddb_entry == NULL) {148		cmd->result = DID_NO_CONNECT << 16;149		goto status_entry_exit;150	}151 152	residual = le32_to_cpu(sts_entry->residualByteCnt);153 154	/* Translate ISP error to a Linux SCSI error. */155	scsi_status = sts_entry->scsiStatus;156	switch (sts_entry->completionStatus) {157	case SCS_COMPLETE:158 159		if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {160			cmd->result = DID_ERROR << 16;161			break;162		}163 164		if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) {165			scsi_set_resid(cmd, residual);166			if (!scsi_status && ((scsi_bufflen(cmd) - residual) <167				cmd->underflow)) {168 169				cmd->result = DID_ERROR << 16;170 171				DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: "172					"Mid-layer Data underrun0, "173					"xferlen = 0x%x, "174					"residual = 0x%x\n", ha->host_no,175					cmd->device->channel,176					cmd->device->id,177					cmd->device->lun, __func__,178					scsi_bufflen(cmd), residual));179				break;180			}181		}182 183		cmd->result = DID_OK << 16 | scsi_status;184 185		if (scsi_status != SAM_STAT_CHECK_CONDITION)186			break;187 188		/* Copy Sense Data into sense buffer. */189		qla4xxx_copy_sense(ha, sts_entry, srb);190		break;191 192	case SCS_INCOMPLETE:193		/* Always set the status to DID_ERROR, since194		 * all conditions result in that status anyway */195		cmd->result = DID_ERROR << 16;196		break;197 198	case SCS_RESET_OCCURRED:199		DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: Device RESET occurred\n",200			      ha->host_no, cmd->device->channel,201			      cmd->device->id, cmd->device->lun, __func__));202 203		cmd->result = DID_RESET << 16;204		break;205 206	case SCS_ABORTED:207		DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: Abort occurred\n",208			      ha->host_no, cmd->device->channel,209			      cmd->device->id, cmd->device->lun, __func__));210 211		cmd->result = DID_RESET << 16;212		break;213 214	case SCS_TIMEOUT:215		DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%llu: Timeout\n",216			      ha->host_no, cmd->device->channel,217			      cmd->device->id, cmd->device->lun));218 219		cmd->result = DID_TRANSPORT_DISRUPTED << 16;220 221		/*222		 * Mark device missing so that we won't continue to send223		 * I/O to this device.	We should get a ddb state change224		 * AEN soon.225		 */226		if (iscsi_is_session_online(ddb_entry->sess))227			qla4xxx_mark_device_missing(ddb_entry->sess);228		break;229 230	case SCS_DATA_UNDERRUN:231	case SCS_DATA_OVERRUN:232		if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) ||233		     (sts_entry->completionStatus == SCS_DATA_OVERRUN)) {234			DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: " "Data overrun\n",235				      ha->host_no,236				      cmd->device->channel, cmd->device->id,237				      cmd->device->lun, __func__));238 239			cmd->result = DID_ERROR << 16;240			break;241		}242 243		scsi_set_resid(cmd, residual);244 245		if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) {246 247			/* Both the firmware and target reported UNDERRUN:248			 *249			 * MID-LAYER UNDERFLOW case:250			 * Some kernels do not properly detect midlayer251			 * underflow, so we manually check it and return252			 * ERROR if the minimum required data was not253			 * received.254			 *255			 * ALL OTHER cases:256			 * Fall thru to check scsi_status257			 */258			if (!scsi_status && (scsi_bufflen(cmd) - residual) <259			    cmd->underflow) {260				DEBUG2(ql4_printk(KERN_INFO, ha,261						  "scsi%ld:%d:%d:%llu: %s: Mid-layer Data underrun, xferlen = 0x%x,residual = 0x%x\n",262						   ha->host_no,263						   cmd->device->channel,264						   cmd->device->id,265						   cmd->device->lun, __func__,266						   scsi_bufflen(cmd),267						   residual));268 269				cmd->result = DID_ERROR << 16;270				break;271			}272 273		} else if (scsi_status != SAM_STAT_TASK_SET_FULL &&274			   scsi_status != SAM_STAT_BUSY) {275 276			/*277			 * The firmware reports UNDERRUN, but the target does278			 * not report it:279			 *280			 *   scsi_status     |    host_byte       device_byte281			 *                   |     (19:16)          (7:0)282			 *   =============   |    =========       ===========283			 *   TASK_SET_FULL   |    DID_OK          scsi_status284			 *   BUSY            |    DID_OK          scsi_status285			 *   ALL OTHERS      |    DID_ERROR       scsi_status286			 *287			 *   Note: If scsi_status is task set full or busy,288			 *   then this else if would fall thru to check the289			 *   scsi_status and return DID_OK.290			 */291 292			DEBUG2(ql4_printk(KERN_INFO, ha,293					  "scsi%ld:%d:%d:%llu: %s: Dropped frame(s) detected (0x%x of 0x%x bytes).\n",294					  ha->host_no,295					  cmd->device->channel,296					  cmd->device->id,297					  cmd->device->lun, __func__,298					  residual,299					  scsi_bufflen(cmd)));300 301			cmd->result = DID_ERROR << 16 | scsi_status;302			goto check_scsi_status;303		}304 305		cmd->result = DID_OK << 16 | scsi_status;306 307check_scsi_status:308		if (scsi_status == SAM_STAT_CHECK_CONDITION)309			qla4xxx_copy_sense(ha, sts_entry, srb);310 311		break;312 313	case SCS_DEVICE_LOGGED_OUT:314	case SCS_DEVICE_UNAVAILABLE:315		DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%llu: SCS_DEVICE "316		    "state: 0x%x\n", ha->host_no,317		    cmd->device->channel, cmd->device->id,318		    cmd->device->lun, sts_entry->completionStatus));319		/*320		 * Mark device missing so that we won't continue to321		 * send I/O to this device.  We should get a ddb322		 * state change AEN soon.323		 */324		if (iscsi_is_session_online(ddb_entry->sess))325			qla4xxx_mark_device_missing(ddb_entry->sess);326 327		cmd->result = DID_TRANSPORT_DISRUPTED << 16;328		break;329 330	case SCS_QUEUE_FULL:331		/*332		 * SCSI Mid-Layer handles device queue full333		 */334		cmd->result = DID_OK << 16 | sts_entry->scsiStatus;335		DEBUG2(printk("scsi%ld:%d:%llu: %s: QUEUE FULL detected "336			      "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x,"337			      " iResp=%02x\n", ha->host_no, cmd->device->id,338			      cmd->device->lun, __func__,339			      sts_entry->completionStatus,340			      sts_entry->scsiStatus, sts_entry->state_flags,341			      sts_entry->iscsiFlags,342			      sts_entry->iscsiResponse));343		break;344 345	default:346		cmd->result = DID_ERROR << 16;347		break;348	}349 350status_entry_exit:351 352	/* complete the request, if not waiting for status_continuation pkt */353	srb->cc_stat = sts_entry->completionStatus;354	if (ha->status_srb == NULL)355		kref_put(&srb->srb_ref, qla4xxx_srb_compl);356}357 358/**359 * qla4xxx_passthru_status_entry - processes passthru status IOCBs (0x3C)360 * @ha: Pointer to host adapter structure.361 * @sts_entry: Pointer to status entry structure.362 **/363static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha,364					  struct passthru_status *sts_entry)365{366	struct iscsi_task *task;367	struct ddb_entry *ddb_entry;368	struct ql4_task_data *task_data;369	struct iscsi_cls_conn *cls_conn;370	struct iscsi_conn *conn;371	itt_t itt;372	uint32_t fw_ddb_index;373 374	itt = sts_entry->handle;375	fw_ddb_index = le32_to_cpu(sts_entry->target);376 377	ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index);378 379	if (ddb_entry == NULL) {380		ql4_printk(KERN_ERR, ha, "%s: Invalid target index = 0x%x\n",381			   __func__, sts_entry->target);382		return;383	}384 385	cls_conn = ddb_entry->conn;386	conn = cls_conn->dd_data;387	spin_lock(&conn->session->back_lock);388	task = iscsi_itt_to_task(conn, itt);389	spin_unlock(&conn->session->back_lock);390 391	if (task == NULL) {392		ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__);393		return;394	}395 396	task_data = task->dd_data;397	memcpy(&task_data->sts, sts_entry, sizeof(struct passthru_status));398	ha->iocb_cnt -= task_data->iocb_req_cnt;399	queue_work(ha->task_wq, &task_data->task_work);400}401 402static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha,403						     uint32_t index)404{405	struct mrb *mrb = NULL;406 407	/* validate handle and remove from active array */408	if (index >= MAX_MRB)409		return mrb;410 411	mrb = ha->active_mrb_array[index];412	ha->active_mrb_array[index] = NULL;413	if (!mrb)414		return mrb;415 416	/* update counters */417	ha->iocb_cnt -= mrb->iocb_cnt;418 419	return mrb;420}421 422static void qla4xxx_mbox_status_entry(struct scsi_qla_host *ha,423				      struct mbox_status_iocb *mbox_sts_entry)424{425	struct mrb *mrb;426	uint32_t status;427	uint32_t data_size;428 429	mrb = qla4xxx_del_mrb_from_active_array(ha,430					le32_to_cpu(mbox_sts_entry->handle));431 432	if (mrb == NULL) {433		ql4_printk(KERN_WARNING, ha, "%s: mrb[%d] is null\n", __func__,434			   mbox_sts_entry->handle);435		return;436	}437 438	switch (mrb->mbox_cmd) {439	case MBOX_CMD_PING:440		DEBUG2(ql4_printk(KERN_INFO, ha, "%s: mbox_cmd = 0x%x, "441				  "mbox_sts[0] = 0x%x, mbox_sts[6] = 0x%x\n",442				  __func__, mrb->mbox_cmd,443				  mbox_sts_entry->out_mbox[0],444				  mbox_sts_entry->out_mbox[6]));445 446		if (mbox_sts_entry->out_mbox[0] == MBOX_STS_COMMAND_COMPLETE)447			status = ISCSI_PING_SUCCESS;448		else449			status = mbox_sts_entry->out_mbox[6];450 451		data_size = sizeof(mbox_sts_entry->out_mbox);452 453		qla4xxx_post_ping_evt_work(ha, status, mrb->pid, data_size,454					(uint8_t *) mbox_sts_entry->out_mbox);455		break;456 457	default:458		DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: invalid mbox_cmd = "459				  "0x%x\n", __func__, mrb->mbox_cmd));460	}461 462	kfree(mrb);463	return;464}465 466/**467 * qla4xxx_process_response_queue - process response queue completions468 * @ha: Pointer to host adapter structure.469 *470 * This routine process response queue completions in interrupt context.471 * Hardware_lock locked upon entry472 **/473void qla4xxx_process_response_queue(struct scsi_qla_host *ha)474{475	struct srb *srb = NULL;476	struct status_entry *sts_entry;477 478	/* Process all responses from response queue */479	while ((ha->response_ptr->signature != RESPONSE_PROCESSED)) {480		sts_entry = (struct status_entry *) ha->response_ptr;481 482		/* Advance pointers for next entry */483		if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) {484			ha->response_out = 0;485			ha->response_ptr = ha->response_ring;486		} else {487			ha->response_out++;488			ha->response_ptr++;489		}490 491		/* process entry */492		switch (sts_entry->hdr.entryType) {493		case ET_STATUS:494			/* Common status */495			qla4xxx_status_entry(ha, sts_entry);496			break;497 498		case ET_PASSTHRU_STATUS:499			if (sts_entry->hdr.systemDefined == SD_ISCSI_PDU)500				qla4xxx_passthru_status_entry(ha,501					(struct passthru_status *)sts_entry);502			else503				ql4_printk(KERN_ERR, ha,504					   "%s: Invalid status received\n",505					   __func__);506 507			break;508 509		case ET_STATUS_CONTINUATION:510			qla4xxx_status_cont_entry(ha,511				(struct status_cont_entry *) sts_entry);512			break;513 514		case ET_COMMAND:515			/* ISP device queue is full. Command not516			 * accepted by ISP.  Queue command for517			 * later */518 519			srb = qla4xxx_del_from_active_array(ha,520						    le32_to_cpu(sts_entry->521								handle));522			if (srb == NULL)523				goto exit_prq_invalid_handle;524 525			DEBUG2(printk("scsi%ld: %s: FW device queue full, "526				      "srb %p\n", ha->host_no, __func__, srb));527 528			/* ETRY normally by sending it back with529			 * DID_BUS_BUSY */530			srb->cmd->result = DID_BUS_BUSY << 16;531			kref_put(&srb->srb_ref, qla4xxx_srb_compl);532			break;533 534		case ET_CONTINUE:535			/* Just throw away the continuation entries */536			DEBUG2(printk("scsi%ld: %s: Continuation entry - "537				      "ignoring\n", ha->host_no, __func__));538			break;539 540		case ET_MBOX_STATUS:541			DEBUG2(ql4_printk(KERN_INFO, ha,542					  "%s: mbox status IOCB\n", __func__));543			qla4xxx_mbox_status_entry(ha,544					(struct mbox_status_iocb *)sts_entry);545			break;546 547		default:548			/*549			 * Invalid entry in response queue, reset RISC550			 * firmware.551			 */552			DEBUG2(printk("scsi%ld: %s: Invalid entry %x in "553				      "response queue \n", ha->host_no,554				      __func__,555				      sts_entry->hdr.entryType));556			goto exit_prq_error;557		}558		((struct response *)sts_entry)->signature = RESPONSE_PROCESSED;559		wmb();560	}561 562	/*563	 * Tell ISP we're done with response(s). This also clears the interrupt.564	 */565	ha->isp_ops->complete_iocb(ha);566 567	return;568 569exit_prq_invalid_handle:570	DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n",571		      ha->host_no, __func__, srb, sts_entry->hdr.entryType,572		      sts_entry->completionStatus));573 574exit_prq_error:575	ha->isp_ops->complete_iocb(ha);576	set_bit(DPC_RESET_HA, &ha->dpc_flags);577}578 579/**580 * qla4_83xx_loopback_in_progress: Is loopback in progress?581 * @ha: Pointer to host adapter structure.582 * returns: 1 = loopback in progress, 0 = loopback not in progress583 **/584static int qla4_83xx_loopback_in_progress(struct scsi_qla_host *ha)585{586	int rval = 1;587 588	if (is_qla8032(ha) || is_qla8042(ha)) {589		if ((ha->idc_info.info2 & ENABLE_INTERNAL_LOOPBACK) ||590		    (ha->idc_info.info2 & ENABLE_EXTERNAL_LOOPBACK)) {591			DEBUG2(ql4_printk(KERN_INFO, ha,592					  "%s: Loopback diagnostics in progress\n",593					  __func__));594			rval = 1;595		} else {596			DEBUG2(ql4_printk(KERN_INFO, ha,597					  "%s: Loopback diagnostics not in progress\n",598					  __func__));599			rval = 0;600		}601	}602 603	return rval;604}605 606static void qla4xxx_update_ipaddr_state(struct scsi_qla_host *ha,607					uint32_t ipaddr_idx,608					uint32_t ipaddr_fw_state)609{610	uint8_t ipaddr_state;611	uint8_t ip_idx;612 613	ip_idx = ipaddr_idx & 0xF;614	ipaddr_state = qla4xxx_set_ipaddr_state((uint8_t)ipaddr_fw_state);615 616	switch (ip_idx) {617	case 0:618		ha->ip_config.ipv4_addr_state = ipaddr_state;619		break;620	case 1:621		ha->ip_config.ipv6_link_local_state = ipaddr_state;622		break;623	case 2:624		ha->ip_config.ipv6_addr0_state = ipaddr_state;625		break;626	case 3:627		ha->ip_config.ipv6_addr1_state = ipaddr_state;628		break;629	default:630		ql4_printk(KERN_INFO, ha, "%s: Invalid IPADDR index %d\n",631			   __func__, ip_idx);632	}633}634 635static void qla4xxx_default_router_changed(struct scsi_qla_host *ha,636					   uint32_t *mbox_sts)637{638	memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[0],639	       &mbox_sts[2], sizeof(uint32_t));640	memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[1],641	       &mbox_sts[3], sizeof(uint32_t));642	memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[2],643	       &mbox_sts[4], sizeof(uint32_t));644	memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[3],645	       &mbox_sts[5], sizeof(uint32_t));646}647 648/**649 * qla4xxx_isr_decode_mailbox - decodes mailbox status650 * @ha: Pointer to host adapter structure.651 * @mbox_status: Mailbox status.652 *653 * This routine decodes the mailbox status during the ISR.654 * Hardware_lock locked upon entry. runs in interrupt context.655 **/656static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,657				       uint32_t mbox_status)658{659	int i;660	uint32_t mbox_sts[MBOX_AEN_REG_COUNT];661	__le32 __iomem *mailbox_out;662	uint32_t opcode = 0;663 664	if (is_qla8032(ha) || is_qla8042(ha))665		mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0];666	else if (is_qla8022(ha))667		mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0];668	else669		mailbox_out = &ha->reg->mailbox[0];670 671	if ((mbox_status == MBOX_STS_BUSY) ||672	    (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||673	    (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) {674		ha->mbox_status[0] = mbox_status;675 676		if (test_bit(AF_MBOX_COMMAND, &ha->flags)) {677			/*678			 * Copy all mailbox registers to a temporary679			 * location and set mailbox command done flag680			 */681			for (i = 0; i < ha->mbox_status_count; i++)682				ha->mbox_status[i] = readl(&mailbox_out[i]);683 684			set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);685 686			if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags))687				complete(&ha->mbx_intr_comp);688		}689	} else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {690		for (i = 0; i < MBOX_AEN_REG_COUNT; i++)691			mbox_sts[i] = readl(&mailbox_out[i]);692 693		/* Immediately process the AENs that don't require much work.694		 * Only queue the database_changed AENs */695		if (ha->aen_log.count < MAX_AEN_ENTRIES) {696			for (i = 0; i < MBOX_AEN_REG_COUNT; i++)697				ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] =698				    mbox_sts[i];699			ha->aen_log.count++;700		}701		switch (mbox_status) {702		case MBOX_ASTS_SYSTEM_ERROR:703			/* Log Mailbox registers */704			ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__);705			qla4xxx_dump_registers(ha);706 707			if ((is_qla8022(ha) && ql4xdontresethba) ||708			    ((is_qla8032(ha) || is_qla8042(ha)) &&709			     qla4_83xx_idc_dontreset(ha))) {710				DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n",711				    ha->host_no, __func__));712			} else {713				set_bit(AF_GET_CRASH_RECORD, &ha->flags);714				set_bit(DPC_RESET_HA, &ha->dpc_flags);715			}716			break;717 718		case MBOX_ASTS_REQUEST_TRANSFER_ERROR:719		case MBOX_ASTS_RESPONSE_TRANSFER_ERROR:720		case MBOX_ASTS_NVRAM_INVALID:721		case MBOX_ASTS_IP_ADDRESS_CHANGED:722		case MBOX_ASTS_DHCP_LEASE_EXPIRED:723			DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, "724				      "Reset HA\n", ha->host_no, mbox_status));725			if (is_qla80XX(ha))726				set_bit(DPC_RESET_HA_FW_CONTEXT,727					&ha->dpc_flags);728			else729				set_bit(DPC_RESET_HA, &ha->dpc_flags);730			break;731 732		case MBOX_ASTS_LINK_UP:733			set_bit(AF_LINK_UP, &ha->flags);734			if (test_bit(AF_INIT_DONE, &ha->flags))735				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);736 737			ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__);738			qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKUP,739					      sizeof(mbox_sts),740					      (uint8_t *) mbox_sts);741 742			if ((is_qla8032(ha) || is_qla8042(ha)) &&743			    ha->notify_link_up_comp)744				complete(&ha->link_up_comp);745 746			break;747 748		case MBOX_ASTS_LINK_DOWN:749			clear_bit(AF_LINK_UP, &ha->flags);750			if (test_bit(AF_INIT_DONE, &ha->flags)) {751				set_bit(DPC_LINK_CHANGED, &ha->dpc_flags);752				qla4xxx_wake_dpc(ha);753			}754 755			ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__);756			qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKDOWN,757					      sizeof(mbox_sts),758					      (uint8_t *) mbox_sts);759			break;760 761		case MBOX_ASTS_HEARTBEAT:762			ha->seconds_since_last_heartbeat = 0;763			break;764 765		case MBOX_ASTS_DHCP_LEASE_ACQUIRED:766			DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE "767				      "ACQUIRED\n", ha->host_no, mbox_status));768			set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);769			break;770 771		case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM:772		case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target773							   * mode774							   * only */775		case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED:  /* Connection mode */776		case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR:777		case MBOX_ASTS_SUBNET_STATE_CHANGE:778		case MBOX_ASTS_DUPLICATE_IP:779			/* No action */780			DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no,781				      mbox_status));782			break;783 784		case MBOX_ASTS_IP_ADDR_STATE_CHANGED:785			printk("scsi%ld: AEN %04x, mbox_sts[2]=%04x, "786			    "mbox_sts[3]=%04x\n", ha->host_no, mbox_sts[0],787			    mbox_sts[2], mbox_sts[3]);788 789			qla4xxx_update_ipaddr_state(ha, mbox_sts[5],790						    mbox_sts[3]);791			/* mbox_sts[2] = Old ACB state792			 * mbox_sts[3] = new ACB state */793			if ((mbox_sts[3] == IP_ADDRSTATE_PREFERRED) &&794			    ((mbox_sts[2] == IP_ADDRSTATE_TENTATIVE) ||795			     (mbox_sts[2] == IP_ADDRSTATE_ACQUIRING))) {796				set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);797			} else if ((mbox_sts[3] == IP_ADDRSTATE_ACQUIRING) &&798				   (mbox_sts[2] == IP_ADDRSTATE_PREFERRED)) {799				if (is_qla80XX(ha))800					set_bit(DPC_RESET_HA_FW_CONTEXT,801						&ha->dpc_flags);802				else803					set_bit(DPC_RESET_HA, &ha->dpc_flags);804			} else if (mbox_sts[3] == IP_ADDRSTATE_DISABLING) {805				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB in disabling state\n",806					   ha->host_no, __func__);807			} else if (mbox_sts[3] == IP_ADDRSTATE_UNCONFIGURED) {808				complete(&ha->disable_acb_comp);809				ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB state unconfigured\n",810					   ha->host_no, __func__);811			}812			break;813 814		case MBOX_ASTS_IPV6_LINK_MTU_CHANGE:815		case MBOX_ASTS_IPV6_AUTO_PREFIX_IGNORED:816		case MBOX_ASTS_IPV6_ND_LOCAL_PREFIX_IGNORED:817			/* No action */818			DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: AEN %04x\n",819					  ha->host_no, mbox_status));820			break;821 822		case MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD:823			DEBUG2(ql4_printk(KERN_INFO, ha,824					  "scsi%ld: AEN %04x, IPv6 ERROR, "825					  "mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3}=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",826					  ha->host_no, mbox_sts[0], mbox_sts[1],827					  mbox_sts[2], mbox_sts[3], mbox_sts[4],828					  mbox_sts[5]));829			break;830 831		case MBOX_ASTS_MAC_ADDRESS_CHANGED:832		case MBOX_ASTS_DNS:833			/* No action */834			DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "835				      "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",836				      ha->host_no, mbox_sts[0],837				      mbox_sts[1], mbox_sts[2]));838			break;839 840		case MBOX_ASTS_SELF_TEST_FAILED:841		case MBOX_ASTS_LOGIN_FAILED:842			/* No action */843			DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "844				      "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",845				      ha->host_no, mbox_sts[0], mbox_sts[1],846				      mbox_sts[2], mbox_sts[3]));847			break;848 849		case MBOX_ASTS_DATABASE_CHANGED:850			/* Queue AEN information and process it in the DPC851			 * routine */852			if (ha->aen_q_count > 0) {853 854				/* decrement available counter */855				ha->aen_q_count--;856 857				for (i = 0; i < MBOX_AEN_REG_COUNT; i++)858					ha->aen_q[ha->aen_in].mbox_sts[i] =859					    mbox_sts[i];860 861				/* print debug message */862				DEBUG2(printk("scsi%ld: AEN[%d] %04x queued "863					      "mb1:0x%x mb2:0x%x mb3:0x%x "864					      "mb4:0x%x mb5:0x%x\n",865					      ha->host_no, ha->aen_in,866					      mbox_sts[0], mbox_sts[1],867					      mbox_sts[2], mbox_sts[3],868					      mbox_sts[4], mbox_sts[5]));869 870				/* advance pointer */871				ha->aen_in++;872				if (ha->aen_in == MAX_AEN_ENTRIES)873					ha->aen_in = 0;874 875				/* The DPC routine will process the aen */876				set_bit(DPC_AEN, &ha->dpc_flags);877			} else {878				DEBUG2(printk("scsi%ld: %s: aen %04x, queue "879					      "overflowed!  AEN LOST!!\n",880					      ha->host_no, __func__,881					      mbox_sts[0]));882 883				DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",884					      ha->host_no));885 886				for (i = 0; i < MAX_AEN_ENTRIES; i++) {887					DEBUG2(printk("AEN[%d] %04x %04x %04x "888						      "%04x\n", i, mbox_sts[0],889						      mbox_sts[1], mbox_sts[2],890						      mbox_sts[3]));891				}892			}893			break;894 895		case MBOX_ASTS_TXSCVR_INSERTED:896			DEBUG2(printk(KERN_WARNING897			    "scsi%ld: AEN %04x Transceiver"898			    " inserted\n",  ha->host_no, mbox_sts[0]));899			break;900 901		case MBOX_ASTS_TXSCVR_REMOVED:902			DEBUG2(printk(KERN_WARNING903			    "scsi%ld: AEN %04x Transceiver"904			    " removed\n",  ha->host_no, mbox_sts[0]));905			break;906 907		case MBOX_ASTS_IDC_REQUEST_NOTIFICATION:908			if (is_qla8032(ha) || is_qla8042(ha)) {909				DEBUG2(ql4_printk(KERN_INFO, ha,910						  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",911						  ha->host_no, mbox_sts[0],912						  mbox_sts[1], mbox_sts[2],913						  mbox_sts[3], mbox_sts[4]));914				opcode = mbox_sts[1] >> 16;915				if ((opcode == MBOX_CMD_SET_PORT_CONFIG) ||916				    (opcode == MBOX_CMD_PORT_RESET)) {917					set_bit(DPC_POST_IDC_ACK,918						&ha->dpc_flags);919					ha->idc_info.request_desc = mbox_sts[1];920					ha->idc_info.info1 = mbox_sts[2];921					ha->idc_info.info2 = mbox_sts[3];922					ha->idc_info.info3 = mbox_sts[4];923					qla4xxx_wake_dpc(ha);924				}925			}926			break;927 928		case MBOX_ASTS_IDC_COMPLETE:929			if (is_qla8032(ha) || is_qla8042(ha)) {930				DEBUG2(ql4_printk(KERN_INFO, ha,931						  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n",932						  ha->host_no, mbox_sts[0],933						  mbox_sts[1], mbox_sts[2],934						  mbox_sts[3], mbox_sts[4]));935				DEBUG2(ql4_printk(KERN_INFO, ha,936						  "scsi:%ld: AEN %04x IDC Complete notification\n",937						  ha->host_no, mbox_sts[0]));938 939				opcode = mbox_sts[1] >> 16;940				if (ha->notify_idc_comp)941					complete(&ha->idc_comp);942 943				if ((opcode == MBOX_CMD_SET_PORT_CONFIG) ||944				    (opcode == MBOX_CMD_PORT_RESET))945					ha->idc_info.info2 = mbox_sts[3];946 947				if (qla4_83xx_loopback_in_progress(ha)) {948					set_bit(AF_LOOPBACK, &ha->flags);949				} else {950					clear_bit(AF_LOOPBACK, &ha->flags);951					if (ha->saved_acb)952						set_bit(DPC_RESTORE_ACB,953							&ha->dpc_flags);954				}955				qla4xxx_wake_dpc(ha);956			}957			break;958 959		case MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED:960			DEBUG2(ql4_printk(KERN_INFO, ha,961					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",962					  ha->host_no, mbox_sts[0], mbox_sts[1],963					  mbox_sts[2], mbox_sts[3], mbox_sts[4],964					  mbox_sts[5]));965			DEBUG2(ql4_printk(KERN_INFO, ha,966					  "scsi%ld: AEN %04x Received IPv6 default router changed notification\n",967					  ha->host_no, mbox_sts[0]));968			qla4xxx_default_router_changed(ha, mbox_sts);969			break;970 971		case MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION:972			DEBUG2(ql4_printk(KERN_INFO, ha,973					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",974					  ha->host_no, mbox_sts[0], mbox_sts[1],975					  mbox_sts[2], mbox_sts[3], mbox_sts[4],976					  mbox_sts[5]));977			DEBUG2(ql4_printk(KERN_INFO, ha,978					  "scsi%ld: AEN %04x Received IDC Extend Timeout notification\n",979					  ha->host_no, mbox_sts[0]));980			/* new IDC timeout */981			ha->idc_extend_tmo = mbox_sts[1];982			break;983 984		case MBOX_ASTS_INITIALIZATION_FAILED:985			DEBUG2(ql4_printk(KERN_INFO, ha,986					  "scsi%ld: AEN %04x, mbox_sts[3]=%08x\n",987					  ha->host_no, mbox_sts[0],988					  mbox_sts[3]));989			break;990 991		case MBOX_ASTS_SYSTEM_WARNING_EVENT:992			DEBUG2(ql4_printk(KERN_WARNING, ha,993					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",994					  ha->host_no, mbox_sts[0], mbox_sts[1],995					  mbox_sts[2], mbox_sts[3], mbox_sts[4],996					  mbox_sts[5]));997			break;998 999		case MBOX_ASTS_DCBX_CONF_CHANGE:1000			DEBUG2(ql4_printk(KERN_INFO, ha,1001					  "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n",1002					  ha->host_no, mbox_sts[0], mbox_sts[1],1003					  mbox_sts[2], mbox_sts[3], mbox_sts[4],1004					  mbox_sts[5]));1005			DEBUG2(ql4_printk(KERN_INFO, ha,1006					  "scsi%ld: AEN %04x Received DCBX configuration changed notification\n",1007					  ha->host_no, mbox_sts[0]));1008			break;1009 1010		default:1011			DEBUG2(printk(KERN_WARNING1012				      "scsi%ld: AEN %04x UNKNOWN\n",1013				      ha->host_no, mbox_sts[0]));1014			break;1015		}1016	} else {1017		DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n",1018			      ha->host_no, mbox_status));1019 1020		ha->mbox_status[0] = mbox_status;1021	}1022}1023 1024void qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha,1025					 uint32_t intr_status)1026{1027	/* Process mailbox/asynch event interrupt.*/1028	if (intr_status) {1029		qla4xxx_isr_decode_mailbox(ha,1030				readl(&ha->qla4_83xx_reg->mailbox_out[0]));1031		/* clear the interrupt */1032		writel(0, &ha->qla4_83xx_reg->risc_intr);1033	} else {1034		qla4xxx_process_response_queue(ha);1035	}1036 1037	/* clear the interrupt */1038	writel(0, &ha->qla4_83xx_reg->mb_int_mask);1039}1040 1041/**1042 * qla4_82xx_interrupt_service_routine - isr1043 * @ha: pointer to host adapter structure.1044 * @intr_status: Local interrupt status/type.1045 *1046 * This is the main interrupt service routine.1047 * hardware_lock locked upon entry. runs in interrupt context.1048 **/1049void qla4_82xx_interrupt_service_routine(struct scsi_qla_host *ha,1050    uint32_t intr_status)1051{1052	/* Process response queue interrupt. */1053	if ((intr_status & HSRX_RISC_IOCB_INT) &&1054	    test_bit(AF_INIT_DONE, &ha->flags))1055		qla4xxx_process_response_queue(ha);1056 1057	/* Process mailbox/asynch event interrupt.*/1058	if (intr_status & HSRX_RISC_MB_INT)1059		qla4xxx_isr_decode_mailbox(ha,1060		    readl(&ha->qla4_82xx_reg->mailbox_out[0]));1061 1062	/* clear the interrupt */1063	writel(0, &ha->qla4_82xx_reg->host_int);1064	readl(&ha->qla4_82xx_reg->host_int);1065}1066 1067/**1068 * qla4xxx_interrupt_service_routine - isr1069 * @ha: pointer to host adapter structure.1070 * @intr_status: Local interrupt status/type.1071 *1072 * This is the main interrupt service routine.1073 * hardware_lock locked upon entry. runs in interrupt context.1074 **/1075void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,1076				       uint32_t intr_status)1077{1078	/* Process response queue interrupt. */1079	if (intr_status & CSR_SCSI_COMPLETION_INTR)1080		qla4xxx_process_response_queue(ha);1081 1082	/* Process mailbox/asynch event	 interrupt.*/1083	if (intr_status & CSR_SCSI_PROCESSOR_INTR) {1084		qla4xxx_isr_decode_mailbox(ha,1085					   readl(&ha->reg->mailbox[0]));1086 1087		/* Clear Mailbox Interrupt */1088		writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),1089		       &ha->reg->ctrl_status);1090		readl(&ha->reg->ctrl_status);1091	}1092}1093 1094/**1095 * qla4_82xx_spurious_interrupt - processes spurious interrupt1096 * @ha: pointer to host adapter structure.1097 * @reqs_count: .1098 *1099 **/1100static void qla4_82xx_spurious_interrupt(struct scsi_qla_host *ha,1101    uint8_t reqs_count)1102{1103	if (reqs_count)1104		return;1105 1106	DEBUG2(ql4_printk(KERN_INFO, ha, "Spurious Interrupt\n"));1107	if (is_qla8022(ha)) {1108		writel(0, &ha->qla4_82xx_reg->host_int);1109		if (!ha->pdev->msi_enabled && !ha->pdev->msix_enabled)1110			qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg,1111			    0xfbff);1112	}1113	ha->spurious_int_count++;1114}1115 1116/**1117 * qla4xxx_intr_handler - hardware interrupt handler.1118 * @irq: Unused1119 * @dev_id: Pointer to host adapter structure1120 **/1121irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)1122{1123	struct scsi_qla_host *ha;1124	uint32_t intr_status;1125	unsigned long flags = 0;1126	uint8_t reqs_count = 0;1127 1128	ha = (struct scsi_qla_host *) dev_id;1129	if (!ha) {1130		DEBUG2(printk(KERN_INFO1131			      "qla4xxx: Interrupt with NULL host ptr\n"));1132		return IRQ_NONE;1133	}1134 1135	spin_lock_irqsave(&ha->hardware_lock, flags);1136 1137	ha->isr_count++;1138	/*1139	 * Repeatedly service interrupts up to a maximum of1140	 * MAX_REQS_SERVICED_PER_INTR1141	 */1142	while (1) {1143		/*1144		 * Read interrupt status1145		 */1146		if (ha->isp_ops->rd_shdw_rsp_q_in(ha) !=1147		    ha->response_out)1148			intr_status = CSR_SCSI_COMPLETION_INTR;1149		else1150			intr_status = readl(&ha->reg->ctrl_status);1151 1152		if ((intr_status &1153		    (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == 0) {1154			if (reqs_count == 0)1155				ha->spurious_int_count++;1156			break;1157		}1158 1159		if (intr_status & CSR_FATAL_ERROR) {1160			DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, "1161				      "Status 0x%04x\n", ha->host_no,1162				      readl(isp_port_error_status (ha))));1163 1164			/* Issue Soft Reset to clear this error condition.1165			 * This will prevent the RISC from repeatedly1166			 * interrupting the driver; thus, allowing the DPC to1167			 * get scheduled to continue error recovery.1168			 * NOTE: Disabling RISC interrupts does not work in1169			 * this case, as CSR_FATAL_ERROR overrides1170			 * CSR_SCSI_INTR_ENABLE */1171			if ((readl(&ha->reg->ctrl_status) &1172			     CSR_SCSI_RESET_INTR) == 0) {1173				writel(set_rmask(CSR_SOFT_RESET),1174				       &ha->reg->ctrl_status);1175				readl(&ha->reg->ctrl_status);1176			}1177 1178			writel(set_rmask(CSR_FATAL_ERROR),1179			       &ha->reg->ctrl_status);1180			readl(&ha->reg->ctrl_status);1181 1182			__qla4xxx_disable_intrs(ha);1183 1184			set_bit(DPC_RESET_HA, &ha->dpc_flags);1185 1186			break;1187		} else if (intr_status & CSR_SCSI_RESET_INTR) {1188			clear_bit(AF_ONLINE, &ha->flags);1189			__qla4xxx_disable_intrs(ha);1190 1191			writel(set_rmask(CSR_SCSI_RESET_INTR),1192			       &ha->reg->ctrl_status);1193			readl(&ha->reg->ctrl_status);1194 1195			if (!test_bit(AF_HA_REMOVAL, &ha->flags))1196				set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);1197 1198			break;1199		} else if (intr_status & INTR_PENDING) {1200			ha->isp_ops->interrupt_service_routine(ha, intr_status);1201			ha->total_io_count++;1202			if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)1203				break;1204		}1205	}1206 1207	spin_unlock_irqrestore(&ha->hardware_lock, flags);1208 1209	return IRQ_HANDLED;1210}1211 1212/**1213 * qla4_82xx_intr_handler - hardware interrupt handler.1214 * @irq: Unused1215 * @dev_id: Pointer to host adapter structure1216 **/1217irqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id)1218{1219	struct scsi_qla_host *ha = dev_id;1220	uint32_t intr_status;1221	uint32_t status;1222	unsigned long flags = 0;1223	uint8_t reqs_count = 0;1224 1225	if (unlikely(pci_channel_offline(ha->pdev)))1226		return IRQ_HANDLED;1227 1228	ha->isr_count++;1229	status = qla4_82xx_rd_32(ha, ISR_INT_VECTOR);1230	if (!(status & ha->nx_legacy_intr.int_vec_bit))1231		return IRQ_NONE;1232 1233	status = qla4_82xx_rd_32(ha, ISR_INT_STATE_REG);1234	if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) {1235		DEBUG7(ql4_printk(KERN_INFO, ha,1236				  "%s legacy Int not triggered\n", __func__));1237		return IRQ_NONE;1238	}1239 1240	/* clear the interrupt */1241	qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);1242 1243	/* read twice to ensure write is flushed */1244	qla4_82xx_rd_32(ha, ISR_INT_VECTOR);1245	qla4_82xx_rd_32(ha, ISR_INT_VECTOR);1246 1247	spin_lock_irqsave(&ha->hardware_lock, flags);1248	while (1) {1249		if (!(readl(&ha->qla4_82xx_reg->host_int) &1250		    ISRX_82XX_RISC_INT)) {1251			qla4_82xx_spurious_interrupt(ha, reqs_count);1252			break;1253		}1254		intr_status =  readl(&ha->qla4_82xx_reg->host_status);1255		if ((intr_status &1256		    (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0)  {1257			qla4_82xx_spurious_interrupt(ha, reqs_count);1258			break;1259		}1260 1261		ha->isp_ops->interrupt_service_routine(ha, intr_status);1262 1263		/* Enable Interrupt */1264		qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);1265 1266		if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)1267			break;1268	}1269 1270	spin_unlock_irqrestore(&ha->hardware_lock, flags);1271	return IRQ_HANDLED;1272}1273 1274#define LEG_INT_PTR_B31		(1 << 31)1275#define LEG_INT_PTR_B30		(1 << 30)1276#define PF_BITS_MASK		(0xF << 16)1277 1278/**1279 * qla4_83xx_intr_handler - hardware interrupt handler.1280 * @irq: Unused1281 * @dev_id: Pointer to host adapter structure1282 **/1283irqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id)1284{1285	struct scsi_qla_host *ha = dev_id;1286	uint32_t leg_int_ptr = 0;1287	unsigned long flags = 0;1288 1289	ha->isr_count++;1290	leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr);1291 1292	/* Legacy interrupt is valid if bit31 of leg_int_ptr is set */1293	if (!(leg_int_ptr & LEG_INT_PTR_B31)) {1294		DEBUG7(ql4_printk(KERN_ERR, ha,1295				  "%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n",1296				  __func__));1297		return IRQ_NONE;1298	}1299 1300	/* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */1301	if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) {1302		DEBUG7(ql4_printk(KERN_ERR, ha,1303				  "%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n",1304				  __func__, (leg_int_ptr & PF_BITS_MASK),1305				  ha->pf_bit));1306		return IRQ_NONE;1307	}1308 1309	/* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger1310	 * Control register and poll till Legacy Interrupt Pointer register1311	 * bit30 is 0.1312	 */1313	writel(0, &ha->qla4_83xx_reg->leg_int_trig);1314	do {1315		leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr);1316		if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit)1317			break;1318	} while (leg_int_ptr & LEG_INT_PTR_B30);1319 1320	spin_lock_irqsave(&ha->hardware_lock, flags);1321	leg_int_ptr = readl(&ha->qla4_83xx_reg->risc_intr);1322	ha->isp_ops->interrupt_service_routine(ha, leg_int_ptr);1323	spin_unlock_irqrestore(&ha->hardware_lock, flags);1324 1325	return IRQ_HANDLED;1326}1327 1328irqreturn_t1329qla4_8xxx_msi_handler(int irq, void *dev_id)1330{1331	struct scsi_qla_host *ha;1332 1333	ha = (struct scsi_qla_host *) dev_id;1334	if (!ha) {1335		DEBUG2(printk(KERN_INFO1336		    "qla4xxx: MSIX: Interrupt with NULL host ptr\n"));1337		return IRQ_NONE;1338	}1339 1340	ha->isr_count++;1341	/* clear the interrupt */1342	qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);1343 1344	/* read twice to ensure write is flushed */1345	qla4_82xx_rd_32(ha, ISR_INT_VECTOR);1346	qla4_82xx_rd_32(ha, ISR_INT_VECTOR);1347 1348	return qla4_8xxx_default_intr_handler(irq, dev_id);1349}1350 1351static irqreturn_t qla4_83xx_mailbox_intr_handler(int irq, void *dev_id)1352{1353	struct scsi_qla_host *ha = dev_id;1354	unsigned long flags;1355	uint32_t ival = 0;1356 1357	spin_lock_irqsave(&ha->hardware_lock, flags);1358 1359	ival = readl(&ha->qla4_83xx_reg->risc_intr);1360	if (ival == 0) {1361		ql4_printk(KERN_INFO, ha,1362			   "%s: It is a spurious mailbox interrupt!\n",1363			   __func__);1364		ival = readl(&ha->qla4_83xx_reg->mb_int_mask);1365		ival &= ~INT_MASK_FW_MB;1366		writel(ival, &ha->qla4_83xx_reg->mb_int_mask);1367		goto exit;1368	}1369 1370	qla4xxx_isr_decode_mailbox(ha,1371				   readl(&ha->qla4_83xx_reg->mailbox_out[0]));1372	writel(0, &ha->qla4_83xx_reg->risc_intr);1373	ival = readl(&ha->qla4_83xx_reg->mb_int_mask);1374	ival &= ~INT_MASK_FW_MB;1375	writel(ival, &ha->qla4_83xx_reg->mb_int_mask);1376	ha->isr_count++;1377exit:1378	spin_unlock_irqrestore(&ha->hardware_lock, flags);1379	return IRQ_HANDLED;1380}1381 1382/**1383 * qla4_8xxx_default_intr_handler - hardware interrupt handler.1384 * @irq: Unused1385 * @dev_id: Pointer to host adapter structure1386 *1387 * This interrupt handler is called directly for MSI-X, and1388 * called indirectly for MSI.1389 **/1390irqreturn_t1391qla4_8xxx_default_intr_handler(int irq, void *dev_id)1392{1393	struct scsi_qla_host *ha = dev_id;1394	unsigned long   flags;1395	uint32_t intr_status;1396	uint8_t reqs_count = 0;1397 1398	if (is_qla8032(ha) || is_qla8042(ha)) {1399		qla4_83xx_mailbox_intr_handler(irq, dev_id);1400	} else {1401		spin_lock_irqsave(&ha->hardware_lock, flags);1402		while (1) {1403			if (!(readl(&ha->qla4_82xx_reg->host_int) &1404			    ISRX_82XX_RISC_INT)) {1405				qla4_82xx_spurious_interrupt(ha, reqs_count);1406				break;1407			}1408 1409			intr_status =  readl(&ha->qla4_82xx_reg->host_status);1410			if ((intr_status &1411			    (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) {1412				qla4_82xx_spurious_interrupt(ha, reqs_count);1413				break;1414			}1415 1416			ha->isp_ops->interrupt_service_routine(ha, intr_status);1417 1418			if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)1419				break;1420		}1421		ha->isr_count++;1422		spin_unlock_irqrestore(&ha->hardware_lock, flags);1423	}1424	return IRQ_HANDLED;1425}1426 1427irqreturn_t1428qla4_8xxx_msix_rsp_q(int irq, void *dev_id)1429{1430	struct scsi_qla_host *ha = dev_id;1431	unsigned long flags;1432	int intr_status;1433	uint32_t ival = 0;1434 1435	spin_lock_irqsave(&ha->hardware_lock, flags);1436	if (is_qla8032(ha) || is_qla8042(ha)) {1437		ival = readl(&ha->qla4_83xx_reg->iocb_int_mask);1438		if (ival == 0) {1439			ql4_printk(KERN_INFO, ha, "%s: It is a spurious iocb interrupt!\n",1440				   __func__);1441			goto exit_msix_rsp_q;1442		}1443		qla4xxx_process_response_queue(ha);1444		writel(0, &ha->qla4_83xx_reg->iocb_int_mask);1445	} else {1446		intr_status = readl(&ha->qla4_82xx_reg->host_status);1447		if (intr_status & HSRX_RISC_IOCB_INT) {1448			qla4xxx_process_response_queue(ha);1449			writel(0, &ha->qla4_82xx_reg->host_int);1450		} else {1451			ql4_printk(KERN_INFO, ha, "%s: spurious iocb interrupt...\n",1452				   __func__);1453			goto exit_msix_rsp_q;1454		}1455	}1456	ha->isr_count++;1457exit_msix_rsp_q:1458	spin_unlock_irqrestore(&ha->hardware_lock, flags);1459	return IRQ_HANDLED;1460}1461 1462/**1463 * qla4xxx_process_aen - processes AENs generated by firmware1464 * @ha: pointer to host adapter structure.1465 * @process_aen: type of AENs to process1466 *1467 * Processes specific types of Asynchronous Events generated by firmware.1468 * The type of AENs to process is specified by process_aen and can be1469 *	PROCESS_ALL_AENS	 01470 *	FLUSH_DDB_CHANGED_AENS	 11471 *	RELOGIN_DDB_CHANGED_AENS 21472 **/1473void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)1474{1475	uint32_t mbox_sts[MBOX_AEN_REG_COUNT];1476	struct aen *aen;1477	int i;1478	unsigned long flags;1479 1480	spin_lock_irqsave(&ha->hardware_lock, flags);1481	while (ha->aen_out != ha->aen_in) {1482		aen = &ha->aen_q[ha->aen_out];1483		/* copy aen information to local structure */1484		for (i = 0; i < MBOX_AEN_REG_COUNT; i++)1485			mbox_sts[i] = aen->mbox_sts[i];1486 1487		ha->aen_q_count++;1488		ha->aen_out++;1489 1490		if (ha->aen_out == MAX_AEN_ENTRIES)1491			ha->aen_out = 0;1492 1493		spin_unlock_irqrestore(&ha->hardware_lock, flags);1494 1495		DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x"1496			" mbx3=0x%08x mbx4=0x%08x\n", ha->host_no,1497			(ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)),1498			mbox_sts[0], mbox_sts[1], mbox_sts[2],1499			mbox_sts[3], mbox_sts[4]));1500 1501		switch (mbox_sts[0]) {1502		case MBOX_ASTS_DATABASE_CHANGED:1503			switch (process_aen) {1504			case FLUSH_DDB_CHANGED_AENS:1505				DEBUG2(printk("scsi%ld: AEN[%d] %04x, index "1506					      "[%d] state=%04x FLUSHED!\n",1507					      ha->host_no, ha->aen_out,1508					      mbox_sts[0], mbox_sts[2],1509					      mbox_sts[3]));1510				break;1511			case PROCESS_ALL_AENS:1512			default:1513				/* Specific device. */1514				if (mbox_sts[1] == 1)1515					qla4xxx_process_ddb_changed(ha,1516						mbox_sts[2], mbox_sts[3],1517						mbox_sts[4]);1518				break;1519			}1520		}1521		spin_lock_irqsave(&ha->hardware_lock, flags);1522	}1523	spin_unlock_irqrestore(&ha->hardware_lock, flags);1524}1525 1526int qla4xxx_request_irqs(struct scsi_qla_host *ha)1527{1528	int ret = 0;1529	int rval = QLA_ERROR;1530 1531	if (is_qla40XX(ha))1532		goto try_intx;1533 1534	if (ql4xenablemsix == 2) {1535		/* Note: MSI Interrupts not supported for ISP8324 and ISP8042 */1536		if (is_qla8032(ha) || is_qla8042(ha)) {1537			ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP%04x, Falling back-to INTx mode\n",1538				   __func__, ha->pdev->device);1539			goto try_intx;1540		}1541		goto try_msi;1542	}1543 1544	if (ql4xenablemsix == 0 || ql4xenablemsix != 1)1545		goto try_intx;1546 1547	/* Trying MSI-X */1548	ret = qla4_8xxx_enable_msix(ha);1549	if (!ret) {1550		DEBUG2(ql4_printk(KERN_INFO, ha,1551		    "MSI-X: Enabled (0x%X).\n", ha->revision_id));1552		goto irq_attached;1553	} else {1554		if (is_qla8032(ha) || is_qla8042(ha)) {1555			ql4_printk(KERN_INFO, ha, "%s: ISP%04x: MSI-X: Falling back-to INTx mode. ret = %d\n",1556				   __func__, ha->pdev->device, ret);1557			goto try_intx;1558		}1559	}1560 1561	ql4_printk(KERN_WARNING, ha,1562	    "MSI-X: Falling back-to MSI mode -- %d.\n", ret);1563 1564try_msi:1565	/* Trying MSI */1566	ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI);1567	if (ret > 0) {1568		ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler,1569			0, DRIVER_NAME, ha);1570		if (!ret) {1571			DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n"));1572			goto irq_attached;1573		} else {1574			ql4_printk(KERN_WARNING, ha,1575			    "MSI: Failed to reserve interrupt %d "1576			    "already in use.\n", ha->pdev->irq);1577			pci_free_irq_vectors(ha->pdev);1578		}1579	}1580 1581try_intx:1582	if (is_qla8022(ha)) {1583		ql4_printk(KERN_WARNING, ha, "%s: ISP82xx Legacy interrupt not supported\n",1584			   __func__);1585		goto irq_not_attached;1586	}1587 1588	/* Trying INTx */1589	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,1590	    IRQF_SHARED, DRIVER_NAME, ha);1591	if (!ret) {1592		DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n"));1593		goto irq_attached;1594 1595	} else {1596		ql4_printk(KERN_WARNING, ha,1597		    "INTx: Failed to reserve interrupt %d already in"1598		    " use.\n", ha->pdev->irq);1599		goto irq_not_attached;1600	}1601 1602irq_attached:1603	set_bit(AF_IRQ_ATTACHED, &ha->flags);1604	ha->host->irq = ha->pdev->irq;1605	ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n",1606		   __func__, ha->pdev->irq);1607	rval = QLA_SUCCESS;1608irq_not_attached:1609	return rval;1610}1611 1612void qla4xxx_free_irqs(struct scsi_qla_host *ha)1613{1614	if (!test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))1615		return;1616 1617	if (ha->pdev->msix_enabled)1618		free_irq(pci_irq_vector(ha->pdev, 1), ha);1619	free_irq(pci_irq_vector(ha->pdev, 0), ha);1620	pci_free_irq_vectors(ha->pdev);1621}1622