ql4_isr.c

来自「linux 内核源代码」· C语言 代码 · 共 822 行 · 第 1/2 页

C
822
字号
/* * QLogic iSCSI HBA Driver * Copyright (c)  2003-2006 QLogic Corporation * * See LICENSE.qla4xxx for copyright and licensing details. */#include "ql4_def.h"#include "ql4_glbl.h"#include "ql4_dbg.h"#include "ql4_inline.h"/** * qla2x00_process_completed_request() - Process a Fast Post response. * @ha: SCSI driver HA context * @index: SRB index **/static void qla4xxx_process_completed_request(struct scsi_qla_host *ha,					      uint32_t index){	struct srb *srb;	srb = qla4xxx_del_from_active_array(ha, index);	if (srb) {		/* Save ISP completion status */		srb->cmd->result = DID_OK << 16;		qla4xxx_srb_compl(ha, srb);	} else {		DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = "			      "%d\n", ha->host_no, index));		set_bit(DPC_RESET_HA, &ha->dpc_flags);	}}/** * qla4xxx_status_entry - processes status IOCBs * @ha: Pointer to host adapter structure. * @sts_entry: Pointer to status entry structure. **/static void qla4xxx_status_entry(struct scsi_qla_host *ha,				 struct status_entry *sts_entry){	uint8_t scsi_status;	struct scsi_cmnd *cmd;	struct srb *srb;	struct ddb_entry *ddb_entry;	uint32_t residual;	uint16_t sensebytecnt;	if (sts_entry->completionStatus == SCS_COMPLETE &&	    sts_entry->scsiStatus == 0) {		qla4xxx_process_completed_request(ha,						  le32_to_cpu(sts_entry->							      handle));		return;	}	srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));	if (!srb) {		/* FIXMEdg: Don't we need to reset ISP in this case??? */		DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "			      "handle 0x%x, sp=%p. This cmd may have already "			      "been completed.\n", ha->host_no, __func__,			      le32_to_cpu(sts_entry->handle), srb));		return;	}	cmd = srb->cmd;	if (cmd == NULL) {		DEBUG2(printk("scsi%ld: %s: Command already returned back to "			      "OS pkt->handle=%d srb=%p srb->state:%d\n",			      ha->host_no, __func__, sts_entry->handle,			      srb, srb->state));		dev_warn(&ha->pdev->dev, "Command is NULL:"			" already returned to OS (srb=%p)\n", srb);		return;	}	ddb_entry = srb->ddb;	if (ddb_entry == NULL) {		cmd->result = DID_NO_CONNECT << 16;		goto status_entry_exit;	}	residual = le32_to_cpu(sts_entry->residualByteCnt);	/* Translate ISP error to a Linux SCSI error. */	scsi_status = sts_entry->scsiStatus;	switch (sts_entry->completionStatus) {	case SCS_COMPLETE:		if (scsi_status == 0) {			cmd->result = DID_OK << 16;			break;		}		if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {			cmd->result = DID_ERROR << 16;			break;		}		if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) {			scsi_set_resid(cmd, residual);			if (!scsi_status && ((scsi_bufflen(cmd) - residual) <				cmd->underflow)) {				cmd->result = DID_ERROR << 16;				DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "					"Mid-layer Data underrun0, "					"xferlen = 0x%x, "					"residual = 0x%x\n", ha->host_no,					cmd->device->channel,					cmd->device->id,					cmd->device->lun, __func__,					scsi_bufflen(cmd), residual));				break;			}		}		cmd->result = DID_OK << 16 | scsi_status;		if (scsi_status != SCSI_CHECK_CONDITION)			break;		/* Copy Sense Data into sense buffer. */		memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));		sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);		if (sensebytecnt == 0)			break;		memcpy(cmd->sense_buffer, sts_entry->senseData,		       min(sensebytecnt,			   (uint16_t) sizeof(cmd->sense_buffer)));		DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "			      "ASC/ASCQ = %02x/%02x\n", ha->host_no,			      cmd->device->channel, cmd->device->id,			      cmd->device->lun, __func__,			      sts_entry->senseData[2] & 0x0f,			      sts_entry->senseData[12],			      sts_entry->senseData[13]));		srb->flags |= SRB_GOT_SENSE;		break;	case SCS_INCOMPLETE:		/* Always set the status to DID_ERROR, since		 * all conditions result in that status anyway */		cmd->result = DID_ERROR << 16;		break;	case SCS_RESET_OCCURRED:		DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n",			      ha->host_no, cmd->device->channel,			      cmd->device->id, cmd->device->lun, __func__));		cmd->result = DID_RESET << 16;		break;	case SCS_ABORTED:		DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Abort occurred\n",			      ha->host_no, cmd->device->channel,			      cmd->device->id, cmd->device->lun, __func__));		cmd->result = DID_RESET << 16;		break;	case SCS_TIMEOUT:		DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n",			      ha->host_no, cmd->device->channel,			      cmd->device->id, cmd->device->lun));		cmd->result = DID_BUS_BUSY << 16;		/*		 * Mark device missing so that we won't continue to send		 * I/O to this device.	We should get a ddb state change		 * AEN soon.		 */		if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)			qla4xxx_mark_device_missing(ha, ddb_entry);		break;	case SCS_DATA_UNDERRUN:	case SCS_DATA_OVERRUN:		if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) ||			(sts_entry->completionStatus == SCS_DATA_OVERRUN)) {			DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "				      "residual = 0x%x\n", ha->host_no,				      cmd->device->channel, cmd->device->id,				      cmd->device->lun, __func__, residual));			cmd->result = DID_ERROR << 16;			break;		}		scsi_set_resid(cmd, residual);		/*		 * If there is scsi_status, it takes precedense over		 * underflow condition.		 */		if (scsi_status != 0) {			cmd->result = DID_OK << 16 | scsi_status;			if (scsi_status != SCSI_CHECK_CONDITION)				break;			/* Copy Sense Data into sense buffer. */			memset(cmd->sense_buffer, 0,			       sizeof(cmd->sense_buffer));			sensebytecnt =				le16_to_cpu(sts_entry->senseDataByteCnt);			if (sensebytecnt == 0)				break;			memcpy(cmd->sense_buffer, sts_entry->senseData,			       min(sensebytecnt,				   (uint16_t) sizeof(cmd->sense_buffer)));			DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "				      "ASC/ASCQ = %02x/%02x\n", ha->host_no,				      cmd->device->channel, cmd->device->id,				      cmd->device->lun, __func__,				      sts_entry->senseData[2] & 0x0f,				      sts_entry->senseData[12],				      sts_entry->senseData[13]));		} else {			/*			 * If RISC reports underrun and target does not			 * report it then we must have a lost frame, so			 * tell upper layer to retry it by reporting a			 * bus busy.			 */			if ((sts_entry->iscsiFlags &			     ISCSI_FLAG_RESIDUAL_UNDER) == 0) {				cmd->result = DID_BUS_BUSY << 16;			} else if ((scsi_bufflen(cmd) - residual) <				   cmd->underflow) {				/*				 * Handle mid-layer underflow???				 *				 * For kernels less than 2.4, the driver must				 * return an error if an underflow is detected.				 * For kernels equal-to and above 2.4, the				 * mid-layer will appearantly handle the				 * underflow by detecting the residual count --				 * unfortunately, we do not see where this is				 * actually being done.	 In the interim, we				 * will return DID_ERROR.				 */				DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "					"Mid-layer Data underrun1, "					"xferlen = 0x%x, "					"residual = 0x%x\n", ha->host_no,					cmd->device->channel,					cmd->device->id,					cmd->device->lun, __func__,					scsi_bufflen(cmd), residual));				cmd->result = DID_ERROR << 16;			} else {				cmd->result = DID_OK << 16;			}		}		break;	case SCS_DEVICE_LOGGED_OUT:	case SCS_DEVICE_UNAVAILABLE:		/*		 * Mark device missing so that we won't continue to		 * send I/O to this device.  We should get a ddb		 * state change AEN soon.		 */		if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)			qla4xxx_mark_device_missing(ha, ddb_entry);		cmd->result = DID_BUS_BUSY << 16;		break;	case SCS_QUEUE_FULL:		/*		 * SCSI Mid-Layer handles device queue full		 */		cmd->result = DID_OK << 16 | sts_entry->scsiStatus;		DEBUG2(printk("scsi%ld:%d:%d: %s: QUEUE FULL detected "			      "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x,"			      " iResp=%02x\n", ha->host_no, cmd->device->id,			      cmd->device->lun, __func__,			      sts_entry->completionStatus,			      sts_entry->scsiStatus, sts_entry->state_flags,			      sts_entry->iscsiFlags,			      sts_entry->iscsiResponse));		break;	default:		cmd->result = DID_ERROR << 16;		break;	}status_entry_exit:	/* complete the request */	srb->cc_stat = sts_entry->completionStatus;	qla4xxx_srb_compl(ha, srb);}/** * qla4xxx_process_response_queue - process response queue completions * @ha: Pointer to host adapter structure. * * This routine process response queue completions in interrupt context. * Hardware_lock locked upon entry **/static void qla4xxx_process_response_queue(struct scsi_qla_host * ha){	uint32_t count = 0;	struct srb *srb = NULL;	struct status_entry *sts_entry;	/* Process all responses from response queue */	while ((ha->response_in =		(uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) !=	       ha->response_out) {		sts_entry = (struct status_entry *) ha->response_ptr;		count++;		/* Advance pointers for next entry */		if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) {			ha->response_out = 0;			ha->response_ptr = ha->response_ring;		} else {			ha->response_out++;			ha->response_ptr++;		}		/* process entry */		switch (sts_entry->hdr.entryType) {		case ET_STATUS:			/*			 * Common status - Single completion posted in single			 * IOSB.			 */			qla4xxx_status_entry(ha, sts_entry);			break;		case ET_PASSTHRU_STATUS:			break;		case ET_STATUS_CONTINUATION:			/* Just throw away the status continuation entries */			DEBUG2(printk("scsi%ld: %s: Status Continuation entry "				      "- ignoring\n", ha->host_no, __func__));			break;		case ET_COMMAND:			/* ISP device queue is full. Command not			 * accepted by ISP.  Queue command for			 * later */			srb = qla4xxx_del_from_active_array(ha,						    le32_to_cpu(sts_entry->								handle));			if (srb == NULL)				goto exit_prq_invalid_handle;			DEBUG2(printk("scsi%ld: %s: FW device queue full, "				      "srb %p\n", ha->host_no, __func__, srb));			/* ETRY normally by sending it back with			 * DID_BUS_BUSY */			srb->cmd->result = DID_BUS_BUSY << 16;			qla4xxx_srb_compl(ha, srb);			break;		case ET_CONTINUE:			/* Just throw away the continuation entries */			DEBUG2(printk("scsi%ld: %s: Continuation entry - "				      "ignoring\n", ha->host_no, __func__));			break;		default:			/*			 * Invalid entry in response queue, reset RISC			 * firmware.			 */			DEBUG2(printk("scsi%ld: %s: Invalid entry %x in "				      "response queue \n", ha->host_no,				      __func__,				      sts_entry->hdr.entryType));			goto exit_prq_error;		}	}	/*	 * Done with responses, update the ISP For QLA4010, this also clears	 * the interrupt.	 */	writel(ha->response_out, &ha->reg->rsp_q_out);	readl(&ha->reg->rsp_q_out);	return;exit_prq_invalid_handle:	DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n",		      ha->host_no, __func__, srb, sts_entry->hdr.entryType,		      sts_entry->completionStatus));exit_prq_error:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?