arcmsr_hba.c
来自「linux 内核源代码」· C语言 代码 · 共 2,271 行 · 第 1/5 页
C
2,271 行
if (nseg) { __le32 length; int i, cdb_sgcount = 0; struct scatterlist *sg; /* map stor port SG list to our iop SG List. */ scsi_for_each_sg(pcmd, sg, nseg, i) { /* Get the physical address of the current data pointer */ length = cpu_to_le32(sg_dma_len(sg)); address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg))); address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg))); if (address_hi == 0) { struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; pdma_sg->address = address_lo; pdma_sg->length = length; psge += sizeof (struct SG32ENTRY); arccdbsize += sizeof (struct SG32ENTRY); } else { struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; pdma_sg->addresshigh = address_hi; pdma_sg->address = address_lo; pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR); psge += sizeof (struct SG64ENTRY); arccdbsize += sizeof (struct SG64ENTRY); } cdb_sgcount++; } arcmsr_cdb->sgcount = (uint8_t)cdb_sgcount; arcmsr_cdb->DataLength = scsi_bufflen(pcmd); if ( arccdbsize > 256) arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; } if (pcmd->sc_data_direction == DMA_TO_DEVICE ) { arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; ccb->ccb_flags |= CCB_FLAG_WRITE; }}static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb){ uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr; struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; atomic_inc(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_START; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, ®->inbound_queueport); else { writel(cdb_shifted_phyaddr, ®->inbound_queueport); } } break; case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; uint32_t ending_index, index = reg->postq_index; ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); writel(0, ®->post_qbuffer[ending_index]); if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ ®->post_qbuffer[index]); } else { writel(cdb_shifted_phyaddr, ®->post_qbuffer[index]); } index++; index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ reg->postq_index = index; writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg); } break; }}static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb){ struct MessageUnit_A __iomem *reg = acb->pmuA; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); if (arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->host->host_no); }}static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb){ struct MessageUnit_B *reg = acb->pmuB; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->host->host_no); }}static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { arcmsr_stop_hba_bgrb(acb); } break; case ACB_ADAPTER_TYPE_B: { arcmsr_stop_hbb_bgrb(acb); } break; }}static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { iounmap(acb->pmuA); break; } case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; iounmap(reg->drv2iop_doorbell_reg - ARCMSR_DRV2IOP_DOORBELL); iounmap(reg->ioctl_wbuffer_reg - ARCMSR_IOCTL_WBUFFER); } } dma_free_coherent(&acb->pdev->dev, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, acb->dma_coherent, acb->dma_coherent_handle);}void arcmsr_iop_message_read(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); } break; case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg); } break; }}static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; /* ** push inbound doorbell tell iop, driver data write ok ** and wait reply on next hwinterrupt for next Qbuffer post */ writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, ®->inbound_doorbell); } break; case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; /* ** push inbound doorbell tell iop, driver data write ok ** and wait reply on next hwinterrupt for next Qbuffer post */ writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg); } break; }}struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb){ struct QBUFFER __iomem *qbuffer = NULL; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; qbuffer = (struct QBUFFER __iomem *)®->message_rbuffer; } break; case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; qbuffer = (struct QBUFFER __iomem *)reg->ioctl_rbuffer_reg; } break; } return qbuffer;}static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb){ struct QBUFFER __iomem *pqbuffer = NULL; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; pqbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer; } break; case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg; } break; } return pqbuffer;}static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb){ struct QBUFFER __iomem *prbuffer; struct QBUFFER *pQbuffer; uint8_t __iomem *iop_data; int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; rqbuf_lastindex = acb->rqbuf_lastindex; rqbuf_firstindex = acb->rqbuf_firstindex; prbuffer = arcmsr_get_iop_rqbuffer(acb); iop_data = (uint8_t __iomem *)prbuffer->data; iop_len = prbuffer->data_len; my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1); if (my_empty_len >= iop_len) { while (iop_len > 0) { pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex]; memcpy(pQbuffer, iop_data,1); rqbuf_lastindex++; rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; iop_data++; iop_len--; } acb->rqbuf_lastindex = rqbuf_lastindex; arcmsr_iop_message_read(acb); } else { acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; }}static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb){ acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { uint8_t *pQbuffer; struct QBUFFER __iomem *pwbuffer; uint8_t __iomem *iop_data; int32_t allxfer_len = 0; acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); pwbuffer = arcmsr_get_iop_wqbuffer(acb); iop_data = (uint8_t __iomem *)pwbuffer->data; while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \ (allxfer_len < 124)) { pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; memcpy(iop_data, pQbuffer, 1); acb->wqbuf_firstindex++; acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; iop_data++; allxfer_len++; } pwbuffer->data_len = allxfer_len; arcmsr_iop_message_wrote(acb); } if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) { acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; }}static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb){ uint32_t outbound_doorbell; struct MessageUnit_A __iomem *reg = acb->pmuA; outbound_doorbell = readl(®->outbound_doorbell); writel(outbound_doorbell, ®->outbound_doorbell); if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { arcmsr_iop2drv_data_read_handle(acb); }}static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb){ uint32_t flag_ccb; struct MessageUnit_A __iomem *reg = acb->pmuA; while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { arcmsr_drain_donequeue(acb, flag_ccb); }}static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb){ uint32_t index; uint32_t flag_ccb; struct MessageUnit_B *reg = acb->pmuB; index = reg->doneq_index; while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) { writel(0, ®->done_qbuffer[index]); arcmsr_drain_donequeue(acb, flag_ccb); index++; index %= ARCMSR_MAX_HBB_POSTQUEUE; reg->doneq_index = index; }}static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb){ uint32_t outbound_intstatus; struct MessageUnit_A __iomem *reg = acb->pmuA; outbound_intstatus = readl(®->outbound_intstatus) & \ acb->outbound_int_enable; if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { return 1; } writel(outbound_intstatus, ®->outbound_intstatus); if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { arcmsr_hba_doorbell_isr(acb); } if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { arcmsr_hba_postqueue_isr(acb); } return 0;}static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb){ uint32_t outbound_doorbell; struct MessageUnit_B *reg = acb->pmuB; outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & \ acb->outbound_int_enable; if (!outbound_doorbell) return 1; writel(~outbound_doorbell, reg->iop2drv_doorbell_reg); if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { arcmsr_iop2drv_data_wrote_handle(acb); } if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { arcmsr_iop2drv_data_read_handle(acb); } if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { arcmsr_hbb_postqueue_isr(acb); } return 0;}static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { if (arcmsr_handle_hba_isr(acb)) { return IRQ_NONE; } } break; case ACB_ADAPTER_TYPE_B: { if (arcmsr_handle_hbb_isr(acb)) { return IRQ_NONE; } } break; } return IRQ_HANDLED;}static void arcmsr_iop_parking(struct AdapterControlBlock *acb){ if (acb) { /* stop adapter background rebuild */ if (acb->acb_flags & ACB_F_MSG_START_BGRB) { uint32_t intmask_org; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); arcmsr_enable_outbound_ints(acb, intmask_org); } }}void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb){ int32_t wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer; struct QBUFFER __iomem *pwbuffer; uint8_t __iomem *iop_data; int32_t allxfer_len = 0; pwbuffer = arcmsr_get_iop_wqbuffer(acb); iop_data = (uint8_t __iomem *)pwbuffer->data; if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); wqbuf_firstindex = acb->wqbuf_firstindex; wqbuf_lastindex = acb->wqbuf_lastindex; while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) { pQbuffer = &acb->wqbuffer[wqbuf_firstindex]; memcpy(iop_data, pQbuffer, 1); wqbuf_firstindex++; wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; iop_data++; allxfer_len++; } acb->wqbuf_firstindex = wqbuf_firstindex; pwbuffer->data_len = allxfer_len; arcmsr_iop_message_wrote(acb); }}static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ struct scsi_cmnd *cmd){ struct CMD_MESSAGE_FIELD *pcmdmessagefld; int retvalue = 0, transfer_len = 0; char *buffer; struct scatterlist *sg; uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 | (uint32_t ) cmd->cmnd[6] << 16 | (uint32_t ) cmd->cmnd[7] << 8 | (uint32_t ) cmd->cmnd[8]; /* 4 bytes: Areca io control code */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?