162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "qla_def.h" 762306a36Sopenharmony_ci#include "qla_target.h" 862306a36Sopenharmony_ci#include "qla_gbl.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/cpu.h> 1362306a36Sopenharmony_ci#include <linux/t10-pi.h> 1462306a36Sopenharmony_ci#include <scsi/scsi_tcq.h> 1562306a36Sopenharmony_ci#include <scsi/scsi_bsg_fc.h> 1662306a36Sopenharmony_ci#include <scsi/scsi_eh.h> 1762306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h> 1862306a36Sopenharmony_ci#include <linux/nvme-fc-driver.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); 2162306a36Sopenharmony_cistatic void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *); 2262306a36Sopenharmony_cistatic void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *); 2362306a36Sopenharmony_cistatic int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, 2462306a36Sopenharmony_ci sts_entry_t *); 2562306a36Sopenharmony_cistatic void qla27xx_process_purex_fpin(struct scsi_qla_host *vha, 2662306a36Sopenharmony_ci struct purex_item *item); 2762306a36Sopenharmony_cistatic struct purex_item *qla24xx_alloc_purex_item(scsi_qla_host_t *vha, 2862306a36Sopenharmony_ci uint16_t size); 2962306a36Sopenharmony_cistatic struct purex_item *qla24xx_copy_std_pkt(struct scsi_qla_host *vha, 3062306a36Sopenharmony_ci void *pkt); 3162306a36Sopenharmony_cistatic struct purex_item *qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, 3262306a36Sopenharmony_ci void **pkt, struct rsp_que **rsp); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_cistatic void 3562306a36Sopenharmony_ciqla27xx_process_purex_fpin(struct scsi_qla_host *vha, struct purex_item *item) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci void *pkt = &item->iocb; 3862306a36Sopenharmony_ci uint16_t pkt_size = item->size; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508d, 4162306a36Sopenharmony_ci "%s: Enter\n", __func__); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508e, 4462306a36Sopenharmony_ci "-------- ELS REQ -------\n"); 4562306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x508f, 4662306a36Sopenharmony_ci pkt, pkt_size); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci fc_host_fpin_rcv(vha->host, pkt_size, (char *)pkt, 0); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciconst char *const port_state_str[] = { 5262306a36Sopenharmony_ci [FCS_UNKNOWN] = "Unknown", 5362306a36Sopenharmony_ci [FCS_UNCONFIGURED] = "UNCONFIGURED", 5462306a36Sopenharmony_ci [FCS_DEVICE_DEAD] = "DEAD", 5562306a36Sopenharmony_ci [FCS_DEVICE_LOST] = "LOST", 5662306a36Sopenharmony_ci [FCS_ONLINE] = "ONLINE" 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci#define SFP_DISABLE_LASER_INITIATED 0x15 /* Sub code of 8070 AEN */ 6062306a36Sopenharmony_ci#define SFP_ENABLE_LASER_INITIATED 0x16 /* Sub code of 8070 AEN */ 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic inline void display_Laser_info(scsi_qla_host_t *vha, 6362306a36Sopenharmony_ci u16 mb1, u16 mb2, u16 mb3) { 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (mb1 == SFP_DISABLE_LASER_INITIATED) 6662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xf0a2, 6762306a36Sopenharmony_ci "SFP temperature (%d C) reached/exceeded the threshold (%d C). Laser is disabled.\n", 6862306a36Sopenharmony_ci mb3, mb2); 6962306a36Sopenharmony_ci if (mb1 == SFP_ENABLE_LASER_INITIATED) 7062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xf0a3, 7162306a36Sopenharmony_ci "SFP temperature (%d C) reached normal operating level. Laser is enabled.\n", 7262306a36Sopenharmony_ci mb3); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void 7662306a36Sopenharmony_ciqla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct abts_entry_24xx *abts = 7962306a36Sopenharmony_ci (struct abts_entry_24xx *)&pkt->iocb; 8062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 8162306a36Sopenharmony_ci struct els_entry_24xx *rsp_els; 8262306a36Sopenharmony_ci struct abts_entry_24xx *abts_rsp; 8362306a36Sopenharmony_ci dma_addr_t dma; 8462306a36Sopenharmony_ci uint32_t fctl; 8562306a36Sopenharmony_ci int rval; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0287, 9062306a36Sopenharmony_ci "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n", 9162306a36Sopenharmony_ci abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id, 9262306a36Sopenharmony_ci abts->seq_id, abts->seq_cnt); 9362306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287, 9462306a36Sopenharmony_ci "-------- ABTS RCV -------\n"); 9562306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287, 9662306a36Sopenharmony_ci (uint8_t *)abts, sizeof(*abts)); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma, 9962306a36Sopenharmony_ci GFP_KERNEL); 10062306a36Sopenharmony_ci if (!rsp_els) { 10162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0287, 10262306a36Sopenharmony_ci "Failed allocate dma buffer ABTS/ELS RSP.\n"); 10362306a36Sopenharmony_ci return; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* terminate exchange */ 10762306a36Sopenharmony_ci rsp_els->entry_type = ELS_IOCB_TYPE; 10862306a36Sopenharmony_ci rsp_els->entry_count = 1; 10962306a36Sopenharmony_ci rsp_els->nport_handle = cpu_to_le16(~0); 11062306a36Sopenharmony_ci rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort; 11162306a36Sopenharmony_ci rsp_els->control_flags = cpu_to_le16(EPD_RX_XCHG); 11262306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0283, 11362306a36Sopenharmony_ci "Sending ELS Response to terminate exchange %#x...\n", 11462306a36Sopenharmony_ci abts->rx_xch_addr_to_abort); 11562306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283, 11662306a36Sopenharmony_ci "-------- ELS RSP -------\n"); 11762306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283, 11862306a36Sopenharmony_ci (uint8_t *)rsp_els, sizeof(*rsp_els)); 11962306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0); 12062306a36Sopenharmony_ci if (rval) { 12162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0288, 12262306a36Sopenharmony_ci "%s: iocb failed to execute -> %x\n", __func__, rval); 12362306a36Sopenharmony_ci } else if (rsp_els->comp_status) { 12462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0289, 12562306a36Sopenharmony_ci "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", 12662306a36Sopenharmony_ci __func__, rsp_els->comp_status, 12762306a36Sopenharmony_ci rsp_els->error_subcode_1, rsp_els->error_subcode_2); 12862306a36Sopenharmony_ci } else { 12962306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x028a, 13062306a36Sopenharmony_ci "%s: abort exchange done.\n", __func__); 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* send ABTS response */ 13462306a36Sopenharmony_ci abts_rsp = (void *)rsp_els; 13562306a36Sopenharmony_ci memset(abts_rsp, 0, sizeof(*abts_rsp)); 13662306a36Sopenharmony_ci abts_rsp->entry_type = ABTS_RSP_TYPE; 13762306a36Sopenharmony_ci abts_rsp->entry_count = 1; 13862306a36Sopenharmony_ci abts_rsp->nport_handle = abts->nport_handle; 13962306a36Sopenharmony_ci abts_rsp->vp_idx = abts->vp_idx; 14062306a36Sopenharmony_ci abts_rsp->sof_type = abts->sof_type & 0xf0; 14162306a36Sopenharmony_ci abts_rsp->rx_xch_addr = abts->rx_xch_addr; 14262306a36Sopenharmony_ci abts_rsp->d_id[0] = abts->s_id[0]; 14362306a36Sopenharmony_ci abts_rsp->d_id[1] = abts->s_id[1]; 14462306a36Sopenharmony_ci abts_rsp->d_id[2] = abts->s_id[2]; 14562306a36Sopenharmony_ci abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC; 14662306a36Sopenharmony_ci abts_rsp->s_id[0] = abts->d_id[0]; 14762306a36Sopenharmony_ci abts_rsp->s_id[1] = abts->d_id[1]; 14862306a36Sopenharmony_ci abts_rsp->s_id[2] = abts->d_id[2]; 14962306a36Sopenharmony_ci abts_rsp->cs_ctl = abts->cs_ctl; 15062306a36Sopenharmony_ci /* include flipping bit23 in fctl */ 15162306a36Sopenharmony_ci fctl = ~(abts->f_ctl[2] | 0x7F) << 16 | 15262306a36Sopenharmony_ci FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT; 15362306a36Sopenharmony_ci abts_rsp->f_ctl[0] = fctl >> 0 & 0xff; 15462306a36Sopenharmony_ci abts_rsp->f_ctl[1] = fctl >> 8 & 0xff; 15562306a36Sopenharmony_ci abts_rsp->f_ctl[2] = fctl >> 16 & 0xff; 15662306a36Sopenharmony_ci abts_rsp->type = FC_TYPE_BLD; 15762306a36Sopenharmony_ci abts_rsp->rx_id = abts->rx_id; 15862306a36Sopenharmony_ci abts_rsp->ox_id = abts->ox_id; 15962306a36Sopenharmony_ci abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id; 16062306a36Sopenharmony_ci abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id; 16162306a36Sopenharmony_ci abts_rsp->payload.ba_acc.high_seq_cnt = cpu_to_le16(~0); 16262306a36Sopenharmony_ci abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort; 16362306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x028b, 16462306a36Sopenharmony_ci "Sending BA ACC response to ABTS %#x...\n", 16562306a36Sopenharmony_ci abts->rx_xch_addr_to_abort); 16662306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b, 16762306a36Sopenharmony_ci "-------- ELS RSP -------\n"); 16862306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b, 16962306a36Sopenharmony_ci (uint8_t *)abts_rsp, sizeof(*abts_rsp)); 17062306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0); 17162306a36Sopenharmony_ci if (rval) { 17262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x028c, 17362306a36Sopenharmony_ci "%s: iocb failed to execute -> %x\n", __func__, rval); 17462306a36Sopenharmony_ci } else if (abts_rsp->comp_status) { 17562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x028d, 17662306a36Sopenharmony_ci "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n", 17762306a36Sopenharmony_ci __func__, abts_rsp->comp_status, 17862306a36Sopenharmony_ci abts_rsp->payload.error.subcode1, 17962306a36Sopenharmony_ci abts_rsp->payload.error.subcode2); 18062306a36Sopenharmony_ci } else { 18162306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x028ea, 18262306a36Sopenharmony_ci "%s: done.\n", __func__); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * __qla_consume_iocb - this routine is used to tell fw driver has processed 19062306a36Sopenharmony_ci * or consumed the head IOCB along with the continuation IOCB's from the 19162306a36Sopenharmony_ci * provided respond queue. 19262306a36Sopenharmony_ci * @vha: host adapter pointer 19362306a36Sopenharmony_ci * @pkt: pointer to current packet. On return, this pointer shall move 19462306a36Sopenharmony_ci * to the next packet. 19562306a36Sopenharmony_ci * @rsp: respond queue pointer. 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * it is assumed pkt is the head iocb, not the continuation iocbk 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_civoid __qla_consume_iocb(struct scsi_qla_host *vha, 20062306a36Sopenharmony_ci void **pkt, struct rsp_que **rsp) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci struct rsp_que *rsp_q = *rsp; 20362306a36Sopenharmony_ci response_t *new_pkt; 20462306a36Sopenharmony_ci uint16_t entry_count_remaining; 20562306a36Sopenharmony_ci struct purex_entry_24xx *purex = *pkt; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci entry_count_remaining = purex->entry_count; 20862306a36Sopenharmony_ci while (entry_count_remaining > 0) { 20962306a36Sopenharmony_ci new_pkt = rsp_q->ring_ptr; 21062306a36Sopenharmony_ci *pkt = new_pkt; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci rsp_q->ring_index++; 21362306a36Sopenharmony_ci if (rsp_q->ring_index == rsp_q->length) { 21462306a36Sopenharmony_ci rsp_q->ring_index = 0; 21562306a36Sopenharmony_ci rsp_q->ring_ptr = rsp_q->ring; 21662306a36Sopenharmony_ci } else { 21762306a36Sopenharmony_ci rsp_q->ring_ptr++; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci new_pkt->signature = RESPONSE_PROCESSED; 22162306a36Sopenharmony_ci /* flush signature */ 22262306a36Sopenharmony_ci wmb(); 22362306a36Sopenharmony_ci --entry_count_remaining; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/** 22862306a36Sopenharmony_ci * __qla_copy_purex_to_buffer - extract ELS payload from Purex IOCB 22962306a36Sopenharmony_ci * and save to provided buffer 23062306a36Sopenharmony_ci * @vha: host adapter pointer 23162306a36Sopenharmony_ci * @pkt: pointer Purex IOCB 23262306a36Sopenharmony_ci * @rsp: respond queue 23362306a36Sopenharmony_ci * @buf: extracted ELS payload copy here 23462306a36Sopenharmony_ci * @buf_len: buffer length 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ciint __qla_copy_purex_to_buffer(struct scsi_qla_host *vha, 23762306a36Sopenharmony_ci void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct purex_entry_24xx *purex = *pkt; 24062306a36Sopenharmony_ci struct rsp_que *rsp_q = *rsp; 24162306a36Sopenharmony_ci sts_cont_entry_t *new_pkt; 24262306a36Sopenharmony_ci uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0; 24362306a36Sopenharmony_ci uint16_t buffer_copy_offset = 0; 24462306a36Sopenharmony_ci uint16_t entry_count_remaining; 24562306a36Sopenharmony_ci u16 tpad; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci entry_count_remaining = purex->entry_count; 24862306a36Sopenharmony_ci total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) 24962306a36Sopenharmony_ci - PURX_ELS_HEADER_SIZE; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* 25262306a36Sopenharmony_ci * end of payload may not end in 4bytes boundary. Need to 25362306a36Sopenharmony_ci * round up / pad for room to swap, before saving data 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci tpad = roundup(total_bytes, 4); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (buf_len < tpad) { 25862306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5084, 25962306a36Sopenharmony_ci "%s buffer is too small %d < %d\n", 26062306a36Sopenharmony_ci __func__, buf_len, tpad); 26162306a36Sopenharmony_ci __qla_consume_iocb(vha, pkt, rsp); 26262306a36Sopenharmony_ci return -EIO; 26362306a36Sopenharmony_ci } 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci pending_bytes = total_bytes = tpad; 26662306a36Sopenharmony_ci no_bytes = (pending_bytes > sizeof(purex->els_frame_payload)) ? 26762306a36Sopenharmony_ci sizeof(purex->els_frame_payload) : pending_bytes; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci memcpy(buf, &purex->els_frame_payload[0], no_bytes); 27062306a36Sopenharmony_ci buffer_copy_offset += no_bytes; 27162306a36Sopenharmony_ci pending_bytes -= no_bytes; 27262306a36Sopenharmony_ci --entry_count_remaining; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci ((response_t *)purex)->signature = RESPONSE_PROCESSED; 27562306a36Sopenharmony_ci /* flush signature */ 27662306a36Sopenharmony_ci wmb(); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci do { 27962306a36Sopenharmony_ci while ((total_bytes > 0) && (entry_count_remaining > 0)) { 28062306a36Sopenharmony_ci new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; 28162306a36Sopenharmony_ci *pkt = new_pkt; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (new_pkt->entry_type != STATUS_CONT_TYPE) { 28462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x507a, 28562306a36Sopenharmony_ci "Unexpected IOCB type, partial data 0x%x\n", 28662306a36Sopenharmony_ci buffer_copy_offset); 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci rsp_q->ring_index++; 29162306a36Sopenharmony_ci if (rsp_q->ring_index == rsp_q->length) { 29262306a36Sopenharmony_ci rsp_q->ring_index = 0; 29362306a36Sopenharmony_ci rsp_q->ring_ptr = rsp_q->ring; 29462306a36Sopenharmony_ci } else { 29562306a36Sopenharmony_ci rsp_q->ring_ptr++; 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci no_bytes = (pending_bytes > sizeof(new_pkt->data)) ? 29862306a36Sopenharmony_ci sizeof(new_pkt->data) : pending_bytes; 29962306a36Sopenharmony_ci if ((buffer_copy_offset + no_bytes) <= total_bytes) { 30062306a36Sopenharmony_ci memcpy((buf + buffer_copy_offset), new_pkt->data, 30162306a36Sopenharmony_ci no_bytes); 30262306a36Sopenharmony_ci buffer_copy_offset += no_bytes; 30362306a36Sopenharmony_ci pending_bytes -= no_bytes; 30462306a36Sopenharmony_ci --entry_count_remaining; 30562306a36Sopenharmony_ci } else { 30662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5044, 30762306a36Sopenharmony_ci "Attempt to copy more that we got, optimizing..%x\n", 30862306a36Sopenharmony_ci buffer_copy_offset); 30962306a36Sopenharmony_ci memcpy((buf + buffer_copy_offset), new_pkt->data, 31062306a36Sopenharmony_ci total_bytes - buffer_copy_offset); 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci ((response_t *)new_pkt)->signature = RESPONSE_PROCESSED; 31462306a36Sopenharmony_ci /* flush signature */ 31562306a36Sopenharmony_ci wmb(); 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (pending_bytes != 0 || entry_count_remaining != 0) { 31962306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x508b, 32062306a36Sopenharmony_ci "Dropping partial Data, underrun bytes = 0x%x, entry cnts 0x%x\n", 32162306a36Sopenharmony_ci total_bytes, entry_count_remaining); 32262306a36Sopenharmony_ci return -EIO; 32362306a36Sopenharmony_ci } 32462306a36Sopenharmony_ci } while (entry_count_remaining > 0); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci be32_to_cpu_array((u32 *)buf, (__be32 *)buf, total_bytes >> 2); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci/** 33262306a36Sopenharmony_ci * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. 33362306a36Sopenharmony_ci * @irq: interrupt number 33462306a36Sopenharmony_ci * @dev_id: SCSI driver HA context 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt. 33762306a36Sopenharmony_ci * 33862306a36Sopenharmony_ci * Returns handled flag. 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_ciirqreturn_t 34162306a36Sopenharmony_ciqla2100_intr_handler(int irq, void *dev_id) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci scsi_qla_host_t *vha; 34462306a36Sopenharmony_ci struct qla_hw_data *ha; 34562306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg; 34662306a36Sopenharmony_ci int status; 34762306a36Sopenharmony_ci unsigned long iter; 34862306a36Sopenharmony_ci uint16_t hccr; 34962306a36Sopenharmony_ci uint16_t mb[8]; 35062306a36Sopenharmony_ci struct rsp_que *rsp; 35162306a36Sopenharmony_ci unsigned long flags; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 35462306a36Sopenharmony_ci if (!rsp) { 35562306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x505d, 35662306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 35762306a36Sopenharmony_ci return (IRQ_NONE); 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ha = rsp->hw; 36162306a36Sopenharmony_ci reg = &ha->iobase->isp; 36262306a36Sopenharmony_ci status = 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 36562306a36Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 36662306a36Sopenharmony_ci for (iter = 50; iter--; ) { 36762306a36Sopenharmony_ci hccr = rd_reg_word(®->hccr); 36862306a36Sopenharmony_ci if (qla2x00_check_reg16_for_disconnect(vha, hccr)) 36962306a36Sopenharmony_ci break; 37062306a36Sopenharmony_ci if (hccr & HCCR_RISC_PAUSE) { 37162306a36Sopenharmony_ci if (pci_channel_offline(ha->pdev)) 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * Issue a "HARD" reset in order for the RISC interrupt 37662306a36Sopenharmony_ci * bit to be cleared. Schedule a big hammer to get 37762306a36Sopenharmony_ci * out of the RISC PAUSED state. 37862306a36Sopenharmony_ci */ 37962306a36Sopenharmony_ci wrt_reg_word(®->hccr, HCCR_RESET_RISC); 38062306a36Sopenharmony_ci rd_reg_word(®->hccr); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci ha->isp_ops->fw_dump(vha); 38362306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci } else if ((rd_reg_word(®->istatus) & ISR_RISC_INT) == 0) 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (rd_reg_word(®->semaphore) & BIT_0) { 38962306a36Sopenharmony_ci wrt_reg_word(®->hccr, HCCR_CLR_RISC_INT); 39062306a36Sopenharmony_ci rd_reg_word(®->hccr); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Get mailbox data. */ 39362306a36Sopenharmony_ci mb[0] = RD_MAILBOX_REG(ha, reg, 0); 39462306a36Sopenharmony_ci if (mb[0] > 0x3fff && mb[0] < 0x8000) { 39562306a36Sopenharmony_ci qla2x00_mbx_completion(vha, mb[0]); 39662306a36Sopenharmony_ci status |= MBX_INTERRUPT; 39762306a36Sopenharmony_ci } else if (mb[0] > 0x7fff && mb[0] < 0xc000) { 39862306a36Sopenharmony_ci mb[1] = RD_MAILBOX_REG(ha, reg, 1); 39962306a36Sopenharmony_ci mb[2] = RD_MAILBOX_REG(ha, reg, 2); 40062306a36Sopenharmony_ci mb[3] = RD_MAILBOX_REG(ha, reg, 3); 40162306a36Sopenharmony_ci qla2x00_async_event(vha, rsp, mb); 40262306a36Sopenharmony_ci } else { 40362306a36Sopenharmony_ci /*EMPTY*/ 40462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5025, 40562306a36Sopenharmony_ci "Unrecognized interrupt type (%d).\n", 40662306a36Sopenharmony_ci mb[0]); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci /* Release mailbox registers. */ 40962306a36Sopenharmony_ci wrt_reg_word(®->semaphore, 0); 41062306a36Sopenharmony_ci rd_reg_word(®->semaphore); 41162306a36Sopenharmony_ci } else { 41262306a36Sopenharmony_ci qla2x00_process_response_queue(rsp); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci wrt_reg_word(®->hccr, HCCR_CLR_RISC_INT); 41562306a36Sopenharmony_ci rd_reg_word(®->hccr); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci qla2x00_handle_mbx_completion(ha, status); 41962306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci return (IRQ_HANDLED); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cibool 42562306a36Sopenharmony_ciqla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci /* Check for PCI disconnection */ 42862306a36Sopenharmony_ci if (reg == 0xffffffff && !pci_channel_offline(vha->hw->pdev)) { 42962306a36Sopenharmony_ci if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) && 43062306a36Sopenharmony_ci !test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) && 43162306a36Sopenharmony_ci !test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) { 43262306a36Sopenharmony_ci qla_schedule_eeh_work(vha); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci return true; 43562306a36Sopenharmony_ci } else 43662306a36Sopenharmony_ci return false; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cibool 44062306a36Sopenharmony_ciqla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci return qla2x00_check_reg32_for_disconnect(vha, 0xffff0000 | reg); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci/** 44662306a36Sopenharmony_ci * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. 44762306a36Sopenharmony_ci * @irq: interrupt number 44862306a36Sopenharmony_ci * @dev_id: SCSI driver HA context 44962306a36Sopenharmony_ci * 45062306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt. 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * Returns handled flag. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ciirqreturn_t 45562306a36Sopenharmony_ciqla2300_intr_handler(int irq, void *dev_id) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci scsi_qla_host_t *vha; 45862306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg; 45962306a36Sopenharmony_ci int status; 46062306a36Sopenharmony_ci unsigned long iter; 46162306a36Sopenharmony_ci uint32_t stat; 46262306a36Sopenharmony_ci uint16_t hccr; 46362306a36Sopenharmony_ci uint16_t mb[8]; 46462306a36Sopenharmony_ci struct rsp_que *rsp; 46562306a36Sopenharmony_ci struct qla_hw_data *ha; 46662306a36Sopenharmony_ci unsigned long flags; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 46962306a36Sopenharmony_ci if (!rsp) { 47062306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x5058, 47162306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 47262306a36Sopenharmony_ci return (IRQ_NONE); 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci ha = rsp->hw; 47662306a36Sopenharmony_ci reg = &ha->iobase->isp; 47762306a36Sopenharmony_ci status = 0; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 48062306a36Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 48162306a36Sopenharmony_ci for (iter = 50; iter--; ) { 48262306a36Sopenharmony_ci stat = rd_reg_dword(®->u.isp2300.host_status); 48362306a36Sopenharmony_ci if (qla2x00_check_reg32_for_disconnect(vha, stat)) 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci if (stat & HSR_RISC_PAUSED) { 48662306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 48762306a36Sopenharmony_ci break; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci hccr = rd_reg_word(®->hccr); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8)) 49262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5026, 49362306a36Sopenharmony_ci "Parity error -- HCCR=%x, Dumping " 49462306a36Sopenharmony_ci "firmware.\n", hccr); 49562306a36Sopenharmony_ci else 49662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5027, 49762306a36Sopenharmony_ci "RISC paused -- HCCR=%x, Dumping " 49862306a36Sopenharmony_ci "firmware.\n", hccr); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* 50162306a36Sopenharmony_ci * Issue a "HARD" reset in order for the RISC 50262306a36Sopenharmony_ci * interrupt bit to be cleared. Schedule a big 50362306a36Sopenharmony_ci * hammer to get out of the RISC PAUSED state. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci wrt_reg_word(®->hccr, HCCR_RESET_RISC); 50662306a36Sopenharmony_ci rd_reg_word(®->hccr); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci ha->isp_ops->fw_dump(vha); 50962306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 51062306a36Sopenharmony_ci break; 51162306a36Sopenharmony_ci } else if ((stat & HSR_RISC_INT) == 0) 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci switch (stat & 0xff) { 51562306a36Sopenharmony_ci case 0x1: 51662306a36Sopenharmony_ci case 0x2: 51762306a36Sopenharmony_ci case 0x10: 51862306a36Sopenharmony_ci case 0x11: 51962306a36Sopenharmony_ci qla2x00_mbx_completion(vha, MSW(stat)); 52062306a36Sopenharmony_ci status |= MBX_INTERRUPT; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Release mailbox registers. */ 52362306a36Sopenharmony_ci wrt_reg_word(®->semaphore, 0); 52462306a36Sopenharmony_ci break; 52562306a36Sopenharmony_ci case 0x12: 52662306a36Sopenharmony_ci mb[0] = MSW(stat); 52762306a36Sopenharmony_ci mb[1] = RD_MAILBOX_REG(ha, reg, 1); 52862306a36Sopenharmony_ci mb[2] = RD_MAILBOX_REG(ha, reg, 2); 52962306a36Sopenharmony_ci mb[3] = RD_MAILBOX_REG(ha, reg, 3); 53062306a36Sopenharmony_ci qla2x00_async_event(vha, rsp, mb); 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci case 0x13: 53362306a36Sopenharmony_ci qla2x00_process_response_queue(rsp); 53462306a36Sopenharmony_ci break; 53562306a36Sopenharmony_ci case 0x15: 53662306a36Sopenharmony_ci mb[0] = MBA_CMPLT_1_16BIT; 53762306a36Sopenharmony_ci mb[1] = MSW(stat); 53862306a36Sopenharmony_ci qla2x00_async_event(vha, rsp, mb); 53962306a36Sopenharmony_ci break; 54062306a36Sopenharmony_ci case 0x16: 54162306a36Sopenharmony_ci mb[0] = MBA_SCSI_COMPLETION; 54262306a36Sopenharmony_ci mb[1] = MSW(stat); 54362306a36Sopenharmony_ci mb[2] = RD_MAILBOX_REG(ha, reg, 2); 54462306a36Sopenharmony_ci qla2x00_async_event(vha, rsp, mb); 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci default: 54762306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5028, 54862306a36Sopenharmony_ci "Unrecognized interrupt type (%d).\n", stat & 0xff); 54962306a36Sopenharmony_ci break; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci wrt_reg_word(®->hccr, HCCR_CLR_RISC_INT); 55262306a36Sopenharmony_ci rd_reg_word_relaxed(®->hccr); 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci qla2x00_handle_mbx_completion(ha, status); 55562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci return (IRQ_HANDLED); 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/** 56162306a36Sopenharmony_ci * qla2x00_mbx_completion() - Process mailbox command completions. 56262306a36Sopenharmony_ci * @vha: SCSI driver HA context 56362306a36Sopenharmony_ci * @mb0: Mailbox0 register 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic void 56662306a36Sopenharmony_ciqla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci uint16_t cnt; 56962306a36Sopenharmony_ci uint32_t mboxes; 57062306a36Sopenharmony_ci __le16 __iomem *wptr; 57162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 57262306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci /* Read all mbox registers? */ 57562306a36Sopenharmony_ci WARN_ON_ONCE(ha->mbx_count > 32); 57662306a36Sopenharmony_ci mboxes = (1ULL << ha->mbx_count) - 1; 57762306a36Sopenharmony_ci if (!ha->mcp) 57862306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n"); 57962306a36Sopenharmony_ci else 58062306a36Sopenharmony_ci mboxes = ha->mcp->in_mb; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* Load return mailbox registers. */ 58362306a36Sopenharmony_ci ha->flags.mbox_int = 1; 58462306a36Sopenharmony_ci ha->mailbox_out[0] = mb0; 58562306a36Sopenharmony_ci mboxes >>= 1; 58662306a36Sopenharmony_ci wptr = MAILBOX_REG(ha, reg, 1); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci for (cnt = 1; cnt < ha->mbx_count; cnt++) { 58962306a36Sopenharmony_ci if (IS_QLA2200(ha) && cnt == 8) 59062306a36Sopenharmony_ci wptr = MAILBOX_REG(ha, reg, 8); 59162306a36Sopenharmony_ci if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0)) 59262306a36Sopenharmony_ci ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr); 59362306a36Sopenharmony_ci else if (mboxes & BIT_0) 59462306a36Sopenharmony_ci ha->mailbox_out[cnt] = rd_reg_word(wptr); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci wptr++; 59762306a36Sopenharmony_ci mboxes >>= 1; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic void 60262306a36Sopenharmony_ciqla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci static char *event[] = 60562306a36Sopenharmony_ci { "Complete", "Request Notification", "Time Extension" }; 60662306a36Sopenharmony_ci int rval; 60762306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24; 60862306a36Sopenharmony_ci struct device_reg_82xx __iomem *reg82 = &vha->hw->iobase->isp82; 60962306a36Sopenharmony_ci __le16 __iomem *wptr; 61062306a36Sopenharmony_ci uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS]; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Seed data -- mailbox1 -> mailbox7. */ 61362306a36Sopenharmony_ci if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw)) 61462306a36Sopenharmony_ci wptr = ®24->mailbox1; 61562306a36Sopenharmony_ci else if (IS_QLA8044(vha->hw)) 61662306a36Sopenharmony_ci wptr = ®82->mailbox_out[1]; 61762306a36Sopenharmony_ci else 61862306a36Sopenharmony_ci return; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++) 62162306a36Sopenharmony_ci mb[cnt] = rd_reg_word(wptr); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5021, 62462306a36Sopenharmony_ci "Inter-Driver Communication %s -- " 62562306a36Sopenharmony_ci "%04x %04x %04x %04x %04x %04x %04x.\n", 62662306a36Sopenharmony_ci event[aen & 0xff], mb[0], mb[1], mb[2], mb[3], 62762306a36Sopenharmony_ci mb[4], mb[5], mb[6]); 62862306a36Sopenharmony_ci switch (aen) { 62962306a36Sopenharmony_ci /* Handle IDC Error completion case. */ 63062306a36Sopenharmony_ci case MBA_IDC_COMPLETE: 63162306a36Sopenharmony_ci if (mb[1] >> 15) { 63262306a36Sopenharmony_ci vha->hw->flags.idc_compl_status = 1; 63362306a36Sopenharmony_ci if (vha->hw->notify_dcbx_comp && !vha->vp_idx) 63462306a36Sopenharmony_ci complete(&vha->hw->dcbx_comp); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci break; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci case MBA_IDC_NOTIFY: 63962306a36Sopenharmony_ci /* Acknowledgement needed? [Notify && non-zero timeout]. */ 64062306a36Sopenharmony_ci timeout = (descr >> 8) & 0xf; 64162306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5022, 64262306a36Sopenharmony_ci "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n", 64362306a36Sopenharmony_ci vha->host_no, event[aen & 0xff], timeout); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (!timeout) 64662306a36Sopenharmony_ci return; 64762306a36Sopenharmony_ci rval = qla2x00_post_idc_ack_work(vha, mb); 64862306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 64962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5023, 65062306a36Sopenharmony_ci "IDC failed to post ACK.\n"); 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci case MBA_IDC_TIME_EXT: 65362306a36Sopenharmony_ci vha->hw->idc_extend_tmo = descr; 65462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5087, 65562306a36Sopenharmony_ci "%lu Inter-Driver Communication %s -- " 65662306a36Sopenharmony_ci "Extend timeout by=%d.\n", 65762306a36Sopenharmony_ci vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo); 65862306a36Sopenharmony_ci break; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci} 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci#define LS_UNKNOWN 2 66362306a36Sopenharmony_ciconst char * 66462306a36Sopenharmony_ciqla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci static const char *const link_speeds[] = { 66762306a36Sopenharmony_ci "1", "2", "?", "4", "8", "16", "32", "64", "10" 66862306a36Sopenharmony_ci }; 66962306a36Sopenharmony_ci#define QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1) 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 67262306a36Sopenharmony_ci return link_speeds[0]; 67362306a36Sopenharmony_ci else if (speed == 0x13) 67462306a36Sopenharmony_ci return link_speeds[QLA_LAST_SPEED]; 67562306a36Sopenharmony_ci else if (speed < QLA_LAST_SPEED) 67662306a36Sopenharmony_ci return link_speeds[speed]; 67762306a36Sopenharmony_ci else 67862306a36Sopenharmony_ci return link_speeds[LS_UNKNOWN]; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic void 68262306a36Sopenharmony_ciqla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb) 68362306a36Sopenharmony_ci{ 68462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci /* 68762306a36Sopenharmony_ci * 8200 AEN Interpretation: 68862306a36Sopenharmony_ci * mb[0] = AEN code 68962306a36Sopenharmony_ci * mb[1] = AEN Reason code 69062306a36Sopenharmony_ci * mb[2] = LSW of Peg-Halt Status-1 Register 69162306a36Sopenharmony_ci * mb[6] = MSW of Peg-Halt Status-1 Register 69262306a36Sopenharmony_ci * mb[3] = LSW of Peg-Halt Status-2 register 69362306a36Sopenharmony_ci * mb[7] = MSW of Peg-Halt Status-2 register 69462306a36Sopenharmony_ci * mb[4] = IDC Device-State Register value 69562306a36Sopenharmony_ci * mb[5] = IDC Driver-Presence Register value 69662306a36Sopenharmony_ci */ 69762306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: " 69862306a36Sopenharmony_ci "mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n", 69962306a36Sopenharmony_ci mb[0], mb[1], mb[2], mb[6]); 70062306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x " 70162306a36Sopenharmony_ci "PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x " 70262306a36Sopenharmony_ci "Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE | 70562306a36Sopenharmony_ci IDC_HEARTBEAT_FAILURE)) { 70662306a36Sopenharmony_ci ha->flags.nic_core_hung = 1; 70762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5060, 70862306a36Sopenharmony_ci "83XX: F/W Error Reported: Check if reset required.\n"); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) { 71162306a36Sopenharmony_ci uint32_t protocol_engine_id, fw_err_code, err_level; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* 71462306a36Sopenharmony_ci * IDC_PEG_HALT_STATUS_CHANGE interpretation: 71562306a36Sopenharmony_ci * - PEG-Halt Status-1 Register: 71662306a36Sopenharmony_ci * (LSW = mb[2], MSW = mb[6]) 71762306a36Sopenharmony_ci * Bits 0-7 = protocol-engine ID 71862306a36Sopenharmony_ci * Bits 8-28 = f/w error code 71962306a36Sopenharmony_ci * Bits 29-31 = Error-level 72062306a36Sopenharmony_ci * Error-level 0x1 = Non-Fatal error 72162306a36Sopenharmony_ci * Error-level 0x2 = Recoverable Fatal error 72262306a36Sopenharmony_ci * Error-level 0x4 = UnRecoverable Fatal error 72362306a36Sopenharmony_ci * - PEG-Halt Status-2 Register: 72462306a36Sopenharmony_ci * (LSW = mb[3], MSW = mb[7]) 72562306a36Sopenharmony_ci */ 72662306a36Sopenharmony_ci protocol_engine_id = (mb[2] & 0xff); 72762306a36Sopenharmony_ci fw_err_code = (((mb[2] & 0xff00) >> 8) | 72862306a36Sopenharmony_ci ((mb[6] & 0x1fff) << 8)); 72962306a36Sopenharmony_ci err_level = ((mb[6] & 0xe000) >> 13); 73062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 " 73162306a36Sopenharmony_ci "Register: protocol_engine_id=0x%x " 73262306a36Sopenharmony_ci "fw_err_code=0x%x err_level=0x%x.\n", 73362306a36Sopenharmony_ci protocol_engine_id, fw_err_code, err_level); 73462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 " 73562306a36Sopenharmony_ci "Register: 0x%x%x.\n", mb[7], mb[3]); 73662306a36Sopenharmony_ci if (err_level == ERR_LEVEL_NON_FATAL) { 73762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5063, 73862306a36Sopenharmony_ci "Not a fatal error, f/w has recovered itself.\n"); 73962306a36Sopenharmony_ci } else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) { 74062306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x5064, 74162306a36Sopenharmony_ci "Recoverable Fatal error: Chip reset " 74262306a36Sopenharmony_ci "required.\n"); 74362306a36Sopenharmony_ci qla83xx_schedule_work(vha, 74462306a36Sopenharmony_ci QLA83XX_NIC_CORE_RESET); 74562306a36Sopenharmony_ci } else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) { 74662306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x5065, 74762306a36Sopenharmony_ci "Unrecoverable Fatal error: Set FAILED " 74862306a36Sopenharmony_ci "state, reboot required.\n"); 74962306a36Sopenharmony_ci qla83xx_schedule_work(vha, 75062306a36Sopenharmony_ci QLA83XX_NIC_CORE_UNRECOVERABLE); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) { 75562306a36Sopenharmony_ci uint16_t peg_fw_state, nw_interface_link_up; 75662306a36Sopenharmony_ci uint16_t nw_interface_signal_detect, sfp_status; 75762306a36Sopenharmony_ci uint16_t htbt_counter, htbt_monitor_enable; 75862306a36Sopenharmony_ci uint16_t sfp_additional_info, sfp_multirate; 75962306a36Sopenharmony_ci uint16_t sfp_tx_fault, link_speed, dcbx_status; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci /* 76262306a36Sopenharmony_ci * IDC_NIC_FW_REPORTED_FAILURE interpretation: 76362306a36Sopenharmony_ci * - PEG-to-FC Status Register: 76462306a36Sopenharmony_ci * (LSW = mb[2], MSW = mb[6]) 76562306a36Sopenharmony_ci * Bits 0-7 = Peg-Firmware state 76662306a36Sopenharmony_ci * Bit 8 = N/W Interface Link-up 76762306a36Sopenharmony_ci * Bit 9 = N/W Interface signal detected 76862306a36Sopenharmony_ci * Bits 10-11 = SFP Status 76962306a36Sopenharmony_ci * SFP Status 0x0 = SFP+ transceiver not expected 77062306a36Sopenharmony_ci * SFP Status 0x1 = SFP+ transceiver not present 77162306a36Sopenharmony_ci * SFP Status 0x2 = SFP+ transceiver invalid 77262306a36Sopenharmony_ci * SFP Status 0x3 = SFP+ transceiver present and 77362306a36Sopenharmony_ci * valid 77462306a36Sopenharmony_ci * Bits 12-14 = Heartbeat Counter 77562306a36Sopenharmony_ci * Bit 15 = Heartbeat Monitor Enable 77662306a36Sopenharmony_ci * Bits 16-17 = SFP Additional Info 77762306a36Sopenharmony_ci * SFP info 0x0 = Unregocnized transceiver for 77862306a36Sopenharmony_ci * Ethernet 77962306a36Sopenharmony_ci * SFP info 0x1 = SFP+ brand validation failed 78062306a36Sopenharmony_ci * SFP info 0x2 = SFP+ speed validation failed 78162306a36Sopenharmony_ci * SFP info 0x3 = SFP+ access error 78262306a36Sopenharmony_ci * Bit 18 = SFP Multirate 78362306a36Sopenharmony_ci * Bit 19 = SFP Tx Fault 78462306a36Sopenharmony_ci * Bits 20-22 = Link Speed 78562306a36Sopenharmony_ci * Bits 23-27 = Reserved 78662306a36Sopenharmony_ci * Bits 28-30 = DCBX Status 78762306a36Sopenharmony_ci * DCBX Status 0x0 = DCBX Disabled 78862306a36Sopenharmony_ci * DCBX Status 0x1 = DCBX Enabled 78962306a36Sopenharmony_ci * DCBX Status 0x2 = DCBX Exchange error 79062306a36Sopenharmony_ci * Bit 31 = Reserved 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci peg_fw_state = (mb[2] & 0x00ff); 79362306a36Sopenharmony_ci nw_interface_link_up = ((mb[2] & 0x0100) >> 8); 79462306a36Sopenharmony_ci nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9); 79562306a36Sopenharmony_ci sfp_status = ((mb[2] & 0x0c00) >> 10); 79662306a36Sopenharmony_ci htbt_counter = ((mb[2] & 0x7000) >> 12); 79762306a36Sopenharmony_ci htbt_monitor_enable = ((mb[2] & 0x8000) >> 15); 79862306a36Sopenharmony_ci sfp_additional_info = (mb[6] & 0x0003); 79962306a36Sopenharmony_ci sfp_multirate = ((mb[6] & 0x0004) >> 2); 80062306a36Sopenharmony_ci sfp_tx_fault = ((mb[6] & 0x0008) >> 3); 80162306a36Sopenharmony_ci link_speed = ((mb[6] & 0x0070) >> 4); 80262306a36Sopenharmony_ci dcbx_status = ((mb[6] & 0x7000) >> 12); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5066, 80562306a36Sopenharmony_ci "Peg-to-Fc Status Register:\n" 80662306a36Sopenharmony_ci "peg_fw_state=0x%x, nw_interface_link_up=0x%x, " 80762306a36Sopenharmony_ci "nw_interface_signal_detect=0x%x" 80862306a36Sopenharmony_ci "\nsfp_statis=0x%x.\n ", peg_fw_state, 80962306a36Sopenharmony_ci nw_interface_link_up, nw_interface_signal_detect, 81062306a36Sopenharmony_ci sfp_status); 81162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5067, 81262306a36Sopenharmony_ci "htbt_counter=0x%x, htbt_monitor_enable=0x%x, " 81362306a36Sopenharmony_ci "sfp_additional_info=0x%x, sfp_multirate=0x%x.\n ", 81462306a36Sopenharmony_ci htbt_counter, htbt_monitor_enable, 81562306a36Sopenharmony_ci sfp_additional_info, sfp_multirate); 81662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5068, 81762306a36Sopenharmony_ci "sfp_tx_fault=0x%x, link_state=0x%x, " 81862306a36Sopenharmony_ci "dcbx_status=0x%x.\n", sfp_tx_fault, link_speed, 81962306a36Sopenharmony_ci dcbx_status); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET); 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (mb[1] & IDC_HEARTBEAT_FAILURE) { 82562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5069, 82662306a36Sopenharmony_ci "Heartbeat Failure encountered, chip reset " 82762306a36Sopenharmony_ci "required.\n"); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET); 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci if (mb[1] & IDC_DEVICE_STATE_CHANGE) { 83462306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x506a, 83562306a36Sopenharmony_ci "IDC Device-State changed = 0x%x.\n", mb[4]); 83662306a36Sopenharmony_ci if (ha->flags.nic_core_reset_owner) 83762306a36Sopenharmony_ci return; 83862306a36Sopenharmony_ci qla83xx_schedule_work(vha, MBA_IDC_AEN); 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci} 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci/** 84362306a36Sopenharmony_ci * qla27xx_copy_multiple_pkt() - Copy over purex/purls packets that can 84462306a36Sopenharmony_ci * span over multiple IOCBs. 84562306a36Sopenharmony_ci * @vha: SCSI driver HA context 84662306a36Sopenharmony_ci * @pkt: ELS packet 84762306a36Sopenharmony_ci * @rsp: Response queue 84862306a36Sopenharmony_ci * @is_purls: True, for Unsolicited Received FC-NVMe LS rsp IOCB 84962306a36Sopenharmony_ci * false, for Unsolicited Received ELS IOCB 85062306a36Sopenharmony_ci * @byte_order: True, to change the byte ordering of iocb payload 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_cistruct purex_item * 85362306a36Sopenharmony_ciqla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt, 85462306a36Sopenharmony_ci struct rsp_que **rsp, bool is_purls, 85562306a36Sopenharmony_ci bool byte_order) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct purex_entry_24xx *purex = NULL; 85862306a36Sopenharmony_ci struct pt_ls4_rx_unsol *purls = NULL; 85962306a36Sopenharmony_ci struct rsp_que *rsp_q = *rsp; 86062306a36Sopenharmony_ci sts_cont_entry_t *new_pkt; 86162306a36Sopenharmony_ci uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0; 86262306a36Sopenharmony_ci uint16_t buffer_copy_offset = 0, payload_size = 0; 86362306a36Sopenharmony_ci uint16_t entry_count, entry_count_remaining; 86462306a36Sopenharmony_ci struct purex_item *item; 86562306a36Sopenharmony_ci void *iocb_pkt = NULL; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (is_purls) { 86862306a36Sopenharmony_ci purls = *pkt; 86962306a36Sopenharmony_ci total_bytes = (le16_to_cpu(purls->frame_size) & 0x0FFF) - 87062306a36Sopenharmony_ci PURX_ELS_HEADER_SIZE; 87162306a36Sopenharmony_ci entry_count = entry_count_remaining = purls->entry_count; 87262306a36Sopenharmony_ci payload_size = sizeof(purls->payload); 87362306a36Sopenharmony_ci } else { 87462306a36Sopenharmony_ci purex = *pkt; 87562306a36Sopenharmony_ci total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) - 87662306a36Sopenharmony_ci PURX_ELS_HEADER_SIZE; 87762306a36Sopenharmony_ci entry_count = entry_count_remaining = purex->entry_count; 87862306a36Sopenharmony_ci payload_size = sizeof(purex->els_frame_payload); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci pending_bytes = total_bytes; 88262306a36Sopenharmony_ci no_bytes = (pending_bytes > payload_size) ? payload_size : 88362306a36Sopenharmony_ci pending_bytes; 88462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x509a, 88562306a36Sopenharmony_ci "%s LS, frame_size 0x%x, entry count %d\n", 88662306a36Sopenharmony_ci (is_purls ? "PURLS" : "FPIN"), total_bytes, entry_count); 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci item = qla24xx_alloc_purex_item(vha, total_bytes); 88962306a36Sopenharmony_ci if (!item) 89062306a36Sopenharmony_ci return item; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci iocb_pkt = &item->iocb; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci if (is_purls) 89562306a36Sopenharmony_ci memcpy(iocb_pkt, &purls->payload[0], no_bytes); 89662306a36Sopenharmony_ci else 89762306a36Sopenharmony_ci memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes); 89862306a36Sopenharmony_ci buffer_copy_offset += no_bytes; 89962306a36Sopenharmony_ci pending_bytes -= no_bytes; 90062306a36Sopenharmony_ci --entry_count_remaining; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (is_purls) 90362306a36Sopenharmony_ci ((response_t *)purls)->signature = RESPONSE_PROCESSED; 90462306a36Sopenharmony_ci else 90562306a36Sopenharmony_ci ((response_t *)purex)->signature = RESPONSE_PROCESSED; 90662306a36Sopenharmony_ci wmb(); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci do { 90962306a36Sopenharmony_ci while ((total_bytes > 0) && (entry_count_remaining > 0)) { 91062306a36Sopenharmony_ci if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) { 91162306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5084, 91262306a36Sopenharmony_ci "Ran out of IOCBs, partial data 0x%x\n", 91362306a36Sopenharmony_ci buffer_copy_offset); 91462306a36Sopenharmony_ci cpu_relax(); 91562306a36Sopenharmony_ci continue; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; 91962306a36Sopenharmony_ci *pkt = new_pkt; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (new_pkt->entry_type != STATUS_CONT_TYPE) { 92262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x507a, 92362306a36Sopenharmony_ci "Unexpected IOCB type, partial data 0x%x\n", 92462306a36Sopenharmony_ci buffer_copy_offset); 92562306a36Sopenharmony_ci break; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci rsp_q->ring_index++; 92962306a36Sopenharmony_ci if (rsp_q->ring_index == rsp_q->length) { 93062306a36Sopenharmony_ci rsp_q->ring_index = 0; 93162306a36Sopenharmony_ci rsp_q->ring_ptr = rsp_q->ring; 93262306a36Sopenharmony_ci } else { 93362306a36Sopenharmony_ci rsp_q->ring_ptr++; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci no_bytes = (pending_bytes > sizeof(new_pkt->data)) ? 93662306a36Sopenharmony_ci sizeof(new_pkt->data) : pending_bytes; 93762306a36Sopenharmony_ci if ((buffer_copy_offset + no_bytes) <= total_bytes) { 93862306a36Sopenharmony_ci memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset), 93962306a36Sopenharmony_ci new_pkt->data, no_bytes); 94062306a36Sopenharmony_ci buffer_copy_offset += no_bytes; 94162306a36Sopenharmony_ci pending_bytes -= no_bytes; 94262306a36Sopenharmony_ci --entry_count_remaining; 94362306a36Sopenharmony_ci } else { 94462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5044, 94562306a36Sopenharmony_ci "Attempt to copy more that we got, optimizing..%x\n", 94662306a36Sopenharmony_ci buffer_copy_offset); 94762306a36Sopenharmony_ci memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset), 94862306a36Sopenharmony_ci new_pkt->data, 94962306a36Sopenharmony_ci total_bytes - buffer_copy_offset); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci ((response_t *)new_pkt)->signature = RESPONSE_PROCESSED; 95362306a36Sopenharmony_ci wmb(); 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (pending_bytes != 0 || entry_count_remaining != 0) { 95762306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x508b, 95862306a36Sopenharmony_ci "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n", 95962306a36Sopenharmony_ci total_bytes, entry_count_remaining); 96062306a36Sopenharmony_ci qla24xx_free_purex_item(item); 96162306a36Sopenharmony_ci return NULL; 96262306a36Sopenharmony_ci } 96362306a36Sopenharmony_ci } while (entry_count_remaining > 0); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci if (byte_order) 96662306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci return item; 96962306a36Sopenharmony_ci} 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ciint 97262306a36Sopenharmony_ciqla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 97562306a36Sopenharmony_ci scsi_qla_host_t *vp; 97662306a36Sopenharmony_ci uint32_t vp_did; 97762306a36Sopenharmony_ci unsigned long flags; 97862306a36Sopenharmony_ci int ret = 0; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (!ha->num_vhosts) 98162306a36Sopenharmony_ci return ret; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 98462306a36Sopenharmony_ci list_for_each_entry(vp, &ha->vp_list, list) { 98562306a36Sopenharmony_ci vp_did = vp->d_id.b24; 98662306a36Sopenharmony_ci if (vp_did == rscn_entry) { 98762306a36Sopenharmony_ci ret = 1; 98862306a36Sopenharmony_ci break; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci return ret; 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cifc_port_t * 99762306a36Sopenharmony_ciqla2x00_find_fcport_by_loopid(scsi_qla_host_t *vha, uint16_t loop_id) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci fc_port_t *f, *tf; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci f = tf = NULL; 100262306a36Sopenharmony_ci list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) 100362306a36Sopenharmony_ci if (f->loop_id == loop_id) 100462306a36Sopenharmony_ci return f; 100562306a36Sopenharmony_ci return NULL; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cifc_port_t * 100962306a36Sopenharmony_ciqla2x00_find_fcport_by_wwpn(scsi_qla_host_t *vha, u8 *wwpn, u8 incl_deleted) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci fc_port_t *f, *tf; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci f = tf = NULL; 101462306a36Sopenharmony_ci list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) { 101562306a36Sopenharmony_ci if (memcmp(f->port_name, wwpn, WWN_SIZE) == 0) { 101662306a36Sopenharmony_ci if (incl_deleted) 101762306a36Sopenharmony_ci return f; 101862306a36Sopenharmony_ci else if (f->deleted == 0) 101962306a36Sopenharmony_ci return f; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci } 102262306a36Sopenharmony_ci return NULL; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cifc_port_t * 102662306a36Sopenharmony_ciqla2x00_find_fcport_by_nportid(scsi_qla_host_t *vha, port_id_t *id, 102762306a36Sopenharmony_ci u8 incl_deleted) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci fc_port_t *f, *tf; 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci f = tf = NULL; 103262306a36Sopenharmony_ci list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) { 103362306a36Sopenharmony_ci if (f->d_id.b24 == id->b24) { 103462306a36Sopenharmony_ci if (incl_deleted) 103562306a36Sopenharmony_ci return f; 103662306a36Sopenharmony_ci else if (f->deleted == 0) 103762306a36Sopenharmony_ci return f; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci } 104062306a36Sopenharmony_ci return NULL; 104162306a36Sopenharmony_ci} 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci/* Shall be called only on supported adapters. */ 104462306a36Sopenharmony_cistatic void 104562306a36Sopenharmony_ciqla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb) 104662306a36Sopenharmony_ci{ 104762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 104862306a36Sopenharmony_ci bool reset_isp_needed = false; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x02f0, 105162306a36Sopenharmony_ci "MPI Heartbeat stop. MPI reset is%s needed. " 105262306a36Sopenharmony_ci "MB0[%xh] MB1[%xh] MB2[%xh] MB3[%xh]\n", 105362306a36Sopenharmony_ci mb[1] & BIT_8 ? "" : " not", 105462306a36Sopenharmony_ci mb[0], mb[1], mb[2], mb[3]); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if ((mb[1] & BIT_8) == 0) 105762306a36Sopenharmony_ci return; 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x02f1, 106062306a36Sopenharmony_ci "MPI Heartbeat stop. FW dump needed\n"); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (ql2xfulldump_on_mpifail) { 106362306a36Sopenharmony_ci ha->isp_ops->fw_dump(vha); 106462306a36Sopenharmony_ci reset_isp_needed = true; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci ha->isp_ops->mpi_fw_dump(vha, 1); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (reset_isp_needed) { 107062306a36Sopenharmony_ci vha->hw->flags.fw_init_done = 0; 107162306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 107262306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic struct purex_item * 107762306a36Sopenharmony_ciqla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size) 107862306a36Sopenharmony_ci{ 107962306a36Sopenharmony_ci struct purex_item *item = NULL; 108062306a36Sopenharmony_ci uint8_t item_hdr_size = sizeof(*item); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci if (size > QLA_DEFAULT_PAYLOAD_SIZE) { 108362306a36Sopenharmony_ci item = kzalloc(item_hdr_size + 108462306a36Sopenharmony_ci (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC); 108562306a36Sopenharmony_ci } else { 108662306a36Sopenharmony_ci if (atomic_inc_return(&vha->default_item.in_use) == 1) { 108762306a36Sopenharmony_ci item = &vha->default_item; 108862306a36Sopenharmony_ci goto initialize_purex_header; 108962306a36Sopenharmony_ci } else { 109062306a36Sopenharmony_ci item = kzalloc(item_hdr_size, GFP_ATOMIC); 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci if (!item) { 109462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5092, 109562306a36Sopenharmony_ci ">> Failed allocate purex list item.\n"); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return NULL; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ciinitialize_purex_header: 110162306a36Sopenharmony_ci item->vha = vha; 110262306a36Sopenharmony_ci item->size = size; 110362306a36Sopenharmony_ci return item; 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_civoid 110762306a36Sopenharmony_ciqla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt, 110862306a36Sopenharmony_ci void (*process_item)(struct scsi_qla_host *vha, 110962306a36Sopenharmony_ci struct purex_item *pkt)) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci struct purex_list *list = &vha->purex_list; 111262306a36Sopenharmony_ci ulong flags; 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci pkt->process_item = process_item; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci spin_lock_irqsave(&list->lock, flags); 111762306a36Sopenharmony_ci list_add_tail(&pkt->list, &list->head); 111862306a36Sopenharmony_ci spin_unlock_irqrestore(&list->lock, flags); 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags); 112162306a36Sopenharmony_ci} 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci/** 112462306a36Sopenharmony_ci * qla24xx_copy_std_pkt() - Copy over purex ELS which is 112562306a36Sopenharmony_ci * contained in a single IOCB. 112662306a36Sopenharmony_ci * purex packet. 112762306a36Sopenharmony_ci * @vha: SCSI driver HA context 112862306a36Sopenharmony_ci * @pkt: ELS packet 112962306a36Sopenharmony_ci */ 113062306a36Sopenharmony_cistatic struct purex_item 113162306a36Sopenharmony_ci*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt) 113262306a36Sopenharmony_ci{ 113362306a36Sopenharmony_ci struct purex_item *item; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci item = qla24xx_alloc_purex_item(vha, 113662306a36Sopenharmony_ci QLA_DEFAULT_PAYLOAD_SIZE); 113762306a36Sopenharmony_ci if (!item) 113862306a36Sopenharmony_ci return item; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci memcpy(&item->iocb, pkt, sizeof(item->iocb)); 114162306a36Sopenharmony_ci return item; 114262306a36Sopenharmony_ci} 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci/** 114562306a36Sopenharmony_ci * qla27xx_copy_fpin_pkt() - Copy over fpin packets that can 114662306a36Sopenharmony_ci * span over multiple IOCBs. 114762306a36Sopenharmony_ci * @vha: SCSI driver HA context 114862306a36Sopenharmony_ci * @pkt: ELS packet 114962306a36Sopenharmony_ci * @rsp: Response queue 115062306a36Sopenharmony_ci */ 115162306a36Sopenharmony_cistatic struct purex_item * 115262306a36Sopenharmony_ciqla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt, 115362306a36Sopenharmony_ci struct rsp_que **rsp) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci struct purex_entry_24xx *purex = *pkt; 115662306a36Sopenharmony_ci struct rsp_que *rsp_q = *rsp; 115762306a36Sopenharmony_ci sts_cont_entry_t *new_pkt; 115862306a36Sopenharmony_ci uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0; 115962306a36Sopenharmony_ci uint16_t buffer_copy_offset = 0; 116062306a36Sopenharmony_ci uint16_t entry_count, entry_count_remaining; 116162306a36Sopenharmony_ci struct purex_item *item; 116262306a36Sopenharmony_ci void *fpin_pkt = NULL; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) 116562306a36Sopenharmony_ci - PURX_ELS_HEADER_SIZE; 116662306a36Sopenharmony_ci pending_bytes = total_bytes; 116762306a36Sopenharmony_ci entry_count = entry_count_remaining = purex->entry_count; 116862306a36Sopenharmony_ci no_bytes = (pending_bytes > sizeof(purex->els_frame_payload)) ? 116962306a36Sopenharmony_ci sizeof(purex->els_frame_payload) : pending_bytes; 117062306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x509a, 117162306a36Sopenharmony_ci "FPIN ELS, frame_size 0x%x, entry count %d\n", 117262306a36Sopenharmony_ci total_bytes, entry_count); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci item = qla24xx_alloc_purex_item(vha, total_bytes); 117562306a36Sopenharmony_ci if (!item) 117662306a36Sopenharmony_ci return item; 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci fpin_pkt = &item->iocb; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes); 118162306a36Sopenharmony_ci buffer_copy_offset += no_bytes; 118262306a36Sopenharmony_ci pending_bytes -= no_bytes; 118362306a36Sopenharmony_ci --entry_count_remaining; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci ((response_t *)purex)->signature = RESPONSE_PROCESSED; 118662306a36Sopenharmony_ci wmb(); 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci do { 118962306a36Sopenharmony_ci while ((total_bytes > 0) && (entry_count_remaining > 0)) { 119062306a36Sopenharmony_ci if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) { 119162306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5084, 119262306a36Sopenharmony_ci "Ran out of IOCBs, partial data 0x%x\n", 119362306a36Sopenharmony_ci buffer_copy_offset); 119462306a36Sopenharmony_ci cpu_relax(); 119562306a36Sopenharmony_ci continue; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr; 119962306a36Sopenharmony_ci *pkt = new_pkt; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci if (new_pkt->entry_type != STATUS_CONT_TYPE) { 120262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x507a, 120362306a36Sopenharmony_ci "Unexpected IOCB type, partial data 0x%x\n", 120462306a36Sopenharmony_ci buffer_copy_offset); 120562306a36Sopenharmony_ci break; 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci rsp_q->ring_index++; 120962306a36Sopenharmony_ci if (rsp_q->ring_index == rsp_q->length) { 121062306a36Sopenharmony_ci rsp_q->ring_index = 0; 121162306a36Sopenharmony_ci rsp_q->ring_ptr = rsp_q->ring; 121262306a36Sopenharmony_ci } else { 121362306a36Sopenharmony_ci rsp_q->ring_ptr++; 121462306a36Sopenharmony_ci } 121562306a36Sopenharmony_ci no_bytes = (pending_bytes > sizeof(new_pkt->data)) ? 121662306a36Sopenharmony_ci sizeof(new_pkt->data) : pending_bytes; 121762306a36Sopenharmony_ci if ((buffer_copy_offset + no_bytes) <= total_bytes) { 121862306a36Sopenharmony_ci memcpy(((uint8_t *)fpin_pkt + 121962306a36Sopenharmony_ci buffer_copy_offset), new_pkt->data, 122062306a36Sopenharmony_ci no_bytes); 122162306a36Sopenharmony_ci buffer_copy_offset += no_bytes; 122262306a36Sopenharmony_ci pending_bytes -= no_bytes; 122362306a36Sopenharmony_ci --entry_count_remaining; 122462306a36Sopenharmony_ci } else { 122562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5044, 122662306a36Sopenharmony_ci "Attempt to copy more that we got, optimizing..%x\n", 122762306a36Sopenharmony_ci buffer_copy_offset); 122862306a36Sopenharmony_ci memcpy(((uint8_t *)fpin_pkt + 122962306a36Sopenharmony_ci buffer_copy_offset), new_pkt->data, 123062306a36Sopenharmony_ci total_bytes - buffer_copy_offset); 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci ((response_t *)new_pkt)->signature = RESPONSE_PROCESSED; 123462306a36Sopenharmony_ci wmb(); 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (pending_bytes != 0 || entry_count_remaining != 0) { 123862306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x508b, 123962306a36Sopenharmony_ci "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n", 124062306a36Sopenharmony_ci total_bytes, entry_count_remaining); 124162306a36Sopenharmony_ci qla24xx_free_purex_item(item); 124262306a36Sopenharmony_ci return NULL; 124362306a36Sopenharmony_ci } 124462306a36Sopenharmony_ci } while (entry_count_remaining > 0); 124562306a36Sopenharmony_ci host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes); 124662306a36Sopenharmony_ci return item; 124762306a36Sopenharmony_ci} 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci/** 125062306a36Sopenharmony_ci * qla2x00_async_event() - Process aynchronous events. 125162306a36Sopenharmony_ci * @vha: SCSI driver HA context 125262306a36Sopenharmony_ci * @rsp: response queue 125362306a36Sopenharmony_ci * @mb: Mailbox registers (0 - 3) 125462306a36Sopenharmony_ci */ 125562306a36Sopenharmony_civoid 125662306a36Sopenharmony_ciqla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) 125762306a36Sopenharmony_ci{ 125862306a36Sopenharmony_ci uint16_t handle_cnt; 125962306a36Sopenharmony_ci uint16_t cnt, mbx; 126062306a36Sopenharmony_ci uint32_t handles[5]; 126162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 126262306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; 126362306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; 126462306a36Sopenharmony_ci struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; 126562306a36Sopenharmony_ci uint32_t rscn_entry, host_pid; 126662306a36Sopenharmony_ci unsigned long flags; 126762306a36Sopenharmony_ci fc_port_t *fcport = NULL; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (!vha->hw->flags.fw_started) { 127062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x50ff, 127162306a36Sopenharmony_ci "Dropping AEN - %04x %04x %04x %04x.\n", 127262306a36Sopenharmony_ci mb[0], mb[1], mb[2], mb[3]); 127362306a36Sopenharmony_ci return; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Setup to process RIO completion. */ 127762306a36Sopenharmony_ci handle_cnt = 0; 127862306a36Sopenharmony_ci if (IS_CNA_CAPABLE(ha)) 127962306a36Sopenharmony_ci goto skip_rio; 128062306a36Sopenharmony_ci switch (mb[0]) { 128162306a36Sopenharmony_ci case MBA_SCSI_COMPLETION: 128262306a36Sopenharmony_ci handles[0] = make_handle(mb[2], mb[1]); 128362306a36Sopenharmony_ci handle_cnt = 1; 128462306a36Sopenharmony_ci break; 128562306a36Sopenharmony_ci case MBA_CMPLT_1_16BIT: 128662306a36Sopenharmony_ci handles[0] = mb[1]; 128762306a36Sopenharmony_ci handle_cnt = 1; 128862306a36Sopenharmony_ci mb[0] = MBA_SCSI_COMPLETION; 128962306a36Sopenharmony_ci break; 129062306a36Sopenharmony_ci case MBA_CMPLT_2_16BIT: 129162306a36Sopenharmony_ci handles[0] = mb[1]; 129262306a36Sopenharmony_ci handles[1] = mb[2]; 129362306a36Sopenharmony_ci handle_cnt = 2; 129462306a36Sopenharmony_ci mb[0] = MBA_SCSI_COMPLETION; 129562306a36Sopenharmony_ci break; 129662306a36Sopenharmony_ci case MBA_CMPLT_3_16BIT: 129762306a36Sopenharmony_ci handles[0] = mb[1]; 129862306a36Sopenharmony_ci handles[1] = mb[2]; 129962306a36Sopenharmony_ci handles[2] = mb[3]; 130062306a36Sopenharmony_ci handle_cnt = 3; 130162306a36Sopenharmony_ci mb[0] = MBA_SCSI_COMPLETION; 130262306a36Sopenharmony_ci break; 130362306a36Sopenharmony_ci case MBA_CMPLT_4_16BIT: 130462306a36Sopenharmony_ci handles[0] = mb[1]; 130562306a36Sopenharmony_ci handles[1] = mb[2]; 130662306a36Sopenharmony_ci handles[2] = mb[3]; 130762306a36Sopenharmony_ci handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6); 130862306a36Sopenharmony_ci handle_cnt = 4; 130962306a36Sopenharmony_ci mb[0] = MBA_SCSI_COMPLETION; 131062306a36Sopenharmony_ci break; 131162306a36Sopenharmony_ci case MBA_CMPLT_5_16BIT: 131262306a36Sopenharmony_ci handles[0] = mb[1]; 131362306a36Sopenharmony_ci handles[1] = mb[2]; 131462306a36Sopenharmony_ci handles[2] = mb[3]; 131562306a36Sopenharmony_ci handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6); 131662306a36Sopenharmony_ci handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7); 131762306a36Sopenharmony_ci handle_cnt = 5; 131862306a36Sopenharmony_ci mb[0] = MBA_SCSI_COMPLETION; 131962306a36Sopenharmony_ci break; 132062306a36Sopenharmony_ci case MBA_CMPLT_2_32BIT: 132162306a36Sopenharmony_ci handles[0] = make_handle(mb[2], mb[1]); 132262306a36Sopenharmony_ci handles[1] = make_handle(RD_MAILBOX_REG(ha, reg, 7), 132362306a36Sopenharmony_ci RD_MAILBOX_REG(ha, reg, 6)); 132462306a36Sopenharmony_ci handle_cnt = 2; 132562306a36Sopenharmony_ci mb[0] = MBA_SCSI_COMPLETION; 132662306a36Sopenharmony_ci break; 132762306a36Sopenharmony_ci default: 132862306a36Sopenharmony_ci break; 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ciskip_rio: 133162306a36Sopenharmony_ci switch (mb[0]) { 133262306a36Sopenharmony_ci case MBA_SCSI_COMPLETION: /* Fast Post */ 133362306a36Sopenharmony_ci if (!vha->flags.online) 133462306a36Sopenharmony_ci break; 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci for (cnt = 0; cnt < handle_cnt; cnt++) 133762306a36Sopenharmony_ci qla2x00_process_completed_request(vha, rsp->req, 133862306a36Sopenharmony_ci handles[cnt]); 133962306a36Sopenharmony_ci break; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci case MBA_RESET: /* Reset */ 134262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5002, 134362306a36Sopenharmony_ci "Asynchronous RESET.\n"); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); 134662306a36Sopenharmony_ci break; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci case MBA_SYSTEM_ERR: /* System Error */ 134962306a36Sopenharmony_ci mbx = 0; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci vha->hw_err_cnt++; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || 135462306a36Sopenharmony_ci IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 135562306a36Sopenharmony_ci u16 m[4]; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci m[0] = rd_reg_word(®24->mailbox4); 135862306a36Sopenharmony_ci m[1] = rd_reg_word(®24->mailbox5); 135962306a36Sopenharmony_ci m[2] = rd_reg_word(®24->mailbox6); 136062306a36Sopenharmony_ci mbx = m[3] = rd_reg_word(®24->mailbox7); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5003, 136362306a36Sopenharmony_ci "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh mbx4=%xh mbx5=%xh mbx6=%xh mbx7=%xh.\n", 136462306a36Sopenharmony_ci mb[1], mb[2], mb[3], m[0], m[1], m[2], m[3]); 136562306a36Sopenharmony_ci } else 136662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5003, 136762306a36Sopenharmony_ci "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n ", 136862306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if ((IS_QLA27XX(ha) || IS_QLA28XX(ha)) && 137162306a36Sopenharmony_ci rd_reg_word(®24->mailbox7) & BIT_8) 137262306a36Sopenharmony_ci ha->isp_ops->mpi_fw_dump(vha, 1); 137362306a36Sopenharmony_ci ha->isp_ops->fw_dump(vha); 137462306a36Sopenharmony_ci ha->flags.fw_init_done = 0; 137562306a36Sopenharmony_ci QLA_FW_STOPPED(ha); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 137862306a36Sopenharmony_ci if (mb[1] == 0 && mb[2] == 0) { 137962306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x5004, 138062306a36Sopenharmony_ci "Unrecoverable Hardware Error: adapter " 138162306a36Sopenharmony_ci "marked OFFLINE!\n"); 138262306a36Sopenharmony_ci vha->flags.online = 0; 138362306a36Sopenharmony_ci vha->device_flags |= DFLG_DEV_FAILED; 138462306a36Sopenharmony_ci } else { 138562306a36Sopenharmony_ci /* Check to see if MPI timeout occurred */ 138662306a36Sopenharmony_ci if ((mbx & MBX_3) && (ha->port_no == 0)) 138762306a36Sopenharmony_ci set_bit(MPI_RESET_NEEDED, 138862306a36Sopenharmony_ci &vha->dpc_flags); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 139162306a36Sopenharmony_ci } 139262306a36Sopenharmony_ci } else if (mb[1] == 0) { 139362306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x5005, 139462306a36Sopenharmony_ci "Unrecoverable Hardware Error: adapter marked " 139562306a36Sopenharmony_ci "OFFLINE!\n"); 139662306a36Sopenharmony_ci vha->flags.online = 0; 139762306a36Sopenharmony_ci vha->device_flags |= DFLG_DEV_FAILED; 139862306a36Sopenharmony_ci } else 139962306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 140062306a36Sopenharmony_ci break; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ 140362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5006, 140462306a36Sopenharmony_ci "ISP Request Transfer Error (%x).\n", mb[1]); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci vha->hw_err_cnt++; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 140962306a36Sopenharmony_ci break; 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ 141262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5007, 141362306a36Sopenharmony_ci "ISP Response Transfer Error (%x).\n", mb[1]); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci vha->hw_err_cnt++; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 141862306a36Sopenharmony_ci break; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ 142162306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5008, 142262306a36Sopenharmony_ci "Asynchronous WAKEUP_THRES (%x).\n", mb[1]); 142362306a36Sopenharmony_ci break; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci case MBA_LOOP_INIT_ERR: 142662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5090, 142762306a36Sopenharmony_ci "LOOP INIT ERROR (%x).\n", mb[1]); 142862306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 142962306a36Sopenharmony_ci break; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ 143262306a36Sopenharmony_ci ha->flags.lip_ae = 1; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5009, 143562306a36Sopenharmony_ci "LIP occurred (%x).\n", mb[1]); 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN) { 143862306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 143962306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); 144062306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 144162306a36Sopenharmony_ci } 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci if (vha->vp_idx) { 144462306a36Sopenharmony_ci atomic_set(&vha->vp_state, VP_FAILED); 144562306a36Sopenharmony_ci fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); 144962306a36Sopenharmony_ci set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 145262306a36Sopenharmony_ci qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]); 145362306a36Sopenharmony_ci break; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci case MBA_LOOP_UP: /* Loop Up Event */ 145662306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 145762306a36Sopenharmony_ci ha->link_data_rate = PORT_SPEED_1GB; 145862306a36Sopenharmony_ci else 145962306a36Sopenharmony_ci ha->link_data_rate = mb[1]; 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x500a, 146262306a36Sopenharmony_ci "LOOP UP detected (%s Gbps).\n", 146362306a36Sopenharmony_ci qla2x00_get_link_speed_str(ha, ha->link_data_rate)); 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_ci if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 146662306a36Sopenharmony_ci if (mb[2] & BIT_0) 146762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x11a0, 146862306a36Sopenharmony_ci "FEC=enabled (link up).\n"); 146962306a36Sopenharmony_ci } 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 147262306a36Sopenharmony_ci qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate); 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (vha->link_down_time < vha->hw->port_down_retry_count) { 147562306a36Sopenharmony_ci vha->short_link_down_cnt++; 147662306a36Sopenharmony_ci vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME; 147762306a36Sopenharmony_ci } 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci break; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci case MBA_LOOP_DOWN: /* Loop Down Event */ 148262306a36Sopenharmony_ci SAVE_TOPO(ha); 148362306a36Sopenharmony_ci ha->flags.lip_ae = 0; 148462306a36Sopenharmony_ci ha->current_topology = 0; 148562306a36Sopenharmony_ci vha->link_down_time = 0; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha)) 148862306a36Sopenharmony_ci ? rd_reg_word(®24->mailbox4) : 0; 148962306a36Sopenharmony_ci mbx = (IS_P3P_TYPE(ha)) ? rd_reg_word(®82->mailbox_out[4]) 149062306a36Sopenharmony_ci : mbx; 149162306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x500b, 149262306a36Sopenharmony_ci "LOOP DOWN detected (%x %x %x %x).\n", 149362306a36Sopenharmony_ci mb[1], mb[2], mb[3], mbx); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN) { 149662306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 149762306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); 149862306a36Sopenharmony_ci /* 149962306a36Sopenharmony_ci * In case of loop down, restore WWPN from 150062306a36Sopenharmony_ci * NVRAM in case of FA-WWPN capable ISP 150162306a36Sopenharmony_ci * Restore for Physical Port only 150262306a36Sopenharmony_ci */ 150362306a36Sopenharmony_ci if (!vha->vp_idx) { 150462306a36Sopenharmony_ci if (ha->flags.fawwpn_enabled && 150562306a36Sopenharmony_ci (ha->current_topology == ISP_CFG_F)) { 150662306a36Sopenharmony_ci memcpy(vha->port_name, ha->port_name, WWN_SIZE); 150762306a36Sopenharmony_ci fc_host_port_name(vha->host) = 150862306a36Sopenharmony_ci wwn_to_u64(vha->port_name); 150962306a36Sopenharmony_ci ql_dbg(ql_dbg_init + ql_dbg_verbose, 151062306a36Sopenharmony_ci vha, 0x00d8, "LOOP DOWN detected," 151162306a36Sopenharmony_ci "restore WWPN %016llx\n", 151262306a36Sopenharmony_ci wwn_to_u64(vha->port_name)); 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci clear_bit(VP_CONFIG_OK, &vha->vp_flags); 151662306a36Sopenharmony_ci } 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci vha->device_flags |= DFLG_NO_CABLE; 151962306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci if (vha->vp_idx) { 152362306a36Sopenharmony_ci atomic_set(&vha->vp_state, VP_FAILED); 152462306a36Sopenharmony_ci fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 152862306a36Sopenharmony_ci ha->link_data_rate = PORT_SPEED_UNKNOWN; 152962306a36Sopenharmony_ci qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0); 153062306a36Sopenharmony_ci break; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci case MBA_LIP_RESET: /* LIP reset occurred */ 153362306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x500c, 153462306a36Sopenharmony_ci "LIP reset occurred (%x).\n", mb[1]); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN) { 153762306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 153862306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); 153962306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (vha->vp_idx) { 154362306a36Sopenharmony_ci atomic_set(&vha->vp_state, VP_FAILED); 154462306a36Sopenharmony_ci fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci ha->operating_mode = LOOP; 155062306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 155162306a36Sopenharmony_ci qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]); 155262306a36Sopenharmony_ci break; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci /* case MBA_DCBX_COMPLETE: */ 155562306a36Sopenharmony_ci case MBA_POINT_TO_POINT: /* Point-to-Point */ 155662306a36Sopenharmony_ci ha->flags.lip_ae = 0; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci if (IS_QLA2100(ha)) 155962306a36Sopenharmony_ci break; 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci if (IS_CNA_CAPABLE(ha)) { 156262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x500d, 156362306a36Sopenharmony_ci "DCBX Completed -- %04x %04x %04x.\n", 156462306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 156562306a36Sopenharmony_ci if (ha->notify_dcbx_comp && !vha->vp_idx) 156662306a36Sopenharmony_ci complete(&ha->dcbx_comp); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci } else 156962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x500e, 157062306a36Sopenharmony_ci "Asynchronous P2P MODE received.\n"); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ci /* 157362306a36Sopenharmony_ci * Until there's a transition from loop down to loop up, treat 157462306a36Sopenharmony_ci * this as loop down only. 157562306a36Sopenharmony_ci */ 157662306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN) { 157762306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 157862306a36Sopenharmony_ci if (!atomic_read(&vha->loop_down_timer)) 157962306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 158062306a36Sopenharmony_ci LOOP_DOWN_TIME); 158162306a36Sopenharmony_ci if (!N2N_TOPO(ha)) 158262306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 158362306a36Sopenharmony_ci } 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (vha->vp_idx) { 158662306a36Sopenharmony_ci atomic_set(&vha->vp_state, VP_FAILED); 158762306a36Sopenharmony_ci fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci 159062306a36Sopenharmony_ci if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))) 159162306a36Sopenharmony_ci set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); 159462306a36Sopenharmony_ci set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 159762306a36Sopenharmony_ci break; 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci case MBA_CHG_IN_CONNECTION: /* Change in connection mode */ 160062306a36Sopenharmony_ci if (IS_QLA2100(ha)) 160162306a36Sopenharmony_ci break; 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x500f, 160462306a36Sopenharmony_ci "Configuration change detected: value=%x.\n", mb[1]); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN) { 160762306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 160862306a36Sopenharmony_ci if (!atomic_read(&vha->loop_down_timer)) 160962306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 161062306a36Sopenharmony_ci LOOP_DOWN_TIME); 161162306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci if (vha->vp_idx) { 161562306a36Sopenharmony_ci atomic_set(&vha->vp_state, VP_FAILED); 161662306a36Sopenharmony_ci fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 162062306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 162162306a36Sopenharmony_ci break; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci case MBA_PORT_UPDATE: /* Port database update */ 162462306a36Sopenharmony_ci /* 162562306a36Sopenharmony_ci * Handle only global and vn-port update events 162662306a36Sopenharmony_ci * 162762306a36Sopenharmony_ci * Relevant inputs: 162862306a36Sopenharmony_ci * mb[1] = N_Port handle of changed port 162962306a36Sopenharmony_ci * OR 0xffff for global event 163062306a36Sopenharmony_ci * mb[2] = New login state 163162306a36Sopenharmony_ci * 7 = Port logged out 163262306a36Sopenharmony_ci * mb[3] = LSB is vp_idx, 0xff = all vps 163362306a36Sopenharmony_ci * 163462306a36Sopenharmony_ci * Skip processing if: 163562306a36Sopenharmony_ci * Event is global, vp_idx is NOT all vps, 163662306a36Sopenharmony_ci * vp_idx does not match 163762306a36Sopenharmony_ci * Event is not global, vp_idx does not match 163862306a36Sopenharmony_ci */ 163962306a36Sopenharmony_ci if (IS_QLA2XXX_MIDTYPE(ha) && 164062306a36Sopenharmony_ci ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) || 164162306a36Sopenharmony_ci (mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff)) 164262306a36Sopenharmony_ci break; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci if (mb[2] == 0x7) { 164562306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5010, 164662306a36Sopenharmony_ci "Port %s %04x %04x %04x.\n", 164762306a36Sopenharmony_ci mb[1] == 0xffff ? "unavailable" : "logout", 164862306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_ci if (mb[1] == 0xffff) 165162306a36Sopenharmony_ci goto global_port_update; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci if (mb[1] == NPH_SNS_LID(ha)) { 165462306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 165562306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 165662306a36Sopenharmony_ci break; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci /* use handle_cnt for loop id/nport handle */ 166062306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) 166162306a36Sopenharmony_ci handle_cnt = NPH_SNS; 166262306a36Sopenharmony_ci else 166362306a36Sopenharmony_ci handle_cnt = SIMPLE_NAME_SERVER; 166462306a36Sopenharmony_ci if (mb[1] == handle_cnt) { 166562306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 166662306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 166762306a36Sopenharmony_ci break; 166862306a36Sopenharmony_ci } 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ci /* Port logout */ 167162306a36Sopenharmony_ci fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]); 167262306a36Sopenharmony_ci if (!fcport) 167362306a36Sopenharmony_ci break; 167462306a36Sopenharmony_ci if (atomic_read(&fcport->state) != FCS_ONLINE) 167562306a36Sopenharmony_ci break; 167662306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x508a, 167762306a36Sopenharmony_ci "Marking port lost loopid=%04x portid=%06x.\n", 167862306a36Sopenharmony_ci fcport->loop_id, fcport->d_id.b24); 167962306a36Sopenharmony_ci if (qla_ini_mode_enabled(vha)) { 168062306a36Sopenharmony_ci fcport->logout_on_delete = 0; 168162306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 168262306a36Sopenharmony_ci } 168362306a36Sopenharmony_ci break; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ciglobal_port_update: 168662306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN) { 168762306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_DOWN); 168862306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 168962306a36Sopenharmony_ci LOOP_DOWN_TIME); 169062306a36Sopenharmony_ci vha->device_flags |= DFLG_NO_CABLE; 169162306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 169262306a36Sopenharmony_ci } 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_ci if (vha->vp_idx) { 169562306a36Sopenharmony_ci atomic_set(&vha->vp_state, VP_FAILED); 169662306a36Sopenharmony_ci fc_vport_set_state(vha->fc_vport, 169762306a36Sopenharmony_ci FC_VPORT_FAILED); 169862306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 169962306a36Sopenharmony_ci } 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 170262306a36Sopenharmony_ci ha->link_data_rate = PORT_SPEED_UNKNOWN; 170362306a36Sopenharmony_ci break; 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci /* 170762306a36Sopenharmony_ci * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET 170862306a36Sopenharmony_ci * event etc. earlier indicating loop is down) then process 170962306a36Sopenharmony_ci * it. Otherwise ignore it and Wait for RSCN to come in. 171062306a36Sopenharmony_ci */ 171162306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 0); 171262306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) != LOOP_DOWN && 171362306a36Sopenharmony_ci !ha->flags.n2n_ae && 171462306a36Sopenharmony_ci atomic_read(&vha->loop_state) != LOOP_DEAD) { 171562306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5011, 171662306a36Sopenharmony_ci "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n", 171762306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 171862306a36Sopenharmony_ci break; 171962306a36Sopenharmony_ci } 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5012, 172262306a36Sopenharmony_ci "Port database changed %04x %04x %04x.\n", 172362306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci /* 172662306a36Sopenharmony_ci * Mark all devices as missing so we will login again. 172762306a36Sopenharmony_ci */ 172862306a36Sopenharmony_ci atomic_set(&vha->loop_state, LOOP_UP); 172962306a36Sopenharmony_ci vha->scan.scan_retry = 0; 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 173262306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 173362306a36Sopenharmony_ci set_bit(VP_CONFIG_OK, &vha->vp_flags); 173462306a36Sopenharmony_ci break; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci case MBA_RSCN_UPDATE: /* State Change Registration */ 173762306a36Sopenharmony_ci /* Check if the Vport has issued a SCR */ 173862306a36Sopenharmony_ci if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags)) 173962306a36Sopenharmony_ci break; 174062306a36Sopenharmony_ci /* Only handle SCNs for our Vport index. */ 174162306a36Sopenharmony_ci if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff)) 174262306a36Sopenharmony_ci break; 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5013, 174562306a36Sopenharmony_ci "RSCN database changed -- %04x %04x %04x.\n", 174662306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci rscn_entry = ((mb[1] & 0xff) << 16) | mb[2]; 174962306a36Sopenharmony_ci host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8) 175062306a36Sopenharmony_ci | vha->d_id.b.al_pa; 175162306a36Sopenharmony_ci if (rscn_entry == host_pid) { 175262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5014, 175362306a36Sopenharmony_ci "Ignoring RSCN update to local host " 175462306a36Sopenharmony_ci "port ID (%06x).\n", host_pid); 175562306a36Sopenharmony_ci break; 175662306a36Sopenharmony_ci } 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_ci /* Ignore reserved bits from RSCN-payload. */ 175962306a36Sopenharmony_ci rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2]; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci /* Skip RSCNs for virtual ports on the same physical port */ 176262306a36Sopenharmony_ci if (qla2x00_is_a_vp_did(vha, rscn_entry)) 176362306a36Sopenharmony_ci break; 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 0); 176662306a36Sopenharmony_ci vha->flags.management_server_logged_in = 0; 176762306a36Sopenharmony_ci { 176862306a36Sopenharmony_ci struct event_arg ea; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci memset(&ea, 0, sizeof(ea)); 177162306a36Sopenharmony_ci ea.id.b24 = rscn_entry; 177262306a36Sopenharmony_ci ea.id.b.rsvd_1 = rscn_entry >> 24; 177362306a36Sopenharmony_ci qla2x00_handle_rscn(vha, &ea); 177462306a36Sopenharmony_ci qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry); 177562306a36Sopenharmony_ci } 177662306a36Sopenharmony_ci break; 177762306a36Sopenharmony_ci case MBA_CONGN_NOTI_RECV: 177862306a36Sopenharmony_ci if (!ha->flags.scm_enabled || 177962306a36Sopenharmony_ci mb[1] != QLA_CON_PRIMITIVE_RECEIVED) 178062306a36Sopenharmony_ci break; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci if (mb[2] == QLA_CONGESTION_ARB_WARNING) { 178362306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x509b, 178462306a36Sopenharmony_ci "Congestion Warning %04x %04x.\n", mb[1], mb[2]); 178562306a36Sopenharmony_ci } else if (mb[2] == QLA_CONGESTION_ARB_ALARM) { 178662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x509b, 178762306a36Sopenharmony_ci "Congestion Alarm %04x %04x.\n", mb[1], mb[2]); 178862306a36Sopenharmony_ci } 178962306a36Sopenharmony_ci break; 179062306a36Sopenharmony_ci /* case MBA_RIO_RESPONSE: */ 179162306a36Sopenharmony_ci case MBA_ZIO_RESPONSE: 179262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5015, 179362306a36Sopenharmony_ci "[R|Z]IO update completion.\n"); 179462306a36Sopenharmony_ci 179562306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) 179662306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 179762306a36Sopenharmony_ci else 179862306a36Sopenharmony_ci qla2x00_process_response_queue(rsp); 179962306a36Sopenharmony_ci break; 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_ci case MBA_DISCARD_RND_FRAME: 180262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5016, 180362306a36Sopenharmony_ci "Discard RND Frame -- %04x %04x %04x.\n", 180462306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 180562306a36Sopenharmony_ci vha->interface_err_cnt++; 180662306a36Sopenharmony_ci break; 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci case MBA_TRACE_NOTIFICATION: 180962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5017, 181062306a36Sopenharmony_ci "Trace Notification -- %04x %04x.\n", mb[1], mb[2]); 181162306a36Sopenharmony_ci break; 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci case MBA_ISP84XX_ALERT: 181462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5018, 181562306a36Sopenharmony_ci "ISP84XX Alert Notification -- %04x %04x %04x.\n", 181662306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci spin_lock_irqsave(&ha->cs84xx->access_lock, flags); 181962306a36Sopenharmony_ci switch (mb[1]) { 182062306a36Sopenharmony_ci case A84_PANIC_RECOVERY: 182162306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x5019, 182262306a36Sopenharmony_ci "Alert 84XX: panic recovery %04x %04x.\n", 182362306a36Sopenharmony_ci mb[2], mb[3]); 182462306a36Sopenharmony_ci break; 182562306a36Sopenharmony_ci case A84_OP_LOGIN_COMPLETE: 182662306a36Sopenharmony_ci ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2]; 182762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x501a, 182862306a36Sopenharmony_ci "Alert 84XX: firmware version %x.\n", 182962306a36Sopenharmony_ci ha->cs84xx->op_fw_version); 183062306a36Sopenharmony_ci break; 183162306a36Sopenharmony_ci case A84_DIAG_LOGIN_COMPLETE: 183262306a36Sopenharmony_ci ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; 183362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x501b, 183462306a36Sopenharmony_ci "Alert 84XX: diagnostic firmware version %x.\n", 183562306a36Sopenharmony_ci ha->cs84xx->diag_fw_version); 183662306a36Sopenharmony_ci break; 183762306a36Sopenharmony_ci case A84_GOLD_LOGIN_COMPLETE: 183862306a36Sopenharmony_ci ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; 183962306a36Sopenharmony_ci ha->cs84xx->fw_update = 1; 184062306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x501c, 184162306a36Sopenharmony_ci "Alert 84XX: gold firmware version %x.\n", 184262306a36Sopenharmony_ci ha->cs84xx->gold_fw_version); 184362306a36Sopenharmony_ci break; 184462306a36Sopenharmony_ci default: 184562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x501d, 184662306a36Sopenharmony_ci "Alert 84xx: Invalid Alert %04x %04x %04x.\n", 184762306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 184862306a36Sopenharmony_ci } 184962306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags); 185062306a36Sopenharmony_ci break; 185162306a36Sopenharmony_ci case MBA_DCBX_START: 185262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x501e, 185362306a36Sopenharmony_ci "DCBX Started -- %04x %04x %04x.\n", 185462306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 185562306a36Sopenharmony_ci break; 185662306a36Sopenharmony_ci case MBA_DCBX_PARAM_UPDATE: 185762306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x501f, 185862306a36Sopenharmony_ci "DCBX Parameters Updated -- %04x %04x %04x.\n", 185962306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 186062306a36Sopenharmony_ci break; 186162306a36Sopenharmony_ci case MBA_FCF_CONF_ERR: 186262306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5020, 186362306a36Sopenharmony_ci "FCF Configuration Error -- %04x %04x %04x.\n", 186462306a36Sopenharmony_ci mb[1], mb[2], mb[3]); 186562306a36Sopenharmony_ci break; 186662306a36Sopenharmony_ci case MBA_IDC_NOTIFY: 186762306a36Sopenharmony_ci if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) { 186862306a36Sopenharmony_ci mb[4] = rd_reg_word(®24->mailbox4); 186962306a36Sopenharmony_ci if (((mb[2] & 0x7fff) == MBC_PORT_RESET || 187062306a36Sopenharmony_ci (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) && 187162306a36Sopenharmony_ci (mb[4] & INTERNAL_LOOPBACK_MASK) != 0) { 187262306a36Sopenharmony_ci set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); 187362306a36Sopenharmony_ci /* 187462306a36Sopenharmony_ci * Extend loop down timer since port is active. 187562306a36Sopenharmony_ci */ 187662306a36Sopenharmony_ci if (atomic_read(&vha->loop_state) == LOOP_DOWN) 187762306a36Sopenharmony_ci atomic_set(&vha->loop_down_timer, 187862306a36Sopenharmony_ci LOOP_DOWN_TIME); 187962306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci } 188262306a36Sopenharmony_ci fallthrough; 188362306a36Sopenharmony_ci case MBA_IDC_COMPLETE: 188462306a36Sopenharmony_ci if (ha->notify_lb_portup_comp && !vha->vp_idx) 188562306a36Sopenharmony_ci complete(&ha->lb_portup_comp); 188662306a36Sopenharmony_ci fallthrough; 188762306a36Sopenharmony_ci case MBA_IDC_TIME_EXT: 188862306a36Sopenharmony_ci if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) || 188962306a36Sopenharmony_ci IS_QLA8044(ha)) 189062306a36Sopenharmony_ci qla81xx_idc_event(vha, mb[0], mb[1]); 189162306a36Sopenharmony_ci break; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci case MBA_IDC_AEN: 189462306a36Sopenharmony_ci if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 189562306a36Sopenharmony_ci vha->hw_err_cnt++; 189662306a36Sopenharmony_ci qla27xx_handle_8200_aen(vha, mb); 189762306a36Sopenharmony_ci } else if (IS_QLA83XX(ha)) { 189862306a36Sopenharmony_ci mb[4] = rd_reg_word(®24->mailbox4); 189962306a36Sopenharmony_ci mb[5] = rd_reg_word(®24->mailbox5); 190062306a36Sopenharmony_ci mb[6] = rd_reg_word(®24->mailbox6); 190162306a36Sopenharmony_ci mb[7] = rd_reg_word(®24->mailbox7); 190262306a36Sopenharmony_ci qla83xx_handle_8200_aen(vha, mb); 190362306a36Sopenharmony_ci } else { 190462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5052, 190562306a36Sopenharmony_ci "skip Heartbeat processing mb0-3=[0x%04x] [0x%04x] [0x%04x] [0x%04x]\n", 190662306a36Sopenharmony_ci mb[0], mb[1], mb[2], mb[3]); 190762306a36Sopenharmony_ci } 190862306a36Sopenharmony_ci break; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci case MBA_DPORT_DIAGNOSTICS: 191162306a36Sopenharmony_ci if ((mb[1] & 0xF) == AEN_DONE_DIAG_TEST_WITH_NOERR || 191262306a36Sopenharmony_ci (mb[1] & 0xF) == AEN_DONE_DIAG_TEST_WITH_ERR) 191362306a36Sopenharmony_ci vha->dport_status &= ~DPORT_DIAG_IN_PROGRESS; 191462306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5052, 191562306a36Sopenharmony_ci "D-Port Diagnostics: %04x %04x %04x %04x\n", 191662306a36Sopenharmony_ci mb[0], mb[1], mb[2], mb[3]); 191762306a36Sopenharmony_ci memcpy(vha->dport_data, mb, sizeof(vha->dport_data)); 191862306a36Sopenharmony_ci if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) { 191962306a36Sopenharmony_ci static char *results[] = { 192062306a36Sopenharmony_ci "start", "done(pass)", "done(error)", "undefined" }; 192162306a36Sopenharmony_ci static char *types[] = { 192262306a36Sopenharmony_ci "none", "dynamic", "static", "other" }; 192362306a36Sopenharmony_ci uint result = mb[1] >> 0 & 0x3; 192462306a36Sopenharmony_ci uint type = mb[1] >> 6 & 0x3; 192562306a36Sopenharmony_ci uint sw = mb[1] >> 15 & 0x1; 192662306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5052, 192762306a36Sopenharmony_ci "D-Port Diagnostics: result=%s type=%s [sw=%u]\n", 192862306a36Sopenharmony_ci results[result], types[type], sw); 192962306a36Sopenharmony_ci if (result == 2) { 193062306a36Sopenharmony_ci static char *reasons[] = { 193162306a36Sopenharmony_ci "reserved", "unexpected reject", 193262306a36Sopenharmony_ci "unexpected phase", "retry exceeded", 193362306a36Sopenharmony_ci "timed out", "not supported", 193462306a36Sopenharmony_ci "user stopped" }; 193562306a36Sopenharmony_ci uint reason = mb[2] >> 0 & 0xf; 193662306a36Sopenharmony_ci uint phase = mb[2] >> 12 & 0xf; 193762306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5052, 193862306a36Sopenharmony_ci "D-Port Diagnostics: reason=%s phase=%u \n", 193962306a36Sopenharmony_ci reason < 7 ? reasons[reason] : "other", 194062306a36Sopenharmony_ci phase >> 1); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci } 194362306a36Sopenharmony_ci break; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci case MBA_TEMPERATURE_ALERT: 194662306a36Sopenharmony_ci if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) 194762306a36Sopenharmony_ci display_Laser_info(vha, mb[1], mb[2], mb[3]); 194862306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x505e, 194962306a36Sopenharmony_ci "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]); 195062306a36Sopenharmony_ci break; 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci case MBA_TRANS_INSERT: 195362306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5091, 195462306a36Sopenharmony_ci "Transceiver Insertion: %04x\n", mb[1]); 195562306a36Sopenharmony_ci set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags); 195662306a36Sopenharmony_ci break; 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci case MBA_TRANS_REMOVE: 195962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n"); 196062306a36Sopenharmony_ci break; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci default: 196362306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5057, 196462306a36Sopenharmony_ci "Unknown AEN:%04x %04x %04x %04x\n", 196562306a36Sopenharmony_ci mb[0], mb[1], mb[2], mb[3]); 196662306a36Sopenharmony_ci } 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci qlt_async_event(mb[0], vha, mb); 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (!vha->vp_idx && ha->num_vhosts) 197162306a36Sopenharmony_ci qla2x00_alert_all_vps(rsp, mb); 197262306a36Sopenharmony_ci} 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci/** 197562306a36Sopenharmony_ci * qla2x00_process_completed_request() - Process a Fast Post response. 197662306a36Sopenharmony_ci * @vha: SCSI driver HA context 197762306a36Sopenharmony_ci * @req: request queue 197862306a36Sopenharmony_ci * @index: SRB index 197962306a36Sopenharmony_ci */ 198062306a36Sopenharmony_civoid 198162306a36Sopenharmony_ciqla2x00_process_completed_request(struct scsi_qla_host *vha, 198262306a36Sopenharmony_ci struct req_que *req, uint32_t index) 198362306a36Sopenharmony_ci{ 198462306a36Sopenharmony_ci srb_t *sp; 198562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 198662306a36Sopenharmony_ci 198762306a36Sopenharmony_ci /* Validate handle. */ 198862306a36Sopenharmony_ci if (index >= req->num_outstanding_cmds) { 198962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x3014, 199062306a36Sopenharmony_ci "Invalid SCSI command index (%x).\n", index); 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) 199362306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); 199462306a36Sopenharmony_ci else 199562306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 199662306a36Sopenharmony_ci return; 199762306a36Sopenharmony_ci } 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_ci sp = req->outstanding_cmds[index]; 200062306a36Sopenharmony_ci if (sp) { 200162306a36Sopenharmony_ci /* Free outstanding command slot. */ 200262306a36Sopenharmony_ci req->outstanding_cmds[index] = NULL; 200362306a36Sopenharmony_ci 200462306a36Sopenharmony_ci /* Save ISP completion status */ 200562306a36Sopenharmony_ci sp->done(sp, DID_OK << 16); 200662306a36Sopenharmony_ci } else { 200762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n"); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) 201062306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); 201162306a36Sopenharmony_ci else 201262306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci} 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_cistatic srb_t * 201762306a36Sopenharmony_ciqla_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, 201862306a36Sopenharmony_ci struct req_que *req, void *iocb, u16 *ret_index) 201962306a36Sopenharmony_ci{ 202062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 202162306a36Sopenharmony_ci sts_entry_t *pkt = iocb; 202262306a36Sopenharmony_ci srb_t *sp; 202362306a36Sopenharmony_ci uint16_t index; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if (pkt->handle == QLA_SKIP_HANDLE) 202662306a36Sopenharmony_ci return NULL; 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci index = LSW(pkt->handle); 202962306a36Sopenharmony_ci if (index >= req->num_outstanding_cmds) { 203062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5031, 203162306a36Sopenharmony_ci "%s: Invalid command index (%x) type %8ph.\n", 203262306a36Sopenharmony_ci func, index, iocb); 203362306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) 203462306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); 203562306a36Sopenharmony_ci else 203662306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 203762306a36Sopenharmony_ci return NULL; 203862306a36Sopenharmony_ci } 203962306a36Sopenharmony_ci sp = req->outstanding_cmds[index]; 204062306a36Sopenharmony_ci if (!sp) { 204162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5032, 204262306a36Sopenharmony_ci "%s: Invalid completion handle (%x) -- timed-out.\n", 204362306a36Sopenharmony_ci func, index); 204462306a36Sopenharmony_ci return NULL; 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci if (sp->handle != index) { 204762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5033, 204862306a36Sopenharmony_ci "%s: SRB handle (%x) mismatch %x.\n", func, 204962306a36Sopenharmony_ci sp->handle, index); 205062306a36Sopenharmony_ci return NULL; 205162306a36Sopenharmony_ci } 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci *ret_index = index; 205462306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 205562306a36Sopenharmony_ci return sp; 205662306a36Sopenharmony_ci} 205762306a36Sopenharmony_ci 205862306a36Sopenharmony_cisrb_t * 205962306a36Sopenharmony_ciqla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, 206062306a36Sopenharmony_ci struct req_que *req, void *iocb) 206162306a36Sopenharmony_ci{ 206262306a36Sopenharmony_ci uint16_t index; 206362306a36Sopenharmony_ci srb_t *sp; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci sp = qla_get_sp_from_handle(vha, func, req, iocb, &index); 206662306a36Sopenharmony_ci if (sp) 206762306a36Sopenharmony_ci req->outstanding_cmds[index] = NULL; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci return sp; 207062306a36Sopenharmony_ci} 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_cistatic void 207362306a36Sopenharmony_ciqla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 207462306a36Sopenharmony_ci struct mbx_entry *mbx) 207562306a36Sopenharmony_ci{ 207662306a36Sopenharmony_ci const char func[] = "MBX-IOCB"; 207762306a36Sopenharmony_ci const char *type; 207862306a36Sopenharmony_ci fc_port_t *fcport; 207962306a36Sopenharmony_ci srb_t *sp; 208062306a36Sopenharmony_ci struct srb_iocb *lio; 208162306a36Sopenharmony_ci uint16_t *data; 208262306a36Sopenharmony_ci uint16_t status; 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, mbx); 208562306a36Sopenharmony_ci if (!sp) 208662306a36Sopenharmony_ci return; 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_ci lio = &sp->u.iocb_cmd; 208962306a36Sopenharmony_ci type = sp->name; 209062306a36Sopenharmony_ci fcport = sp->fcport; 209162306a36Sopenharmony_ci data = lio->u.logio.data; 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci data[0] = MBS_COMMAND_ERROR; 209462306a36Sopenharmony_ci data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? 209562306a36Sopenharmony_ci QLA_LOGIO_LOGIN_RETRIED : 0; 209662306a36Sopenharmony_ci if (mbx->entry_status) { 209762306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5043, 209862306a36Sopenharmony_ci "Async-%s error entry - hdl=%x portid=%02x%02x%02x " 209962306a36Sopenharmony_ci "entry-status=%x status=%x state-flag=%x " 210062306a36Sopenharmony_ci "status-flags=%x.\n", type, sp->handle, 210162306a36Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, 210262306a36Sopenharmony_ci fcport->d_id.b.al_pa, mbx->entry_status, 210362306a36Sopenharmony_ci le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags), 210462306a36Sopenharmony_ci le16_to_cpu(mbx->status_flags)); 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029, 210762306a36Sopenharmony_ci mbx, sizeof(*mbx)); 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci goto logio_done; 211062306a36Sopenharmony_ci } 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci status = le16_to_cpu(mbx->status); 211362306a36Sopenharmony_ci if (status == 0x30 && sp->type == SRB_LOGIN_CMD && 211462306a36Sopenharmony_ci le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) 211562306a36Sopenharmony_ci status = 0; 211662306a36Sopenharmony_ci if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { 211762306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5045, 211862306a36Sopenharmony_ci "Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n", 211962306a36Sopenharmony_ci type, sp->handle, fcport->d_id.b.domain, 212062306a36Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa, 212162306a36Sopenharmony_ci le16_to_cpu(mbx->mb1)); 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci data[0] = MBS_COMMAND_COMPLETE; 212462306a36Sopenharmony_ci if (sp->type == SRB_LOGIN_CMD) { 212562306a36Sopenharmony_ci fcport->port_type = FCT_TARGET; 212662306a36Sopenharmony_ci if (le16_to_cpu(mbx->mb1) & BIT_0) 212762306a36Sopenharmony_ci fcport->port_type = FCT_INITIATOR; 212862306a36Sopenharmony_ci else if (le16_to_cpu(mbx->mb1) & BIT_1) 212962306a36Sopenharmony_ci fcport->flags |= FCF_FCP2_DEVICE; 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_ci goto logio_done; 213262306a36Sopenharmony_ci } 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci data[0] = le16_to_cpu(mbx->mb0); 213562306a36Sopenharmony_ci switch (data[0]) { 213662306a36Sopenharmony_ci case MBS_PORT_ID_USED: 213762306a36Sopenharmony_ci data[1] = le16_to_cpu(mbx->mb1); 213862306a36Sopenharmony_ci break; 213962306a36Sopenharmony_ci case MBS_LOOP_ID_USED: 214062306a36Sopenharmony_ci break; 214162306a36Sopenharmony_ci default: 214262306a36Sopenharmony_ci data[0] = MBS_COMMAND_ERROR; 214362306a36Sopenharmony_ci break; 214462306a36Sopenharmony_ci } 214562306a36Sopenharmony_ci 214662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5046, 214762306a36Sopenharmony_ci "Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x " 214862306a36Sopenharmony_ci "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle, 214962306a36Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, 215062306a36Sopenharmony_ci status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), 215162306a36Sopenharmony_ci le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), 215262306a36Sopenharmony_ci le16_to_cpu(mbx->mb7)); 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_cilogio_done: 215562306a36Sopenharmony_ci sp->done(sp, 0); 215662306a36Sopenharmony_ci} 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_cistatic void 215962306a36Sopenharmony_ciqla24xx_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 216062306a36Sopenharmony_ci struct mbx_24xx_entry *pkt) 216162306a36Sopenharmony_ci{ 216262306a36Sopenharmony_ci const char func[] = "MBX-IOCB2"; 216362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 216462306a36Sopenharmony_ci srb_t *sp; 216562306a36Sopenharmony_ci struct srb_iocb *si; 216662306a36Sopenharmony_ci u16 sz, i; 216762306a36Sopenharmony_ci int res; 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 217062306a36Sopenharmony_ci if (!sp) 217162306a36Sopenharmony_ci return; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci if (sp->type == SRB_SCSI_CMD || 217462306a36Sopenharmony_ci sp->type == SRB_NVME_CMD || 217562306a36Sopenharmony_ci sp->type == SRB_TM_CMD) { 217662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x509d, 217762306a36Sopenharmony_ci "Inconsistent event entry type %d\n", sp->type); 217862306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) 217962306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); 218062306a36Sopenharmony_ci else 218162306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 218262306a36Sopenharmony_ci return; 218362306a36Sopenharmony_ci } 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci si = &sp->u.iocb_cmd; 218662306a36Sopenharmony_ci sz = min(ARRAY_SIZE(pkt->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.in_mb)); 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_ci for (i = 0; i < sz; i++) 218962306a36Sopenharmony_ci si->u.mbx.in_mb[i] = pkt->mb[i]; 219062306a36Sopenharmony_ci 219162306a36Sopenharmony_ci res = (si->u.mbx.in_mb[0] & MBS_MASK); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci sp->done(sp, res); 219462306a36Sopenharmony_ci} 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_cistatic void 219762306a36Sopenharmony_ciqla24xxx_nack_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 219862306a36Sopenharmony_ci struct nack_to_isp *pkt) 219962306a36Sopenharmony_ci{ 220062306a36Sopenharmony_ci const char func[] = "nack"; 220162306a36Sopenharmony_ci srb_t *sp; 220262306a36Sopenharmony_ci int res = 0; 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 220562306a36Sopenharmony_ci if (!sp) 220662306a36Sopenharmony_ci return; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci if (pkt->u.isp2x.status != cpu_to_le16(NOTIFY_ACK_SUCCESS)) 220962306a36Sopenharmony_ci res = QLA_FUNCTION_FAILED; 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci sp->done(sp, res); 221262306a36Sopenharmony_ci} 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_cistatic void 221562306a36Sopenharmony_ciqla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req, 221662306a36Sopenharmony_ci sts_entry_t *pkt, int iocb_type) 221762306a36Sopenharmony_ci{ 221862306a36Sopenharmony_ci const char func[] = "CT_IOCB"; 221962306a36Sopenharmony_ci const char *type; 222062306a36Sopenharmony_ci srb_t *sp; 222162306a36Sopenharmony_ci struct bsg_job *bsg_job; 222262306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply; 222362306a36Sopenharmony_ci uint16_t comp_status; 222462306a36Sopenharmony_ci int res = 0; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 222762306a36Sopenharmony_ci if (!sp) 222862306a36Sopenharmony_ci return; 222962306a36Sopenharmony_ci 223062306a36Sopenharmony_ci switch (sp->type) { 223162306a36Sopenharmony_ci case SRB_CT_CMD: 223262306a36Sopenharmony_ci bsg_job = sp->u.bsg_job; 223362306a36Sopenharmony_ci bsg_reply = bsg_job->reply; 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci type = "ct pass-through"; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci comp_status = le16_to_cpu(pkt->comp_status); 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci /* 224062306a36Sopenharmony_ci * return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT 224162306a36Sopenharmony_ci * fc payload to the caller 224262306a36Sopenharmony_ci */ 224362306a36Sopenharmony_ci bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; 224462306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_ci if (comp_status != CS_COMPLETE) { 224762306a36Sopenharmony_ci if (comp_status == CS_DATA_UNDERRUN) { 224862306a36Sopenharmony_ci res = DID_OK << 16; 224962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 225062306a36Sopenharmony_ci le16_to_cpu(pkt->rsp_info_len); 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5048, 225362306a36Sopenharmony_ci "CT pass-through-%s error comp_status=0x%x total_byte=0x%x.\n", 225462306a36Sopenharmony_ci type, comp_status, 225562306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len); 225662306a36Sopenharmony_ci } else { 225762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5049, 225862306a36Sopenharmony_ci "CT pass-through-%s error comp_status=0x%x.\n", 225962306a36Sopenharmony_ci type, comp_status); 226062306a36Sopenharmony_ci res = DID_ERROR << 16; 226162306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035, 226462306a36Sopenharmony_ci pkt, sizeof(*pkt)); 226562306a36Sopenharmony_ci } else { 226662306a36Sopenharmony_ci res = DID_OK << 16; 226762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 226862306a36Sopenharmony_ci bsg_job->reply_payload.payload_len; 226962306a36Sopenharmony_ci bsg_job->reply_len = 0; 227062306a36Sopenharmony_ci } 227162306a36Sopenharmony_ci break; 227262306a36Sopenharmony_ci case SRB_CT_PTHRU_CMD: 227362306a36Sopenharmony_ci /* 227462306a36Sopenharmony_ci * borrowing sts_entry_24xx.comp_status. 227562306a36Sopenharmony_ci * same location as ct_entry_24xx.comp_status 227662306a36Sopenharmony_ci */ 227762306a36Sopenharmony_ci res = qla2x00_chk_ms_status(vha, (ms_iocb_entry_t *)pkt, 227862306a36Sopenharmony_ci (struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp, 227962306a36Sopenharmony_ci sp->name); 228062306a36Sopenharmony_ci break; 228162306a36Sopenharmony_ci } 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci sp->done(sp, res); 228462306a36Sopenharmony_ci} 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_cistatic void 228762306a36Sopenharmony_ciqla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req, 228862306a36Sopenharmony_ci struct sts_entry_24xx *pkt, int iocb_type) 228962306a36Sopenharmony_ci{ 229062306a36Sopenharmony_ci struct els_sts_entry_24xx *ese = (struct els_sts_entry_24xx *)pkt; 229162306a36Sopenharmony_ci const char func[] = "ELS_CT_IOCB"; 229262306a36Sopenharmony_ci const char *type; 229362306a36Sopenharmony_ci srb_t *sp; 229462306a36Sopenharmony_ci struct bsg_job *bsg_job; 229562306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply; 229662306a36Sopenharmony_ci uint16_t comp_status; 229762306a36Sopenharmony_ci uint32_t fw_status[3]; 229862306a36Sopenharmony_ci int res, logit = 1; 229962306a36Sopenharmony_ci struct srb_iocb *els; 230062306a36Sopenharmony_ci uint n; 230162306a36Sopenharmony_ci scsi_qla_host_t *vha; 230262306a36Sopenharmony_ci struct els_sts_entry_24xx *e = (struct els_sts_entry_24xx *)pkt; 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(v, func, req, pkt); 230562306a36Sopenharmony_ci if (!sp) 230662306a36Sopenharmony_ci return; 230762306a36Sopenharmony_ci bsg_job = sp->u.bsg_job; 230862306a36Sopenharmony_ci vha = sp->vha; 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci type = NULL; 231162306a36Sopenharmony_ci 231262306a36Sopenharmony_ci comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status); 231362306a36Sopenharmony_ci fw_status[1] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_1); 231462306a36Sopenharmony_ci fw_status[2] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_2); 231562306a36Sopenharmony_ci 231662306a36Sopenharmony_ci switch (sp->type) { 231762306a36Sopenharmony_ci case SRB_ELS_CMD_RPT: 231862306a36Sopenharmony_ci case SRB_ELS_CMD_HST: 231962306a36Sopenharmony_ci type = "rpt hst"; 232062306a36Sopenharmony_ci break; 232162306a36Sopenharmony_ci case SRB_ELS_CMD_HST_NOLOGIN: 232262306a36Sopenharmony_ci type = "els"; 232362306a36Sopenharmony_ci { 232462306a36Sopenharmony_ci struct els_entry_24xx *els = (void *)pkt; 232562306a36Sopenharmony_ci struct qla_bsg_auth_els_request *p = 232662306a36Sopenharmony_ci (struct qla_bsg_auth_els_request *)bsg_job->request; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x700f, 232962306a36Sopenharmony_ci "%s %s. portid=%02x%02x%02x status %x xchg %x bsg ptr %p\n", 233062306a36Sopenharmony_ci __func__, sc_to_str(p->e.sub_cmd), 233162306a36Sopenharmony_ci e->d_id[2], e->d_id[1], e->d_id[0], 233262306a36Sopenharmony_ci comp_status, p->e.extra_rx_xchg_address, bsg_job); 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci if (!(le16_to_cpu(els->control_flags) & ECF_PAYLOAD_DESCR_MASK)) { 233562306a36Sopenharmony_ci if (sp->remap.remapped) { 233662306a36Sopenharmony_ci n = sg_copy_from_buffer(bsg_job->reply_payload.sg_list, 233762306a36Sopenharmony_ci bsg_job->reply_payload.sg_cnt, 233862306a36Sopenharmony_ci sp->remap.rsp.buf, 233962306a36Sopenharmony_ci sp->remap.rsp.len); 234062306a36Sopenharmony_ci ql_dbg(ql_dbg_user + ql_dbg_verbose, vha, 0x700e, 234162306a36Sopenharmony_ci "%s: SG copied %x of %x\n", 234262306a36Sopenharmony_ci __func__, n, sp->remap.rsp.len); 234362306a36Sopenharmony_ci } else { 234462306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x700f, 234562306a36Sopenharmony_ci "%s: NOT REMAPPED (error)...!!!\n", 234662306a36Sopenharmony_ci __func__); 234762306a36Sopenharmony_ci } 234862306a36Sopenharmony_ci } 234962306a36Sopenharmony_ci } 235062306a36Sopenharmony_ci break; 235162306a36Sopenharmony_ci case SRB_CT_CMD: 235262306a36Sopenharmony_ci type = "ct pass-through"; 235362306a36Sopenharmony_ci break; 235462306a36Sopenharmony_ci case SRB_ELS_DCMD: 235562306a36Sopenharmony_ci type = "Driver ELS logo"; 235662306a36Sopenharmony_ci if (iocb_type != ELS_IOCB_TYPE) { 235762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x5047, 235862306a36Sopenharmony_ci "Completing %s: (%p) type=%d.\n", 235962306a36Sopenharmony_ci type, sp, sp->type); 236062306a36Sopenharmony_ci sp->done(sp, 0); 236162306a36Sopenharmony_ci return; 236262306a36Sopenharmony_ci } 236362306a36Sopenharmony_ci break; 236462306a36Sopenharmony_ci case SRB_CT_PTHRU_CMD: 236562306a36Sopenharmony_ci /* borrowing sts_entry_24xx.comp_status. 236662306a36Sopenharmony_ci same location as ct_entry_24xx.comp_status 236762306a36Sopenharmony_ci */ 236862306a36Sopenharmony_ci res = qla2x00_chk_ms_status(sp->vha, (ms_iocb_entry_t *)pkt, 236962306a36Sopenharmony_ci (struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp, 237062306a36Sopenharmony_ci sp->name); 237162306a36Sopenharmony_ci sp->done(sp, res); 237262306a36Sopenharmony_ci return; 237362306a36Sopenharmony_ci default: 237462306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x503e, 237562306a36Sopenharmony_ci "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type); 237662306a36Sopenharmony_ci return; 237762306a36Sopenharmony_ci } 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci if (iocb_type == ELS_IOCB_TYPE) { 238062306a36Sopenharmony_ci els = &sp->u.iocb_cmd; 238162306a36Sopenharmony_ci els->u.els_plogi.fw_status[0] = cpu_to_le32(fw_status[0]); 238262306a36Sopenharmony_ci els->u.els_plogi.fw_status[1] = cpu_to_le32(fw_status[1]); 238362306a36Sopenharmony_ci els->u.els_plogi.fw_status[2] = cpu_to_le32(fw_status[2]); 238462306a36Sopenharmony_ci els->u.els_plogi.comp_status = cpu_to_le16(fw_status[0]); 238562306a36Sopenharmony_ci if (comp_status == CS_COMPLETE) { 238662306a36Sopenharmony_ci res = DID_OK << 16; 238762306a36Sopenharmony_ci } else { 238862306a36Sopenharmony_ci if (comp_status == CS_DATA_UNDERRUN) { 238962306a36Sopenharmony_ci res = DID_OK << 16; 239062306a36Sopenharmony_ci els->u.els_plogi.len = cpu_to_le16(le32_to_cpu( 239162306a36Sopenharmony_ci ese->total_byte_count)); 239262306a36Sopenharmony_ci 239362306a36Sopenharmony_ci if (sp->remap.remapped && 239462306a36Sopenharmony_ci ((u8 *)sp->remap.rsp.buf)[0] == ELS_LS_ACC) { 239562306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x503f, 239662306a36Sopenharmony_ci "%s IOCB Done LS_ACC %02x%02x%02x -> %02x%02x%02x", 239762306a36Sopenharmony_ci __func__, e->s_id[0], e->s_id[2], e->s_id[1], 239862306a36Sopenharmony_ci e->d_id[2], e->d_id[1], e->d_id[0]); 239962306a36Sopenharmony_ci logit = 0; 240062306a36Sopenharmony_ci } 240162306a36Sopenharmony_ci 240262306a36Sopenharmony_ci } else if (comp_status == CS_PORT_LOGGED_OUT) { 240362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x911e, 240462306a36Sopenharmony_ci "%s %d schedule session deletion\n", 240562306a36Sopenharmony_ci __func__, __LINE__); 240662306a36Sopenharmony_ci 240762306a36Sopenharmony_ci els->u.els_plogi.len = 0; 240862306a36Sopenharmony_ci res = DID_IMM_RETRY << 16; 240962306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(sp->fcport); 241062306a36Sopenharmony_ci } else { 241162306a36Sopenharmony_ci els->u.els_plogi.len = 0; 241262306a36Sopenharmony_ci res = DID_ERROR << 16; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci if (sp->remap.remapped && 241662306a36Sopenharmony_ci ((u8 *)sp->remap.rsp.buf)[0] == ELS_LS_RJT) { 241762306a36Sopenharmony_ci if (logit) { 241862306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x503f, 241962306a36Sopenharmony_ci "%s IOCB Done LS_RJT hdl=%x comp_status=0x%x\n", 242062306a36Sopenharmony_ci type, sp->handle, comp_status); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x503f, 242362306a36Sopenharmony_ci "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n", 242462306a36Sopenharmony_ci fw_status[1], fw_status[2], 242562306a36Sopenharmony_ci le32_to_cpu(((struct els_sts_entry_24xx *) 242662306a36Sopenharmony_ci pkt)->total_byte_count), 242762306a36Sopenharmony_ci e->s_id[0], e->s_id[2], e->s_id[1], 242862306a36Sopenharmony_ci e->d_id[2], e->d_id[1], e->d_id[0]); 242962306a36Sopenharmony_ci } 243062306a36Sopenharmony_ci if (sp->fcport && sp->fcport->flags & FCF_FCSP_DEVICE && 243162306a36Sopenharmony_ci sp->type == SRB_ELS_CMD_HST_NOLOGIN) { 243262306a36Sopenharmony_ci ql_dbg(ql_dbg_edif, vha, 0x911e, 243362306a36Sopenharmony_ci "%s rcv reject. Sched delete\n", __func__); 243462306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(sp->fcport); 243562306a36Sopenharmony_ci } 243662306a36Sopenharmony_ci } else if (logit) { 243762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x503f, 243862306a36Sopenharmony_ci "%s IOCB Done hdl=%x comp_status=0x%x\n", 243962306a36Sopenharmony_ci type, sp->handle, comp_status); 244062306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x503f, 244162306a36Sopenharmony_ci "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n", 244262306a36Sopenharmony_ci fw_status[1], fw_status[2], 244362306a36Sopenharmony_ci le32_to_cpu(((struct els_sts_entry_24xx *) 244462306a36Sopenharmony_ci pkt)->total_byte_count), 244562306a36Sopenharmony_ci e->s_id[0], e->s_id[2], e->s_id[1], 244662306a36Sopenharmony_ci e->d_id[2], e->d_id[1], e->d_id[0]); 244762306a36Sopenharmony_ci } 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci goto els_ct_done; 245062306a36Sopenharmony_ci } 245162306a36Sopenharmony_ci 245262306a36Sopenharmony_ci /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT 245362306a36Sopenharmony_ci * fc payload to the caller 245462306a36Sopenharmony_ci */ 245562306a36Sopenharmony_ci bsg_job = sp->u.bsg_job; 245662306a36Sopenharmony_ci bsg_reply = bsg_job->reply; 245762306a36Sopenharmony_ci bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; 245862306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status); 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci if (comp_status != CS_COMPLETE) { 246162306a36Sopenharmony_ci if (comp_status == CS_DATA_UNDERRUN) { 246262306a36Sopenharmony_ci res = DID_OK << 16; 246362306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 246462306a36Sopenharmony_ci le32_to_cpu(ese->total_byte_count); 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x503f, 246762306a36Sopenharmony_ci "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x " 246862306a36Sopenharmony_ci "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n", 246962306a36Sopenharmony_ci type, sp->handle, comp_status, fw_status[1], fw_status[2], 247062306a36Sopenharmony_ci le32_to_cpu(ese->total_byte_count)); 247162306a36Sopenharmony_ci } else { 247262306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x5040, 247362306a36Sopenharmony_ci "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x " 247462306a36Sopenharmony_ci "error subcode 1=0x%x error subcode 2=0x%x.\n", 247562306a36Sopenharmony_ci type, sp->handle, comp_status, 247662306a36Sopenharmony_ci le32_to_cpu(ese->error_subcode_1), 247762306a36Sopenharmony_ci le32_to_cpu(ese->error_subcode_2)); 247862306a36Sopenharmony_ci res = DID_ERROR << 16; 247962306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 248062306a36Sopenharmony_ci } 248162306a36Sopenharmony_ci memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply), 248262306a36Sopenharmony_ci fw_status, sizeof(fw_status)); 248362306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056, 248462306a36Sopenharmony_ci pkt, sizeof(*pkt)); 248562306a36Sopenharmony_ci } 248662306a36Sopenharmony_ci else { 248762306a36Sopenharmony_ci res = DID_OK << 16; 248862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; 248962306a36Sopenharmony_ci bsg_job->reply_len = 0; 249062306a36Sopenharmony_ci } 249162306a36Sopenharmony_ciels_ct_done: 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci sp->done(sp, res); 249462306a36Sopenharmony_ci} 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_cistatic void 249762306a36Sopenharmony_ciqla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, 249862306a36Sopenharmony_ci struct logio_entry_24xx *logio) 249962306a36Sopenharmony_ci{ 250062306a36Sopenharmony_ci const char func[] = "LOGIO-IOCB"; 250162306a36Sopenharmony_ci const char *type; 250262306a36Sopenharmony_ci fc_port_t *fcport; 250362306a36Sopenharmony_ci srb_t *sp; 250462306a36Sopenharmony_ci struct srb_iocb *lio; 250562306a36Sopenharmony_ci uint16_t *data; 250662306a36Sopenharmony_ci uint32_t iop[2]; 250762306a36Sopenharmony_ci int logit = 1; 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, logio); 251062306a36Sopenharmony_ci if (!sp) 251162306a36Sopenharmony_ci return; 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_ci lio = &sp->u.iocb_cmd; 251462306a36Sopenharmony_ci type = sp->name; 251562306a36Sopenharmony_ci fcport = sp->fcport; 251662306a36Sopenharmony_ci data = lio->u.logio.data; 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci data[0] = MBS_COMMAND_ERROR; 251962306a36Sopenharmony_ci data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? 252062306a36Sopenharmony_ci QLA_LOGIO_LOGIN_RETRIED : 0; 252162306a36Sopenharmony_ci if (logio->entry_status) { 252262306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x5034, 252362306a36Sopenharmony_ci "Async-%s error entry - %8phC hdl=%x" 252462306a36Sopenharmony_ci "portid=%02x%02x%02x entry-status=%x.\n", 252562306a36Sopenharmony_ci type, fcport->port_name, sp->handle, fcport->d_id.b.domain, 252662306a36Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa, 252762306a36Sopenharmony_ci logio->entry_status); 252862306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d, 252962306a36Sopenharmony_ci logio, sizeof(*logio)); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci goto logio_done; 253262306a36Sopenharmony_ci } 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { 253562306a36Sopenharmony_ci ql_dbg(ql_dbg_async, sp->vha, 0x5036, 253662306a36Sopenharmony_ci "Async-%s complete: handle=%x pid=%06x wwpn=%8phC iop0=%x\n", 253762306a36Sopenharmony_ci type, sp->handle, fcport->d_id.b24, fcport->port_name, 253862306a36Sopenharmony_ci le32_to_cpu(logio->io_parameter[0])); 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci vha->hw->exch_starvation = 0; 254162306a36Sopenharmony_ci data[0] = MBS_COMMAND_COMPLETE; 254262306a36Sopenharmony_ci 254362306a36Sopenharmony_ci if (sp->type == SRB_PRLI_CMD) { 254462306a36Sopenharmony_ci lio->u.logio.iop[0] = 254562306a36Sopenharmony_ci le32_to_cpu(logio->io_parameter[0]); 254662306a36Sopenharmony_ci lio->u.logio.iop[1] = 254762306a36Sopenharmony_ci le32_to_cpu(logio->io_parameter[1]); 254862306a36Sopenharmony_ci goto logio_done; 254962306a36Sopenharmony_ci } 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci if (sp->type != SRB_LOGIN_CMD) 255262306a36Sopenharmony_ci goto logio_done; 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci lio->u.logio.iop[1] = le32_to_cpu(logio->io_parameter[5]); 255562306a36Sopenharmony_ci if (le32_to_cpu(logio->io_parameter[5]) & LIO_COMM_FEAT_FCSP) 255662306a36Sopenharmony_ci fcport->flags |= FCF_FCSP_DEVICE; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci iop[0] = le32_to_cpu(logio->io_parameter[0]); 255962306a36Sopenharmony_ci if (iop[0] & BIT_4) { 256062306a36Sopenharmony_ci fcport->port_type = FCT_TARGET; 256162306a36Sopenharmony_ci if (iop[0] & BIT_8) 256262306a36Sopenharmony_ci fcport->flags |= FCF_FCP2_DEVICE; 256362306a36Sopenharmony_ci } else if (iop[0] & BIT_5) 256462306a36Sopenharmony_ci fcport->port_type = FCT_INITIATOR; 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci if (iop[0] & BIT_7) 256762306a36Sopenharmony_ci fcport->flags |= FCF_CONF_COMP_SUPPORTED; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci if (logio->io_parameter[7] || logio->io_parameter[8]) 257062306a36Sopenharmony_ci fcport->supported_classes |= FC_COS_CLASS2; 257162306a36Sopenharmony_ci if (logio->io_parameter[9] || logio->io_parameter[10]) 257262306a36Sopenharmony_ci fcport->supported_classes |= FC_COS_CLASS3; 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci goto logio_done; 257562306a36Sopenharmony_ci } 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_ci iop[0] = le32_to_cpu(logio->io_parameter[0]); 257862306a36Sopenharmony_ci iop[1] = le32_to_cpu(logio->io_parameter[1]); 257962306a36Sopenharmony_ci lio->u.logio.iop[0] = iop[0]; 258062306a36Sopenharmony_ci lio->u.logio.iop[1] = iop[1]; 258162306a36Sopenharmony_ci switch (iop[0]) { 258262306a36Sopenharmony_ci case LSC_SCODE_PORTID_USED: 258362306a36Sopenharmony_ci data[0] = MBS_PORT_ID_USED; 258462306a36Sopenharmony_ci data[1] = LSW(iop[1]); 258562306a36Sopenharmony_ci logit = 0; 258662306a36Sopenharmony_ci break; 258762306a36Sopenharmony_ci case LSC_SCODE_NPORT_USED: 258862306a36Sopenharmony_ci data[0] = MBS_LOOP_ID_USED; 258962306a36Sopenharmony_ci logit = 0; 259062306a36Sopenharmony_ci break; 259162306a36Sopenharmony_ci case LSC_SCODE_CMD_FAILED: 259262306a36Sopenharmony_ci if (iop[1] == 0x0606) { 259362306a36Sopenharmony_ci /* 259462306a36Sopenharmony_ci * PLOGI/PRLI Completed. We must have Recv PLOGI/PRLI, 259562306a36Sopenharmony_ci * Target side acked. 259662306a36Sopenharmony_ci */ 259762306a36Sopenharmony_ci data[0] = MBS_COMMAND_COMPLETE; 259862306a36Sopenharmony_ci goto logio_done; 259962306a36Sopenharmony_ci } 260062306a36Sopenharmony_ci data[0] = MBS_COMMAND_ERROR; 260162306a36Sopenharmony_ci break; 260262306a36Sopenharmony_ci case LSC_SCODE_NOXCB: 260362306a36Sopenharmony_ci vha->hw->exch_starvation++; 260462306a36Sopenharmony_ci if (vha->hw->exch_starvation > 5) { 260562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd046, 260662306a36Sopenharmony_ci "Exchange starvation. Resetting RISC\n"); 260762306a36Sopenharmony_ci 260862306a36Sopenharmony_ci vha->hw->exch_starvation = 0; 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci if (IS_P3P_TYPE(vha->hw)) 261162306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); 261262306a36Sopenharmony_ci else 261362306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 261462306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 261562306a36Sopenharmony_ci } 261662306a36Sopenharmony_ci fallthrough; 261762306a36Sopenharmony_ci default: 261862306a36Sopenharmony_ci data[0] = MBS_COMMAND_ERROR; 261962306a36Sopenharmony_ci break; 262062306a36Sopenharmony_ci } 262162306a36Sopenharmony_ci 262262306a36Sopenharmony_ci if (logit) 262362306a36Sopenharmony_ci ql_log(ql_log_warn, sp->vha, 0x5037, "Async-%s failed: " 262462306a36Sopenharmony_ci "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n", 262562306a36Sopenharmony_ci type, sp->handle, fcport->d_id.b24, fcport->port_name, 262662306a36Sopenharmony_ci le16_to_cpu(logio->comp_status), 262762306a36Sopenharmony_ci le32_to_cpu(logio->io_parameter[0]), 262862306a36Sopenharmony_ci le32_to_cpu(logio->io_parameter[1])); 262962306a36Sopenharmony_ci else 263062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, sp->vha, 0x5037, "Async-%s failed: " 263162306a36Sopenharmony_ci "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n", 263262306a36Sopenharmony_ci type, sp->handle, fcport->d_id.b24, fcport->port_name, 263362306a36Sopenharmony_ci le16_to_cpu(logio->comp_status), 263462306a36Sopenharmony_ci le32_to_cpu(logio->io_parameter[0]), 263562306a36Sopenharmony_ci le32_to_cpu(logio->io_parameter[1])); 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_cilogio_done: 263862306a36Sopenharmony_ci sp->done(sp, 0); 263962306a36Sopenharmony_ci} 264062306a36Sopenharmony_ci 264162306a36Sopenharmony_cistatic void 264262306a36Sopenharmony_ciqla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) 264362306a36Sopenharmony_ci{ 264462306a36Sopenharmony_ci const char func[] = "TMF-IOCB"; 264562306a36Sopenharmony_ci const char *type; 264662306a36Sopenharmony_ci fc_port_t *fcport; 264762306a36Sopenharmony_ci srb_t *sp; 264862306a36Sopenharmony_ci struct srb_iocb *iocb; 264962306a36Sopenharmony_ci struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; 265062306a36Sopenharmony_ci u16 comp_status; 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, tsk); 265362306a36Sopenharmony_ci if (!sp) 265462306a36Sopenharmony_ci return; 265562306a36Sopenharmony_ci 265662306a36Sopenharmony_ci comp_status = le16_to_cpu(sts->comp_status); 265762306a36Sopenharmony_ci iocb = &sp->u.iocb_cmd; 265862306a36Sopenharmony_ci type = sp->name; 265962306a36Sopenharmony_ci fcport = sp->fcport; 266062306a36Sopenharmony_ci iocb->u.tmf.data = QLA_SUCCESS; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci if (sts->entry_status) { 266362306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x5038, 266462306a36Sopenharmony_ci "Async-%s error - hdl=%x entry-status(%x).\n", 266562306a36Sopenharmony_ci type, sp->handle, sts->entry_status); 266662306a36Sopenharmony_ci iocb->u.tmf.data = QLA_FUNCTION_FAILED; 266762306a36Sopenharmony_ci } else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) { 266862306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x5039, 266962306a36Sopenharmony_ci "Async-%s error - hdl=%x completion status(%x).\n", 267062306a36Sopenharmony_ci type, sp->handle, comp_status); 267162306a36Sopenharmony_ci iocb->u.tmf.data = QLA_FUNCTION_FAILED; 267262306a36Sopenharmony_ci } else if ((le16_to_cpu(sts->scsi_status) & 267362306a36Sopenharmony_ci SS_RESPONSE_INFO_LEN_VALID)) { 267462306a36Sopenharmony_ci host_to_fcp_swap(sts->data, sizeof(sts->data)); 267562306a36Sopenharmony_ci if (le32_to_cpu(sts->rsp_data_len) < 4) { 267662306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x503b, 267762306a36Sopenharmony_ci "Async-%s error - hdl=%x not enough response(%d).\n", 267862306a36Sopenharmony_ci type, sp->handle, sts->rsp_data_len); 267962306a36Sopenharmony_ci } else if (sts->data[3]) { 268062306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x503c, 268162306a36Sopenharmony_ci "Async-%s error - hdl=%x response(%x).\n", 268262306a36Sopenharmony_ci type, sp->handle, sts->data[3]); 268362306a36Sopenharmony_ci iocb->u.tmf.data = QLA_FUNCTION_FAILED; 268462306a36Sopenharmony_ci } 268562306a36Sopenharmony_ci } 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci switch (comp_status) { 268862306a36Sopenharmony_ci case CS_PORT_LOGGED_OUT: 268962306a36Sopenharmony_ci case CS_PORT_CONFIG_CHG: 269062306a36Sopenharmony_ci case CS_PORT_BUSY: 269162306a36Sopenharmony_ci case CS_INCOMPLETE: 269262306a36Sopenharmony_ci case CS_PORT_UNAVAILABLE: 269362306a36Sopenharmony_ci case CS_RESET: 269462306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_ONLINE) { 269562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, fcport->vha, 0x3021, 269662306a36Sopenharmony_ci "-Port to be marked lost on fcport=%02x%02x%02x, current port state= %s comp_status %x.\n", 269762306a36Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, 269862306a36Sopenharmony_ci fcport->d_id.b.al_pa, 269962306a36Sopenharmony_ci port_state_str[FCS_ONLINE], 270062306a36Sopenharmony_ci comp_status); 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 270362306a36Sopenharmony_ci } 270462306a36Sopenharmony_ci break; 270562306a36Sopenharmony_ci 270662306a36Sopenharmony_ci default: 270762306a36Sopenharmony_ci break; 270862306a36Sopenharmony_ci } 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci if (iocb->u.tmf.data != QLA_SUCCESS) 271162306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055, 271262306a36Sopenharmony_ci sts, sizeof(*sts)); 271362306a36Sopenharmony_ci 271462306a36Sopenharmony_ci sp->done(sp, 0); 271562306a36Sopenharmony_ci} 271662306a36Sopenharmony_ci 271762306a36Sopenharmony_cistatic void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 271862306a36Sopenharmony_ci void *tsk, srb_t *sp) 271962306a36Sopenharmony_ci{ 272062306a36Sopenharmony_ci fc_port_t *fcport; 272162306a36Sopenharmony_ci struct srb_iocb *iocb; 272262306a36Sopenharmony_ci struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; 272362306a36Sopenharmony_ci uint16_t state_flags; 272462306a36Sopenharmony_ci struct nvmefc_fcp_req *fd; 272562306a36Sopenharmony_ci uint16_t ret = QLA_SUCCESS; 272662306a36Sopenharmony_ci __le16 comp_status = sts->comp_status; 272762306a36Sopenharmony_ci int logit = 0; 272862306a36Sopenharmony_ci 272962306a36Sopenharmony_ci iocb = &sp->u.iocb_cmd; 273062306a36Sopenharmony_ci fcport = sp->fcport; 273162306a36Sopenharmony_ci iocb->u.nvme.comp_status = comp_status; 273262306a36Sopenharmony_ci state_flags = le16_to_cpu(sts->state_flags); 273362306a36Sopenharmony_ci fd = iocb->u.nvme.desc; 273462306a36Sopenharmony_ci 273562306a36Sopenharmony_ci if (unlikely(iocb->u.nvme.aen_op)) 273662306a36Sopenharmony_ci atomic_dec(&sp->vha->hw->nvme_active_aen_cnt); 273762306a36Sopenharmony_ci else 273862306a36Sopenharmony_ci sp->qpair->cmd_completion_cnt++; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci if (unlikely(comp_status != CS_COMPLETE)) 274162306a36Sopenharmony_ci logit = 1; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci fd->transferred_length = fd->payload_length - 274462306a36Sopenharmony_ci le32_to_cpu(sts->residual_len); 274562306a36Sopenharmony_ci 274662306a36Sopenharmony_ci /* 274762306a36Sopenharmony_ci * State flags: Bit 6 and 0. 274862306a36Sopenharmony_ci * If 0 is set, we don't care about 6. 274962306a36Sopenharmony_ci * both cases resp was dma'd to host buffer 275062306a36Sopenharmony_ci * if both are 0, that is good path case. 275162306a36Sopenharmony_ci * if six is set and 0 is clear, we need to 275262306a36Sopenharmony_ci * copy resp data from status iocb to resp buffer. 275362306a36Sopenharmony_ci */ 275462306a36Sopenharmony_ci if (!(state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP))) { 275562306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len = 0; 275662306a36Sopenharmony_ci } else if ((state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP)) == 275762306a36Sopenharmony_ci (SF_FCP_RSP_DMA | SF_NVME_ERSP)) { 275862306a36Sopenharmony_ci /* Response already DMA'd to fd->rspaddr. */ 275962306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len; 276062306a36Sopenharmony_ci } else if ((state_flags & SF_FCP_RSP_DMA)) { 276162306a36Sopenharmony_ci /* 276262306a36Sopenharmony_ci * Non-zero value in first 12 bytes of NVMe_RSP IU, treat this 276362306a36Sopenharmony_ci * as an error. 276462306a36Sopenharmony_ci */ 276562306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len = 0; 276662306a36Sopenharmony_ci fd->transferred_length = 0; 276762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x307a, 276862306a36Sopenharmony_ci "Unexpected values in NVMe_RSP IU.\n"); 276962306a36Sopenharmony_ci logit = 1; 277062306a36Sopenharmony_ci } else if (state_flags & SF_NVME_ERSP) { 277162306a36Sopenharmony_ci uint32_t *inbuf, *outbuf; 277262306a36Sopenharmony_ci uint16_t iter; 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci inbuf = (uint32_t *)&sts->nvme_ersp_data; 277562306a36Sopenharmony_ci outbuf = (uint32_t *)fd->rspaddr; 277662306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len; 277762306a36Sopenharmony_ci if (unlikely(le16_to_cpu(iocb->u.nvme.rsp_pyld_len) > 277862306a36Sopenharmony_ci sizeof(struct nvme_fc_ersp_iu))) { 277962306a36Sopenharmony_ci if (ql_mask_match(ql_dbg_io)) { 278062306a36Sopenharmony_ci WARN_ONCE(1, "Unexpected response payload length %u.\n", 278162306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len); 278262306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x5100, 278362306a36Sopenharmony_ci "Unexpected response payload length %u.\n", 278462306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len); 278562306a36Sopenharmony_ci } 278662306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len = 278762306a36Sopenharmony_ci cpu_to_le16(sizeof(struct nvme_fc_ersp_iu)); 278862306a36Sopenharmony_ci } 278962306a36Sopenharmony_ci iter = le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >> 2; 279062306a36Sopenharmony_ci for (; iter; iter--) 279162306a36Sopenharmony_ci *outbuf++ = swab32(*inbuf++); 279262306a36Sopenharmony_ci } 279362306a36Sopenharmony_ci 279462306a36Sopenharmony_ci if (state_flags & SF_NVME_ERSP) { 279562306a36Sopenharmony_ci struct nvme_fc_ersp_iu *rsp_iu = fd->rspaddr; 279662306a36Sopenharmony_ci u32 tgt_xfer_len; 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci tgt_xfer_len = be32_to_cpu(rsp_iu->xfrd_len); 279962306a36Sopenharmony_ci if (fd->transferred_length != tgt_xfer_len) { 280062306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x3079, 280162306a36Sopenharmony_ci "Dropped frame(s) detected (sent/rcvd=%u/%u).\n", 280262306a36Sopenharmony_ci tgt_xfer_len, fd->transferred_length); 280362306a36Sopenharmony_ci logit = 1; 280462306a36Sopenharmony_ci } else if (le16_to_cpu(comp_status) == CS_DATA_UNDERRUN) { 280562306a36Sopenharmony_ci /* 280662306a36Sopenharmony_ci * Do not log if this is just an underflow and there 280762306a36Sopenharmony_ci * is no data loss. 280862306a36Sopenharmony_ci */ 280962306a36Sopenharmony_ci logit = 0; 281062306a36Sopenharmony_ci } 281162306a36Sopenharmony_ci } 281262306a36Sopenharmony_ci 281362306a36Sopenharmony_ci if (unlikely(logit)) 281462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x5060, 281562306a36Sopenharmony_ci "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x ox_id=%x\n", 281662306a36Sopenharmony_ci sp->name, sp->handle, comp_status, 281762306a36Sopenharmony_ci fd->transferred_length, le32_to_cpu(sts->residual_len), 281862306a36Sopenharmony_ci sts->ox_id); 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci /* 282162306a36Sopenharmony_ci * If transport error then Failure (HBA rejects request) 282262306a36Sopenharmony_ci * otherwise transport will handle. 282362306a36Sopenharmony_ci */ 282462306a36Sopenharmony_ci switch (le16_to_cpu(comp_status)) { 282562306a36Sopenharmony_ci case CS_COMPLETE: 282662306a36Sopenharmony_ci break; 282762306a36Sopenharmony_ci 282862306a36Sopenharmony_ci case CS_RESET: 282962306a36Sopenharmony_ci case CS_PORT_UNAVAILABLE: 283062306a36Sopenharmony_ci case CS_PORT_LOGGED_OUT: 283162306a36Sopenharmony_ci fcport->nvme_flag |= NVME_FLAG_RESETTING; 283262306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_ONLINE) { 283362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, fcport->vha, 0x3021, 283462306a36Sopenharmony_ci "Port to be marked lost on fcport=%06x, current " 283562306a36Sopenharmony_ci "port state= %s comp_status %x.\n", 283662306a36Sopenharmony_ci fcport->d_id.b24, port_state_str[FCS_ONLINE], 283762306a36Sopenharmony_ci comp_status); 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 284062306a36Sopenharmony_ci } 284162306a36Sopenharmony_ci fallthrough; 284262306a36Sopenharmony_ci case CS_ABORTED: 284362306a36Sopenharmony_ci case CS_PORT_BUSY: 284462306a36Sopenharmony_ci fd->transferred_length = 0; 284562306a36Sopenharmony_ci iocb->u.nvme.rsp_pyld_len = 0; 284662306a36Sopenharmony_ci ret = QLA_ABORTED; 284762306a36Sopenharmony_ci break; 284862306a36Sopenharmony_ci case CS_DATA_UNDERRUN: 284962306a36Sopenharmony_ci break; 285062306a36Sopenharmony_ci default: 285162306a36Sopenharmony_ci ret = QLA_FUNCTION_FAILED; 285262306a36Sopenharmony_ci break; 285362306a36Sopenharmony_ci } 285462306a36Sopenharmony_ci sp->done(sp, ret); 285562306a36Sopenharmony_ci} 285662306a36Sopenharmony_ci 285762306a36Sopenharmony_cistatic void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req, 285862306a36Sopenharmony_ci struct vp_ctrl_entry_24xx *vce) 285962306a36Sopenharmony_ci{ 286062306a36Sopenharmony_ci const char func[] = "CTRLVP-IOCB"; 286162306a36Sopenharmony_ci srb_t *sp; 286262306a36Sopenharmony_ci int rval = QLA_SUCCESS; 286362306a36Sopenharmony_ci 286462306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, vce); 286562306a36Sopenharmony_ci if (!sp) 286662306a36Sopenharmony_ci return; 286762306a36Sopenharmony_ci 286862306a36Sopenharmony_ci if (vce->entry_status != 0) { 286962306a36Sopenharmony_ci ql_dbg(ql_dbg_vport, vha, 0x10c4, 287062306a36Sopenharmony_ci "%s: Failed to complete IOCB -- error status (%x)\n", 287162306a36Sopenharmony_ci sp->name, vce->entry_status); 287262306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 287362306a36Sopenharmony_ci } else if (vce->comp_status != cpu_to_le16(CS_COMPLETE)) { 287462306a36Sopenharmony_ci ql_dbg(ql_dbg_vport, vha, 0x10c5, 287562306a36Sopenharmony_ci "%s: Failed to complete IOCB -- completion status (%x) vpidx %x\n", 287662306a36Sopenharmony_ci sp->name, le16_to_cpu(vce->comp_status), 287762306a36Sopenharmony_ci le16_to_cpu(vce->vp_idx_failed)); 287862306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 287962306a36Sopenharmony_ci } else { 288062306a36Sopenharmony_ci ql_dbg(ql_dbg_vport, vha, 0x10c6, 288162306a36Sopenharmony_ci "Done %s.\n", __func__); 288262306a36Sopenharmony_ci } 288362306a36Sopenharmony_ci 288462306a36Sopenharmony_ci sp->rc = rval; 288562306a36Sopenharmony_ci sp->done(sp, rval); 288662306a36Sopenharmony_ci} 288762306a36Sopenharmony_ci 288862306a36Sopenharmony_ci/* Process a single response queue entry. */ 288962306a36Sopenharmony_cistatic void qla2x00_process_response_entry(struct scsi_qla_host *vha, 289062306a36Sopenharmony_ci struct rsp_que *rsp, 289162306a36Sopenharmony_ci sts_entry_t *pkt) 289262306a36Sopenharmony_ci{ 289362306a36Sopenharmony_ci sts21_entry_t *sts21_entry; 289462306a36Sopenharmony_ci sts22_entry_t *sts22_entry; 289562306a36Sopenharmony_ci uint16_t handle_cnt; 289662306a36Sopenharmony_ci uint16_t cnt; 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci switch (pkt->entry_type) { 289962306a36Sopenharmony_ci case STATUS_TYPE: 290062306a36Sopenharmony_ci qla2x00_status_entry(vha, rsp, pkt); 290162306a36Sopenharmony_ci break; 290262306a36Sopenharmony_ci case STATUS_TYPE_21: 290362306a36Sopenharmony_ci sts21_entry = (sts21_entry_t *)pkt; 290462306a36Sopenharmony_ci handle_cnt = sts21_entry->handle_count; 290562306a36Sopenharmony_ci for (cnt = 0; cnt < handle_cnt; cnt++) 290662306a36Sopenharmony_ci qla2x00_process_completed_request(vha, rsp->req, 290762306a36Sopenharmony_ci sts21_entry->handle[cnt]); 290862306a36Sopenharmony_ci break; 290962306a36Sopenharmony_ci case STATUS_TYPE_22: 291062306a36Sopenharmony_ci sts22_entry = (sts22_entry_t *)pkt; 291162306a36Sopenharmony_ci handle_cnt = sts22_entry->handle_count; 291262306a36Sopenharmony_ci for (cnt = 0; cnt < handle_cnt; cnt++) 291362306a36Sopenharmony_ci qla2x00_process_completed_request(vha, rsp->req, 291462306a36Sopenharmony_ci sts22_entry->handle[cnt]); 291562306a36Sopenharmony_ci break; 291662306a36Sopenharmony_ci case STATUS_CONT_TYPE: 291762306a36Sopenharmony_ci qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); 291862306a36Sopenharmony_ci break; 291962306a36Sopenharmony_ci case MBX_IOCB_TYPE: 292062306a36Sopenharmony_ci qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt); 292162306a36Sopenharmony_ci break; 292262306a36Sopenharmony_ci case CT_IOCB_TYPE: 292362306a36Sopenharmony_ci qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); 292462306a36Sopenharmony_ci break; 292562306a36Sopenharmony_ci default: 292662306a36Sopenharmony_ci /* Type Not Supported. */ 292762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x504a, 292862306a36Sopenharmony_ci "Received unknown response pkt type %x entry status=%x.\n", 292962306a36Sopenharmony_ci pkt->entry_type, pkt->entry_status); 293062306a36Sopenharmony_ci break; 293162306a36Sopenharmony_ci } 293262306a36Sopenharmony_ci} 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci/** 293562306a36Sopenharmony_ci * qla2x00_process_response_queue() - Process response queue entries. 293662306a36Sopenharmony_ci * @rsp: response queue 293762306a36Sopenharmony_ci */ 293862306a36Sopenharmony_civoid 293962306a36Sopenharmony_ciqla2x00_process_response_queue(struct rsp_que *rsp) 294062306a36Sopenharmony_ci{ 294162306a36Sopenharmony_ci struct scsi_qla_host *vha; 294262306a36Sopenharmony_ci struct qla_hw_data *ha = rsp->hw; 294362306a36Sopenharmony_ci struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; 294462306a36Sopenharmony_ci sts_entry_t *pkt; 294562306a36Sopenharmony_ci 294662306a36Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 294762306a36Sopenharmony_ci 294862306a36Sopenharmony_ci if (!vha->flags.online) 294962306a36Sopenharmony_ci return; 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_ci while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) { 295262306a36Sopenharmony_ci pkt = (sts_entry_t *)rsp->ring_ptr; 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci rsp->ring_index++; 295562306a36Sopenharmony_ci if (rsp->ring_index == rsp->length) { 295662306a36Sopenharmony_ci rsp->ring_index = 0; 295762306a36Sopenharmony_ci rsp->ring_ptr = rsp->ring; 295862306a36Sopenharmony_ci } else { 295962306a36Sopenharmony_ci rsp->ring_ptr++; 296062306a36Sopenharmony_ci } 296162306a36Sopenharmony_ci 296262306a36Sopenharmony_ci if (pkt->entry_status != 0) { 296362306a36Sopenharmony_ci qla2x00_error_entry(vha, rsp, pkt); 296462306a36Sopenharmony_ci ((response_t *)pkt)->signature = RESPONSE_PROCESSED; 296562306a36Sopenharmony_ci wmb(); 296662306a36Sopenharmony_ci continue; 296762306a36Sopenharmony_ci } 296862306a36Sopenharmony_ci 296962306a36Sopenharmony_ci qla2x00_process_response_entry(vha, rsp, pkt); 297062306a36Sopenharmony_ci ((response_t *)pkt)->signature = RESPONSE_PROCESSED; 297162306a36Sopenharmony_ci wmb(); 297262306a36Sopenharmony_ci } 297362306a36Sopenharmony_ci 297462306a36Sopenharmony_ci /* Adjust ring index */ 297562306a36Sopenharmony_ci wrt_reg_word(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index); 297662306a36Sopenharmony_ci} 297762306a36Sopenharmony_ci 297862306a36Sopenharmony_cistatic inline void 297962306a36Sopenharmony_ciqla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len, 298062306a36Sopenharmony_ci uint32_t sense_len, struct rsp_que *rsp, int res) 298162306a36Sopenharmony_ci{ 298262306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 298362306a36Sopenharmony_ci struct scsi_cmnd *cp = GET_CMD_SP(sp); 298462306a36Sopenharmony_ci uint32_t track_sense_len; 298562306a36Sopenharmony_ci 298662306a36Sopenharmony_ci if (sense_len >= SCSI_SENSE_BUFFERSIZE) 298762306a36Sopenharmony_ci sense_len = SCSI_SENSE_BUFFERSIZE; 298862306a36Sopenharmony_ci 298962306a36Sopenharmony_ci SET_CMD_SENSE_LEN(sp, sense_len); 299062306a36Sopenharmony_ci SET_CMD_SENSE_PTR(sp, cp->sense_buffer); 299162306a36Sopenharmony_ci track_sense_len = sense_len; 299262306a36Sopenharmony_ci 299362306a36Sopenharmony_ci if (sense_len > par_sense_len) 299462306a36Sopenharmony_ci sense_len = par_sense_len; 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci memcpy(cp->sense_buffer, sense_data, sense_len); 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len); 299962306a36Sopenharmony_ci track_sense_len -= sense_len; 300062306a36Sopenharmony_ci SET_CMD_SENSE_LEN(sp, track_sense_len); 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci if (track_sense_len != 0) { 300362306a36Sopenharmony_ci rsp->status_srb = sp; 300462306a36Sopenharmony_ci cp->result = res; 300562306a36Sopenharmony_ci } 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci if (sense_len) { 300862306a36Sopenharmony_ci ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c, 300962306a36Sopenharmony_ci "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n", 301062306a36Sopenharmony_ci sp->vha->host_no, cp->device->id, cp->device->lun, 301162306a36Sopenharmony_ci cp); 301262306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b, 301362306a36Sopenharmony_ci cp->sense_buffer, sense_len); 301462306a36Sopenharmony_ci } 301562306a36Sopenharmony_ci} 301662306a36Sopenharmony_ci 301762306a36Sopenharmony_cistruct scsi_dif_tuple { 301862306a36Sopenharmony_ci __be16 guard; /* Checksum */ 301962306a36Sopenharmony_ci __be16 app_tag; /* APPL identifier */ 302062306a36Sopenharmony_ci __be32 ref_tag; /* Target LBA or indirect LBA */ 302162306a36Sopenharmony_ci}; 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci/* 302462306a36Sopenharmony_ci * Checks the guard or meta-data for the type of error 302562306a36Sopenharmony_ci * detected by the HBA. In case of errors, we set the 302662306a36Sopenharmony_ci * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST 302762306a36Sopenharmony_ci * to indicate to the kernel that the HBA detected error. 302862306a36Sopenharmony_ci */ 302962306a36Sopenharmony_cistatic inline int 303062306a36Sopenharmony_ciqla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) 303162306a36Sopenharmony_ci{ 303262306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 303362306a36Sopenharmony_ci struct scsi_cmnd *cmd = GET_CMD_SP(sp); 303462306a36Sopenharmony_ci uint8_t *ap = &sts24->data[12]; 303562306a36Sopenharmony_ci uint8_t *ep = &sts24->data[20]; 303662306a36Sopenharmony_ci uint32_t e_ref_tag, a_ref_tag; 303762306a36Sopenharmony_ci uint16_t e_app_tag, a_app_tag; 303862306a36Sopenharmony_ci uint16_t e_guard, a_guard; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci /* 304162306a36Sopenharmony_ci * swab32 of the "data" field in the beginning of qla2x00_status_entry() 304262306a36Sopenharmony_ci * would make guard field appear at offset 2 304362306a36Sopenharmony_ci */ 304462306a36Sopenharmony_ci a_guard = get_unaligned_le16(ap + 2); 304562306a36Sopenharmony_ci a_app_tag = get_unaligned_le16(ap + 0); 304662306a36Sopenharmony_ci a_ref_tag = get_unaligned_le32(ap + 4); 304762306a36Sopenharmony_ci e_guard = get_unaligned_le16(ep + 2); 304862306a36Sopenharmony_ci e_app_tag = get_unaligned_le16(ep + 0); 304962306a36Sopenharmony_ci e_ref_tag = get_unaligned_le32(ep + 4); 305062306a36Sopenharmony_ci 305162306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3023, 305262306a36Sopenharmony_ci "iocb(s) %p Returned STATUS.\n", sts24); 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3024, 305562306a36Sopenharmony_ci "DIF ERROR in cmd 0x%x lba 0x%llx act ref" 305662306a36Sopenharmony_ci " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app" 305762306a36Sopenharmony_ci " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n", 305862306a36Sopenharmony_ci cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag, 305962306a36Sopenharmony_ci a_app_tag, e_app_tag, a_guard, e_guard); 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci /* 306262306a36Sopenharmony_ci * Ignore sector if: 306362306a36Sopenharmony_ci * For type 3: ref & app tag is all 'f's 306462306a36Sopenharmony_ci * For type 0,1,2: app tag is all 'f's 306562306a36Sopenharmony_ci */ 306662306a36Sopenharmony_ci if (a_app_tag == be16_to_cpu(T10_PI_APP_ESCAPE) && 306762306a36Sopenharmony_ci (scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3 || 306862306a36Sopenharmony_ci a_ref_tag == be32_to_cpu(T10_PI_REF_ESCAPE))) { 306962306a36Sopenharmony_ci uint32_t blocks_done, resid; 307062306a36Sopenharmony_ci sector_t lba_s = scsi_get_lba(cmd); 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci /* 2TB boundary case covered automatically with this */ 307362306a36Sopenharmony_ci blocks_done = e_ref_tag - (uint32_t)lba_s + 1; 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci resid = scsi_bufflen(cmd) - (blocks_done * 307662306a36Sopenharmony_ci cmd->device->sector_size); 307762306a36Sopenharmony_ci 307862306a36Sopenharmony_ci scsi_set_resid(cmd, resid); 307962306a36Sopenharmony_ci cmd->result = DID_OK << 16; 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci /* Update protection tag */ 308262306a36Sopenharmony_ci if (scsi_prot_sg_count(cmd)) { 308362306a36Sopenharmony_ci uint32_t i, j = 0, k = 0, num_ent; 308462306a36Sopenharmony_ci struct scatterlist *sg; 308562306a36Sopenharmony_ci struct t10_pi_tuple *spt; 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci /* Patch the corresponding protection tags */ 308862306a36Sopenharmony_ci scsi_for_each_prot_sg(cmd, sg, 308962306a36Sopenharmony_ci scsi_prot_sg_count(cmd), i) { 309062306a36Sopenharmony_ci num_ent = sg_dma_len(sg) / 8; 309162306a36Sopenharmony_ci if (k + num_ent < blocks_done) { 309262306a36Sopenharmony_ci k += num_ent; 309362306a36Sopenharmony_ci continue; 309462306a36Sopenharmony_ci } 309562306a36Sopenharmony_ci j = blocks_done - k - 1; 309662306a36Sopenharmony_ci k = blocks_done; 309762306a36Sopenharmony_ci break; 309862306a36Sopenharmony_ci } 309962306a36Sopenharmony_ci 310062306a36Sopenharmony_ci if (k != blocks_done) { 310162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x302f, 310262306a36Sopenharmony_ci "unexpected tag values tag:lba=%x:%llx)\n", 310362306a36Sopenharmony_ci e_ref_tag, (unsigned long long)lba_s); 310462306a36Sopenharmony_ci return 1; 310562306a36Sopenharmony_ci } 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_ci spt = page_address(sg_page(sg)) + sg->offset; 310862306a36Sopenharmony_ci spt += j; 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci spt->app_tag = T10_PI_APP_ESCAPE; 311162306a36Sopenharmony_ci if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3) 311262306a36Sopenharmony_ci spt->ref_tag = T10_PI_REF_ESCAPE; 311362306a36Sopenharmony_ci } 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci return 0; 311662306a36Sopenharmony_ci } 311762306a36Sopenharmony_ci 311862306a36Sopenharmony_ci /* check guard */ 311962306a36Sopenharmony_ci if (e_guard != a_guard) { 312062306a36Sopenharmony_ci scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1); 312162306a36Sopenharmony_ci set_host_byte(cmd, DID_ABORT); 312262306a36Sopenharmony_ci return 1; 312362306a36Sopenharmony_ci } 312462306a36Sopenharmony_ci 312562306a36Sopenharmony_ci /* check ref tag */ 312662306a36Sopenharmony_ci if (e_ref_tag != a_ref_tag) { 312762306a36Sopenharmony_ci scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3); 312862306a36Sopenharmony_ci set_host_byte(cmd, DID_ABORT); 312962306a36Sopenharmony_ci return 1; 313062306a36Sopenharmony_ci } 313162306a36Sopenharmony_ci 313262306a36Sopenharmony_ci /* check appl tag */ 313362306a36Sopenharmony_ci if (e_app_tag != a_app_tag) { 313462306a36Sopenharmony_ci scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2); 313562306a36Sopenharmony_ci set_host_byte(cmd, DID_ABORT); 313662306a36Sopenharmony_ci return 1; 313762306a36Sopenharmony_ci } 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci return 1; 314062306a36Sopenharmony_ci} 314162306a36Sopenharmony_ci 314262306a36Sopenharmony_cistatic void 314362306a36Sopenharmony_ciqla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt, 314462306a36Sopenharmony_ci struct req_que *req, uint32_t index) 314562306a36Sopenharmony_ci{ 314662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 314762306a36Sopenharmony_ci srb_t *sp; 314862306a36Sopenharmony_ci uint16_t comp_status; 314962306a36Sopenharmony_ci uint16_t scsi_status; 315062306a36Sopenharmony_ci uint16_t thread_id; 315162306a36Sopenharmony_ci uint32_t rval = EXT_STATUS_OK; 315262306a36Sopenharmony_ci struct bsg_job *bsg_job = NULL; 315362306a36Sopenharmony_ci struct fc_bsg_request *bsg_request; 315462306a36Sopenharmony_ci struct fc_bsg_reply *bsg_reply; 315562306a36Sopenharmony_ci sts_entry_t *sts = pkt; 315662306a36Sopenharmony_ci struct sts_entry_24xx *sts24 = pkt; 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci /* Validate handle. */ 315962306a36Sopenharmony_ci if (index >= req->num_outstanding_cmds) { 316062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70af, 316162306a36Sopenharmony_ci "Invalid SCSI completion handle 0x%x.\n", index); 316262306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 316362306a36Sopenharmony_ci return; 316462306a36Sopenharmony_ci } 316562306a36Sopenharmony_ci 316662306a36Sopenharmony_ci sp = req->outstanding_cmds[index]; 316762306a36Sopenharmony_ci if (!sp) { 316862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x70b0, 316962306a36Sopenharmony_ci "Req:%d: Invalid ISP SCSI completion handle(0x%x)\n", 317062306a36Sopenharmony_ci req->id, index); 317162306a36Sopenharmony_ci 317262306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 317362306a36Sopenharmony_ci return; 317462306a36Sopenharmony_ci } 317562306a36Sopenharmony_ci 317662306a36Sopenharmony_ci /* Free outstanding command slot. */ 317762306a36Sopenharmony_ci req->outstanding_cmds[index] = NULL; 317862306a36Sopenharmony_ci bsg_job = sp->u.bsg_job; 317962306a36Sopenharmony_ci bsg_request = bsg_job->request; 318062306a36Sopenharmony_ci bsg_reply = bsg_job->reply; 318162306a36Sopenharmony_ci 318262306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 318362306a36Sopenharmony_ci comp_status = le16_to_cpu(sts24->comp_status); 318462306a36Sopenharmony_ci scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK; 318562306a36Sopenharmony_ci } else { 318662306a36Sopenharmony_ci comp_status = le16_to_cpu(sts->comp_status); 318762306a36Sopenharmony_ci scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK; 318862306a36Sopenharmony_ci } 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_ci thread_id = bsg_request->rqst_data.h_vendor.vendor_cmd[1]; 319162306a36Sopenharmony_ci switch (comp_status) { 319262306a36Sopenharmony_ci case CS_COMPLETE: 319362306a36Sopenharmony_ci if (scsi_status == 0) { 319462306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 319562306a36Sopenharmony_ci bsg_job->reply_payload.payload_len; 319662306a36Sopenharmony_ci vha->qla_stats.input_bytes += 319762306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len; 319862306a36Sopenharmony_ci vha->qla_stats.input_requests++; 319962306a36Sopenharmony_ci rval = EXT_STATUS_OK; 320062306a36Sopenharmony_ci } 320162306a36Sopenharmony_ci goto done; 320262306a36Sopenharmony_ci 320362306a36Sopenharmony_ci case CS_DATA_OVERRUN: 320462306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b1, 320562306a36Sopenharmony_ci "Command completed with data overrun thread_id=%d\n", 320662306a36Sopenharmony_ci thread_id); 320762306a36Sopenharmony_ci rval = EXT_STATUS_DATA_OVERRUN; 320862306a36Sopenharmony_ci break; 320962306a36Sopenharmony_ci 321062306a36Sopenharmony_ci case CS_DATA_UNDERRUN: 321162306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b2, 321262306a36Sopenharmony_ci "Command completed with data underrun thread_id=%d\n", 321362306a36Sopenharmony_ci thread_id); 321462306a36Sopenharmony_ci rval = EXT_STATUS_DATA_UNDERRUN; 321562306a36Sopenharmony_ci break; 321662306a36Sopenharmony_ci case CS_BIDIR_RD_OVERRUN: 321762306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b3, 321862306a36Sopenharmony_ci "Command completed with read data overrun thread_id=%d\n", 321962306a36Sopenharmony_ci thread_id); 322062306a36Sopenharmony_ci rval = EXT_STATUS_DATA_OVERRUN; 322162306a36Sopenharmony_ci break; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci case CS_BIDIR_RD_WR_OVERRUN: 322462306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b4, 322562306a36Sopenharmony_ci "Command completed with read and write data overrun " 322662306a36Sopenharmony_ci "thread_id=%d\n", thread_id); 322762306a36Sopenharmony_ci rval = EXT_STATUS_DATA_OVERRUN; 322862306a36Sopenharmony_ci break; 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci case CS_BIDIR_RD_OVERRUN_WR_UNDERRUN: 323162306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b5, 323262306a36Sopenharmony_ci "Command completed with read data over and write data " 323362306a36Sopenharmony_ci "underrun thread_id=%d\n", thread_id); 323462306a36Sopenharmony_ci rval = EXT_STATUS_DATA_OVERRUN; 323562306a36Sopenharmony_ci break; 323662306a36Sopenharmony_ci 323762306a36Sopenharmony_ci case CS_BIDIR_RD_UNDERRUN: 323862306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b6, 323962306a36Sopenharmony_ci "Command completed with read data underrun " 324062306a36Sopenharmony_ci "thread_id=%d\n", thread_id); 324162306a36Sopenharmony_ci rval = EXT_STATUS_DATA_UNDERRUN; 324262306a36Sopenharmony_ci break; 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci case CS_BIDIR_RD_UNDERRUN_WR_OVERRUN: 324562306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b7, 324662306a36Sopenharmony_ci "Command completed with read data under and write data " 324762306a36Sopenharmony_ci "overrun thread_id=%d\n", thread_id); 324862306a36Sopenharmony_ci rval = EXT_STATUS_DATA_UNDERRUN; 324962306a36Sopenharmony_ci break; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci case CS_BIDIR_RD_WR_UNDERRUN: 325262306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b8, 325362306a36Sopenharmony_ci "Command completed with read and write data underrun " 325462306a36Sopenharmony_ci "thread_id=%d\n", thread_id); 325562306a36Sopenharmony_ci rval = EXT_STATUS_DATA_UNDERRUN; 325662306a36Sopenharmony_ci break; 325762306a36Sopenharmony_ci 325862306a36Sopenharmony_ci case CS_BIDIR_DMA: 325962306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70b9, 326062306a36Sopenharmony_ci "Command completed with data DMA error thread_id=%d\n", 326162306a36Sopenharmony_ci thread_id); 326262306a36Sopenharmony_ci rval = EXT_STATUS_DMA_ERR; 326362306a36Sopenharmony_ci break; 326462306a36Sopenharmony_ci 326562306a36Sopenharmony_ci case CS_TIMEOUT: 326662306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70ba, 326762306a36Sopenharmony_ci "Command completed with timeout thread_id=%d\n", 326862306a36Sopenharmony_ci thread_id); 326962306a36Sopenharmony_ci rval = EXT_STATUS_TIMEOUT; 327062306a36Sopenharmony_ci break; 327162306a36Sopenharmony_ci default: 327262306a36Sopenharmony_ci ql_dbg(ql_dbg_user, vha, 0x70bb, 327362306a36Sopenharmony_ci "Command completed with completion status=0x%x " 327462306a36Sopenharmony_ci "thread_id=%d\n", comp_status, thread_id); 327562306a36Sopenharmony_ci rval = EXT_STATUS_ERR; 327662306a36Sopenharmony_ci break; 327762306a36Sopenharmony_ci } 327862306a36Sopenharmony_ci bsg_reply->reply_payload_rcv_len = 0; 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_cidone: 328162306a36Sopenharmony_ci /* Return the vendor specific reply to API */ 328262306a36Sopenharmony_ci bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval; 328362306a36Sopenharmony_ci bsg_job->reply_len = sizeof(struct fc_bsg_reply); 328462306a36Sopenharmony_ci /* Always return DID_OK, bsg will send the vendor specific response 328562306a36Sopenharmony_ci * in this case only */ 328662306a36Sopenharmony_ci sp->done(sp, DID_OK << 16); 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci} 328962306a36Sopenharmony_ci 329062306a36Sopenharmony_ci/** 329162306a36Sopenharmony_ci * qla2x00_status_entry() - Process a Status IOCB entry. 329262306a36Sopenharmony_ci * @vha: SCSI driver HA context 329362306a36Sopenharmony_ci * @rsp: response queue 329462306a36Sopenharmony_ci * @pkt: Entry pointer 329562306a36Sopenharmony_ci */ 329662306a36Sopenharmony_cistatic void 329762306a36Sopenharmony_ciqla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) 329862306a36Sopenharmony_ci{ 329962306a36Sopenharmony_ci srb_t *sp; 330062306a36Sopenharmony_ci fc_port_t *fcport; 330162306a36Sopenharmony_ci struct scsi_cmnd *cp; 330262306a36Sopenharmony_ci sts_entry_t *sts = pkt; 330362306a36Sopenharmony_ci struct sts_entry_24xx *sts24 = pkt; 330462306a36Sopenharmony_ci uint16_t comp_status; 330562306a36Sopenharmony_ci uint16_t scsi_status; 330662306a36Sopenharmony_ci uint16_t ox_id; 330762306a36Sopenharmony_ci uint8_t lscsi_status; 330862306a36Sopenharmony_ci int32_t resid; 330962306a36Sopenharmony_ci uint32_t sense_len, par_sense_len, rsp_info_len, resid_len, 331062306a36Sopenharmony_ci fw_resid_len; 331162306a36Sopenharmony_ci uint8_t *rsp_info, *sense_data; 331262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 331362306a36Sopenharmony_ci uint32_t handle; 331462306a36Sopenharmony_ci uint16_t que; 331562306a36Sopenharmony_ci struct req_que *req; 331662306a36Sopenharmony_ci int logit = 1; 331762306a36Sopenharmony_ci int res = 0; 331862306a36Sopenharmony_ci uint16_t state_flags = 0; 331962306a36Sopenharmony_ci uint16_t sts_qual = 0; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 332262306a36Sopenharmony_ci comp_status = le16_to_cpu(sts24->comp_status); 332362306a36Sopenharmony_ci scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK; 332462306a36Sopenharmony_ci state_flags = le16_to_cpu(sts24->state_flags); 332562306a36Sopenharmony_ci } else { 332662306a36Sopenharmony_ci comp_status = le16_to_cpu(sts->comp_status); 332762306a36Sopenharmony_ci scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK; 332862306a36Sopenharmony_ci } 332962306a36Sopenharmony_ci handle = (uint32_t) LSW(sts->handle); 333062306a36Sopenharmony_ci que = MSW(sts->handle); 333162306a36Sopenharmony_ci req = ha->req_q_map[que]; 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci /* Check for invalid queue pointer */ 333462306a36Sopenharmony_ci if (req == NULL || 333562306a36Sopenharmony_ci que >= find_first_zero_bit(ha->req_qid_map, ha->max_req_queues)) { 333662306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3059, 333762306a36Sopenharmony_ci "Invalid status handle (0x%x): Bad req pointer. req=%p, " 333862306a36Sopenharmony_ci "que=%u.\n", sts->handle, req, que); 333962306a36Sopenharmony_ci return; 334062306a36Sopenharmony_ci } 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci /* Validate handle. */ 334362306a36Sopenharmony_ci if (handle < req->num_outstanding_cmds) { 334462306a36Sopenharmony_ci sp = req->outstanding_cmds[handle]; 334562306a36Sopenharmony_ci if (!sp) { 334662306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3075, 334762306a36Sopenharmony_ci "%s(%ld): Already returned command for status handle (0x%x).\n", 334862306a36Sopenharmony_ci __func__, vha->host_no, sts->handle); 334962306a36Sopenharmony_ci return; 335062306a36Sopenharmony_ci } 335162306a36Sopenharmony_ci } else { 335262306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3017, 335362306a36Sopenharmony_ci "Invalid status handle, out of range (0x%x).\n", 335462306a36Sopenharmony_ci sts->handle); 335562306a36Sopenharmony_ci 335662306a36Sopenharmony_ci if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { 335762306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) 335862306a36Sopenharmony_ci set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); 335962306a36Sopenharmony_ci else 336062306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 336162306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 336262306a36Sopenharmony_ci } 336362306a36Sopenharmony_ci return; 336462306a36Sopenharmony_ci } 336562306a36Sopenharmony_ci qla_put_fw_resources(sp->qpair, &sp->iores); 336662306a36Sopenharmony_ci 336762306a36Sopenharmony_ci if (sp->cmd_type != TYPE_SRB) { 336862306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 336962306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3015, 337062306a36Sopenharmony_ci "Unknown sp->cmd_type %x %p).\n", 337162306a36Sopenharmony_ci sp->cmd_type, sp); 337262306a36Sopenharmony_ci return; 337362306a36Sopenharmony_ci } 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci /* NVME completion. */ 337662306a36Sopenharmony_ci if (sp->type == SRB_NVME_CMD) { 337762306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 337862306a36Sopenharmony_ci qla24xx_nvme_iocb_entry(vha, req, pkt, sp); 337962306a36Sopenharmony_ci return; 338062306a36Sopenharmony_ci } 338162306a36Sopenharmony_ci 338262306a36Sopenharmony_ci if (unlikely((state_flags & BIT_1) && (sp->type == SRB_BIDI_CMD))) { 338362306a36Sopenharmony_ci qla25xx_process_bidir_status_iocb(vha, pkt, req, handle); 338462306a36Sopenharmony_ci return; 338562306a36Sopenharmony_ci } 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_ci /* Task Management completion. */ 338862306a36Sopenharmony_ci if (sp->type == SRB_TM_CMD) { 338962306a36Sopenharmony_ci qla24xx_tm_iocb_entry(vha, req, pkt); 339062306a36Sopenharmony_ci return; 339162306a36Sopenharmony_ci } 339262306a36Sopenharmony_ci 339362306a36Sopenharmony_ci /* Fast path completion. */ 339462306a36Sopenharmony_ci qla_chk_edif_rx_sa_delete_pending(vha, sp, sts24); 339562306a36Sopenharmony_ci sp->qpair->cmd_completion_cnt++; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_ci if (comp_status == CS_COMPLETE && scsi_status == 0) { 339862306a36Sopenharmony_ci qla2x00_process_completed_request(vha, req, handle); 339962306a36Sopenharmony_ci 340062306a36Sopenharmony_ci return; 340162306a36Sopenharmony_ci } 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci cp = GET_CMD_SP(sp); 340462306a36Sopenharmony_ci if (cp == NULL) { 340562306a36Sopenharmony_ci ql_dbg(ql_dbg_io, vha, 0x3018, 340662306a36Sopenharmony_ci "Command already returned (0x%x/%p).\n", 340762306a36Sopenharmony_ci sts->handle, sp); 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 341062306a36Sopenharmony_ci return; 341162306a36Sopenharmony_ci } 341262306a36Sopenharmony_ci 341362306a36Sopenharmony_ci lscsi_status = scsi_status & STATUS_MASK; 341462306a36Sopenharmony_ci 341562306a36Sopenharmony_ci fcport = sp->fcport; 341662306a36Sopenharmony_ci 341762306a36Sopenharmony_ci ox_id = 0; 341862306a36Sopenharmony_ci sense_len = par_sense_len = rsp_info_len = resid_len = 341962306a36Sopenharmony_ci fw_resid_len = 0; 342062306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 342162306a36Sopenharmony_ci if (scsi_status & SS_SENSE_LEN_VALID) 342262306a36Sopenharmony_ci sense_len = le32_to_cpu(sts24->sense_len); 342362306a36Sopenharmony_ci if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) 342462306a36Sopenharmony_ci rsp_info_len = le32_to_cpu(sts24->rsp_data_len); 342562306a36Sopenharmony_ci if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) 342662306a36Sopenharmony_ci resid_len = le32_to_cpu(sts24->rsp_residual_count); 342762306a36Sopenharmony_ci if (comp_status == CS_DATA_UNDERRUN) 342862306a36Sopenharmony_ci fw_resid_len = le32_to_cpu(sts24->residual_len); 342962306a36Sopenharmony_ci rsp_info = sts24->data; 343062306a36Sopenharmony_ci sense_data = sts24->data; 343162306a36Sopenharmony_ci host_to_fcp_swap(sts24->data, sizeof(sts24->data)); 343262306a36Sopenharmony_ci ox_id = le16_to_cpu(sts24->ox_id); 343362306a36Sopenharmony_ci par_sense_len = sizeof(sts24->data); 343462306a36Sopenharmony_ci sts_qual = le16_to_cpu(sts24->status_qualifier); 343562306a36Sopenharmony_ci } else { 343662306a36Sopenharmony_ci if (scsi_status & SS_SENSE_LEN_VALID) 343762306a36Sopenharmony_ci sense_len = le16_to_cpu(sts->req_sense_length); 343862306a36Sopenharmony_ci if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) 343962306a36Sopenharmony_ci rsp_info_len = le16_to_cpu(sts->rsp_info_len); 344062306a36Sopenharmony_ci resid_len = le32_to_cpu(sts->residual_length); 344162306a36Sopenharmony_ci rsp_info = sts->rsp_info; 344262306a36Sopenharmony_ci sense_data = sts->req_sense_data; 344362306a36Sopenharmony_ci par_sense_len = sizeof(sts->req_sense_data); 344462306a36Sopenharmony_ci } 344562306a36Sopenharmony_ci 344662306a36Sopenharmony_ci /* Check for any FCP transport errors. */ 344762306a36Sopenharmony_ci if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) { 344862306a36Sopenharmony_ci /* Sense data lies beyond any FCP RESPONSE data. */ 344962306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 345062306a36Sopenharmony_ci sense_data += rsp_info_len; 345162306a36Sopenharmony_ci par_sense_len -= rsp_info_len; 345262306a36Sopenharmony_ci } 345362306a36Sopenharmony_ci if (rsp_info_len > 3 && rsp_info[3]) { 345462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3019, 345562306a36Sopenharmony_ci "FCP I/O protocol failure (0x%x/0x%x).\n", 345662306a36Sopenharmony_ci rsp_info_len, rsp_info[3]); 345762306a36Sopenharmony_ci 345862306a36Sopenharmony_ci res = DID_BUS_BUSY << 16; 345962306a36Sopenharmony_ci goto out; 346062306a36Sopenharmony_ci } 346162306a36Sopenharmony_ci } 346262306a36Sopenharmony_ci 346362306a36Sopenharmony_ci /* Check for overrun. */ 346462306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE && 346562306a36Sopenharmony_ci scsi_status & SS_RESIDUAL_OVER) 346662306a36Sopenharmony_ci comp_status = CS_DATA_OVERRUN; 346762306a36Sopenharmony_ci 346862306a36Sopenharmony_ci /* 346962306a36Sopenharmony_ci * Check retry_delay_timer value if we receive a busy or 347062306a36Sopenharmony_ci * queue full. 347162306a36Sopenharmony_ci */ 347262306a36Sopenharmony_ci if (unlikely(lscsi_status == SAM_STAT_TASK_SET_FULL || 347362306a36Sopenharmony_ci lscsi_status == SAM_STAT_BUSY)) 347462306a36Sopenharmony_ci qla2x00_set_retry_delay_timestamp(fcport, sts_qual); 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci /* 347762306a36Sopenharmony_ci * Based on Host and scsi status generate status code for Linux 347862306a36Sopenharmony_ci */ 347962306a36Sopenharmony_ci switch (comp_status) { 348062306a36Sopenharmony_ci case CS_COMPLETE: 348162306a36Sopenharmony_ci case CS_QUEUE_FULL: 348262306a36Sopenharmony_ci if (scsi_status == 0) { 348362306a36Sopenharmony_ci res = DID_OK << 16; 348462306a36Sopenharmony_ci break; 348562306a36Sopenharmony_ci } 348662306a36Sopenharmony_ci if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) { 348762306a36Sopenharmony_ci resid = resid_len; 348862306a36Sopenharmony_ci scsi_set_resid(cp, resid); 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci if (!lscsi_status && 349162306a36Sopenharmony_ci ((unsigned)(scsi_bufflen(cp) - resid) < 349262306a36Sopenharmony_ci cp->underflow)) { 349362306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x301a, 349462306a36Sopenharmony_ci "Mid-layer underflow detected (0x%x of 0x%x bytes).\n", 349562306a36Sopenharmony_ci resid, scsi_bufflen(cp)); 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci res = DID_ERROR << 16; 349862306a36Sopenharmony_ci break; 349962306a36Sopenharmony_ci } 350062306a36Sopenharmony_ci } 350162306a36Sopenharmony_ci res = DID_OK << 16 | lscsi_status; 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci if (lscsi_status == SAM_STAT_TASK_SET_FULL) { 350462306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x301b, 350562306a36Sopenharmony_ci "QUEUE FULL detected.\n"); 350662306a36Sopenharmony_ci break; 350762306a36Sopenharmony_ci } 350862306a36Sopenharmony_ci logit = 0; 350962306a36Sopenharmony_ci if (lscsi_status != SS_CHECK_CONDITION) 351062306a36Sopenharmony_ci break; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 351362306a36Sopenharmony_ci if (!(scsi_status & SS_SENSE_LEN_VALID)) 351462306a36Sopenharmony_ci break; 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len, 351762306a36Sopenharmony_ci rsp, res); 351862306a36Sopenharmony_ci break; 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci case CS_DATA_UNDERRUN: 352162306a36Sopenharmony_ci /* Use F/W calculated residual length. */ 352262306a36Sopenharmony_ci resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len; 352362306a36Sopenharmony_ci scsi_set_resid(cp, resid); 352462306a36Sopenharmony_ci if (scsi_status & SS_RESIDUAL_UNDER) { 352562306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) { 352662306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x301d, 352762306a36Sopenharmony_ci "Dropped frame(s) detected (0x%x of 0x%x bytes).\n", 352862306a36Sopenharmony_ci resid, scsi_bufflen(cp)); 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_ci res = DID_ERROR << 16 | lscsi_status; 353162306a36Sopenharmony_ci goto check_scsi_status; 353262306a36Sopenharmony_ci } 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci if (!lscsi_status && 353562306a36Sopenharmony_ci ((unsigned)(scsi_bufflen(cp) - resid) < 353662306a36Sopenharmony_ci cp->underflow)) { 353762306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x301e, 353862306a36Sopenharmony_ci "Mid-layer underflow detected (0x%x of 0x%x bytes).\n", 353962306a36Sopenharmony_ci resid, scsi_bufflen(cp)); 354062306a36Sopenharmony_ci 354162306a36Sopenharmony_ci res = DID_ERROR << 16; 354262306a36Sopenharmony_ci break; 354362306a36Sopenharmony_ci } 354462306a36Sopenharmony_ci } else if (lscsi_status != SAM_STAT_TASK_SET_FULL && 354562306a36Sopenharmony_ci lscsi_status != SAM_STAT_BUSY) { 354662306a36Sopenharmony_ci /* 354762306a36Sopenharmony_ci * scsi status of task set and busy are considered to be 354862306a36Sopenharmony_ci * task not completed. 354962306a36Sopenharmony_ci */ 355062306a36Sopenharmony_ci 355162306a36Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x301f, 355262306a36Sopenharmony_ci "Dropped frame(s) detected (0x%x of 0x%x bytes).\n", 355362306a36Sopenharmony_ci resid, scsi_bufflen(cp)); 355462306a36Sopenharmony_ci 355562306a36Sopenharmony_ci vha->interface_err_cnt++; 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci res = DID_ERROR << 16 | lscsi_status; 355862306a36Sopenharmony_ci goto check_scsi_status; 355962306a36Sopenharmony_ci } else { 356062306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3030, 356162306a36Sopenharmony_ci "scsi_status: 0x%x, lscsi_status: 0x%x\n", 356262306a36Sopenharmony_ci scsi_status, lscsi_status); 356362306a36Sopenharmony_ci } 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci res = DID_OK << 16 | lscsi_status; 356662306a36Sopenharmony_ci logit = 0; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_cicheck_scsi_status: 356962306a36Sopenharmony_ci /* 357062306a36Sopenharmony_ci * Check to see if SCSI Status is non zero. If so report SCSI 357162306a36Sopenharmony_ci * Status. 357262306a36Sopenharmony_ci */ 357362306a36Sopenharmony_ci if (lscsi_status != 0) { 357462306a36Sopenharmony_ci if (lscsi_status == SAM_STAT_TASK_SET_FULL) { 357562306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3020, 357662306a36Sopenharmony_ci "QUEUE FULL detected.\n"); 357762306a36Sopenharmony_ci logit = 1; 357862306a36Sopenharmony_ci break; 357962306a36Sopenharmony_ci } 358062306a36Sopenharmony_ci if (lscsi_status != SS_CHECK_CONDITION) 358162306a36Sopenharmony_ci break; 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 358462306a36Sopenharmony_ci if (!(scsi_status & SS_SENSE_LEN_VALID)) 358562306a36Sopenharmony_ci break; 358662306a36Sopenharmony_ci 358762306a36Sopenharmony_ci qla2x00_handle_sense(sp, sense_data, par_sense_len, 358862306a36Sopenharmony_ci sense_len, rsp, res); 358962306a36Sopenharmony_ci } 359062306a36Sopenharmony_ci break; 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci case CS_PORT_LOGGED_OUT: 359362306a36Sopenharmony_ci case CS_PORT_CONFIG_CHG: 359462306a36Sopenharmony_ci case CS_PORT_BUSY: 359562306a36Sopenharmony_ci case CS_INCOMPLETE: 359662306a36Sopenharmony_ci case CS_PORT_UNAVAILABLE: 359762306a36Sopenharmony_ci case CS_TIMEOUT: 359862306a36Sopenharmony_ci case CS_RESET: 359962306a36Sopenharmony_ci case CS_EDIF_INV_REQ: 360062306a36Sopenharmony_ci 360162306a36Sopenharmony_ci /* 360262306a36Sopenharmony_ci * We are going to have the fc class block the rport 360362306a36Sopenharmony_ci * while we try to recover so instruct the mid layer 360462306a36Sopenharmony_ci * to requeue until the class decides how to handle this. 360562306a36Sopenharmony_ci */ 360662306a36Sopenharmony_ci res = DID_TRANSPORT_DISRUPTED << 16; 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci if (comp_status == CS_TIMEOUT) { 360962306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) 361062306a36Sopenharmony_ci break; 361162306a36Sopenharmony_ci else if ((le16_to_cpu(sts->status_flags) & 361262306a36Sopenharmony_ci SF_LOGOUT_SENT) == 0) 361362306a36Sopenharmony_ci break; 361462306a36Sopenharmony_ci } 361562306a36Sopenharmony_ci 361662306a36Sopenharmony_ci if (atomic_read(&fcport->state) == FCS_ONLINE) { 361762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, fcport->vha, 0x3021, 361862306a36Sopenharmony_ci "Port to be marked lost on fcport=%02x%02x%02x, current " 361962306a36Sopenharmony_ci "port state= %s comp_status %x.\n", fcport->d_id.b.domain, 362062306a36Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa, 362162306a36Sopenharmony_ci port_state_str[FCS_ONLINE], 362262306a36Sopenharmony_ci comp_status); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 362562306a36Sopenharmony_ci } 362662306a36Sopenharmony_ci 362762306a36Sopenharmony_ci break; 362862306a36Sopenharmony_ci 362962306a36Sopenharmony_ci case CS_ABORTED: 363062306a36Sopenharmony_ci res = DID_RESET << 16; 363162306a36Sopenharmony_ci break; 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci case CS_DIF_ERROR: 363462306a36Sopenharmony_ci logit = qla2x00_handle_dif_error(sp, sts24); 363562306a36Sopenharmony_ci res = cp->result; 363662306a36Sopenharmony_ci break; 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci case CS_TRANSPORT: 363962306a36Sopenharmony_ci res = DID_ERROR << 16; 364062306a36Sopenharmony_ci vha->hw_err_cnt++; 364162306a36Sopenharmony_ci 364262306a36Sopenharmony_ci if (!IS_PI_SPLIT_DET_CAPABLE(ha)) 364362306a36Sopenharmony_ci break; 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci if (state_flags & BIT_4) 364662306a36Sopenharmony_ci scmd_printk(KERN_WARNING, cp, 364762306a36Sopenharmony_ci "Unsupported device '%s' found.\n", 364862306a36Sopenharmony_ci cp->device->vendor); 364962306a36Sopenharmony_ci break; 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci case CS_DMA: 365262306a36Sopenharmony_ci ql_log(ql_log_info, fcport->vha, 0x3022, 365362306a36Sopenharmony_ci "CS_DMA error: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%06x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n", 365462306a36Sopenharmony_ci comp_status, scsi_status, res, vha->host_no, 365562306a36Sopenharmony_ci cp->device->id, cp->device->lun, fcport->d_id.b24, 365662306a36Sopenharmony_ci ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len, 365762306a36Sopenharmony_ci resid_len, fw_resid_len, sp, cp); 365862306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee, 365962306a36Sopenharmony_ci pkt, sizeof(*sts24)); 366062306a36Sopenharmony_ci res = DID_ERROR << 16; 366162306a36Sopenharmony_ci vha->hw_err_cnt++; 366262306a36Sopenharmony_ci break; 366362306a36Sopenharmony_ci default: 366462306a36Sopenharmony_ci res = DID_ERROR << 16; 366562306a36Sopenharmony_ci break; 366662306a36Sopenharmony_ci } 366762306a36Sopenharmony_ci 366862306a36Sopenharmony_ciout: 366962306a36Sopenharmony_ci if (logit) 367062306a36Sopenharmony_ci ql_dbg(ql_dbg_io, fcport->vha, 0x3022, 367162306a36Sopenharmony_ci "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n", 367262306a36Sopenharmony_ci comp_status, scsi_status, res, vha->host_no, 367362306a36Sopenharmony_ci cp->device->id, cp->device->lun, fcport->d_id.b.domain, 367462306a36Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id, 367562306a36Sopenharmony_ci cp->cmnd, scsi_bufflen(cp), rsp_info_len, 367662306a36Sopenharmony_ci resid_len, fw_resid_len, sp, cp); 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_ci if (rsp->status_srb == NULL) 367962306a36Sopenharmony_ci sp->done(sp, res); 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_ci /* for io's, clearing of outstanding_cmds[handle] means scsi_done was called */ 368262306a36Sopenharmony_ci req->outstanding_cmds[handle] = NULL; 368362306a36Sopenharmony_ci} 368462306a36Sopenharmony_ci 368562306a36Sopenharmony_ci/** 368662306a36Sopenharmony_ci * qla2x00_status_cont_entry() - Process a Status Continuations entry. 368762306a36Sopenharmony_ci * @rsp: response queue 368862306a36Sopenharmony_ci * @pkt: Entry pointer 368962306a36Sopenharmony_ci * 369062306a36Sopenharmony_ci * Extended sense data. 369162306a36Sopenharmony_ci */ 369262306a36Sopenharmony_cistatic void 369362306a36Sopenharmony_ciqla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) 369462306a36Sopenharmony_ci{ 369562306a36Sopenharmony_ci uint8_t sense_sz = 0; 369662306a36Sopenharmony_ci struct qla_hw_data *ha = rsp->hw; 369762306a36Sopenharmony_ci struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev); 369862306a36Sopenharmony_ci srb_t *sp = rsp->status_srb; 369962306a36Sopenharmony_ci struct scsi_cmnd *cp; 370062306a36Sopenharmony_ci uint32_t sense_len; 370162306a36Sopenharmony_ci uint8_t *sense_ptr; 370262306a36Sopenharmony_ci 370362306a36Sopenharmony_ci if (!sp || !GET_CMD_SENSE_LEN(sp)) 370462306a36Sopenharmony_ci return; 370562306a36Sopenharmony_ci 370662306a36Sopenharmony_ci sense_len = GET_CMD_SENSE_LEN(sp); 370762306a36Sopenharmony_ci sense_ptr = GET_CMD_SENSE_PTR(sp); 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci cp = GET_CMD_SP(sp); 371062306a36Sopenharmony_ci if (cp == NULL) { 371162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x3025, 371262306a36Sopenharmony_ci "cmd is NULL: already returned to OS (sp=%p).\n", sp); 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_ci rsp->status_srb = NULL; 371562306a36Sopenharmony_ci return; 371662306a36Sopenharmony_ci } 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci if (sense_len > sizeof(pkt->data)) 371962306a36Sopenharmony_ci sense_sz = sizeof(pkt->data); 372062306a36Sopenharmony_ci else 372162306a36Sopenharmony_ci sense_sz = sense_len; 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci /* Move sense data. */ 372462306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) 372562306a36Sopenharmony_ci host_to_fcp_swap(pkt->data, sizeof(pkt->data)); 372662306a36Sopenharmony_ci memcpy(sense_ptr, pkt->data, sense_sz); 372762306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c, 372862306a36Sopenharmony_ci sense_ptr, sense_sz); 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci sense_len -= sense_sz; 373162306a36Sopenharmony_ci sense_ptr += sense_sz; 373262306a36Sopenharmony_ci 373362306a36Sopenharmony_ci SET_CMD_SENSE_PTR(sp, sense_ptr); 373462306a36Sopenharmony_ci SET_CMD_SENSE_LEN(sp, sense_len); 373562306a36Sopenharmony_ci 373662306a36Sopenharmony_ci /* Place command on done queue. */ 373762306a36Sopenharmony_ci if (sense_len == 0) { 373862306a36Sopenharmony_ci rsp->status_srb = NULL; 373962306a36Sopenharmony_ci sp->done(sp, cp->result); 374062306a36Sopenharmony_ci } 374162306a36Sopenharmony_ci} 374262306a36Sopenharmony_ci 374362306a36Sopenharmony_ci/** 374462306a36Sopenharmony_ci * qla2x00_error_entry() - Process an error entry. 374562306a36Sopenharmony_ci * @vha: SCSI driver HA context 374662306a36Sopenharmony_ci * @rsp: response queue 374762306a36Sopenharmony_ci * @pkt: Entry pointer 374862306a36Sopenharmony_ci * return : 1=allow further error analysis. 0=no additional error analysis. 374962306a36Sopenharmony_ci */ 375062306a36Sopenharmony_cistatic int 375162306a36Sopenharmony_ciqla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) 375262306a36Sopenharmony_ci{ 375362306a36Sopenharmony_ci srb_t *sp; 375462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 375562306a36Sopenharmony_ci const char func[] = "ERROR-IOCB"; 375662306a36Sopenharmony_ci uint16_t que = MSW(pkt->handle); 375762306a36Sopenharmony_ci struct req_que *req = NULL; 375862306a36Sopenharmony_ci int res = DID_ERROR << 16; 375962306a36Sopenharmony_ci u16 index; 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x502a, 376262306a36Sopenharmony_ci "iocb type %xh with error status %xh, handle %xh, rspq id %d\n", 376362306a36Sopenharmony_ci pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id); 376462306a36Sopenharmony_ci 376562306a36Sopenharmony_ci if (que >= ha->max_req_queues || !ha->req_q_map[que]) 376662306a36Sopenharmony_ci goto fatal; 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci req = ha->req_q_map[que]; 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci if (pkt->entry_status & RF_BUSY) 377162306a36Sopenharmony_ci res = DID_BUS_BUSY << 16; 377262306a36Sopenharmony_ci 377362306a36Sopenharmony_ci if ((pkt->handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE) 377462306a36Sopenharmony_ci return 0; 377562306a36Sopenharmony_ci 377662306a36Sopenharmony_ci switch (pkt->entry_type) { 377762306a36Sopenharmony_ci case NOTIFY_ACK_TYPE: 377862306a36Sopenharmony_ci case STATUS_CONT_TYPE: 377962306a36Sopenharmony_ci case LOGINOUT_PORT_IOCB_TYPE: 378062306a36Sopenharmony_ci case CT_IOCB_TYPE: 378162306a36Sopenharmony_ci case ELS_IOCB_TYPE: 378262306a36Sopenharmony_ci case ABORT_IOCB_TYPE: 378362306a36Sopenharmony_ci case MBX_IOCB_TYPE: 378462306a36Sopenharmony_ci default: 378562306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 378662306a36Sopenharmony_ci if (sp) { 378762306a36Sopenharmony_ci sp->done(sp, res); 378862306a36Sopenharmony_ci return 0; 378962306a36Sopenharmony_ci } 379062306a36Sopenharmony_ci break; 379162306a36Sopenharmony_ci 379262306a36Sopenharmony_ci case SA_UPDATE_IOCB_TYPE: 379362306a36Sopenharmony_ci case ABTS_RESP_24XX: 379462306a36Sopenharmony_ci case CTIO_TYPE7: 379562306a36Sopenharmony_ci case CTIO_CRC2: 379662306a36Sopenharmony_ci return 1; 379762306a36Sopenharmony_ci case STATUS_TYPE: 379862306a36Sopenharmony_ci sp = qla_get_sp_from_handle(vha, func, req, pkt, &index); 379962306a36Sopenharmony_ci if (sp) { 380062306a36Sopenharmony_ci sp->done(sp, res); 380162306a36Sopenharmony_ci req->outstanding_cmds[index] = NULL; 380262306a36Sopenharmony_ci return 0; 380362306a36Sopenharmony_ci } 380462306a36Sopenharmony_ci break; 380562306a36Sopenharmony_ci } 380662306a36Sopenharmony_cifatal: 380762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5030, 380862306a36Sopenharmony_ci "Error entry - invalid handle/queue (%04x).\n", que); 380962306a36Sopenharmony_ci return 0; 381062306a36Sopenharmony_ci} 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci/** 381362306a36Sopenharmony_ci * qla24xx_mbx_completion() - Process mailbox command completions. 381462306a36Sopenharmony_ci * @vha: SCSI driver HA context 381562306a36Sopenharmony_ci * @mb0: Mailbox0 register 381662306a36Sopenharmony_ci */ 381762306a36Sopenharmony_cistatic void 381862306a36Sopenharmony_ciqla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) 381962306a36Sopenharmony_ci{ 382062306a36Sopenharmony_ci uint16_t cnt; 382162306a36Sopenharmony_ci uint32_t mboxes; 382262306a36Sopenharmony_ci __le16 __iomem *wptr; 382362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 382462306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; 382562306a36Sopenharmony_ci 382662306a36Sopenharmony_ci /* Read all mbox registers? */ 382762306a36Sopenharmony_ci WARN_ON_ONCE(ha->mbx_count > 32); 382862306a36Sopenharmony_ci mboxes = (1ULL << ha->mbx_count) - 1; 382962306a36Sopenharmony_ci if (!ha->mcp) 383062306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n"); 383162306a36Sopenharmony_ci else 383262306a36Sopenharmony_ci mboxes = ha->mcp->in_mb; 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci /* Load return mailbox registers. */ 383562306a36Sopenharmony_ci ha->flags.mbox_int = 1; 383662306a36Sopenharmony_ci ha->mailbox_out[0] = mb0; 383762306a36Sopenharmony_ci mboxes >>= 1; 383862306a36Sopenharmony_ci wptr = ®->mailbox1; 383962306a36Sopenharmony_ci 384062306a36Sopenharmony_ci for (cnt = 1; cnt < ha->mbx_count; cnt++) { 384162306a36Sopenharmony_ci if (mboxes & BIT_0) 384262306a36Sopenharmony_ci ha->mailbox_out[cnt] = rd_reg_word(wptr); 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ci mboxes >>= 1; 384562306a36Sopenharmony_ci wptr++; 384662306a36Sopenharmony_ci } 384762306a36Sopenharmony_ci} 384862306a36Sopenharmony_ci 384962306a36Sopenharmony_cistatic void 385062306a36Sopenharmony_ciqla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 385162306a36Sopenharmony_ci struct abort_entry_24xx *pkt) 385262306a36Sopenharmony_ci{ 385362306a36Sopenharmony_ci const char func[] = "ABT_IOCB"; 385462306a36Sopenharmony_ci srb_t *sp; 385562306a36Sopenharmony_ci srb_t *orig_sp = NULL; 385662306a36Sopenharmony_ci struct srb_iocb *abt; 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 385962306a36Sopenharmony_ci if (!sp) 386062306a36Sopenharmony_ci return; 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci abt = &sp->u.iocb_cmd; 386362306a36Sopenharmony_ci abt->u.abt.comp_status = pkt->comp_status; 386462306a36Sopenharmony_ci orig_sp = sp->cmd_sp; 386562306a36Sopenharmony_ci /* Need to pass original sp */ 386662306a36Sopenharmony_ci if (orig_sp) 386762306a36Sopenharmony_ci qla_nvme_abort_process_comp_status(pkt, orig_sp); 386862306a36Sopenharmony_ci 386962306a36Sopenharmony_ci sp->done(sp, 0); 387062306a36Sopenharmony_ci} 387162306a36Sopenharmony_ci 387262306a36Sopenharmony_civoid qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha, 387362306a36Sopenharmony_ci struct pt_ls4_request *pkt, struct req_que *req) 387462306a36Sopenharmony_ci{ 387562306a36Sopenharmony_ci srb_t *sp; 387662306a36Sopenharmony_ci const char func[] = "LS4_IOCB"; 387762306a36Sopenharmony_ci uint16_t comp_status; 387862306a36Sopenharmony_ci 387962306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 388062306a36Sopenharmony_ci if (!sp) 388162306a36Sopenharmony_ci return; 388262306a36Sopenharmony_ci 388362306a36Sopenharmony_ci comp_status = le16_to_cpu(pkt->status); 388462306a36Sopenharmony_ci sp->done(sp, comp_status); 388562306a36Sopenharmony_ci} 388662306a36Sopenharmony_ci 388762306a36Sopenharmony_ci/** 388862306a36Sopenharmony_ci * qla_chk_cont_iocb_avail - check for all continuation iocbs are available 388962306a36Sopenharmony_ci * before iocb processing can start. 389062306a36Sopenharmony_ci * @vha: host adapter pointer 389162306a36Sopenharmony_ci * @rsp: respond queue 389262306a36Sopenharmony_ci * @pkt: head iocb describing how many continuation iocb 389362306a36Sopenharmony_ci * Return: 0 all iocbs has arrived, xx- all iocbs have not arrived. 389462306a36Sopenharmony_ci */ 389562306a36Sopenharmony_cistatic int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha, 389662306a36Sopenharmony_ci struct rsp_que *rsp, response_t *pkt, u32 rsp_q_in) 389762306a36Sopenharmony_ci{ 389862306a36Sopenharmony_ci int start_pkt_ring_index; 389962306a36Sopenharmony_ci u32 iocb_cnt = 0; 390062306a36Sopenharmony_ci int rc = 0; 390162306a36Sopenharmony_ci 390262306a36Sopenharmony_ci if (pkt->entry_count == 1) 390362306a36Sopenharmony_ci return rc; 390462306a36Sopenharmony_ci 390562306a36Sopenharmony_ci /* ring_index was pre-increment. set it back to current pkt */ 390662306a36Sopenharmony_ci if (rsp->ring_index == 0) 390762306a36Sopenharmony_ci start_pkt_ring_index = rsp->length - 1; 390862306a36Sopenharmony_ci else 390962306a36Sopenharmony_ci start_pkt_ring_index = rsp->ring_index - 1; 391062306a36Sopenharmony_ci 391162306a36Sopenharmony_ci if (rsp_q_in < start_pkt_ring_index) 391262306a36Sopenharmony_ci /* q in ptr is wrapped */ 391362306a36Sopenharmony_ci iocb_cnt = rsp->length - start_pkt_ring_index + rsp_q_in; 391462306a36Sopenharmony_ci else 391562306a36Sopenharmony_ci iocb_cnt = rsp_q_in - start_pkt_ring_index; 391662306a36Sopenharmony_ci 391762306a36Sopenharmony_ci if (iocb_cnt < pkt->entry_count) 391862306a36Sopenharmony_ci rc = -EIO; 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x5091, 392162306a36Sopenharmony_ci "%s - ring %p pkt %p entry count %d iocb_cnt %d rsp_q_in %d rc %d\n", 392262306a36Sopenharmony_ci __func__, rsp->ring, pkt, pkt->entry_count, iocb_cnt, rsp_q_in, rc); 392362306a36Sopenharmony_ci 392462306a36Sopenharmony_ci return rc; 392562306a36Sopenharmony_ci} 392662306a36Sopenharmony_ci 392762306a36Sopenharmony_cistatic void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, 392862306a36Sopenharmony_ci struct mrk_entry_24xx *pkt) 392962306a36Sopenharmony_ci{ 393062306a36Sopenharmony_ci const char func[] = "MRK-IOCB"; 393162306a36Sopenharmony_ci srb_t *sp; 393262306a36Sopenharmony_ci int res = QLA_SUCCESS; 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ci if (!IS_FWI2_CAPABLE(vha->hw)) 393562306a36Sopenharmony_ci return; 393662306a36Sopenharmony_ci 393762306a36Sopenharmony_ci sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); 393862306a36Sopenharmony_ci if (!sp) 393962306a36Sopenharmony_ci return; 394062306a36Sopenharmony_ci 394162306a36Sopenharmony_ci if (pkt->entry_status) { 394262306a36Sopenharmony_ci ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n"); 394362306a36Sopenharmony_ci res = QLA_COMMAND_ERROR; 394462306a36Sopenharmony_ci } 394562306a36Sopenharmony_ci sp->u.iocb_cmd.u.tmf.data = res; 394662306a36Sopenharmony_ci sp->done(sp, res); 394762306a36Sopenharmony_ci} 394862306a36Sopenharmony_ci 394962306a36Sopenharmony_ci/** 395062306a36Sopenharmony_ci * qla24xx_process_response_queue() - Process response queue entries. 395162306a36Sopenharmony_ci * @vha: SCSI driver HA context 395262306a36Sopenharmony_ci * @rsp: response queue 395362306a36Sopenharmony_ci */ 395462306a36Sopenharmony_civoid qla24xx_process_response_queue(struct scsi_qla_host *vha, 395562306a36Sopenharmony_ci struct rsp_que *rsp) 395662306a36Sopenharmony_ci{ 395762306a36Sopenharmony_ci struct sts_entry_24xx *pkt; 395862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 395962306a36Sopenharmony_ci struct purex_entry_24xx *purex_entry; 396062306a36Sopenharmony_ci struct purex_item *pure_item; 396162306a36Sopenharmony_ci struct pt_ls4_rx_unsol *p; 396262306a36Sopenharmony_ci u16 rsp_in = 0, cur_ring_index; 396362306a36Sopenharmony_ci int is_shadow_hba; 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_ci if (!ha->flags.fw_started) 396662306a36Sopenharmony_ci return; 396762306a36Sopenharmony_ci 396862306a36Sopenharmony_ci if (rsp->qpair->cpuid != raw_smp_processor_id() || !rsp->qpair->rcv_intr) { 396962306a36Sopenharmony_ci rsp->qpair->rcv_intr = 1; 397062306a36Sopenharmony_ci 397162306a36Sopenharmony_ci if (!rsp->qpair->cpu_mapped) 397262306a36Sopenharmony_ci qla_cpu_update(rsp->qpair, raw_smp_processor_id()); 397362306a36Sopenharmony_ci } 397462306a36Sopenharmony_ci 397562306a36Sopenharmony_ci#define __update_rsp_in(_is_shadow_hba, _rsp, _rsp_in) \ 397662306a36Sopenharmony_ci do { \ 397762306a36Sopenharmony_ci _rsp_in = _is_shadow_hba ? *(_rsp)->in_ptr : \ 397862306a36Sopenharmony_ci rd_reg_dword_relaxed((_rsp)->rsp_q_in); \ 397962306a36Sopenharmony_ci } while (0) 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci is_shadow_hba = IS_SHADOW_REG_CAPABLE(ha); 398262306a36Sopenharmony_ci 398362306a36Sopenharmony_ci __update_rsp_in(is_shadow_hba, rsp, rsp_in); 398462306a36Sopenharmony_ci 398562306a36Sopenharmony_ci while (rsp->ring_index != rsp_in && 398662306a36Sopenharmony_ci rsp->ring_ptr->signature != RESPONSE_PROCESSED) { 398762306a36Sopenharmony_ci pkt = (struct sts_entry_24xx *)rsp->ring_ptr; 398862306a36Sopenharmony_ci cur_ring_index = rsp->ring_index; 398962306a36Sopenharmony_ci 399062306a36Sopenharmony_ci rsp->ring_index++; 399162306a36Sopenharmony_ci if (rsp->ring_index == rsp->length) { 399262306a36Sopenharmony_ci rsp->ring_index = 0; 399362306a36Sopenharmony_ci rsp->ring_ptr = rsp->ring; 399462306a36Sopenharmony_ci } else { 399562306a36Sopenharmony_ci rsp->ring_ptr++; 399662306a36Sopenharmony_ci } 399762306a36Sopenharmony_ci 399862306a36Sopenharmony_ci if (pkt->entry_status != 0) { 399962306a36Sopenharmony_ci if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt)) 400062306a36Sopenharmony_ci goto process_err; 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci ((response_t *)pkt)->signature = RESPONSE_PROCESSED; 400362306a36Sopenharmony_ci wmb(); 400462306a36Sopenharmony_ci continue; 400562306a36Sopenharmony_ci } 400662306a36Sopenharmony_ciprocess_err: 400762306a36Sopenharmony_ci 400862306a36Sopenharmony_ci switch (pkt->entry_type) { 400962306a36Sopenharmony_ci case STATUS_TYPE: 401062306a36Sopenharmony_ci qla2x00_status_entry(vha, rsp, pkt); 401162306a36Sopenharmony_ci break; 401262306a36Sopenharmony_ci case STATUS_CONT_TYPE: 401362306a36Sopenharmony_ci qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); 401462306a36Sopenharmony_ci break; 401562306a36Sopenharmony_ci case VP_RPT_ID_IOCB_TYPE: 401662306a36Sopenharmony_ci qla24xx_report_id_acquisition(vha, 401762306a36Sopenharmony_ci (struct vp_rpt_id_entry_24xx *)pkt); 401862306a36Sopenharmony_ci break; 401962306a36Sopenharmony_ci case LOGINOUT_PORT_IOCB_TYPE: 402062306a36Sopenharmony_ci qla24xx_logio_entry(vha, rsp->req, 402162306a36Sopenharmony_ci (struct logio_entry_24xx *)pkt); 402262306a36Sopenharmony_ci break; 402362306a36Sopenharmony_ci case CT_IOCB_TYPE: 402462306a36Sopenharmony_ci qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); 402562306a36Sopenharmony_ci break; 402662306a36Sopenharmony_ci case ELS_IOCB_TYPE: 402762306a36Sopenharmony_ci qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); 402862306a36Sopenharmony_ci break; 402962306a36Sopenharmony_ci case ABTS_RECV_24XX: 403062306a36Sopenharmony_ci if (qla_ini_mode_enabled(vha)) { 403162306a36Sopenharmony_ci pure_item = qla24xx_copy_std_pkt(vha, pkt); 403262306a36Sopenharmony_ci if (!pure_item) 403362306a36Sopenharmony_ci break; 403462306a36Sopenharmony_ci qla24xx_queue_purex_item(vha, pure_item, 403562306a36Sopenharmony_ci qla24xx_process_abts); 403662306a36Sopenharmony_ci break; 403762306a36Sopenharmony_ci } 403862306a36Sopenharmony_ci if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || 403962306a36Sopenharmony_ci IS_QLA28XX(ha)) { 404062306a36Sopenharmony_ci /* ensure that the ATIO queue is empty */ 404162306a36Sopenharmony_ci qlt_handle_abts_recv(vha, rsp, 404262306a36Sopenharmony_ci (response_t *)pkt); 404362306a36Sopenharmony_ci break; 404462306a36Sopenharmony_ci } else { 404562306a36Sopenharmony_ci qlt_24xx_process_atio_queue(vha, 1); 404662306a36Sopenharmony_ci } 404762306a36Sopenharmony_ci fallthrough; 404862306a36Sopenharmony_ci case ABTS_RESP_24XX: 404962306a36Sopenharmony_ci case CTIO_TYPE7: 405062306a36Sopenharmony_ci case CTIO_CRC2: 405162306a36Sopenharmony_ci qlt_response_pkt_all_vps(vha, rsp, (response_t *)pkt); 405262306a36Sopenharmony_ci break; 405362306a36Sopenharmony_ci case PT_LS4_REQUEST: 405462306a36Sopenharmony_ci qla24xx_nvme_ls4_iocb(vha, (struct pt_ls4_request *)pkt, 405562306a36Sopenharmony_ci rsp->req); 405662306a36Sopenharmony_ci break; 405762306a36Sopenharmony_ci case NOTIFY_ACK_TYPE: 405862306a36Sopenharmony_ci if (pkt->handle == QLA_TGT_SKIP_HANDLE) 405962306a36Sopenharmony_ci qlt_response_pkt_all_vps(vha, rsp, 406062306a36Sopenharmony_ci (response_t *)pkt); 406162306a36Sopenharmony_ci else 406262306a36Sopenharmony_ci qla24xxx_nack_iocb_entry(vha, rsp->req, 406362306a36Sopenharmony_ci (struct nack_to_isp *)pkt); 406462306a36Sopenharmony_ci break; 406562306a36Sopenharmony_ci case MARKER_TYPE: 406662306a36Sopenharmony_ci qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt); 406762306a36Sopenharmony_ci break; 406862306a36Sopenharmony_ci case ABORT_IOCB_TYPE: 406962306a36Sopenharmony_ci qla24xx_abort_iocb_entry(vha, rsp->req, 407062306a36Sopenharmony_ci (struct abort_entry_24xx *)pkt); 407162306a36Sopenharmony_ci break; 407262306a36Sopenharmony_ci case MBX_IOCB_TYPE: 407362306a36Sopenharmony_ci qla24xx_mbx_iocb_entry(vha, rsp->req, 407462306a36Sopenharmony_ci (struct mbx_24xx_entry *)pkt); 407562306a36Sopenharmony_ci break; 407662306a36Sopenharmony_ci case VP_CTRL_IOCB_TYPE: 407762306a36Sopenharmony_ci qla_ctrlvp_completed(vha, rsp->req, 407862306a36Sopenharmony_ci (struct vp_ctrl_entry_24xx *)pkt); 407962306a36Sopenharmony_ci break; 408062306a36Sopenharmony_ci case PUREX_IOCB_TYPE: 408162306a36Sopenharmony_ci purex_entry = (void *)pkt; 408262306a36Sopenharmony_ci switch (purex_entry->els_frame_payload[3]) { 408362306a36Sopenharmony_ci case ELS_RDP: 408462306a36Sopenharmony_ci pure_item = qla24xx_copy_std_pkt(vha, pkt); 408562306a36Sopenharmony_ci if (!pure_item) 408662306a36Sopenharmony_ci break; 408762306a36Sopenharmony_ci qla24xx_queue_purex_item(vha, pure_item, 408862306a36Sopenharmony_ci qla24xx_process_purex_rdp); 408962306a36Sopenharmony_ci break; 409062306a36Sopenharmony_ci case ELS_FPIN: 409162306a36Sopenharmony_ci if (!vha->hw->flags.scm_enabled) { 409262306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x5094, 409362306a36Sopenharmony_ci "SCM not active for this port\n"); 409462306a36Sopenharmony_ci break; 409562306a36Sopenharmony_ci } 409662306a36Sopenharmony_ci pure_item = qla27xx_copy_fpin_pkt(vha, 409762306a36Sopenharmony_ci (void **)&pkt, &rsp); 409862306a36Sopenharmony_ci __update_rsp_in(is_shadow_hba, rsp, rsp_in); 409962306a36Sopenharmony_ci if (!pure_item) 410062306a36Sopenharmony_ci break; 410162306a36Sopenharmony_ci qla24xx_queue_purex_item(vha, pure_item, 410262306a36Sopenharmony_ci qla27xx_process_purex_fpin); 410362306a36Sopenharmony_ci break; 410462306a36Sopenharmony_ci 410562306a36Sopenharmony_ci case ELS_AUTH_ELS: 410662306a36Sopenharmony_ci if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) { 410762306a36Sopenharmony_ci /* 410862306a36Sopenharmony_ci * ring_ptr and ring_index were 410962306a36Sopenharmony_ci * pre-incremented above. Reset them 411062306a36Sopenharmony_ci * back to current. Wait for next 411162306a36Sopenharmony_ci * interrupt with all IOCBs to arrive 411262306a36Sopenharmony_ci * and re-process. 411362306a36Sopenharmony_ci */ 411462306a36Sopenharmony_ci rsp->ring_ptr = (response_t *)pkt; 411562306a36Sopenharmony_ci rsp->ring_index = cur_ring_index; 411662306a36Sopenharmony_ci 411762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x5091, 411862306a36Sopenharmony_ci "Defer processing ELS opcode %#x...\n", 411962306a36Sopenharmony_ci purex_entry->els_frame_payload[3]); 412062306a36Sopenharmony_ci return; 412162306a36Sopenharmony_ci } 412262306a36Sopenharmony_ci qla24xx_auth_els(vha, (void **)&pkt, &rsp); 412362306a36Sopenharmony_ci break; 412462306a36Sopenharmony_ci default: 412562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x509c, 412662306a36Sopenharmony_ci "Discarding ELS Request opcode 0x%x\n", 412762306a36Sopenharmony_ci purex_entry->els_frame_payload[3]); 412862306a36Sopenharmony_ci } 412962306a36Sopenharmony_ci break; 413062306a36Sopenharmony_ci case SA_UPDATE_IOCB_TYPE: 413162306a36Sopenharmony_ci qla28xx_sa_update_iocb_entry(vha, rsp->req, 413262306a36Sopenharmony_ci (struct sa_update_28xx *)pkt); 413362306a36Sopenharmony_ci break; 413462306a36Sopenharmony_ci case PT_LS4_UNSOL: 413562306a36Sopenharmony_ci p = (void *)pkt; 413662306a36Sopenharmony_ci if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) { 413762306a36Sopenharmony_ci rsp->ring_ptr = (response_t *)pkt; 413862306a36Sopenharmony_ci rsp->ring_index = cur_ring_index; 413962306a36Sopenharmony_ci 414062306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x2124, 414162306a36Sopenharmony_ci "Defer processing UNSOL LS req opcode %#x...\n", 414262306a36Sopenharmony_ci p->payload[0]); 414362306a36Sopenharmony_ci return; 414462306a36Sopenharmony_ci } 414562306a36Sopenharmony_ci qla2xxx_process_purls_iocb((void **)&pkt, &rsp); 414662306a36Sopenharmony_ci break; 414762306a36Sopenharmony_ci default: 414862306a36Sopenharmony_ci /* Type Not Supported. */ 414962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5042, 415062306a36Sopenharmony_ci "Received unknown response pkt type 0x%x entry status=%x.\n", 415162306a36Sopenharmony_ci pkt->entry_type, pkt->entry_status); 415262306a36Sopenharmony_ci break; 415362306a36Sopenharmony_ci } 415462306a36Sopenharmony_ci ((response_t *)pkt)->signature = RESPONSE_PROCESSED; 415562306a36Sopenharmony_ci wmb(); 415662306a36Sopenharmony_ci } 415762306a36Sopenharmony_ci 415862306a36Sopenharmony_ci /* Adjust ring index */ 415962306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) { 416062306a36Sopenharmony_ci struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; 416162306a36Sopenharmony_ci 416262306a36Sopenharmony_ci wrt_reg_dword(®->rsp_q_out[0], rsp->ring_index); 416362306a36Sopenharmony_ci } else { 416462306a36Sopenharmony_ci wrt_reg_dword(rsp->rsp_q_out, rsp->ring_index); 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci} 416762306a36Sopenharmony_ci 416862306a36Sopenharmony_cistatic void 416962306a36Sopenharmony_ciqla2xxx_check_risc_status(scsi_qla_host_t *vha) 417062306a36Sopenharmony_ci{ 417162306a36Sopenharmony_ci int rval; 417262306a36Sopenharmony_ci uint32_t cnt; 417362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 417462306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; 417562306a36Sopenharmony_ci 417662306a36Sopenharmony_ci if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) && 417762306a36Sopenharmony_ci !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) 417862306a36Sopenharmony_ci return; 417962306a36Sopenharmony_ci 418062306a36Sopenharmony_ci rval = QLA_SUCCESS; 418162306a36Sopenharmony_ci wrt_reg_dword(®->iobase_addr, 0x7C00); 418262306a36Sopenharmony_ci rd_reg_dword(®->iobase_addr); 418362306a36Sopenharmony_ci wrt_reg_dword(®->iobase_window, 0x0001); 418462306a36Sopenharmony_ci for (cnt = 10000; (rd_reg_dword(®->iobase_window) & BIT_0) == 0 && 418562306a36Sopenharmony_ci rval == QLA_SUCCESS; cnt--) { 418662306a36Sopenharmony_ci if (cnt) { 418762306a36Sopenharmony_ci wrt_reg_dword(®->iobase_window, 0x0001); 418862306a36Sopenharmony_ci udelay(10); 418962306a36Sopenharmony_ci } else 419062306a36Sopenharmony_ci rval = QLA_FUNCTION_TIMEOUT; 419162306a36Sopenharmony_ci } 419262306a36Sopenharmony_ci if (rval == QLA_SUCCESS) 419362306a36Sopenharmony_ci goto next_test; 419462306a36Sopenharmony_ci 419562306a36Sopenharmony_ci rval = QLA_SUCCESS; 419662306a36Sopenharmony_ci wrt_reg_dword(®->iobase_window, 0x0003); 419762306a36Sopenharmony_ci for (cnt = 100; (rd_reg_dword(®->iobase_window) & BIT_0) == 0 && 419862306a36Sopenharmony_ci rval == QLA_SUCCESS; cnt--) { 419962306a36Sopenharmony_ci if (cnt) { 420062306a36Sopenharmony_ci wrt_reg_dword(®->iobase_window, 0x0003); 420162306a36Sopenharmony_ci udelay(10); 420262306a36Sopenharmony_ci } else 420362306a36Sopenharmony_ci rval = QLA_FUNCTION_TIMEOUT; 420462306a36Sopenharmony_ci } 420562306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 420662306a36Sopenharmony_ci goto done; 420762306a36Sopenharmony_ci 420862306a36Sopenharmony_cinext_test: 420962306a36Sopenharmony_ci if (rd_reg_dword(®->iobase_c8) & BIT_3) 421062306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x504c, 421162306a36Sopenharmony_ci "Additional code -- 0x55AA.\n"); 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_cidone: 421462306a36Sopenharmony_ci wrt_reg_dword(®->iobase_window, 0x0000); 421562306a36Sopenharmony_ci rd_reg_dword(®->iobase_window); 421662306a36Sopenharmony_ci} 421762306a36Sopenharmony_ci 421862306a36Sopenharmony_ci/** 421962306a36Sopenharmony_ci * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx. 422062306a36Sopenharmony_ci * @irq: interrupt number 422162306a36Sopenharmony_ci * @dev_id: SCSI driver HA context 422262306a36Sopenharmony_ci * 422362306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt. 422462306a36Sopenharmony_ci * 422562306a36Sopenharmony_ci * Returns handled flag. 422662306a36Sopenharmony_ci */ 422762306a36Sopenharmony_ciirqreturn_t 422862306a36Sopenharmony_ciqla24xx_intr_handler(int irq, void *dev_id) 422962306a36Sopenharmony_ci{ 423062306a36Sopenharmony_ci scsi_qla_host_t *vha; 423162306a36Sopenharmony_ci struct qla_hw_data *ha; 423262306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg; 423362306a36Sopenharmony_ci int status; 423462306a36Sopenharmony_ci unsigned long iter; 423562306a36Sopenharmony_ci uint32_t stat; 423662306a36Sopenharmony_ci uint32_t hccr; 423762306a36Sopenharmony_ci uint16_t mb[8]; 423862306a36Sopenharmony_ci struct rsp_que *rsp; 423962306a36Sopenharmony_ci unsigned long flags; 424062306a36Sopenharmony_ci bool process_atio = false; 424162306a36Sopenharmony_ci 424262306a36Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 424362306a36Sopenharmony_ci if (!rsp) { 424462306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x5059, 424562306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 424662306a36Sopenharmony_ci return IRQ_NONE; 424762306a36Sopenharmony_ci } 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_ci ha = rsp->hw; 425062306a36Sopenharmony_ci reg = &ha->iobase->isp24; 425162306a36Sopenharmony_ci status = 0; 425262306a36Sopenharmony_ci 425362306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 425462306a36Sopenharmony_ci return IRQ_HANDLED; 425562306a36Sopenharmony_ci 425662306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 425762306a36Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 425862306a36Sopenharmony_ci for (iter = 50; iter--; ) { 425962306a36Sopenharmony_ci stat = rd_reg_dword(®->host_status); 426062306a36Sopenharmony_ci if (qla2x00_check_reg32_for_disconnect(vha, stat)) 426162306a36Sopenharmony_ci break; 426262306a36Sopenharmony_ci if (stat & HSRX_RISC_PAUSED) { 426362306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 426462306a36Sopenharmony_ci break; 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_ci hccr = rd_reg_dword(®->hccr); 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x504b, 426962306a36Sopenharmony_ci "RISC paused -- HCCR=%x, Dumping firmware.\n", 427062306a36Sopenharmony_ci hccr); 427162306a36Sopenharmony_ci 427262306a36Sopenharmony_ci qla2xxx_check_risc_status(vha); 427362306a36Sopenharmony_ci 427462306a36Sopenharmony_ci ha->isp_ops->fw_dump(vha); 427562306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 427662306a36Sopenharmony_ci break; 427762306a36Sopenharmony_ci } else if ((stat & HSRX_RISC_INT) == 0) 427862306a36Sopenharmony_ci break; 427962306a36Sopenharmony_ci 428062306a36Sopenharmony_ci switch (stat & 0xff) { 428162306a36Sopenharmony_ci case INTR_ROM_MB_SUCCESS: 428262306a36Sopenharmony_ci case INTR_ROM_MB_FAILED: 428362306a36Sopenharmony_ci case INTR_MB_SUCCESS: 428462306a36Sopenharmony_ci case INTR_MB_FAILED: 428562306a36Sopenharmony_ci qla24xx_mbx_completion(vha, MSW(stat)); 428662306a36Sopenharmony_ci status |= MBX_INTERRUPT; 428762306a36Sopenharmony_ci 428862306a36Sopenharmony_ci break; 428962306a36Sopenharmony_ci case INTR_ASYNC_EVENT: 429062306a36Sopenharmony_ci mb[0] = MSW(stat); 429162306a36Sopenharmony_ci mb[1] = rd_reg_word(®->mailbox1); 429262306a36Sopenharmony_ci mb[2] = rd_reg_word(®->mailbox2); 429362306a36Sopenharmony_ci mb[3] = rd_reg_word(®->mailbox3); 429462306a36Sopenharmony_ci qla2x00_async_event(vha, rsp, mb); 429562306a36Sopenharmony_ci break; 429662306a36Sopenharmony_ci case INTR_RSP_QUE_UPDATE: 429762306a36Sopenharmony_ci case INTR_RSP_QUE_UPDATE_83XX: 429862306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 429962306a36Sopenharmony_ci break; 430062306a36Sopenharmony_ci case INTR_ATIO_QUE_UPDATE_27XX: 430162306a36Sopenharmony_ci case INTR_ATIO_QUE_UPDATE: 430262306a36Sopenharmony_ci process_atio = true; 430362306a36Sopenharmony_ci break; 430462306a36Sopenharmony_ci case INTR_ATIO_RSP_QUE_UPDATE: 430562306a36Sopenharmony_ci process_atio = true; 430662306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 430762306a36Sopenharmony_ci break; 430862306a36Sopenharmony_ci default: 430962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x504f, 431062306a36Sopenharmony_ci "Unrecognized interrupt type (%d).\n", stat * 0xff); 431162306a36Sopenharmony_ci break; 431262306a36Sopenharmony_ci } 431362306a36Sopenharmony_ci wrt_reg_dword(®->hccr, HCCRX_CLR_RISC_INT); 431462306a36Sopenharmony_ci rd_reg_dword_relaxed(®->hccr); 431562306a36Sopenharmony_ci if (unlikely(IS_QLA83XX(ha) && (ha->pdev->revision == 1))) 431662306a36Sopenharmony_ci ndelay(3500); 431762306a36Sopenharmony_ci } 431862306a36Sopenharmony_ci qla2x00_handle_mbx_completion(ha, status); 431962306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 432062306a36Sopenharmony_ci 432162306a36Sopenharmony_ci if (process_atio) { 432262306a36Sopenharmony_ci spin_lock_irqsave(&ha->tgt.atio_lock, flags); 432362306a36Sopenharmony_ci qlt_24xx_process_atio_queue(vha, 0); 432462306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); 432562306a36Sopenharmony_ci } 432662306a36Sopenharmony_ci 432762306a36Sopenharmony_ci return IRQ_HANDLED; 432862306a36Sopenharmony_ci} 432962306a36Sopenharmony_ci 433062306a36Sopenharmony_cistatic irqreturn_t 433162306a36Sopenharmony_ciqla24xx_msix_rsp_q(int irq, void *dev_id) 433262306a36Sopenharmony_ci{ 433362306a36Sopenharmony_ci struct qla_hw_data *ha; 433462306a36Sopenharmony_ci struct rsp_que *rsp; 433562306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg; 433662306a36Sopenharmony_ci struct scsi_qla_host *vha; 433762306a36Sopenharmony_ci unsigned long flags; 433862306a36Sopenharmony_ci 433962306a36Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 434062306a36Sopenharmony_ci if (!rsp) { 434162306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x505a, 434262306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 434362306a36Sopenharmony_ci return IRQ_NONE; 434462306a36Sopenharmony_ci } 434562306a36Sopenharmony_ci ha = rsp->hw; 434662306a36Sopenharmony_ci reg = &ha->iobase->isp24; 434762306a36Sopenharmony_ci 434862306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 435162306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 435262306a36Sopenharmony_ci if (!ha->flags.disable_msix_handshake) { 435362306a36Sopenharmony_ci wrt_reg_dword(®->hccr, HCCRX_CLR_RISC_INT); 435462306a36Sopenharmony_ci rd_reg_dword_relaxed(®->hccr); 435562306a36Sopenharmony_ci } 435662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 435762306a36Sopenharmony_ci 435862306a36Sopenharmony_ci return IRQ_HANDLED; 435962306a36Sopenharmony_ci} 436062306a36Sopenharmony_ci 436162306a36Sopenharmony_cistatic irqreturn_t 436262306a36Sopenharmony_ciqla24xx_msix_default(int irq, void *dev_id) 436362306a36Sopenharmony_ci{ 436462306a36Sopenharmony_ci scsi_qla_host_t *vha; 436562306a36Sopenharmony_ci struct qla_hw_data *ha; 436662306a36Sopenharmony_ci struct rsp_que *rsp; 436762306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg; 436862306a36Sopenharmony_ci int status; 436962306a36Sopenharmony_ci uint32_t stat; 437062306a36Sopenharmony_ci uint32_t hccr; 437162306a36Sopenharmony_ci uint16_t mb[8]; 437262306a36Sopenharmony_ci unsigned long flags; 437362306a36Sopenharmony_ci bool process_atio = false; 437462306a36Sopenharmony_ci 437562306a36Sopenharmony_ci rsp = (struct rsp_que *) dev_id; 437662306a36Sopenharmony_ci if (!rsp) { 437762306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x505c, 437862306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 437962306a36Sopenharmony_ci return IRQ_NONE; 438062306a36Sopenharmony_ci } 438162306a36Sopenharmony_ci ha = rsp->hw; 438262306a36Sopenharmony_ci reg = &ha->iobase->isp24; 438362306a36Sopenharmony_ci status = 0; 438462306a36Sopenharmony_ci 438562306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 438662306a36Sopenharmony_ci vha = pci_get_drvdata(ha->pdev); 438762306a36Sopenharmony_ci do { 438862306a36Sopenharmony_ci stat = rd_reg_dword(®->host_status); 438962306a36Sopenharmony_ci if (qla2x00_check_reg32_for_disconnect(vha, stat)) 439062306a36Sopenharmony_ci break; 439162306a36Sopenharmony_ci if (stat & HSRX_RISC_PAUSED) { 439262306a36Sopenharmony_ci if (unlikely(pci_channel_offline(ha->pdev))) 439362306a36Sopenharmony_ci break; 439462306a36Sopenharmony_ci 439562306a36Sopenharmony_ci hccr = rd_reg_dword(®->hccr); 439662306a36Sopenharmony_ci 439762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x5050, 439862306a36Sopenharmony_ci "RISC paused -- HCCR=%x, Dumping firmware.\n", 439962306a36Sopenharmony_ci hccr); 440062306a36Sopenharmony_ci 440162306a36Sopenharmony_ci qla2xxx_check_risc_status(vha); 440262306a36Sopenharmony_ci vha->hw_err_cnt++; 440362306a36Sopenharmony_ci 440462306a36Sopenharmony_ci ha->isp_ops->fw_dump(vha); 440562306a36Sopenharmony_ci set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); 440662306a36Sopenharmony_ci break; 440762306a36Sopenharmony_ci } else if ((stat & HSRX_RISC_INT) == 0) 440862306a36Sopenharmony_ci break; 440962306a36Sopenharmony_ci 441062306a36Sopenharmony_ci switch (stat & 0xff) { 441162306a36Sopenharmony_ci case INTR_ROM_MB_SUCCESS: 441262306a36Sopenharmony_ci case INTR_ROM_MB_FAILED: 441362306a36Sopenharmony_ci case INTR_MB_SUCCESS: 441462306a36Sopenharmony_ci case INTR_MB_FAILED: 441562306a36Sopenharmony_ci qla24xx_mbx_completion(vha, MSW(stat)); 441662306a36Sopenharmony_ci status |= MBX_INTERRUPT; 441762306a36Sopenharmony_ci 441862306a36Sopenharmony_ci break; 441962306a36Sopenharmony_ci case INTR_ASYNC_EVENT: 442062306a36Sopenharmony_ci mb[0] = MSW(stat); 442162306a36Sopenharmony_ci mb[1] = rd_reg_word(®->mailbox1); 442262306a36Sopenharmony_ci mb[2] = rd_reg_word(®->mailbox2); 442362306a36Sopenharmony_ci mb[3] = rd_reg_word(®->mailbox3); 442462306a36Sopenharmony_ci qla2x00_async_event(vha, rsp, mb); 442562306a36Sopenharmony_ci break; 442662306a36Sopenharmony_ci case INTR_RSP_QUE_UPDATE: 442762306a36Sopenharmony_ci case INTR_RSP_QUE_UPDATE_83XX: 442862306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 442962306a36Sopenharmony_ci break; 443062306a36Sopenharmony_ci case INTR_ATIO_QUE_UPDATE_27XX: 443162306a36Sopenharmony_ci case INTR_ATIO_QUE_UPDATE: 443262306a36Sopenharmony_ci process_atio = true; 443362306a36Sopenharmony_ci break; 443462306a36Sopenharmony_ci case INTR_ATIO_RSP_QUE_UPDATE: 443562306a36Sopenharmony_ci process_atio = true; 443662306a36Sopenharmony_ci qla24xx_process_response_queue(vha, rsp); 443762306a36Sopenharmony_ci break; 443862306a36Sopenharmony_ci default: 443962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x5051, 444062306a36Sopenharmony_ci "Unrecognized interrupt type (%d).\n", stat & 0xff); 444162306a36Sopenharmony_ci break; 444262306a36Sopenharmony_ci } 444362306a36Sopenharmony_ci wrt_reg_dword(®->hccr, HCCRX_CLR_RISC_INT); 444462306a36Sopenharmony_ci } while (0); 444562306a36Sopenharmony_ci qla2x00_handle_mbx_completion(ha, status); 444662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 444762306a36Sopenharmony_ci 444862306a36Sopenharmony_ci if (process_atio) { 444962306a36Sopenharmony_ci spin_lock_irqsave(&ha->tgt.atio_lock, flags); 445062306a36Sopenharmony_ci qlt_24xx_process_atio_queue(vha, 0); 445162306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); 445262306a36Sopenharmony_ci } 445362306a36Sopenharmony_ci 445462306a36Sopenharmony_ci return IRQ_HANDLED; 445562306a36Sopenharmony_ci} 445662306a36Sopenharmony_ci 445762306a36Sopenharmony_ciirqreturn_t 445862306a36Sopenharmony_ciqla2xxx_msix_rsp_q(int irq, void *dev_id) 445962306a36Sopenharmony_ci{ 446062306a36Sopenharmony_ci struct qla_hw_data *ha; 446162306a36Sopenharmony_ci struct qla_qpair *qpair; 446262306a36Sopenharmony_ci 446362306a36Sopenharmony_ci qpair = dev_id; 446462306a36Sopenharmony_ci if (!qpair) { 446562306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x505b, 446662306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 446762306a36Sopenharmony_ci return IRQ_NONE; 446862306a36Sopenharmony_ci } 446962306a36Sopenharmony_ci ha = qpair->hw; 447062306a36Sopenharmony_ci 447162306a36Sopenharmony_ci queue_work(ha->wq, &qpair->q_work); 447262306a36Sopenharmony_ci 447362306a36Sopenharmony_ci return IRQ_HANDLED; 447462306a36Sopenharmony_ci} 447562306a36Sopenharmony_ci 447662306a36Sopenharmony_ciirqreturn_t 447762306a36Sopenharmony_ciqla2xxx_msix_rsp_q_hs(int irq, void *dev_id) 447862306a36Sopenharmony_ci{ 447962306a36Sopenharmony_ci struct qla_hw_data *ha; 448062306a36Sopenharmony_ci struct qla_qpair *qpair; 448162306a36Sopenharmony_ci struct device_reg_24xx __iomem *reg; 448262306a36Sopenharmony_ci unsigned long flags; 448362306a36Sopenharmony_ci 448462306a36Sopenharmony_ci qpair = dev_id; 448562306a36Sopenharmony_ci if (!qpair) { 448662306a36Sopenharmony_ci ql_log(ql_log_info, NULL, 0x505b, 448762306a36Sopenharmony_ci "%s: NULL response queue pointer.\n", __func__); 448862306a36Sopenharmony_ci return IRQ_NONE; 448962306a36Sopenharmony_ci } 449062306a36Sopenharmony_ci ha = qpair->hw; 449162306a36Sopenharmony_ci 449262306a36Sopenharmony_ci reg = &ha->iobase->isp24; 449362306a36Sopenharmony_ci spin_lock_irqsave(&ha->hardware_lock, flags); 449462306a36Sopenharmony_ci wrt_reg_dword(®->hccr, HCCRX_CLR_RISC_INT); 449562306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->hardware_lock, flags); 449662306a36Sopenharmony_ci 449762306a36Sopenharmony_ci queue_work(ha->wq, &qpair->q_work); 449862306a36Sopenharmony_ci 449962306a36Sopenharmony_ci return IRQ_HANDLED; 450062306a36Sopenharmony_ci} 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci/* Interrupt handling helpers. */ 450362306a36Sopenharmony_ci 450462306a36Sopenharmony_cistruct qla_init_msix_entry { 450562306a36Sopenharmony_ci const char *name; 450662306a36Sopenharmony_ci irq_handler_t handler; 450762306a36Sopenharmony_ci}; 450862306a36Sopenharmony_ci 450962306a36Sopenharmony_cistatic const struct qla_init_msix_entry msix_entries[] = { 451062306a36Sopenharmony_ci { "default", qla24xx_msix_default }, 451162306a36Sopenharmony_ci { "rsp_q", qla24xx_msix_rsp_q }, 451262306a36Sopenharmony_ci { "atio_q", qla83xx_msix_atio_q }, 451362306a36Sopenharmony_ci { "qpair_multiq", qla2xxx_msix_rsp_q }, 451462306a36Sopenharmony_ci { "qpair_multiq_hs", qla2xxx_msix_rsp_q_hs }, 451562306a36Sopenharmony_ci}; 451662306a36Sopenharmony_ci 451762306a36Sopenharmony_cistatic const struct qla_init_msix_entry qla82xx_msix_entries[] = { 451862306a36Sopenharmony_ci { "qla2xxx (default)", qla82xx_msix_default }, 451962306a36Sopenharmony_ci { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, 452062306a36Sopenharmony_ci}; 452162306a36Sopenharmony_ci 452262306a36Sopenharmony_cistatic int 452362306a36Sopenharmony_ciqla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) 452462306a36Sopenharmony_ci{ 452562306a36Sopenharmony_ci int i, ret; 452662306a36Sopenharmony_ci struct qla_msix_entry *qentry; 452762306a36Sopenharmony_ci scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); 452862306a36Sopenharmony_ci int min_vecs = QLA_BASE_VECTORS; 452962306a36Sopenharmony_ci struct irq_affinity desc = { 453062306a36Sopenharmony_ci .pre_vectors = QLA_BASE_VECTORS, 453162306a36Sopenharmony_ci }; 453262306a36Sopenharmony_ci 453362306a36Sopenharmony_ci if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) && 453462306a36Sopenharmony_ci IS_ATIO_MSIX_CAPABLE(ha)) { 453562306a36Sopenharmony_ci desc.pre_vectors++; 453662306a36Sopenharmony_ci min_vecs++; 453762306a36Sopenharmony_ci } 453862306a36Sopenharmony_ci 453962306a36Sopenharmony_ci if (USER_CTRL_IRQ(ha) || !ha->mqiobase) { 454062306a36Sopenharmony_ci /* user wants to control IRQ setting for target mode */ 454162306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(ha->pdev, min_vecs, 454262306a36Sopenharmony_ci min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)), 454362306a36Sopenharmony_ci PCI_IRQ_MSIX); 454462306a36Sopenharmony_ci } else 454562306a36Sopenharmony_ci ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs, 454662306a36Sopenharmony_ci min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)), 454762306a36Sopenharmony_ci PCI_IRQ_MSIX | PCI_IRQ_AFFINITY, 454862306a36Sopenharmony_ci &desc); 454962306a36Sopenharmony_ci 455062306a36Sopenharmony_ci if (ret < 0) { 455162306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x00c7, 455262306a36Sopenharmony_ci "MSI-X: Failed to enable support, " 455362306a36Sopenharmony_ci "giving up -- %d/%d.\n", 455462306a36Sopenharmony_ci ha->msix_count, ret); 455562306a36Sopenharmony_ci goto msix_out; 455662306a36Sopenharmony_ci } else if (ret < ha->msix_count) { 455762306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x00c6, 455862306a36Sopenharmony_ci "MSI-X: Using %d vectors\n", ret); 455962306a36Sopenharmony_ci ha->msix_count = ret; 456062306a36Sopenharmony_ci /* Recalculate queue values */ 456162306a36Sopenharmony_ci if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) { 456262306a36Sopenharmony_ci ha->max_req_queues = ha->msix_count - 1; 456362306a36Sopenharmony_ci 456462306a36Sopenharmony_ci /* ATIOQ needs 1 vector. That's 1 less QPair */ 456562306a36Sopenharmony_ci if (QLA_TGT_MODE_ENABLED()) 456662306a36Sopenharmony_ci ha->max_req_queues--; 456762306a36Sopenharmony_ci 456862306a36Sopenharmony_ci ha->max_rsp_queues = ha->max_req_queues; 456962306a36Sopenharmony_ci 457062306a36Sopenharmony_ci ha->max_qpairs = ha->max_req_queues - 1; 457162306a36Sopenharmony_ci ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190, 457262306a36Sopenharmony_ci "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs); 457362306a36Sopenharmony_ci } 457462306a36Sopenharmony_ci } 457562306a36Sopenharmony_ci vha->irq_offset = desc.pre_vectors; 457662306a36Sopenharmony_ci ha->msix_entries = kcalloc(ha->msix_count, 457762306a36Sopenharmony_ci sizeof(struct qla_msix_entry), 457862306a36Sopenharmony_ci GFP_KERNEL); 457962306a36Sopenharmony_ci if (!ha->msix_entries) { 458062306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x00c8, 458162306a36Sopenharmony_ci "Failed to allocate memory for ha->msix_entries.\n"); 458262306a36Sopenharmony_ci ret = -ENOMEM; 458362306a36Sopenharmony_ci goto free_irqs; 458462306a36Sopenharmony_ci } 458562306a36Sopenharmony_ci ha->flags.msix_enabled = 1; 458662306a36Sopenharmony_ci 458762306a36Sopenharmony_ci for (i = 0; i < ha->msix_count; i++) { 458862306a36Sopenharmony_ci qentry = &ha->msix_entries[i]; 458962306a36Sopenharmony_ci qentry->vector = pci_irq_vector(ha->pdev, i); 459062306a36Sopenharmony_ci qentry->vector_base0 = i; 459162306a36Sopenharmony_ci qentry->entry = i; 459262306a36Sopenharmony_ci qentry->have_irq = 0; 459362306a36Sopenharmony_ci qentry->in_use = 0; 459462306a36Sopenharmony_ci qentry->handle = NULL; 459562306a36Sopenharmony_ci } 459662306a36Sopenharmony_ci 459762306a36Sopenharmony_ci /* Enable MSI-X vectors for the base queue */ 459862306a36Sopenharmony_ci for (i = 0; i < QLA_BASE_VECTORS; i++) { 459962306a36Sopenharmony_ci qentry = &ha->msix_entries[i]; 460062306a36Sopenharmony_ci qentry->handle = rsp; 460162306a36Sopenharmony_ci rsp->msix = qentry; 460262306a36Sopenharmony_ci scnprintf(qentry->name, sizeof(qentry->name), 460362306a36Sopenharmony_ci "qla2xxx%lu_%s", vha->host_no, msix_entries[i].name); 460462306a36Sopenharmony_ci if (IS_P3P_TYPE(ha)) 460562306a36Sopenharmony_ci ret = request_irq(qentry->vector, 460662306a36Sopenharmony_ci qla82xx_msix_entries[i].handler, 460762306a36Sopenharmony_ci 0, qla82xx_msix_entries[i].name, rsp); 460862306a36Sopenharmony_ci else 460962306a36Sopenharmony_ci ret = request_irq(qentry->vector, 461062306a36Sopenharmony_ci msix_entries[i].handler, 461162306a36Sopenharmony_ci 0, qentry->name, rsp); 461262306a36Sopenharmony_ci if (ret) 461362306a36Sopenharmony_ci goto msix_register_fail; 461462306a36Sopenharmony_ci qentry->have_irq = 1; 461562306a36Sopenharmony_ci qentry->in_use = 1; 461662306a36Sopenharmony_ci } 461762306a36Sopenharmony_ci 461862306a36Sopenharmony_ci /* 461962306a36Sopenharmony_ci * If target mode is enable, also request the vector for the ATIO 462062306a36Sopenharmony_ci * queue. 462162306a36Sopenharmony_ci */ 462262306a36Sopenharmony_ci if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) && 462362306a36Sopenharmony_ci IS_ATIO_MSIX_CAPABLE(ha)) { 462462306a36Sopenharmony_ci qentry = &ha->msix_entries[QLA_ATIO_VECTOR]; 462562306a36Sopenharmony_ci rsp->msix = qentry; 462662306a36Sopenharmony_ci qentry->handle = rsp; 462762306a36Sopenharmony_ci scnprintf(qentry->name, sizeof(qentry->name), 462862306a36Sopenharmony_ci "qla2xxx%lu_%s", vha->host_no, 462962306a36Sopenharmony_ci msix_entries[QLA_ATIO_VECTOR].name); 463062306a36Sopenharmony_ci qentry->in_use = 1; 463162306a36Sopenharmony_ci ret = request_irq(qentry->vector, 463262306a36Sopenharmony_ci msix_entries[QLA_ATIO_VECTOR].handler, 463362306a36Sopenharmony_ci 0, qentry->name, rsp); 463462306a36Sopenharmony_ci qentry->have_irq = 1; 463562306a36Sopenharmony_ci } 463662306a36Sopenharmony_ci 463762306a36Sopenharmony_cimsix_register_fail: 463862306a36Sopenharmony_ci if (ret) { 463962306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x00cb, 464062306a36Sopenharmony_ci "MSI-X: unable to register handler -- %x/%d.\n", 464162306a36Sopenharmony_ci qentry->vector, ret); 464262306a36Sopenharmony_ci qla2x00_free_irqs(vha); 464362306a36Sopenharmony_ci ha->mqenable = 0; 464462306a36Sopenharmony_ci goto msix_out; 464562306a36Sopenharmony_ci } 464662306a36Sopenharmony_ci 464762306a36Sopenharmony_ci /* Enable MSI-X vector for response queue update for queue 0 */ 464862306a36Sopenharmony_ci if (IS_MQUE_CAPABLE(ha) && 464962306a36Sopenharmony_ci (ha->msixbase && ha->mqiobase && ha->max_qpairs)) 465062306a36Sopenharmony_ci ha->mqenable = 1; 465162306a36Sopenharmony_ci else 465262306a36Sopenharmony_ci ha->mqenable = 0; 465362306a36Sopenharmony_ci 465462306a36Sopenharmony_ci ql_dbg(ql_dbg_multiq, vha, 0xc005, 465562306a36Sopenharmony_ci "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n", 465662306a36Sopenharmony_ci ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues); 465762306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0055, 465862306a36Sopenharmony_ci "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n", 465962306a36Sopenharmony_ci ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues); 466062306a36Sopenharmony_ci 466162306a36Sopenharmony_cimsix_out: 466262306a36Sopenharmony_ci return ret; 466362306a36Sopenharmony_ci 466462306a36Sopenharmony_cifree_irqs: 466562306a36Sopenharmony_ci pci_free_irq_vectors(ha->pdev); 466662306a36Sopenharmony_ci goto msix_out; 466762306a36Sopenharmony_ci} 466862306a36Sopenharmony_ci 466962306a36Sopenharmony_ciint 467062306a36Sopenharmony_ciqla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) 467162306a36Sopenharmony_ci{ 467262306a36Sopenharmony_ci int ret = QLA_FUNCTION_FAILED; 467362306a36Sopenharmony_ci device_reg_t *reg = ha->iobase; 467462306a36Sopenharmony_ci scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); 467562306a36Sopenharmony_ci 467662306a36Sopenharmony_ci /* If possible, enable MSI-X. */ 467762306a36Sopenharmony_ci if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) && 467862306a36Sopenharmony_ci !IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && 467962306a36Sopenharmony_ci !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))) 468062306a36Sopenharmony_ci goto skip_msi; 468162306a36Sopenharmony_ci 468262306a36Sopenharmony_ci if (ql2xenablemsix == 2) 468362306a36Sopenharmony_ci goto skip_msix; 468462306a36Sopenharmony_ci 468562306a36Sopenharmony_ci if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP && 468662306a36Sopenharmony_ci (ha->pdev->subsystem_device == 0x7040 || 468762306a36Sopenharmony_ci ha->pdev->subsystem_device == 0x7041 || 468862306a36Sopenharmony_ci ha->pdev->subsystem_device == 0x1705)) { 468962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0034, 469062306a36Sopenharmony_ci "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n", 469162306a36Sopenharmony_ci ha->pdev->subsystem_vendor, 469262306a36Sopenharmony_ci ha->pdev->subsystem_device); 469362306a36Sopenharmony_ci goto skip_msi; 469462306a36Sopenharmony_ci } 469562306a36Sopenharmony_ci 469662306a36Sopenharmony_ci if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) { 469762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0035, 469862306a36Sopenharmony_ci "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n", 469962306a36Sopenharmony_ci ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX); 470062306a36Sopenharmony_ci goto skip_msix; 470162306a36Sopenharmony_ci } 470262306a36Sopenharmony_ci 470362306a36Sopenharmony_ci ret = qla24xx_enable_msix(ha, rsp); 470462306a36Sopenharmony_ci if (!ret) { 470562306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0036, 470662306a36Sopenharmony_ci "MSI-X: Enabled (0x%X, 0x%X).\n", 470762306a36Sopenharmony_ci ha->chip_revision, ha->fw_attributes); 470862306a36Sopenharmony_ci goto clear_risc_ints; 470962306a36Sopenharmony_ci } 471062306a36Sopenharmony_ci 471162306a36Sopenharmony_ciskip_msix: 471262306a36Sopenharmony_ci 471362306a36Sopenharmony_ci ql_log(ql_log_info, vha, 0x0037, 471462306a36Sopenharmony_ci "Falling back-to MSI mode -- ret=%d.\n", ret); 471562306a36Sopenharmony_ci 471662306a36Sopenharmony_ci if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && 471762306a36Sopenharmony_ci !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) && 471862306a36Sopenharmony_ci !IS_QLA27XX(ha) && !IS_QLA28XX(ha)) 471962306a36Sopenharmony_ci goto skip_msi; 472062306a36Sopenharmony_ci 472162306a36Sopenharmony_ci ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI); 472262306a36Sopenharmony_ci if (ret > 0) { 472362306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0038, 472462306a36Sopenharmony_ci "MSI: Enabled.\n"); 472562306a36Sopenharmony_ci ha->flags.msi_enabled = 1; 472662306a36Sopenharmony_ci } else 472762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x0039, 472862306a36Sopenharmony_ci "Falling back-to INTa mode -- ret=%d.\n", ret); 472962306a36Sopenharmony_ciskip_msi: 473062306a36Sopenharmony_ci 473162306a36Sopenharmony_ci /* Skip INTx on ISP82xx. */ 473262306a36Sopenharmony_ci if (!ha->flags.msi_enabled && IS_QLA82XX(ha)) 473362306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 473462306a36Sopenharmony_ci 473562306a36Sopenharmony_ci ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, 473662306a36Sopenharmony_ci ha->flags.msi_enabled ? 0 : IRQF_SHARED, 473762306a36Sopenharmony_ci QLA2XXX_DRIVER_NAME, rsp); 473862306a36Sopenharmony_ci if (ret) { 473962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x003a, 474062306a36Sopenharmony_ci "Failed to reserve interrupt %d already in use.\n", 474162306a36Sopenharmony_ci ha->pdev->irq); 474262306a36Sopenharmony_ci goto fail; 474362306a36Sopenharmony_ci } else if (!ha->flags.msi_enabled) { 474462306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0125, 474562306a36Sopenharmony_ci "INTa mode: Enabled.\n"); 474662306a36Sopenharmony_ci ha->flags.mr_intr_valid = 1; 474762306a36Sopenharmony_ci /* Set max_qpair to 0, as MSI-X and MSI in not enabled */ 474862306a36Sopenharmony_ci ha->max_qpairs = 0; 474962306a36Sopenharmony_ci } 475062306a36Sopenharmony_ci 475162306a36Sopenharmony_ciclear_risc_ints: 475262306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha)) 475362306a36Sopenharmony_ci goto fail; 475462306a36Sopenharmony_ci 475562306a36Sopenharmony_ci spin_lock_irq(&ha->hardware_lock); 475662306a36Sopenharmony_ci wrt_reg_word(®->isp.semaphore, 0); 475762306a36Sopenharmony_ci spin_unlock_irq(&ha->hardware_lock); 475862306a36Sopenharmony_ci 475962306a36Sopenharmony_cifail: 476062306a36Sopenharmony_ci return ret; 476162306a36Sopenharmony_ci} 476262306a36Sopenharmony_ci 476362306a36Sopenharmony_civoid 476462306a36Sopenharmony_ciqla2x00_free_irqs(scsi_qla_host_t *vha) 476562306a36Sopenharmony_ci{ 476662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 476762306a36Sopenharmony_ci struct rsp_que *rsp; 476862306a36Sopenharmony_ci struct qla_msix_entry *qentry; 476962306a36Sopenharmony_ci int i; 477062306a36Sopenharmony_ci 477162306a36Sopenharmony_ci /* 477262306a36Sopenharmony_ci * We need to check that ha->rsp_q_map is valid in case we are called 477362306a36Sopenharmony_ci * from a probe failure context. 477462306a36Sopenharmony_ci */ 477562306a36Sopenharmony_ci if (!ha->rsp_q_map || !ha->rsp_q_map[0]) 477662306a36Sopenharmony_ci goto free_irqs; 477762306a36Sopenharmony_ci rsp = ha->rsp_q_map[0]; 477862306a36Sopenharmony_ci 477962306a36Sopenharmony_ci if (ha->flags.msix_enabled) { 478062306a36Sopenharmony_ci for (i = 0; i < ha->msix_count; i++) { 478162306a36Sopenharmony_ci qentry = &ha->msix_entries[i]; 478262306a36Sopenharmony_ci if (qentry->have_irq) { 478362306a36Sopenharmony_ci irq_set_affinity_notifier(qentry->vector, NULL); 478462306a36Sopenharmony_ci free_irq(pci_irq_vector(ha->pdev, i), qentry->handle); 478562306a36Sopenharmony_ci } 478662306a36Sopenharmony_ci } 478762306a36Sopenharmony_ci kfree(ha->msix_entries); 478862306a36Sopenharmony_ci ha->msix_entries = NULL; 478962306a36Sopenharmony_ci ha->flags.msix_enabled = 0; 479062306a36Sopenharmony_ci ql_dbg(ql_dbg_init, vha, 0x0042, 479162306a36Sopenharmony_ci "Disabled MSI-X.\n"); 479262306a36Sopenharmony_ci } else { 479362306a36Sopenharmony_ci free_irq(pci_irq_vector(ha->pdev, 0), rsp); 479462306a36Sopenharmony_ci } 479562306a36Sopenharmony_ci 479662306a36Sopenharmony_cifree_irqs: 479762306a36Sopenharmony_ci pci_free_irq_vectors(ha->pdev); 479862306a36Sopenharmony_ci} 479962306a36Sopenharmony_ci 480062306a36Sopenharmony_ciint qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair, 480162306a36Sopenharmony_ci struct qla_msix_entry *msix, int vector_type) 480262306a36Sopenharmony_ci{ 480362306a36Sopenharmony_ci const struct qla_init_msix_entry *intr = &msix_entries[vector_type]; 480462306a36Sopenharmony_ci scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); 480562306a36Sopenharmony_ci int ret; 480662306a36Sopenharmony_ci 480762306a36Sopenharmony_ci scnprintf(msix->name, sizeof(msix->name), 480862306a36Sopenharmony_ci "qla2xxx%lu_qpair%d", vha->host_no, qpair->id); 480962306a36Sopenharmony_ci ret = request_irq(msix->vector, intr->handler, 0, msix->name, qpair); 481062306a36Sopenharmony_ci if (ret) { 481162306a36Sopenharmony_ci ql_log(ql_log_fatal, vha, 0x00e6, 481262306a36Sopenharmony_ci "MSI-X: Unable to register handler -- %x/%d.\n", 481362306a36Sopenharmony_ci msix->vector, ret); 481462306a36Sopenharmony_ci return ret; 481562306a36Sopenharmony_ci } 481662306a36Sopenharmony_ci msix->have_irq = 1; 481762306a36Sopenharmony_ci msix->handle = qpair; 481862306a36Sopenharmony_ci qla_mapq_init_qp_cpu_map(ha, msix, qpair); 481962306a36Sopenharmony_ci return ret; 482062306a36Sopenharmony_ci} 4821