arcmsr_hba.c
来自「linux 内核源代码」· C语言 代码 · 共 2,271 行 · 第 1/5 页
C
2,271 行
error = arcmsr_alloc_sysfs_attr(acb); if (error) goto out_free_sysfs; scsi_scan_host(host); #ifdef CONFIG_SCSI_ARCMSR_AER pci_enable_pcie_error_reporting(pdev); #endif return 0; out_free_sysfs: out_free_irq: free_irq(pdev->irq, acb); out_free_ccb_pool: arcmsr_free_ccb_pool(acb); out_release_regions: pci_release_regions(pdev); out_host_put: scsi_host_put(host); out_disable_device: pci_disable_device(pdev); out: return error;}static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb){ struct MessageUnit_A __iomem *reg = acb->pmuA; uint32_t Index; uint8_t Retries = 0x00; do { for (Index = 0; Index < 100; Index++) { if (readl(®->outbound_intstatus) & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus); return 0x00; } msleep(10); }/*max 1 seconds*/ } while (Retries++ < 20);/*max 20 sec*/ return 0xff;}static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb){ struct MessageUnit_B *reg = acb->pmuB; uint32_t Index; uint8_t Retries = 0x00; do { for (Index = 0; Index < 100; Index++) { if (readl(reg->iop2drv_doorbell_reg) & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN , reg->iop2drv_doorbell_reg); return 0x00; } msleep(10); }/*max 1 seconds*/ } while (Retries++ < 20);/*max 20 sec*/ return 0xff;}static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb){ struct MessageUnit_A __iomem *reg = acb->pmuA; writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); if (arcmsr_hba_wait_msgint_ready(acb)) printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" , acb->host->host_no);}static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb){ struct MessageUnit_B *reg = acb->pmuB; writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg); if (arcmsr_hbb_wait_msgint_ready(acb)) printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" , acb->host->host_no);}static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { arcmsr_abort_hba_allcmd(acb); } break; case ACB_ADAPTER_TYPE_B: { arcmsr_abort_hbb_allcmd(acb); } }}static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb){ struct scsi_cmnd *pcmd = ccb->pcmd; scsi_dma_unmap(pcmd);}static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag){ struct AdapterControlBlock *acb = ccb->acb; struct scsi_cmnd *pcmd = ccb->pcmd; arcmsr_pci_unmap_dma(ccb); if (stand_flag == 1) atomic_dec(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_DONE; ccb->ccb_flags = 0; list_add_tail(&ccb->list, &acb->ccb_free_list); pcmd->scsi_done(pcmd);}static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb){ struct MessageUnit_A __iomem *reg = acb->pmuA; int retry_count = 30; writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); do { if (!arcmsr_hba_wait_msgint_ready(acb)) break; else { retry_count--; printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ timeout, retry count down = %d \n", acb->host->host_no, retry_count); } } while (retry_count != 0);}static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb){ struct MessageUnit_B *reg = acb->pmuB; int retry_count = 30; writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg); do { if (!arcmsr_hbb_wait_msgint_ready(acb)) break; else { retry_count--; printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ timeout,retry count down = %d \n", acb->host->host_no, retry_count); } } while (retry_count != 0);}static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { arcmsr_flush_hba_cache(acb); } break; case ACB_ADAPTER_TYPE_B: { arcmsr_flush_hbb_cache(acb); } }}static void arcmsr_report_sense_info(struct CommandControlBlock *ccb){ struct scsi_cmnd *pcmd = ccb->pcmd; struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; pcmd->result = DID_OK << 16; if (sensebuffer) { int sense_data_length = sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer) ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer); memset(sensebuffer, 0, sizeof(pcmd->sense_buffer)); memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; sensebuffer->Valid = 1; }}static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb){ u32 orig_mask = 0; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A : { struct MessageUnit_A __iomem *reg = acb->pmuA; orig_mask = readl(®->outbound_intmask)|\ ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \ ®->outbound_intmask); } break; case ACB_ADAPTER_TYPE_B : { struct MessageUnit_B *reg = acb->pmuB; orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \ (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); writel(0, reg->iop2drv_doorbell_mask_reg); } break; } return orig_mask;}static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \ struct CommandControlBlock *ccb, uint32_t flag_ccb){ uint8_t id, lun; id = ccb->pcmd->device->id; lun = ccb->pcmd->device->lun; if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { if (acb->devstate[id][lun] == ARECA_RAID_GONE) acb->devstate[id][lun] = ARECA_RAID_GOOD; ccb->pcmd->result = DID_OK << 16; arcmsr_ccb_complete(ccb, 1); } else { switch (ccb->arcmsr_cdb.DeviceStatus) { case ARCMSR_DEV_SELECT_TIMEOUT: { acb->devstate[id][lun] = ARECA_RAID_GONE; ccb->pcmd->result = DID_NO_CONNECT << 16; arcmsr_ccb_complete(ccb, 1); } break; case ARCMSR_DEV_ABORTED: case ARCMSR_DEV_INIT_FAIL: { acb->devstate[id][lun] = ARECA_RAID_GONE; ccb->pcmd->result = DID_BAD_TARGET << 16; arcmsr_ccb_complete(ccb, 1); } break; case ARCMSR_DEV_CHECK_CONDITION: { acb->devstate[id][lun] = ARECA_RAID_GOOD; arcmsr_report_sense_info(ccb); arcmsr_ccb_complete(ccb, 1); } break; default: printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d" " isr get command error done, " "but got unknown DeviceStatus = 0x%x \n" , acb->host->host_no , id , lun , ccb->arcmsr_cdb.DeviceStatus); acb->devstate[id][lun] = ARECA_RAID_GONE; ccb->pcmd->result = DID_NO_CONNECT << 16; arcmsr_ccb_complete(ccb, 1); break; } }}static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb){ struct CommandControlBlock *ccb; ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5)); if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { if (ccb->startdone == ARCMSR_CCB_ABORTED) { struct scsi_cmnd *abortcmd = ccb->pcmd; if (abortcmd) { abortcmd->result |= DID_ABORT << 16; arcmsr_ccb_complete(ccb, 1); printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \ isr got aborted command \n", acb->host->host_no, ccb); } } printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \ done acb = '0x%p'" "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" " ccboutstandingcount = %d \n" , acb->host->host_no , acb , ccb , ccb->acb , ccb->startdone , atomic_read(&acb->ccboutstandingcount)); } arcmsr_report_ccb_state(acb, ccb, flag_ccb);}static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb){ int i = 0; uint32_t flag_ccb; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { struct MessageUnit_A __iomem *reg = acb->pmuA; uint32_t outbound_intstatus; outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; /*clear and abort all outbound posted Q*/ writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { arcmsr_drain_donequeue(acb, flag_ccb); } } break; case ACB_ADAPTER_TYPE_B: { struct MessageUnit_B *reg = acb->pmuB; /*clear all outbound posted Q*/ for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { writel(0, ®->done_qbuffer[i]); arcmsr_drain_donequeue(acb, flag_ccb); } writel(0, ®->post_qbuffer[i]); } reg->doneq_index = 0; reg->postq_index = 0; } break; }}static void arcmsr_remove(struct pci_dev *pdev){ struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; int poll_count = 0; arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); arcmsr_disable_outbound_ints(acb); acb->acb_flags |= ACB_F_SCSISTOPADAPTER; acb->acb_flags &= ~ACB_F_IOP_INITED; for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) { if (!atomic_read(&acb->ccboutstandingcount)) break; arcmsr_interrupt(acb);/* FIXME: need spinlock */ msleep(25); } if (atomic_read(&acb->ccboutstandingcount)) { int i; arcmsr_abort_allcmd(acb); arcmsr_done4abort_postqueue(acb); for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { struct CommandControlBlock *ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START) { ccb->startdone = ARCMSR_CCB_ABORTED; ccb->pcmd->result = DID_ABORT << 16; arcmsr_ccb_complete(ccb, 1); } } } free_irq(pdev->irq, acb); arcmsr_free_ccb_pool(acb); pci_release_regions(pdev); scsi_host_put(host); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL);}static void arcmsr_shutdown(struct pci_dev *pdev){ struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb);}static int arcmsr_module_init(void){ int error = 0; error = pci_register_driver(&arcmsr_pci_driver); return error;}static void arcmsr_module_exit(void){ pci_unregister_driver(&arcmsr_pci_driver);}module_init(arcmsr_module_init);module_exit(arcmsr_module_exit);static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \ u32 intmask_org){ u32 mask; switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A : { struct MessageUnit_A __iomem *reg = acb->pmuA; mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); writel(mask, ®->outbound_intmask); acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; } break; case ACB_ADAPTER_TYPE_B : { struct MessageUnit_B *reg = acb->pmuB; mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \ ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE); writel(mask, reg->iop2drv_doorbell_mask_reg); acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; } }}static void arcmsr_build_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd){ struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; int8_t *psge = (int8_t *)&arcmsr_cdb->u; __le32 address_lo, address_hi; int arccdbsize = 0x30; int nseg; ccb->pcmd = pcmd; memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); arcmsr_cdb->Bus = 0; arcmsr_cdb->TargetID = pcmd->device->id; arcmsr_cdb->LUN = pcmd->device->lun; arcmsr_cdb->Function = 1; arcmsr_cdb->CdbLength = (uint8_t)pcmd->cmd_len; arcmsr_cdb->Context = (unsigned long)arcmsr_cdb; memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); nseg = scsi_dma_map(pcmd); BUG_ON(nseg < 0);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?