162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic iSCSI HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2013 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include "ql4_def.h" 862306a36Sopenharmony_ci#include "ql4_glbl.h" 962306a36Sopenharmony_ci#include "ql4_dbg.h" 1062306a36Sopenharmony_ci#include "ql4_inline.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/** 1362306a36Sopenharmony_ci * qla4xxx_copy_sense - copy sense data into cmd sense buffer 1462306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 1562306a36Sopenharmony_ci * @sts_entry: Pointer to status entry structure. 1662306a36Sopenharmony_ci * @srb: Pointer to srb structure. 1762306a36Sopenharmony_ci **/ 1862306a36Sopenharmony_cistatic void qla4xxx_copy_sense(struct scsi_qla_host *ha, 1962306a36Sopenharmony_ci struct status_entry *sts_entry, 2062306a36Sopenharmony_ci struct srb *srb) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct scsi_cmnd *cmd = srb->cmd; 2362306a36Sopenharmony_ci uint16_t sense_len; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 2662306a36Sopenharmony_ci sense_len = le16_to_cpu(sts_entry->senseDataByteCnt); 2762306a36Sopenharmony_ci if (sense_len == 0) { 2862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d:%llu: %s:" 2962306a36Sopenharmony_ci " sense len 0\n", ha->host_no, 3062306a36Sopenharmony_ci cmd->device->channel, cmd->device->id, 3162306a36Sopenharmony_ci cmd->device->lun, __func__)); 3262306a36Sopenharmony_ci ha->status_srb = NULL; 3362306a36Sopenharmony_ci return; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci /* Save total available sense length, 3662306a36Sopenharmony_ci * not to exceed cmd's sense buffer size */ 3762306a36Sopenharmony_ci sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE); 3862306a36Sopenharmony_ci srb->req_sense_ptr = cmd->sense_buffer; 3962306a36Sopenharmony_ci srb->req_sense_len = sense_len; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci /* Copy sense from sts_entry pkt */ 4262306a36Sopenharmony_ci sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN); 4362306a36Sopenharmony_ci memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%llu: %s: sense key = %x, " 4662306a36Sopenharmony_ci "ASL= %02x, ASC/ASCQ = %02x/%02x\n", ha->host_no, 4762306a36Sopenharmony_ci cmd->device->channel, cmd->device->id, 4862306a36Sopenharmony_ci cmd->device->lun, __func__, 4962306a36Sopenharmony_ci sts_entry->senseData[2] & 0x0f, 5062306a36Sopenharmony_ci sts_entry->senseData[7], 5162306a36Sopenharmony_ci sts_entry->senseData[12], 5262306a36Sopenharmony_ci sts_entry->senseData[13])); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci DEBUG5(qla4xxx_dump_buffer(cmd->sense_buffer, sense_len)); 5562306a36Sopenharmony_ci srb->flags |= SRB_GOT_SENSE; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* Update srb, in case a sts_cont pkt follows */ 5862306a36Sopenharmony_ci srb->req_sense_ptr += sense_len; 5962306a36Sopenharmony_ci srb->req_sense_len -= sense_len; 6062306a36Sopenharmony_ci if (srb->req_sense_len != 0) 6162306a36Sopenharmony_ci ha->status_srb = srb; 6262306a36Sopenharmony_ci else 6362306a36Sopenharmony_ci ha->status_srb = NULL; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/** 6762306a36Sopenharmony_ci * qla4xxx_status_cont_entry - Process a Status Continuations entry. 6862306a36Sopenharmony_ci * @ha: SCSI driver HA context 6962306a36Sopenharmony_ci * @sts_cont: Entry pointer 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Extended sense data. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic void 7462306a36Sopenharmony_ciqla4xxx_status_cont_entry(struct scsi_qla_host *ha, 7562306a36Sopenharmony_ci struct status_cont_entry *sts_cont) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci struct srb *srb = ha->status_srb; 7862306a36Sopenharmony_ci struct scsi_cmnd *cmd; 7962306a36Sopenharmony_ci uint16_t sense_len; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (srb == NULL) 8262306a36Sopenharmony_ci return; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci cmd = srb->cmd; 8562306a36Sopenharmony_ci if (cmd == NULL) { 8662306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: %s: Cmd already returned " 8762306a36Sopenharmony_ci "back to OS srb=%p srb->state:%d\n", ha->host_no, 8862306a36Sopenharmony_ci __func__, srb, srb->state)); 8962306a36Sopenharmony_ci ha->status_srb = NULL; 9062306a36Sopenharmony_ci return; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /* Copy sense data. */ 9462306a36Sopenharmony_ci sense_len = min_t(uint16_t, srb->req_sense_len, 9562306a36Sopenharmony_ci IOCB_MAX_EXT_SENSEDATA_LEN); 9662306a36Sopenharmony_ci memcpy(srb->req_sense_ptr, sts_cont->ext_sense_data, sense_len); 9762306a36Sopenharmony_ci DEBUG5(qla4xxx_dump_buffer(srb->req_sense_ptr, sense_len)); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci srb->req_sense_ptr += sense_len; 10062306a36Sopenharmony_ci srb->req_sense_len -= sense_len; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* Place command on done queue. */ 10362306a36Sopenharmony_ci if (srb->req_sense_len == 0) { 10462306a36Sopenharmony_ci kref_put(&srb->srb_ref, qla4xxx_srb_compl); 10562306a36Sopenharmony_ci ha->status_srb = NULL; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/** 11062306a36Sopenharmony_ci * qla4xxx_status_entry - processes status IOCBs 11162306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 11262306a36Sopenharmony_ci * @sts_entry: Pointer to status entry structure. 11362306a36Sopenharmony_ci **/ 11462306a36Sopenharmony_cistatic void qla4xxx_status_entry(struct scsi_qla_host *ha, 11562306a36Sopenharmony_ci struct status_entry *sts_entry) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci uint8_t scsi_status; 11862306a36Sopenharmony_ci struct scsi_cmnd *cmd; 11962306a36Sopenharmony_ci struct srb *srb; 12062306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 12162306a36Sopenharmony_ci uint32_t residual; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); 12462306a36Sopenharmony_ci if (!srb) { 12562306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s invalid status entry: " 12662306a36Sopenharmony_ci "handle=0x%0x, srb=%p\n", __func__, 12762306a36Sopenharmony_ci sts_entry->handle, srb); 12862306a36Sopenharmony_ci if (is_qla80XX(ha)) 12962306a36Sopenharmony_ci set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); 13062306a36Sopenharmony_ci else 13162306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 13262306a36Sopenharmony_ci return; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci cmd = srb->cmd; 13662306a36Sopenharmony_ci if (cmd == NULL) { 13762306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Command already returned back to " 13862306a36Sopenharmony_ci "OS pkt->handle=%d srb=%p srb->state:%d\n", 13962306a36Sopenharmony_ci ha->host_no, __func__, sts_entry->handle, 14062306a36Sopenharmony_ci srb, srb->state)); 14162306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "Command is NULL:" 14262306a36Sopenharmony_ci " already returned to OS (srb=%p)\n", srb); 14362306a36Sopenharmony_ci return; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci ddb_entry = srb->ddb; 14762306a36Sopenharmony_ci if (ddb_entry == NULL) { 14862306a36Sopenharmony_ci cmd->result = DID_NO_CONNECT << 16; 14962306a36Sopenharmony_ci goto status_entry_exit; 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci residual = le32_to_cpu(sts_entry->residualByteCnt); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci /* Translate ISP error to a Linux SCSI error. */ 15562306a36Sopenharmony_ci scsi_status = sts_entry->scsiStatus; 15662306a36Sopenharmony_ci switch (sts_entry->completionStatus) { 15762306a36Sopenharmony_ci case SCS_COMPLETE: 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) { 16062306a36Sopenharmony_ci cmd->result = DID_ERROR << 16; 16162306a36Sopenharmony_ci break; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) { 16562306a36Sopenharmony_ci scsi_set_resid(cmd, residual); 16662306a36Sopenharmony_ci if (!scsi_status && ((scsi_bufflen(cmd) - residual) < 16762306a36Sopenharmony_ci cmd->underflow)) { 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci cmd->result = DID_ERROR << 16; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: " 17262306a36Sopenharmony_ci "Mid-layer Data underrun0, " 17362306a36Sopenharmony_ci "xferlen = 0x%x, " 17462306a36Sopenharmony_ci "residual = 0x%x\n", ha->host_no, 17562306a36Sopenharmony_ci cmd->device->channel, 17662306a36Sopenharmony_ci cmd->device->id, 17762306a36Sopenharmony_ci cmd->device->lun, __func__, 17862306a36Sopenharmony_ci scsi_bufflen(cmd), residual)); 17962306a36Sopenharmony_ci break; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci cmd->result = DID_OK << 16 | scsi_status; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (scsi_status != SAM_STAT_CHECK_CONDITION) 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* Copy Sense Data into sense buffer. */ 18962306a36Sopenharmony_ci qla4xxx_copy_sense(ha, sts_entry, srb); 19062306a36Sopenharmony_ci break; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci case SCS_INCOMPLETE: 19362306a36Sopenharmony_ci /* Always set the status to DID_ERROR, since 19462306a36Sopenharmony_ci * all conditions result in that status anyway */ 19562306a36Sopenharmony_ci cmd->result = DID_ERROR << 16; 19662306a36Sopenharmony_ci break; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci case SCS_RESET_OCCURRED: 19962306a36Sopenharmony_ci DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: Device RESET occurred\n", 20062306a36Sopenharmony_ci ha->host_no, cmd->device->channel, 20162306a36Sopenharmony_ci cmd->device->id, cmd->device->lun, __func__)); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci cmd->result = DID_RESET << 16; 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci case SCS_ABORTED: 20762306a36Sopenharmony_ci DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: Abort occurred\n", 20862306a36Sopenharmony_ci ha->host_no, cmd->device->channel, 20962306a36Sopenharmony_ci cmd->device->id, cmd->device->lun, __func__)); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci cmd->result = DID_RESET << 16; 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci case SCS_TIMEOUT: 21562306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%llu: Timeout\n", 21662306a36Sopenharmony_ci ha->host_no, cmd->device->channel, 21762306a36Sopenharmony_ci cmd->device->id, cmd->device->lun)); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci cmd->result = DID_TRANSPORT_DISRUPTED << 16; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* 22262306a36Sopenharmony_ci * Mark device missing so that we won't continue to send 22362306a36Sopenharmony_ci * I/O to this device. We should get a ddb state change 22462306a36Sopenharmony_ci * AEN soon. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci if (iscsi_is_session_online(ddb_entry->sess)) 22762306a36Sopenharmony_ci qla4xxx_mark_device_missing(ddb_entry->sess); 22862306a36Sopenharmony_ci break; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci case SCS_DATA_UNDERRUN: 23162306a36Sopenharmony_ci case SCS_DATA_OVERRUN: 23262306a36Sopenharmony_ci if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) || 23362306a36Sopenharmony_ci (sts_entry->completionStatus == SCS_DATA_OVERRUN)) { 23462306a36Sopenharmony_ci DEBUG2(printk("scsi%ld:%d:%d:%llu: %s: " "Data overrun\n", 23562306a36Sopenharmony_ci ha->host_no, 23662306a36Sopenharmony_ci cmd->device->channel, cmd->device->id, 23762306a36Sopenharmony_ci cmd->device->lun, __func__)); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci cmd->result = DID_ERROR << 16; 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci scsi_set_resid(cmd, residual); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) { 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci /* Both the firmware and target reported UNDERRUN: 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * MID-LAYER UNDERFLOW case: 25062306a36Sopenharmony_ci * Some kernels do not properly detect midlayer 25162306a36Sopenharmony_ci * underflow, so we manually check it and return 25262306a36Sopenharmony_ci * ERROR if the minimum required data was not 25362306a36Sopenharmony_ci * received. 25462306a36Sopenharmony_ci * 25562306a36Sopenharmony_ci * ALL OTHER cases: 25662306a36Sopenharmony_ci * Fall thru to check scsi_status 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_ci if (!scsi_status && (scsi_bufflen(cmd) - residual) < 25962306a36Sopenharmony_ci cmd->underflow) { 26062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 26162306a36Sopenharmony_ci "scsi%ld:%d:%d:%llu: %s: Mid-layer Data underrun, xferlen = 0x%x,residual = 0x%x\n", 26262306a36Sopenharmony_ci ha->host_no, 26362306a36Sopenharmony_ci cmd->device->channel, 26462306a36Sopenharmony_ci cmd->device->id, 26562306a36Sopenharmony_ci cmd->device->lun, __func__, 26662306a36Sopenharmony_ci scsi_bufflen(cmd), 26762306a36Sopenharmony_ci residual)); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci cmd->result = DID_ERROR << 16; 27062306a36Sopenharmony_ci break; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci } else if (scsi_status != SAM_STAT_TASK_SET_FULL && 27462306a36Sopenharmony_ci scsi_status != SAM_STAT_BUSY) { 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci /* 27762306a36Sopenharmony_ci * The firmware reports UNDERRUN, but the target does 27862306a36Sopenharmony_ci * not report it: 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * scsi_status | host_byte device_byte 28162306a36Sopenharmony_ci * | (19:16) (7:0) 28262306a36Sopenharmony_ci * ============= | ========= =========== 28362306a36Sopenharmony_ci * TASK_SET_FULL | DID_OK scsi_status 28462306a36Sopenharmony_ci * BUSY | DID_OK scsi_status 28562306a36Sopenharmony_ci * ALL OTHERS | DID_ERROR scsi_status 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * Note: If scsi_status is task set full or busy, 28862306a36Sopenharmony_ci * then this else if would fall thru to check the 28962306a36Sopenharmony_ci * scsi_status and return DID_OK. 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 29362306a36Sopenharmony_ci "scsi%ld:%d:%d:%llu: %s: Dropped frame(s) detected (0x%x of 0x%x bytes).\n", 29462306a36Sopenharmony_ci ha->host_no, 29562306a36Sopenharmony_ci cmd->device->channel, 29662306a36Sopenharmony_ci cmd->device->id, 29762306a36Sopenharmony_ci cmd->device->lun, __func__, 29862306a36Sopenharmony_ci residual, 29962306a36Sopenharmony_ci scsi_bufflen(cmd))); 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci cmd->result = DID_ERROR << 16 | scsi_status; 30262306a36Sopenharmony_ci goto check_scsi_status; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci cmd->result = DID_OK << 16 | scsi_status; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cicheck_scsi_status: 30862306a36Sopenharmony_ci if (scsi_status == SAM_STAT_CHECK_CONDITION) 30962306a36Sopenharmony_ci qla4xxx_copy_sense(ha, sts_entry, srb); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci case SCS_DEVICE_LOGGED_OUT: 31462306a36Sopenharmony_ci case SCS_DEVICE_UNAVAILABLE: 31562306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%llu: SCS_DEVICE " 31662306a36Sopenharmony_ci "state: 0x%x\n", ha->host_no, 31762306a36Sopenharmony_ci cmd->device->channel, cmd->device->id, 31862306a36Sopenharmony_ci cmd->device->lun, sts_entry->completionStatus)); 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * Mark device missing so that we won't continue to 32162306a36Sopenharmony_ci * send I/O to this device. We should get a ddb 32262306a36Sopenharmony_ci * state change AEN soon. 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ci if (iscsi_is_session_online(ddb_entry->sess)) 32562306a36Sopenharmony_ci qla4xxx_mark_device_missing(ddb_entry->sess); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci cmd->result = DID_TRANSPORT_DISRUPTED << 16; 32862306a36Sopenharmony_ci break; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci case SCS_QUEUE_FULL: 33162306a36Sopenharmony_ci /* 33262306a36Sopenharmony_ci * SCSI Mid-Layer handles device queue full 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci cmd->result = DID_OK << 16 | sts_entry->scsiStatus; 33562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld:%d:%llu: %s: QUEUE FULL detected " 33662306a36Sopenharmony_ci "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x," 33762306a36Sopenharmony_ci " iResp=%02x\n", ha->host_no, cmd->device->id, 33862306a36Sopenharmony_ci cmd->device->lun, __func__, 33962306a36Sopenharmony_ci sts_entry->completionStatus, 34062306a36Sopenharmony_ci sts_entry->scsiStatus, sts_entry->state_flags, 34162306a36Sopenharmony_ci sts_entry->iscsiFlags, 34262306a36Sopenharmony_ci sts_entry->iscsiResponse)); 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci default: 34662306a36Sopenharmony_ci cmd->result = DID_ERROR << 16; 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatus_entry_exit: 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* complete the request, if not waiting for status_continuation pkt */ 35362306a36Sopenharmony_ci srb->cc_stat = sts_entry->completionStatus; 35462306a36Sopenharmony_ci if (ha->status_srb == NULL) 35562306a36Sopenharmony_ci kref_put(&srb->srb_ref, qla4xxx_srb_compl); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci/** 35962306a36Sopenharmony_ci * qla4xxx_passthru_status_entry - processes passthru status IOCBs (0x3C) 36062306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 36162306a36Sopenharmony_ci * @sts_entry: Pointer to status entry structure. 36262306a36Sopenharmony_ci **/ 36362306a36Sopenharmony_cistatic void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha, 36462306a36Sopenharmony_ci struct passthru_status *sts_entry) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct iscsi_task *task; 36762306a36Sopenharmony_ci struct ddb_entry *ddb_entry; 36862306a36Sopenharmony_ci struct ql4_task_data *task_data; 36962306a36Sopenharmony_ci struct iscsi_cls_conn *cls_conn; 37062306a36Sopenharmony_ci struct iscsi_conn *conn; 37162306a36Sopenharmony_ci itt_t itt; 37262306a36Sopenharmony_ci uint32_t fw_ddb_index; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci itt = sts_entry->handle; 37562306a36Sopenharmony_ci fw_ddb_index = le32_to_cpu(sts_entry->target); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (ddb_entry == NULL) { 38062306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Invalid target index = 0x%x\n", 38162306a36Sopenharmony_ci __func__, sts_entry->target); 38262306a36Sopenharmony_ci return; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci cls_conn = ddb_entry->conn; 38662306a36Sopenharmony_ci conn = cls_conn->dd_data; 38762306a36Sopenharmony_ci spin_lock(&conn->session->back_lock); 38862306a36Sopenharmony_ci task = iscsi_itt_to_task(conn, itt); 38962306a36Sopenharmony_ci spin_unlock(&conn->session->back_lock); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (task == NULL) { 39262306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__); 39362306a36Sopenharmony_ci return; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci task_data = task->dd_data; 39762306a36Sopenharmony_ci memcpy(&task_data->sts, sts_entry, sizeof(struct passthru_status)); 39862306a36Sopenharmony_ci ha->iocb_cnt -= task_data->iocb_req_cnt; 39962306a36Sopenharmony_ci queue_work(ha->task_wq, &task_data->task_work); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha, 40362306a36Sopenharmony_ci uint32_t index) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci struct mrb *mrb = NULL; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* validate handle and remove from active array */ 40862306a36Sopenharmony_ci if (index >= MAX_MRB) 40962306a36Sopenharmony_ci return mrb; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci mrb = ha->active_mrb_array[index]; 41262306a36Sopenharmony_ci ha->active_mrb_array[index] = NULL; 41362306a36Sopenharmony_ci if (!mrb) 41462306a36Sopenharmony_ci return mrb; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci /* update counters */ 41762306a36Sopenharmony_ci ha->iocb_cnt -= mrb->iocb_cnt; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci return mrb; 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic void qla4xxx_mbox_status_entry(struct scsi_qla_host *ha, 42362306a36Sopenharmony_ci struct mbox_status_iocb *mbox_sts_entry) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct mrb *mrb; 42662306a36Sopenharmony_ci uint32_t status; 42762306a36Sopenharmony_ci uint32_t data_size; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci mrb = qla4xxx_del_mrb_from_active_array(ha, 43062306a36Sopenharmony_ci le32_to_cpu(mbox_sts_entry->handle)); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (mrb == NULL) { 43362306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s: mrb[%d] is null\n", __func__, 43462306a36Sopenharmony_ci mbox_sts_entry->handle); 43562306a36Sopenharmony_ci return; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci switch (mrb->mbox_cmd) { 43962306a36Sopenharmony_ci case MBOX_CMD_PING: 44062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "%s: mbox_cmd = 0x%x, " 44162306a36Sopenharmony_ci "mbox_sts[0] = 0x%x, mbox_sts[6] = 0x%x\n", 44262306a36Sopenharmony_ci __func__, mrb->mbox_cmd, 44362306a36Sopenharmony_ci mbox_sts_entry->out_mbox[0], 44462306a36Sopenharmony_ci mbox_sts_entry->out_mbox[6])); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci if (mbox_sts_entry->out_mbox[0] == MBOX_STS_COMMAND_COMPLETE) 44762306a36Sopenharmony_ci status = ISCSI_PING_SUCCESS; 44862306a36Sopenharmony_ci else 44962306a36Sopenharmony_ci status = mbox_sts_entry->out_mbox[6]; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci data_size = sizeof(mbox_sts_entry->out_mbox); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci qla4xxx_post_ping_evt_work(ha, status, mrb->pid, data_size, 45462306a36Sopenharmony_ci (uint8_t *) mbox_sts_entry->out_mbox); 45562306a36Sopenharmony_ci break; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci default: 45862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: invalid mbox_cmd = " 45962306a36Sopenharmony_ci "0x%x\n", __func__, mrb->mbox_cmd)); 46062306a36Sopenharmony_ci } 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci kfree(mrb); 46362306a36Sopenharmony_ci return; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci/** 46762306a36Sopenharmony_ci * qla4xxx_process_response_queue - process response queue completions 46862306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 46962306a36Sopenharmony_ci * 47062306a36Sopenharmony_ci * This routine process response queue completions in interrupt context. 47162306a36Sopenharmony_ci * Hardware_lock locked upon entry 47262306a36Sopenharmony_ci **/ 47362306a36Sopenharmony_civoid qla4xxx_process_response_queue(struct scsi_qla_host *ha) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci struct srb *srb = NULL; 47662306a36Sopenharmony_ci struct status_entry *sts_entry; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Process all responses from response queue */ 47962306a36Sopenharmony_ci while ((ha->response_ptr->signature != RESPONSE_PROCESSED)) { 48062306a36Sopenharmony_ci sts_entry = (struct status_entry *) ha->response_ptr; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci /* Advance pointers for next entry */ 48362306a36Sopenharmony_ci if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) { 48462306a36Sopenharmony_ci ha->response_out = 0; 48562306a36Sopenharmony_ci ha->response_ptr = ha->response_ring; 48662306a36Sopenharmony_ci } else { 48762306a36Sopenharmony_ci ha->response_out++; 48862306a36Sopenharmony_ci ha->response_ptr++; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* process entry */ 49262306a36Sopenharmony_ci switch (sts_entry->hdr.entryType) { 49362306a36Sopenharmony_ci case ET_STATUS: 49462306a36Sopenharmony_ci /* Common status */ 49562306a36Sopenharmony_ci qla4xxx_status_entry(ha, sts_entry); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci case ET_PASSTHRU_STATUS: 49962306a36Sopenharmony_ci if (sts_entry->hdr.systemDefined == SD_ISCSI_PDU) 50062306a36Sopenharmony_ci qla4xxx_passthru_status_entry(ha, 50162306a36Sopenharmony_ci (struct passthru_status *)sts_entry); 50262306a36Sopenharmony_ci else 50362306a36Sopenharmony_ci ql4_printk(KERN_ERR, ha, 50462306a36Sopenharmony_ci "%s: Invalid status received\n", 50562306a36Sopenharmony_ci __func__); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci case ET_STATUS_CONTINUATION: 51062306a36Sopenharmony_ci qla4xxx_status_cont_entry(ha, 51162306a36Sopenharmony_ci (struct status_cont_entry *) sts_entry); 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci case ET_COMMAND: 51562306a36Sopenharmony_ci /* ISP device queue is full. Command not 51662306a36Sopenharmony_ci * accepted by ISP. Queue command for 51762306a36Sopenharmony_ci * later */ 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci srb = qla4xxx_del_from_active_array(ha, 52062306a36Sopenharmony_ci le32_to_cpu(sts_entry-> 52162306a36Sopenharmony_ci handle)); 52262306a36Sopenharmony_ci if (srb == NULL) 52362306a36Sopenharmony_ci goto exit_prq_invalid_handle; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: FW device queue full, " 52662306a36Sopenharmony_ci "srb %p\n", ha->host_no, __func__, srb)); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* ETRY normally by sending it back with 52962306a36Sopenharmony_ci * DID_BUS_BUSY */ 53062306a36Sopenharmony_ci srb->cmd->result = DID_BUS_BUSY << 16; 53162306a36Sopenharmony_ci kref_put(&srb->srb_ref, qla4xxx_srb_compl); 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci case ET_CONTINUE: 53562306a36Sopenharmony_ci /* Just throw away the continuation entries */ 53662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Continuation entry - " 53762306a36Sopenharmony_ci "ignoring\n", ha->host_no, __func__)); 53862306a36Sopenharmony_ci break; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci case ET_MBOX_STATUS: 54162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 54262306a36Sopenharmony_ci "%s: mbox status IOCB\n", __func__)); 54362306a36Sopenharmony_ci qla4xxx_mbox_status_entry(ha, 54462306a36Sopenharmony_ci (struct mbox_status_iocb *)sts_entry); 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci default: 54862306a36Sopenharmony_ci /* 54962306a36Sopenharmony_ci * Invalid entry in response queue, reset RISC 55062306a36Sopenharmony_ci * firmware. 55162306a36Sopenharmony_ci */ 55262306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Invalid entry %x in " 55362306a36Sopenharmony_ci "response queue \n", ha->host_no, 55462306a36Sopenharmony_ci __func__, 55562306a36Sopenharmony_ci sts_entry->hdr.entryType)); 55662306a36Sopenharmony_ci goto exit_prq_error; 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci ((struct response *)sts_entry)->signature = RESPONSE_PROCESSED; 55962306a36Sopenharmony_ci wmb(); 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* 56362306a36Sopenharmony_ci * Tell ISP we're done with response(s). This also clears the interrupt. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci ha->isp_ops->complete_iocb(ha); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci return; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ciexit_prq_invalid_handle: 57062306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n", 57162306a36Sopenharmony_ci ha->host_no, __func__, srb, sts_entry->hdr.entryType, 57262306a36Sopenharmony_ci sts_entry->completionStatus)); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ciexit_prq_error: 57562306a36Sopenharmony_ci ha->isp_ops->complete_iocb(ha); 57662306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci/** 58062306a36Sopenharmony_ci * qla4_83xx_loopback_in_progress: Is loopback in progress? 58162306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 58262306a36Sopenharmony_ci * returns: 1 = loopback in progress, 0 = loopback not in progress 58362306a36Sopenharmony_ci **/ 58462306a36Sopenharmony_cistatic int qla4_83xx_loopback_in_progress(struct scsi_qla_host *ha) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci int rval = 1; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 58962306a36Sopenharmony_ci if ((ha->idc_info.info2 & ENABLE_INTERNAL_LOOPBACK) || 59062306a36Sopenharmony_ci (ha->idc_info.info2 & ENABLE_EXTERNAL_LOOPBACK)) { 59162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 59262306a36Sopenharmony_ci "%s: Loopback diagnostics in progress\n", 59362306a36Sopenharmony_ci __func__)); 59462306a36Sopenharmony_ci rval = 1; 59562306a36Sopenharmony_ci } else { 59662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 59762306a36Sopenharmony_ci "%s: Loopback diagnostics not in progress\n", 59862306a36Sopenharmony_ci __func__)); 59962306a36Sopenharmony_ci rval = 0; 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return rval; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic void qla4xxx_update_ipaddr_state(struct scsi_qla_host *ha, 60762306a36Sopenharmony_ci uint32_t ipaddr_idx, 60862306a36Sopenharmony_ci uint32_t ipaddr_fw_state) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci uint8_t ipaddr_state; 61162306a36Sopenharmony_ci uint8_t ip_idx; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci ip_idx = ipaddr_idx & 0xF; 61462306a36Sopenharmony_ci ipaddr_state = qla4xxx_set_ipaddr_state((uint8_t)ipaddr_fw_state); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci switch (ip_idx) { 61762306a36Sopenharmony_ci case 0: 61862306a36Sopenharmony_ci ha->ip_config.ipv4_addr_state = ipaddr_state; 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci case 1: 62162306a36Sopenharmony_ci ha->ip_config.ipv6_link_local_state = ipaddr_state; 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci case 2: 62462306a36Sopenharmony_ci ha->ip_config.ipv6_addr0_state = ipaddr_state; 62562306a36Sopenharmony_ci break; 62662306a36Sopenharmony_ci case 3: 62762306a36Sopenharmony_ci ha->ip_config.ipv6_addr1_state = ipaddr_state; 62862306a36Sopenharmony_ci break; 62962306a36Sopenharmony_ci default: 63062306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: Invalid IPADDR index %d\n", 63162306a36Sopenharmony_ci __func__, ip_idx); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void qla4xxx_default_router_changed(struct scsi_qla_host *ha, 63662306a36Sopenharmony_ci uint32_t *mbox_sts) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[0], 63962306a36Sopenharmony_ci &mbox_sts[2], sizeof(uint32_t)); 64062306a36Sopenharmony_ci memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[1], 64162306a36Sopenharmony_ci &mbox_sts[3], sizeof(uint32_t)); 64262306a36Sopenharmony_ci memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[2], 64362306a36Sopenharmony_ci &mbox_sts[4], sizeof(uint32_t)); 64462306a36Sopenharmony_ci memcpy(&ha->ip_config.ipv6_default_router_addr.s6_addr32[3], 64562306a36Sopenharmony_ci &mbox_sts[5], sizeof(uint32_t)); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci/** 64962306a36Sopenharmony_ci * qla4xxx_isr_decode_mailbox - decodes mailbox status 65062306a36Sopenharmony_ci * @ha: Pointer to host adapter structure. 65162306a36Sopenharmony_ci * @mbox_status: Mailbox status. 65262306a36Sopenharmony_ci * 65362306a36Sopenharmony_ci * This routine decodes the mailbox status during the ISR. 65462306a36Sopenharmony_ci * Hardware_lock locked upon entry. runs in interrupt context. 65562306a36Sopenharmony_ci **/ 65662306a36Sopenharmony_cistatic void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, 65762306a36Sopenharmony_ci uint32_t mbox_status) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci int i; 66062306a36Sopenharmony_ci uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; 66162306a36Sopenharmony_ci __le32 __iomem *mailbox_out; 66262306a36Sopenharmony_ci uint32_t opcode = 0; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) 66562306a36Sopenharmony_ci mailbox_out = &ha->qla4_83xx_reg->mailbox_out[0]; 66662306a36Sopenharmony_ci else if (is_qla8022(ha)) 66762306a36Sopenharmony_ci mailbox_out = &ha->qla4_82xx_reg->mailbox_out[0]; 66862306a36Sopenharmony_ci else 66962306a36Sopenharmony_ci mailbox_out = &ha->reg->mailbox[0]; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if ((mbox_status == MBOX_STS_BUSY) || 67262306a36Sopenharmony_ci (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || 67362306a36Sopenharmony_ci (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) { 67462306a36Sopenharmony_ci ha->mbox_status[0] = mbox_status; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci if (test_bit(AF_MBOX_COMMAND, &ha->flags)) { 67762306a36Sopenharmony_ci /* 67862306a36Sopenharmony_ci * Copy all mailbox registers to a temporary 67962306a36Sopenharmony_ci * location and set mailbox command done flag 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_ci for (i = 0; i < ha->mbox_status_count; i++) 68262306a36Sopenharmony_ci ha->mbox_status[i] = readl(&mailbox_out[i]); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags)) 68762306a36Sopenharmony_ci complete(&ha->mbx_intr_comp); 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { 69062306a36Sopenharmony_ci for (i = 0; i < MBOX_AEN_REG_COUNT; i++) 69162306a36Sopenharmony_ci mbox_sts[i] = readl(&mailbox_out[i]); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* Immediately process the AENs that don't require much work. 69462306a36Sopenharmony_ci * Only queue the database_changed AENs */ 69562306a36Sopenharmony_ci if (ha->aen_log.count < MAX_AEN_ENTRIES) { 69662306a36Sopenharmony_ci for (i = 0; i < MBOX_AEN_REG_COUNT; i++) 69762306a36Sopenharmony_ci ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] = 69862306a36Sopenharmony_ci mbox_sts[i]; 69962306a36Sopenharmony_ci ha->aen_log.count++; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci switch (mbox_status) { 70262306a36Sopenharmony_ci case MBOX_ASTS_SYSTEM_ERROR: 70362306a36Sopenharmony_ci /* Log Mailbox registers */ 70462306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__); 70562306a36Sopenharmony_ci qla4xxx_dump_registers(ha); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if ((is_qla8022(ha) && ql4xdontresethba) || 70862306a36Sopenharmony_ci ((is_qla8032(ha) || is_qla8042(ha)) && 70962306a36Sopenharmony_ci qla4_83xx_idc_dontreset(ha))) { 71062306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n", 71162306a36Sopenharmony_ci ha->host_no, __func__)); 71262306a36Sopenharmony_ci } else { 71362306a36Sopenharmony_ci set_bit(AF_GET_CRASH_RECORD, &ha->flags); 71462306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci break; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci case MBOX_ASTS_REQUEST_TRANSFER_ERROR: 71962306a36Sopenharmony_ci case MBOX_ASTS_RESPONSE_TRANSFER_ERROR: 72062306a36Sopenharmony_ci case MBOX_ASTS_NVRAM_INVALID: 72162306a36Sopenharmony_ci case MBOX_ASTS_IP_ADDRESS_CHANGED: 72262306a36Sopenharmony_ci case MBOX_ASTS_DHCP_LEASE_EXPIRED: 72362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " 72462306a36Sopenharmony_ci "Reset HA\n", ha->host_no, mbox_status)); 72562306a36Sopenharmony_ci if (is_qla80XX(ha)) 72662306a36Sopenharmony_ci set_bit(DPC_RESET_HA_FW_CONTEXT, 72762306a36Sopenharmony_ci &ha->dpc_flags); 72862306a36Sopenharmony_ci else 72962306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 73062306a36Sopenharmony_ci break; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci case MBOX_ASTS_LINK_UP: 73362306a36Sopenharmony_ci set_bit(AF_LINK_UP, &ha->flags); 73462306a36Sopenharmony_ci if (test_bit(AF_INIT_DONE, &ha->flags)) 73562306a36Sopenharmony_ci set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__); 73862306a36Sopenharmony_ci qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKUP, 73962306a36Sopenharmony_ci sizeof(mbox_sts), 74062306a36Sopenharmony_ci (uint8_t *) mbox_sts); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if ((is_qla8032(ha) || is_qla8042(ha)) && 74362306a36Sopenharmony_ci ha->notify_link_up_comp) 74462306a36Sopenharmony_ci complete(&ha->link_up_comp); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci case MBOX_ASTS_LINK_DOWN: 74962306a36Sopenharmony_ci clear_bit(AF_LINK_UP, &ha->flags); 75062306a36Sopenharmony_ci if (test_bit(AF_INIT_DONE, &ha->flags)) { 75162306a36Sopenharmony_ci set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); 75262306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__); 75662306a36Sopenharmony_ci qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKDOWN, 75762306a36Sopenharmony_ci sizeof(mbox_sts), 75862306a36Sopenharmony_ci (uint8_t *) mbox_sts); 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci case MBOX_ASTS_HEARTBEAT: 76262306a36Sopenharmony_ci ha->seconds_since_last_heartbeat = 0; 76362306a36Sopenharmony_ci break; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci case MBOX_ASTS_DHCP_LEASE_ACQUIRED: 76662306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE " 76762306a36Sopenharmony_ci "ACQUIRED\n", ha->host_no, mbox_status)); 76862306a36Sopenharmony_ci set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); 76962306a36Sopenharmony_ci break; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM: 77262306a36Sopenharmony_ci case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target 77362306a36Sopenharmony_ci * mode 77462306a36Sopenharmony_ci * only */ 77562306a36Sopenharmony_ci case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED: /* Connection mode */ 77662306a36Sopenharmony_ci case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR: 77762306a36Sopenharmony_ci case MBOX_ASTS_SUBNET_STATE_CHANGE: 77862306a36Sopenharmony_ci case MBOX_ASTS_DUPLICATE_IP: 77962306a36Sopenharmony_ci /* No action */ 78062306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no, 78162306a36Sopenharmony_ci mbox_status)); 78262306a36Sopenharmony_ci break; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci case MBOX_ASTS_IP_ADDR_STATE_CHANGED: 78562306a36Sopenharmony_ci printk("scsi%ld: AEN %04x, mbox_sts[2]=%04x, " 78662306a36Sopenharmony_ci "mbox_sts[3]=%04x\n", ha->host_no, mbox_sts[0], 78762306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3]); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci qla4xxx_update_ipaddr_state(ha, mbox_sts[5], 79062306a36Sopenharmony_ci mbox_sts[3]); 79162306a36Sopenharmony_ci /* mbox_sts[2] = Old ACB state 79262306a36Sopenharmony_ci * mbox_sts[3] = new ACB state */ 79362306a36Sopenharmony_ci if ((mbox_sts[3] == IP_ADDRSTATE_PREFERRED) && 79462306a36Sopenharmony_ci ((mbox_sts[2] == IP_ADDRSTATE_TENTATIVE) || 79562306a36Sopenharmony_ci (mbox_sts[2] == IP_ADDRSTATE_ACQUIRING))) { 79662306a36Sopenharmony_ci set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); 79762306a36Sopenharmony_ci } else if ((mbox_sts[3] == IP_ADDRSTATE_ACQUIRING) && 79862306a36Sopenharmony_ci (mbox_sts[2] == IP_ADDRSTATE_PREFERRED)) { 79962306a36Sopenharmony_ci if (is_qla80XX(ha)) 80062306a36Sopenharmony_ci set_bit(DPC_RESET_HA_FW_CONTEXT, 80162306a36Sopenharmony_ci &ha->dpc_flags); 80262306a36Sopenharmony_ci else 80362306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 80462306a36Sopenharmony_ci } else if (mbox_sts[3] == IP_ADDRSTATE_DISABLING) { 80562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB in disabling state\n", 80662306a36Sopenharmony_ci ha->host_no, __func__); 80762306a36Sopenharmony_ci } else if (mbox_sts[3] == IP_ADDRSTATE_UNCONFIGURED) { 80862306a36Sopenharmony_ci complete(&ha->disable_acb_comp); 80962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ACB state unconfigured\n", 81062306a36Sopenharmony_ci ha->host_no, __func__); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci break; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci case MBOX_ASTS_IPV6_LINK_MTU_CHANGE: 81562306a36Sopenharmony_ci case MBOX_ASTS_IPV6_AUTO_PREFIX_IGNORED: 81662306a36Sopenharmony_ci case MBOX_ASTS_IPV6_ND_LOCAL_PREFIX_IGNORED: 81762306a36Sopenharmony_ci /* No action */ 81862306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld: AEN %04x\n", 81962306a36Sopenharmony_ci ha->host_no, mbox_status)); 82062306a36Sopenharmony_ci break; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci case MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD: 82362306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 82462306a36Sopenharmony_ci "scsi%ld: AEN %04x, IPv6 ERROR, " 82562306a36Sopenharmony_ci "mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3}=%08x, mbox_sts[4]=%08x mbox_sts[5]=%08x\n", 82662306a36Sopenharmony_ci ha->host_no, mbox_sts[0], mbox_sts[1], 82762306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3], mbox_sts[4], 82862306a36Sopenharmony_ci mbox_sts[5])); 82962306a36Sopenharmony_ci break; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci case MBOX_ASTS_MAC_ADDRESS_CHANGED: 83262306a36Sopenharmony_ci case MBOX_ASTS_DNS: 83362306a36Sopenharmony_ci /* No action */ 83462306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, " 83562306a36Sopenharmony_ci "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n", 83662306a36Sopenharmony_ci ha->host_no, mbox_sts[0], 83762306a36Sopenharmony_ci mbox_sts[1], mbox_sts[2])); 83862306a36Sopenharmony_ci break; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci case MBOX_ASTS_SELF_TEST_FAILED: 84162306a36Sopenharmony_ci case MBOX_ASTS_LOGIN_FAILED: 84262306a36Sopenharmony_ci /* No action */ 84362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, " 84462306a36Sopenharmony_ci "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n", 84562306a36Sopenharmony_ci ha->host_no, mbox_sts[0], mbox_sts[1], 84662306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3])); 84762306a36Sopenharmony_ci break; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci case MBOX_ASTS_DATABASE_CHANGED: 85062306a36Sopenharmony_ci /* Queue AEN information and process it in the DPC 85162306a36Sopenharmony_ci * routine */ 85262306a36Sopenharmony_ci if (ha->aen_q_count > 0) { 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* decrement available counter */ 85562306a36Sopenharmony_ci ha->aen_q_count--; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci for (i = 0; i < MBOX_AEN_REG_COUNT; i++) 85862306a36Sopenharmony_ci ha->aen_q[ha->aen_in].mbox_sts[i] = 85962306a36Sopenharmony_ci mbox_sts[i]; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* print debug message */ 86262306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: AEN[%d] %04x queued " 86362306a36Sopenharmony_ci "mb1:0x%x mb2:0x%x mb3:0x%x " 86462306a36Sopenharmony_ci "mb4:0x%x mb5:0x%x\n", 86562306a36Sopenharmony_ci ha->host_no, ha->aen_in, 86662306a36Sopenharmony_ci mbox_sts[0], mbox_sts[1], 86762306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3], 86862306a36Sopenharmony_ci mbox_sts[4], mbox_sts[5])); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* advance pointer */ 87162306a36Sopenharmony_ci ha->aen_in++; 87262306a36Sopenharmony_ci if (ha->aen_in == MAX_AEN_ENTRIES) 87362306a36Sopenharmony_ci ha->aen_in = 0; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci /* The DPC routine will process the aen */ 87662306a36Sopenharmony_ci set_bit(DPC_AEN, &ha->dpc_flags); 87762306a36Sopenharmony_ci } else { 87862306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: %s: aen %04x, queue " 87962306a36Sopenharmony_ci "overflowed! AEN LOST!!\n", 88062306a36Sopenharmony_ci ha->host_no, __func__, 88162306a36Sopenharmony_ci mbox_sts[0])); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n", 88462306a36Sopenharmony_ci ha->host_no)); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci for (i = 0; i < MAX_AEN_ENTRIES; i++) { 88762306a36Sopenharmony_ci DEBUG2(printk("AEN[%d] %04x %04x %04x " 88862306a36Sopenharmony_ci "%04x\n", i, mbox_sts[0], 88962306a36Sopenharmony_ci mbox_sts[1], mbox_sts[2], 89062306a36Sopenharmony_ci mbox_sts[3])); 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci } 89362306a36Sopenharmony_ci break; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci case MBOX_ASTS_TXSCVR_INSERTED: 89662306a36Sopenharmony_ci DEBUG2(printk(KERN_WARNING 89762306a36Sopenharmony_ci "scsi%ld: AEN %04x Transceiver" 89862306a36Sopenharmony_ci " inserted\n", ha->host_no, mbox_sts[0])); 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci case MBOX_ASTS_TXSCVR_REMOVED: 90262306a36Sopenharmony_ci DEBUG2(printk(KERN_WARNING 90362306a36Sopenharmony_ci "scsi%ld: AEN %04x Transceiver" 90462306a36Sopenharmony_ci " removed\n", ha->host_no, mbox_sts[0])); 90562306a36Sopenharmony_ci break; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci case MBOX_ASTS_IDC_REQUEST_NOTIFICATION: 90862306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 90962306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 91062306a36Sopenharmony_ci "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n", 91162306a36Sopenharmony_ci ha->host_no, mbox_sts[0], 91262306a36Sopenharmony_ci mbox_sts[1], mbox_sts[2], 91362306a36Sopenharmony_ci mbox_sts[3], mbox_sts[4])); 91462306a36Sopenharmony_ci opcode = mbox_sts[1] >> 16; 91562306a36Sopenharmony_ci if ((opcode == MBOX_CMD_SET_PORT_CONFIG) || 91662306a36Sopenharmony_ci (opcode == MBOX_CMD_PORT_RESET)) { 91762306a36Sopenharmony_ci set_bit(DPC_POST_IDC_ACK, 91862306a36Sopenharmony_ci &ha->dpc_flags); 91962306a36Sopenharmony_ci ha->idc_info.request_desc = mbox_sts[1]; 92062306a36Sopenharmony_ci ha->idc_info.info1 = mbox_sts[2]; 92162306a36Sopenharmony_ci ha->idc_info.info2 = mbox_sts[3]; 92262306a36Sopenharmony_ci ha->idc_info.info3 = mbox_sts[4]; 92362306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci break; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci case MBOX_ASTS_IDC_COMPLETE: 92962306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 93062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 93162306a36Sopenharmony_ci "scsi%ld: AEN %04x, mbox_sts[1]=%08x, mbox_sts[2]=%08x, mbox_sts[3]=%08x, mbox_sts[4]=%08x\n", 93262306a36Sopenharmony_ci ha->host_no, mbox_sts[0], 93362306a36Sopenharmony_ci mbox_sts[1], mbox_sts[2], 93462306a36Sopenharmony_ci mbox_sts[3], mbox_sts[4])); 93562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 93662306a36Sopenharmony_ci "scsi:%ld: AEN %04x IDC Complete notification\n", 93762306a36Sopenharmony_ci ha->host_no, mbox_sts[0])); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci opcode = mbox_sts[1] >> 16; 94062306a36Sopenharmony_ci if (ha->notify_idc_comp) 94162306a36Sopenharmony_ci complete(&ha->idc_comp); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci if ((opcode == MBOX_CMD_SET_PORT_CONFIG) || 94462306a36Sopenharmony_ci (opcode == MBOX_CMD_PORT_RESET)) 94562306a36Sopenharmony_ci ha->idc_info.info2 = mbox_sts[3]; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (qla4_83xx_loopback_in_progress(ha)) { 94862306a36Sopenharmony_ci set_bit(AF_LOOPBACK, &ha->flags); 94962306a36Sopenharmony_ci } else { 95062306a36Sopenharmony_ci clear_bit(AF_LOOPBACK, &ha->flags); 95162306a36Sopenharmony_ci if (ha->saved_acb) 95262306a36Sopenharmony_ci set_bit(DPC_RESTORE_ACB, 95362306a36Sopenharmony_ci &ha->dpc_flags); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci qla4xxx_wake_dpc(ha); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci break; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci case MBOX_ASTS_IPV6_DEFAULT_ROUTER_CHANGED: 96062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 96162306a36Sopenharmony_ci "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", 96262306a36Sopenharmony_ci ha->host_no, mbox_sts[0], mbox_sts[1], 96362306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3], mbox_sts[4], 96462306a36Sopenharmony_ci mbox_sts[5])); 96562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 96662306a36Sopenharmony_ci "scsi%ld: AEN %04x Received IPv6 default router changed notification\n", 96762306a36Sopenharmony_ci ha->host_no, mbox_sts[0])); 96862306a36Sopenharmony_ci qla4xxx_default_router_changed(ha, mbox_sts); 96962306a36Sopenharmony_ci break; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci case MBOX_ASTS_IDC_TIME_EXTEND_NOTIFICATION: 97262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 97362306a36Sopenharmony_ci "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", 97462306a36Sopenharmony_ci ha->host_no, mbox_sts[0], mbox_sts[1], 97562306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3], mbox_sts[4], 97662306a36Sopenharmony_ci mbox_sts[5])); 97762306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 97862306a36Sopenharmony_ci "scsi%ld: AEN %04x Received IDC Extend Timeout notification\n", 97962306a36Sopenharmony_ci ha->host_no, mbox_sts[0])); 98062306a36Sopenharmony_ci /* new IDC timeout */ 98162306a36Sopenharmony_ci ha->idc_extend_tmo = mbox_sts[1]; 98262306a36Sopenharmony_ci break; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci case MBOX_ASTS_INITIALIZATION_FAILED: 98562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 98662306a36Sopenharmony_ci "scsi%ld: AEN %04x, mbox_sts[3]=%08x\n", 98762306a36Sopenharmony_ci ha->host_no, mbox_sts[0], 98862306a36Sopenharmony_ci mbox_sts[3])); 98962306a36Sopenharmony_ci break; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci case MBOX_ASTS_SYSTEM_WARNING_EVENT: 99262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_WARNING, ha, 99362306a36Sopenharmony_ci "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", 99462306a36Sopenharmony_ci ha->host_no, mbox_sts[0], mbox_sts[1], 99562306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3], mbox_sts[4], 99662306a36Sopenharmony_ci mbox_sts[5])); 99762306a36Sopenharmony_ci break; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci case MBOX_ASTS_DCBX_CONF_CHANGE: 100062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 100162306a36Sopenharmony_ci "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", 100262306a36Sopenharmony_ci ha->host_no, mbox_sts[0], mbox_sts[1], 100362306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3], mbox_sts[4], 100462306a36Sopenharmony_ci mbox_sts[5])); 100562306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 100662306a36Sopenharmony_ci "scsi%ld: AEN %04x Received DCBX configuration changed notification\n", 100762306a36Sopenharmony_ci ha->host_no, mbox_sts[0])); 100862306a36Sopenharmony_ci break; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci default: 101162306a36Sopenharmony_ci DEBUG2(printk(KERN_WARNING 101262306a36Sopenharmony_ci "scsi%ld: AEN %04x UNKNOWN\n", 101362306a36Sopenharmony_ci ha->host_no, mbox_sts[0])); 101462306a36Sopenharmony_ci break; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci } else { 101762306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n", 101862306a36Sopenharmony_ci ha->host_no, mbox_status)); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci ha->mbox_status[0] = mbox_status; 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci} 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_civoid qla4_83xx_interrupt_service_routine(struct scsi_qla_host *ha, 102562306a36Sopenharmony_ci uint32_t intr_status) 102662306a36Sopenharmony_ci{ 102762306a36Sopenharmony_ci /* Process mailbox/asynch event interrupt.*/ 102862306a36Sopenharmony_ci if (intr_status) { 102962306a36Sopenharmony_ci qla4xxx_isr_decode_mailbox(ha, 103062306a36Sopenharmony_ci readl(&ha->qla4_83xx_reg->mailbox_out[0])); 103162306a36Sopenharmony_ci /* clear the interrupt */ 103262306a36Sopenharmony_ci writel(0, &ha->qla4_83xx_reg->risc_intr); 103362306a36Sopenharmony_ci } else { 103462306a36Sopenharmony_ci qla4xxx_process_response_queue(ha); 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* clear the interrupt */ 103862306a36Sopenharmony_ci writel(0, &ha->qla4_83xx_reg->mb_int_mask); 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci/** 104262306a36Sopenharmony_ci * qla4_82xx_interrupt_service_routine - isr 104362306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 104462306a36Sopenharmony_ci * @intr_status: Local interrupt status/type. 104562306a36Sopenharmony_ci * 104662306a36Sopenharmony_ci * This is the main interrupt service routine. 104762306a36Sopenharmony_ci * hardware_lock locked upon entry. runs in interrupt context. 104862306a36Sopenharmony_ci **/ 104962306a36Sopenharmony_civoid qla4_82xx_interrupt_service_routine(struct scsi_qla_host *ha, 105062306a36Sopenharmony_ci uint32_t intr_status) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci /* Process response queue interrupt. */ 105362306a36Sopenharmony_ci if ((intr_status & HSRX_RISC_IOCB_INT) && 105462306a36Sopenharmony_ci test_bit(AF_INIT_DONE, &ha->flags)) 105562306a36Sopenharmony_ci qla4xxx_process_response_queue(ha); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci /* Process mailbox/asynch event interrupt.*/ 105862306a36Sopenharmony_ci if (intr_status & HSRX_RISC_MB_INT) 105962306a36Sopenharmony_ci qla4xxx_isr_decode_mailbox(ha, 106062306a36Sopenharmony_ci readl(&ha->qla4_82xx_reg->mailbox_out[0])); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci /* clear the interrupt */ 106362306a36Sopenharmony_ci writel(0, &ha->qla4_82xx_reg->host_int); 106462306a36Sopenharmony_ci readl(&ha->qla4_82xx_reg->host_int); 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci/** 106862306a36Sopenharmony_ci * qla4xxx_interrupt_service_routine - isr 106962306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 107062306a36Sopenharmony_ci * @intr_status: Local interrupt status/type. 107162306a36Sopenharmony_ci * 107262306a36Sopenharmony_ci * This is the main interrupt service routine. 107362306a36Sopenharmony_ci * hardware_lock locked upon entry. runs in interrupt context. 107462306a36Sopenharmony_ci **/ 107562306a36Sopenharmony_civoid qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, 107662306a36Sopenharmony_ci uint32_t intr_status) 107762306a36Sopenharmony_ci{ 107862306a36Sopenharmony_ci /* Process response queue interrupt. */ 107962306a36Sopenharmony_ci if (intr_status & CSR_SCSI_COMPLETION_INTR) 108062306a36Sopenharmony_ci qla4xxx_process_response_queue(ha); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci /* Process mailbox/asynch event interrupt.*/ 108362306a36Sopenharmony_ci if (intr_status & CSR_SCSI_PROCESSOR_INTR) { 108462306a36Sopenharmony_ci qla4xxx_isr_decode_mailbox(ha, 108562306a36Sopenharmony_ci readl(&ha->reg->mailbox[0])); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci /* Clear Mailbox Interrupt */ 108862306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), 108962306a36Sopenharmony_ci &ha->reg->ctrl_status); 109062306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci/** 109562306a36Sopenharmony_ci * qla4_82xx_spurious_interrupt - processes spurious interrupt 109662306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 109762306a36Sopenharmony_ci * @reqs_count: . 109862306a36Sopenharmony_ci * 109962306a36Sopenharmony_ci **/ 110062306a36Sopenharmony_cistatic void qla4_82xx_spurious_interrupt(struct scsi_qla_host *ha, 110162306a36Sopenharmony_ci uint8_t reqs_count) 110262306a36Sopenharmony_ci{ 110362306a36Sopenharmony_ci if (reqs_count) 110462306a36Sopenharmony_ci return; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "Spurious Interrupt\n")); 110762306a36Sopenharmony_ci if (is_qla8022(ha)) { 110862306a36Sopenharmony_ci writel(0, &ha->qla4_82xx_reg->host_int); 110962306a36Sopenharmony_ci if (!ha->pdev->msi_enabled && !ha->pdev->msix_enabled) 111062306a36Sopenharmony_ci qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 111162306a36Sopenharmony_ci 0xfbff); 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci ha->spurious_int_count++; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci/** 111762306a36Sopenharmony_ci * qla4xxx_intr_handler - hardware interrupt handler. 111862306a36Sopenharmony_ci * @irq: Unused 111962306a36Sopenharmony_ci * @dev_id: Pointer to host adapter structure 112062306a36Sopenharmony_ci **/ 112162306a36Sopenharmony_ciirqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) 112262306a36Sopenharmony_ci{ 112362306a36Sopenharmony_ci struct scsi_qla_host *ha; 112462306a36Sopenharmony_ci uint32_t intr_status; 112562306a36Sopenharmony_ci unsigned long flags = 0; 112662306a36Sopenharmony_ci uint8_t reqs_count = 0; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci ha = (struct scsi_qla_host *) dev_id; 112962306a36Sopenharmony_ci if (!ha) { 113062306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO 113162306a36Sopenharmony_ci "qla4xxx: Interrupt with NULL host ptr\n")); 113262306a36Sopenharmony_ci return IRQ_NONE; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci ha->isr_count++; 113862306a36Sopenharmony_ci /* 113962306a36Sopenharmony_ci * Repeatedly service interrupts up to a maximum of 114062306a36Sopenharmony_ci * MAX_REQS_SERVICED_PER_INTR 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_ci while (1) { 114362306a36Sopenharmony_ci /* 114462306a36Sopenharmony_ci * Read interrupt status 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_ci if (ha->isp_ops->rd_shdw_rsp_q_in(ha) != 114762306a36Sopenharmony_ci ha->response_out) 114862306a36Sopenharmony_ci intr_status = CSR_SCSI_COMPLETION_INTR; 114962306a36Sopenharmony_ci else 115062306a36Sopenharmony_ci intr_status = readl(&ha->reg->ctrl_status); 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci if ((intr_status & 115362306a36Sopenharmony_ci (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == 0) { 115462306a36Sopenharmony_ci if (reqs_count == 0) 115562306a36Sopenharmony_ci ha->spurious_int_count++; 115662306a36Sopenharmony_ci break; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci if (intr_status & CSR_FATAL_ERROR) { 116062306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, " 116162306a36Sopenharmony_ci "Status 0x%04x\n", ha->host_no, 116262306a36Sopenharmony_ci readl(isp_port_error_status (ha)))); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci /* Issue Soft Reset to clear this error condition. 116562306a36Sopenharmony_ci * This will prevent the RISC from repeatedly 116662306a36Sopenharmony_ci * interrupting the driver; thus, allowing the DPC to 116762306a36Sopenharmony_ci * get scheduled to continue error recovery. 116862306a36Sopenharmony_ci * NOTE: Disabling RISC interrupts does not work in 116962306a36Sopenharmony_ci * this case, as CSR_FATAL_ERROR overrides 117062306a36Sopenharmony_ci * CSR_SCSI_INTR_ENABLE */ 117162306a36Sopenharmony_ci if ((readl(&ha->reg->ctrl_status) & 117262306a36Sopenharmony_ci CSR_SCSI_RESET_INTR) == 0) { 117362306a36Sopenharmony_ci writel(set_rmask(CSR_SOFT_RESET), 117462306a36Sopenharmony_ci &ha->reg->ctrl_status); 117562306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci writel(set_rmask(CSR_FATAL_ERROR), 117962306a36Sopenharmony_ci &ha->reg->ctrl_status); 118062306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci __qla4xxx_disable_intrs(ha); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci set_bit(DPC_RESET_HA, &ha->dpc_flags); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci break; 118762306a36Sopenharmony_ci } else if (intr_status & CSR_SCSI_RESET_INTR) { 118862306a36Sopenharmony_ci clear_bit(AF_ONLINE, &ha->flags); 118962306a36Sopenharmony_ci __qla4xxx_disable_intrs(ha); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci writel(set_rmask(CSR_SCSI_RESET_INTR), 119262306a36Sopenharmony_ci &ha->reg->ctrl_status); 119362306a36Sopenharmony_ci readl(&ha->reg->ctrl_status); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci if (!test_bit(AF_HA_REMOVAL, &ha->flags)) 119662306a36Sopenharmony_ci set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci break; 119962306a36Sopenharmony_ci } else if (intr_status & INTR_PENDING) { 120062306a36Sopenharmony_ci ha->isp_ops->interrupt_service_routine(ha, intr_status); 120162306a36Sopenharmony_ci ha->total_io_count++; 120262306a36Sopenharmony_ci if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) 120362306a36Sopenharmony_ci break; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci return IRQ_HANDLED; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci/** 121362306a36Sopenharmony_ci * qla4_82xx_intr_handler - hardware interrupt handler. 121462306a36Sopenharmony_ci * @irq: Unused 121562306a36Sopenharmony_ci * @dev_id: Pointer to host adapter structure 121662306a36Sopenharmony_ci **/ 121762306a36Sopenharmony_ciirqreturn_t qla4_82xx_intr_handler(int irq, void *dev_id) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci struct scsi_qla_host *ha = dev_id; 122062306a36Sopenharmony_ci uint32_t intr_status; 122162306a36Sopenharmony_ci uint32_t status; 122262306a36Sopenharmony_ci unsigned long flags = 0; 122362306a36Sopenharmony_ci uint8_t reqs_count = 0; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 122662306a36Sopenharmony_ci return IRQ_HANDLED; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci ha->isr_count++; 122962306a36Sopenharmony_ci status = qla4_82xx_rd_32(ha, ISR_INT_VECTOR); 123062306a36Sopenharmony_ci if (!(status & ha->nx_legacy_intr.int_vec_bit)) 123162306a36Sopenharmony_ci return IRQ_NONE; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci status = qla4_82xx_rd_32(ha, ISR_INT_STATE_REG); 123462306a36Sopenharmony_ci if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) { 123562306a36Sopenharmony_ci DEBUG7(ql4_printk(KERN_INFO, ha, 123662306a36Sopenharmony_ci "%s legacy Int not triggered\n", __func__)); 123762306a36Sopenharmony_ci return IRQ_NONE; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* clear the interrupt */ 124162306a36Sopenharmony_ci qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci /* read twice to ensure write is flushed */ 124462306a36Sopenharmony_ci qla4_82xx_rd_32(ha, ISR_INT_VECTOR); 124562306a36Sopenharmony_ci qla4_82xx_rd_32(ha, ISR_INT_VECTOR); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 124862306a36Sopenharmony_ci while (1) { 124962306a36Sopenharmony_ci if (!(readl(&ha->qla4_82xx_reg->host_int) & 125062306a36Sopenharmony_ci ISRX_82XX_RISC_INT)) { 125162306a36Sopenharmony_ci qla4_82xx_spurious_interrupt(ha, reqs_count); 125262306a36Sopenharmony_ci break; 125362306a36Sopenharmony_ci } 125462306a36Sopenharmony_ci intr_status = readl(&ha->qla4_82xx_reg->host_status); 125562306a36Sopenharmony_ci if ((intr_status & 125662306a36Sopenharmony_ci (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { 125762306a36Sopenharmony_ci qla4_82xx_spurious_interrupt(ha, reqs_count); 125862306a36Sopenharmony_ci break; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci ha->isp_ops->interrupt_service_routine(ha, intr_status); 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci /* Enable Interrupt */ 126462306a36Sopenharmony_ci qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) 126762306a36Sopenharmony_ci break; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 127162306a36Sopenharmony_ci return IRQ_HANDLED; 127262306a36Sopenharmony_ci} 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci#define LEG_INT_PTR_B31 (1 << 31) 127562306a36Sopenharmony_ci#define LEG_INT_PTR_B30 (1 << 30) 127662306a36Sopenharmony_ci#define PF_BITS_MASK (0xF << 16) 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci/** 127962306a36Sopenharmony_ci * qla4_83xx_intr_handler - hardware interrupt handler. 128062306a36Sopenharmony_ci * @irq: Unused 128162306a36Sopenharmony_ci * @dev_id: Pointer to host adapter structure 128262306a36Sopenharmony_ci **/ 128362306a36Sopenharmony_ciirqreturn_t qla4_83xx_intr_handler(int irq, void *dev_id) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct scsi_qla_host *ha = dev_id; 128662306a36Sopenharmony_ci uint32_t leg_int_ptr = 0; 128762306a36Sopenharmony_ci unsigned long flags = 0; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci ha->isr_count++; 129062306a36Sopenharmony_ci leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr); 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* Legacy interrupt is valid if bit31 of leg_int_ptr is set */ 129362306a36Sopenharmony_ci if (!(leg_int_ptr & LEG_INT_PTR_B31)) { 129462306a36Sopenharmony_ci DEBUG7(ql4_printk(KERN_ERR, ha, 129562306a36Sopenharmony_ci "%s: Legacy Interrupt Bit 31 not set, spurious interrupt!\n", 129662306a36Sopenharmony_ci __func__)); 129762306a36Sopenharmony_ci return IRQ_NONE; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */ 130162306a36Sopenharmony_ci if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) { 130262306a36Sopenharmony_ci DEBUG7(ql4_printk(KERN_ERR, ha, 130362306a36Sopenharmony_ci "%s: Incorrect function ID 0x%x in legacy interrupt register, ha->pf_bit = 0x%x\n", 130462306a36Sopenharmony_ci __func__, (leg_int_ptr & PF_BITS_MASK), 130562306a36Sopenharmony_ci ha->pf_bit)); 130662306a36Sopenharmony_ci return IRQ_NONE; 130762306a36Sopenharmony_ci } 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci /* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger 131062306a36Sopenharmony_ci * Control register and poll till Legacy Interrupt Pointer register 131162306a36Sopenharmony_ci * bit30 is 0. 131262306a36Sopenharmony_ci */ 131362306a36Sopenharmony_ci writel(0, &ha->qla4_83xx_reg->leg_int_trig); 131462306a36Sopenharmony_ci do { 131562306a36Sopenharmony_ci leg_int_ptr = readl(&ha->qla4_83xx_reg->leg_int_ptr); 131662306a36Sopenharmony_ci if ((leg_int_ptr & PF_BITS_MASK) != ha->pf_bit) 131762306a36Sopenharmony_ci break; 131862306a36Sopenharmony_ci } while (leg_int_ptr & LEG_INT_PTR_B30); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 132162306a36Sopenharmony_ci leg_int_ptr = readl(&ha->qla4_83xx_reg->risc_intr); 132262306a36Sopenharmony_ci ha->isp_ops->interrupt_service_routine(ha, leg_int_ptr); 132362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci return IRQ_HANDLED; 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ciirqreturn_t 132962306a36Sopenharmony_ciqla4_8xxx_msi_handler(int irq, void *dev_id) 133062306a36Sopenharmony_ci{ 133162306a36Sopenharmony_ci struct scsi_qla_host *ha; 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci ha = (struct scsi_qla_host *) dev_id; 133462306a36Sopenharmony_ci if (!ha) { 133562306a36Sopenharmony_ci DEBUG2(printk(KERN_INFO 133662306a36Sopenharmony_ci "qla4xxx: MSIX: Interrupt with NULL host ptr\n")); 133762306a36Sopenharmony_ci return IRQ_NONE; 133862306a36Sopenharmony_ci } 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci ha->isr_count++; 134162306a36Sopenharmony_ci /* clear the interrupt */ 134262306a36Sopenharmony_ci qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci /* read twice to ensure write is flushed */ 134562306a36Sopenharmony_ci qla4_82xx_rd_32(ha, ISR_INT_VECTOR); 134662306a36Sopenharmony_ci qla4_82xx_rd_32(ha, ISR_INT_VECTOR); 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci return qla4_8xxx_default_intr_handler(irq, dev_id); 134962306a36Sopenharmony_ci} 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_cistatic irqreturn_t qla4_83xx_mailbox_intr_handler(int irq, void *dev_id) 135262306a36Sopenharmony_ci{ 135362306a36Sopenharmony_ci struct scsi_qla_host *ha = dev_id; 135462306a36Sopenharmony_ci unsigned long flags; 135562306a36Sopenharmony_ci uint32_t ival = 0; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 135862306a36Sopenharmony_ci 135962306a36Sopenharmony_ci ival = readl(&ha->qla4_83xx_reg->risc_intr); 136062306a36Sopenharmony_ci if (ival == 0) { 136162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, 136262306a36Sopenharmony_ci "%s: It is a spurious mailbox interrupt!\n", 136362306a36Sopenharmony_ci __func__); 136462306a36Sopenharmony_ci ival = readl(&ha->qla4_83xx_reg->mb_int_mask); 136562306a36Sopenharmony_ci ival &= ~INT_MASK_FW_MB; 136662306a36Sopenharmony_ci writel(ival, &ha->qla4_83xx_reg->mb_int_mask); 136762306a36Sopenharmony_ci goto exit; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci qla4xxx_isr_decode_mailbox(ha, 137162306a36Sopenharmony_ci readl(&ha->qla4_83xx_reg->mailbox_out[0])); 137262306a36Sopenharmony_ci writel(0, &ha->qla4_83xx_reg->risc_intr); 137362306a36Sopenharmony_ci ival = readl(&ha->qla4_83xx_reg->mb_int_mask); 137462306a36Sopenharmony_ci ival &= ~INT_MASK_FW_MB; 137562306a36Sopenharmony_ci writel(ival, &ha->qla4_83xx_reg->mb_int_mask); 137662306a36Sopenharmony_ci ha->isr_count++; 137762306a36Sopenharmony_ciexit: 137862306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 137962306a36Sopenharmony_ci return IRQ_HANDLED; 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci/** 138362306a36Sopenharmony_ci * qla4_8xxx_default_intr_handler - hardware interrupt handler. 138462306a36Sopenharmony_ci * @irq: Unused 138562306a36Sopenharmony_ci * @dev_id: Pointer to host adapter structure 138662306a36Sopenharmony_ci * 138762306a36Sopenharmony_ci * This interrupt handler is called directly for MSI-X, and 138862306a36Sopenharmony_ci * called indirectly for MSI. 138962306a36Sopenharmony_ci **/ 139062306a36Sopenharmony_ciirqreturn_t 139162306a36Sopenharmony_ciqla4_8xxx_default_intr_handler(int irq, void *dev_id) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci struct scsi_qla_host *ha = dev_id; 139462306a36Sopenharmony_ci unsigned long flags; 139562306a36Sopenharmony_ci uint32_t intr_status; 139662306a36Sopenharmony_ci uint8_t reqs_count = 0; 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 139962306a36Sopenharmony_ci qla4_83xx_mailbox_intr_handler(irq, dev_id); 140062306a36Sopenharmony_ci } else { 140162306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 140262306a36Sopenharmony_ci while (1) { 140362306a36Sopenharmony_ci if (!(readl(&ha->qla4_82xx_reg->host_int) & 140462306a36Sopenharmony_ci ISRX_82XX_RISC_INT)) { 140562306a36Sopenharmony_ci qla4_82xx_spurious_interrupt(ha, reqs_count); 140662306a36Sopenharmony_ci break; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci intr_status = readl(&ha->qla4_82xx_reg->host_status); 141062306a36Sopenharmony_ci if ((intr_status & 141162306a36Sopenharmony_ci (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { 141262306a36Sopenharmony_ci qla4_82xx_spurious_interrupt(ha, reqs_count); 141362306a36Sopenharmony_ci break; 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci ha->isp_ops->interrupt_service_routine(ha, intr_status); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) 141962306a36Sopenharmony_ci break; 142062306a36Sopenharmony_ci } 142162306a36Sopenharmony_ci ha->isr_count++; 142262306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci return IRQ_HANDLED; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ciirqreturn_t 142862306a36Sopenharmony_ciqla4_8xxx_msix_rsp_q(int irq, void *dev_id) 142962306a36Sopenharmony_ci{ 143062306a36Sopenharmony_ci struct scsi_qla_host *ha = dev_id; 143162306a36Sopenharmony_ci unsigned long flags; 143262306a36Sopenharmony_ci int intr_status; 143362306a36Sopenharmony_ci uint32_t ival = 0; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 143662306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 143762306a36Sopenharmony_ci ival = readl(&ha->qla4_83xx_reg->iocb_int_mask); 143862306a36Sopenharmony_ci if (ival == 0) { 143962306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: It is a spurious iocb interrupt!\n", 144062306a36Sopenharmony_ci __func__); 144162306a36Sopenharmony_ci goto exit_msix_rsp_q; 144262306a36Sopenharmony_ci } 144362306a36Sopenharmony_ci qla4xxx_process_response_queue(ha); 144462306a36Sopenharmony_ci writel(0, &ha->qla4_83xx_reg->iocb_int_mask); 144562306a36Sopenharmony_ci } else { 144662306a36Sopenharmony_ci intr_status = readl(&ha->qla4_82xx_reg->host_status); 144762306a36Sopenharmony_ci if (intr_status & HSRX_RISC_IOCB_INT) { 144862306a36Sopenharmony_ci qla4xxx_process_response_queue(ha); 144962306a36Sopenharmony_ci writel(0, &ha->qla4_82xx_reg->host_int); 145062306a36Sopenharmony_ci } else { 145162306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: spurious iocb interrupt...\n", 145262306a36Sopenharmony_ci __func__); 145362306a36Sopenharmony_ci goto exit_msix_rsp_q; 145462306a36Sopenharmony_ci } 145562306a36Sopenharmony_ci } 145662306a36Sopenharmony_ci ha->isr_count++; 145762306a36Sopenharmony_ciexit_msix_rsp_q: 145862306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 145962306a36Sopenharmony_ci return IRQ_HANDLED; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci/** 146362306a36Sopenharmony_ci * qla4xxx_process_aen - processes AENs generated by firmware 146462306a36Sopenharmony_ci * @ha: pointer to host adapter structure. 146562306a36Sopenharmony_ci * @process_aen: type of AENs to process 146662306a36Sopenharmony_ci * 146762306a36Sopenharmony_ci * Processes specific types of Asynchronous Events generated by firmware. 146862306a36Sopenharmony_ci * The type of AENs to process is specified by process_aen and can be 146962306a36Sopenharmony_ci * PROCESS_ALL_AENS 0 147062306a36Sopenharmony_ci * FLUSH_DDB_CHANGED_AENS 1 147162306a36Sopenharmony_ci * RELOGIN_DDB_CHANGED_AENS 2 147262306a36Sopenharmony_ci **/ 147362306a36Sopenharmony_civoid qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; 147662306a36Sopenharmony_ci struct aen *aen; 147762306a36Sopenharmony_ci int i; 147862306a36Sopenharmony_ci unsigned long flags; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 148162306a36Sopenharmony_ci while (ha->aen_out != ha->aen_in) { 148262306a36Sopenharmony_ci aen = &ha->aen_q[ha->aen_out]; 148362306a36Sopenharmony_ci /* copy aen information to local structure */ 148462306a36Sopenharmony_ci for (i = 0; i < MBOX_AEN_REG_COUNT; i++) 148562306a36Sopenharmony_ci mbox_sts[i] = aen->mbox_sts[i]; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci ha->aen_q_count++; 148862306a36Sopenharmony_ci ha->aen_out++; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci if (ha->aen_out == MAX_AEN_ENTRIES) 149162306a36Sopenharmony_ci ha->aen_out = 0; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x" 149662306a36Sopenharmony_ci " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no, 149762306a36Sopenharmony_ci (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)), 149862306a36Sopenharmony_ci mbox_sts[0], mbox_sts[1], mbox_sts[2], 149962306a36Sopenharmony_ci mbox_sts[3], mbox_sts[4])); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci switch (mbox_sts[0]) { 150262306a36Sopenharmony_ci case MBOX_ASTS_DATABASE_CHANGED: 150362306a36Sopenharmony_ci switch (process_aen) { 150462306a36Sopenharmony_ci case FLUSH_DDB_CHANGED_AENS: 150562306a36Sopenharmony_ci DEBUG2(printk("scsi%ld: AEN[%d] %04x, index " 150662306a36Sopenharmony_ci "[%d] state=%04x FLUSHED!\n", 150762306a36Sopenharmony_ci ha->host_no, ha->aen_out, 150862306a36Sopenharmony_ci mbox_sts[0], mbox_sts[2], 150962306a36Sopenharmony_ci mbox_sts[3])); 151062306a36Sopenharmony_ci break; 151162306a36Sopenharmony_ci case PROCESS_ALL_AENS: 151262306a36Sopenharmony_ci default: 151362306a36Sopenharmony_ci /* Specific device. */ 151462306a36Sopenharmony_ci if (mbox_sts[1] == 1) 151562306a36Sopenharmony_ci qla4xxx_process_ddb_changed(ha, 151662306a36Sopenharmony_ci mbox_sts[2], mbox_sts[3], 151762306a36Sopenharmony_ci mbox_sts[4]); 151862306a36Sopenharmony_ci break; 151962306a36Sopenharmony_ci } 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 152462306a36Sopenharmony_ci} 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ciint qla4xxx_request_irqs(struct scsi_qla_host *ha) 152762306a36Sopenharmony_ci{ 152862306a36Sopenharmony_ci int ret = 0; 152962306a36Sopenharmony_ci int rval = QLA_ERROR; 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (is_qla40XX(ha)) 153262306a36Sopenharmony_ci goto try_intx; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci if (ql4xenablemsix == 2) { 153562306a36Sopenharmony_ci /* Note: MSI Interrupts not supported for ISP8324 and ISP8042 */ 153662306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 153762306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: MSI Interrupts not supported for ISP%04x, Falling back-to INTx mode\n", 153862306a36Sopenharmony_ci __func__, ha->pdev->device); 153962306a36Sopenharmony_ci goto try_intx; 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci goto try_msi; 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci if (ql4xenablemsix == 0 || ql4xenablemsix != 1) 154562306a36Sopenharmony_ci goto try_intx; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci /* Trying MSI-X */ 154862306a36Sopenharmony_ci ret = qla4_8xxx_enable_msix(ha); 154962306a36Sopenharmony_ci if (!ret) { 155062306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, 155162306a36Sopenharmony_ci "MSI-X: Enabled (0x%X).\n", ha->revision_id)); 155262306a36Sopenharmony_ci goto irq_attached; 155362306a36Sopenharmony_ci } else { 155462306a36Sopenharmony_ci if (is_qla8032(ha) || is_qla8042(ha)) { 155562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: ISP%04x: MSI-X: Falling back-to INTx mode. ret = %d\n", 155662306a36Sopenharmony_ci __func__, ha->pdev->device, ret); 155762306a36Sopenharmony_ci goto try_intx; 155862306a36Sopenharmony_ci } 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 156262306a36Sopenharmony_ci "MSI-X: Falling back-to MSI mode -- %d.\n", ret); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_citry_msi: 156562306a36Sopenharmony_ci /* Trying MSI */ 156662306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI); 156762306a36Sopenharmony_ci if (ret > 0) { 156862306a36Sopenharmony_ci ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler, 156962306a36Sopenharmony_ci 0, DRIVER_NAME, ha); 157062306a36Sopenharmony_ci if (!ret) { 157162306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n")); 157262306a36Sopenharmony_ci goto irq_attached; 157362306a36Sopenharmony_ci } else { 157462306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 157562306a36Sopenharmony_ci "MSI: Failed to reserve interrupt %d " 157662306a36Sopenharmony_ci "already in use.\n", ha->pdev->irq); 157762306a36Sopenharmony_ci pci_free_irq_vectors(ha->pdev); 157862306a36Sopenharmony_ci } 157962306a36Sopenharmony_ci } 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_citry_intx: 158262306a36Sopenharmony_ci if (is_qla8022(ha)) { 158362306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, "%s: ISP82xx Legacy interrupt not supported\n", 158462306a36Sopenharmony_ci __func__); 158562306a36Sopenharmony_ci goto irq_not_attached; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci /* Trying INTx */ 158962306a36Sopenharmony_ci ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, 159062306a36Sopenharmony_ci IRQF_SHARED, DRIVER_NAME, ha); 159162306a36Sopenharmony_ci if (!ret) { 159262306a36Sopenharmony_ci DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n")); 159362306a36Sopenharmony_ci goto irq_attached; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci } else { 159662306a36Sopenharmony_ci ql4_printk(KERN_WARNING, ha, 159762306a36Sopenharmony_ci "INTx: Failed to reserve interrupt %d already in" 159862306a36Sopenharmony_ci " use.\n", ha->pdev->irq); 159962306a36Sopenharmony_ci goto irq_not_attached; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ciirq_attached: 160362306a36Sopenharmony_ci set_bit(AF_IRQ_ATTACHED, &ha->flags); 160462306a36Sopenharmony_ci ha->host->irq = ha->pdev->irq; 160562306a36Sopenharmony_ci ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n", 160662306a36Sopenharmony_ci __func__, ha->pdev->irq); 160762306a36Sopenharmony_ci rval = QLA_SUCCESS; 160862306a36Sopenharmony_ciirq_not_attached: 160962306a36Sopenharmony_ci return rval; 161062306a36Sopenharmony_ci} 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_civoid qla4xxx_free_irqs(struct scsi_qla_host *ha) 161362306a36Sopenharmony_ci{ 161462306a36Sopenharmony_ci if (!test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) 161562306a36Sopenharmony_ci return; 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci if (ha->pdev->msix_enabled) 161862306a36Sopenharmony_ci free_irq(pci_irq_vector(ha->pdev, 1), ha); 161962306a36Sopenharmony_ci free_irq(pci_irq_vector(ha->pdev, 0), ha); 162062306a36Sopenharmony_ci pci_free_irq_vectors(ha->pdev); 162162306a36Sopenharmony_ci} 1622