]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/scsi/qla2xxx/qla_isr.c
Merge branch 'x86-ptrace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[mv-sheeva.git] / drivers / scsi / qla2xxx / qla_isr.c
index ffd0efdff40e5f04504e2d148349e0909172364f..ab90329ff2e4877ce57ccd15e1a7ee28ab5acd9f 100644 (file)
@@ -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;
 }
@@ -981,6 +984,100 @@ done_post_logio_done_work:
        lio->ctx.free(sp);
 }
 
+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(&reg->hccr, HCCRX_CLR_RISC_INT);
                RD_REG_DWORD_RELAXED(&reg->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(&reg->hccr, HCCRX_CLR_RISC_INT);
                RD_REG_DWORD_RELAXED(&reg->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(&reg->host_status);
@@ -2039,14 +2146,13 @@ qla24xx_msix_default(int irq, void *dev_id)
                }
                WRT_REG_DWORD(&reg->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;
-}