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 + -
显示快捷键?