diff options
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_isr.c')
-rw-r--r-- | drivers/scsi/qla2xxx/qla_isr.c | 154 |
1 files changed, 117 insertions, 37 deletions
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ffd0efdff40..ab90329ff2e 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -8,6 +8,7 @@ #include <linux/delay.h> #include <scsi/scsi_tcq.h> +#include <scsi/scsi_bsg_fc.h> static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); static void qla2x00_process_completed_request(struct scsi_qla_host *, @@ -881,7 +882,9 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, index); return NULL; } + req->outstanding_cmds[index] = NULL; + done: return sp; } @@ -982,6 +985,100 @@ done_post_logio_done_work: } static void +qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, + struct sts_entry_24xx *pkt, int iocb_type) +{ + const char func[] = "ELS_CT_IOCB"; + const char *type; + struct qla_hw_data *ha = vha->hw; + srb_t *sp; + struct srb_bsg *sp_bsg; + struct fc_bsg_job *bsg_job; + uint16_t comp_status; + uint32_t fw_status[3]; + uint8_t* fw_sts_ptr; + + sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); + if (!sp) + return; + sp_bsg = (struct srb_bsg*)sp->ctx; + bsg_job = sp_bsg->bsg_job; + + type = NULL; + switch (sp_bsg->ctx.type) { + case SRB_ELS_CMD_RPT: + case SRB_ELS_CMD_HST: + type = "els"; + break; + case SRB_CT_CMD: + type = "ct pass-through"; + break; + default: + qla_printk(KERN_WARNING, ha, + "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp, + sp_bsg->ctx.type); + return; + } + + comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status); + fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1); + fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2); + + /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT + * fc payload to the caller + */ + bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; + bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status); + + if (comp_status != CS_COMPLETE) { + if (comp_status == CS_DATA_UNDERRUN) { + bsg_job->reply->result = DID_OK << 16; + bsg_job->reply->reply_payload_rcv_len = + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count); + + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x " + "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n", + vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2], + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count))); + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); + } + else { + DEBUG2(qla_printk(KERN_WARNING, ha, + "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x " + "error subcode 1=0x%x error subcode 2=0x%x.\n", + vha->host_no, sp->handle, type, comp_status, + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1), + le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2))); + bsg_job->reply->result = DID_ERROR << 16; + bsg_job->reply->reply_payload_rcv_len = 0; + fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); + memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); + } + DEBUG2(qla2x00_dump_buffer((uint8_t *)pkt, sizeof(*pkt))); + } + else { + bsg_job->reply->result = DID_OK << 16;; + bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; + bsg_job->reply_len = 0; + } + + dma_unmap_sg(&ha->pdev->dev, + bsg_job->request_payload.sg_list, + bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); + dma_unmap_sg(&ha->pdev->dev, + bsg_job->reply_payload.sg_list, + bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); + if ((sp_bsg->ctx.type == SRB_ELS_CMD_HST) || + (sp_bsg->ctx.type == SRB_CT_CMD)) + kfree(sp->fcport); + kfree(sp->ctx); + mempool_free(sp, ha->srb_mempool); + bsg_job->job_done(bsg_job); +} + +static void qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, struct logio_entry_24xx *logio) { @@ -1749,6 +1846,13 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, qla24xx_logio_entry(vha, rsp->req, (struct logio_entry_24xx *)pkt); break; + case CT_IOCB_TYPE: + qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); + clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags); + break; + case ELS_IOCB_TYPE: + qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); + break; default: /* Type Not Supported. */ DEBUG4(printk(KERN_WARNING @@ -1917,6 +2021,7 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) struct rsp_que *rsp; struct device_reg_24xx __iomem *reg; struct scsi_qla_host *vha; + unsigned long flags; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -1927,15 +2032,15 @@ qla24xx_msix_rsp_q(int irq, void *dev_id) ha = rsp->hw; reg = &ha->iobase->isp24; - spin_lock_irq(&ha->hardware_lock); + spin_lock_irqsave(&ha->hardware_lock, flags); - vha = qla25xx_get_host(rsp); + vha = pci_get_drvdata(ha->pdev); qla24xx_process_response_queue(vha, rsp); if (!ha->flags.disable_msix_handshake) { WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); } - spin_unlock_irq(&ha->hardware_lock); + spin_unlock_irqrestore(&ha->hardware_lock, flags); return IRQ_HANDLED; } @@ -1946,6 +2051,7 @@ qla25xx_msix_rsp_q(int irq, void *dev_id) struct qla_hw_data *ha; struct rsp_que *rsp; struct device_reg_24xx __iomem *reg; + unsigned long flags; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -1958,10 +2064,10 @@ qla25xx_msix_rsp_q(int irq, void *dev_id) /* Clear the interrupt, if enabled, for this response queue */ if (rsp->options & ~BIT_6) { reg = &ha->iobase->isp24; - spin_lock_irq(&ha->hardware_lock); + spin_lock_irqsave(&ha->hardware_lock, flags); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); RD_REG_DWORD_RELAXED(®->hccr); - spin_unlock_irq(&ha->hardware_lock); + spin_unlock_irqrestore(&ha->hardware_lock, flags); } queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work); @@ -1979,6 +2085,7 @@ qla24xx_msix_default(int irq, void *dev_id) uint32_t stat; uint32_t hccr; uint16_t mb[4]; + unsigned long flags; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -1990,7 +2097,7 @@ qla24xx_msix_default(int irq, void *dev_id) reg = &ha->iobase->isp24; status = 0; - spin_lock_irq(&ha->hardware_lock); + spin_lock_irqsave(&ha->hardware_lock, flags); vha = pci_get_drvdata(ha->pdev); do { stat = RD_REG_DWORD(®->host_status); @@ -2039,14 +2146,13 @@ qla24xx_msix_default(int irq, void *dev_id) } WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); } while (0); - spin_unlock_irq(&ha->hardware_lock); + spin_unlock_irqrestore(&ha->hardware_lock, flags); if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && (status & MBX_INTERRUPT) && ha->flags.mbox_int) { set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); complete(&ha->mbx_intr_comp); } - return IRQ_HANDLED; } @@ -2252,10 +2358,11 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) if (ha->flags.msix_enabled) qla24xx_disable_msix(ha); - else if (ha->flags.inta_enabled) { + else if (ha->flags.msi_enabled) { free_irq(ha->pdev->irq, rsp); pci_disable_msi(ha->pdev); - } + } else + free_irq(ha->pdev->irq, rsp); } @@ -2277,30 +2384,3 @@ int qla25xx_request_irq(struct rsp_que *rsp) msix->rsp = rsp; return ret; } - -struct scsi_qla_host * -qla25xx_get_host(struct rsp_que *rsp) -{ - srb_t *sp; - struct qla_hw_data *ha = rsp->hw; - struct scsi_qla_host *vha = NULL; - struct sts_entry_24xx *pkt; - struct req_que *req; - uint16_t que; - uint32_t handle; - - pkt = (struct sts_entry_24xx *) rsp->ring_ptr; - que = MSW(pkt->handle); - handle = (uint32_t) LSW(pkt->handle); - req = ha->req_q_map[que]; - if (handle < MAX_OUTSTANDING_COMMANDS) { - sp = req->outstanding_cmds[handle]; - if (sp) - return sp->fcport->vha; - else - goto base_que; - } -base_que: - vha = pci_get_drvdata(ha->pdev); - return vha; -} |