arcmsr_hba.c
来自「linux 内核源代码」· C语言 代码 · 共 2,271 行 · 第 1/5 页
C
2,271 行
sg = scsi_sglist(cmd); buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; if (scsi_sg_count(cmd) > 1) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } transfer_len += sg->length; if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; switch(controlcode) { case ARCMSR_MESSAGE_READ_RQBUFFER: { unsigned long *ver_addr; dma_addr_t buf_handle; uint8_t *pQbuffer, *ptmpQbuffer; int32_t allxfer_len = 0; ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } ptmpQbuffer = (uint8_t *) ver_addr; while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) && (allxfer_len < 1031)) { pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; memcpy(ptmpQbuffer, pQbuffer, 1); acb->rqbuf_firstindex++; acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; ptmpQbuffer++; allxfer_len++; } if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { struct QBUFFER __iomem *prbuffer; uint8_t __iomem *iop_data; int32_t iop_len; acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; prbuffer = arcmsr_get_iop_rqbuffer(acb); iop_data = prbuffer->data; iop_len = readl(&prbuffer->data_len); while (iop_len > 0) { acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); acb->rqbuf_lastindex++; acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; iop_data++; iop_len--; } arcmsr_iop_message_read(acb); } memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len); pcmdmessagefld->cmdmessage.Length = allxfer_len; pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; case ARCMSR_MESSAGE_WRITE_WQBUFFER: { unsigned long *ver_addr; dma_addr_t buf_handle; int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; uint8_t *pQbuffer, *ptmpuserbuffer; ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); if (!ver_addr) { retvalue = ARCMSR_MESSAGE_FAIL; goto message_out; } ptmpuserbuffer = (uint8_t *)ver_addr; user_len = pcmdmessagefld->cmdmessage.Length; memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); wqbuf_lastindex = acb->wqbuf_lastindex; wqbuf_firstindex = acb->wqbuf_firstindex; if (wqbuf_lastindex != wqbuf_firstindex) { struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)cmd->sense_buffer; arcmsr_post_ioctldata2iop(acb); /* has error report sensedata */ sensebuffer->ErrorCode = 0x70; sensebuffer->SenseKey = ILLEGAL_REQUEST; sensebuffer->AdditionalSenseLength = 0x0A; sensebuffer->AdditionalSenseCode = 0x20; sensebuffer->Valid = 1; retvalue = ARCMSR_MESSAGE_FAIL; } else { my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) &(ARCMSR_MAX_QBUFFER - 1); if (my_empty_len >= user_len) { while (user_len > 0) { pQbuffer = &acb->wqbuffer[acb->wqbuf_lastindex]; memcpy(pQbuffer, ptmpuserbuffer, 1); acb->wqbuf_lastindex++; acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; ptmpuserbuffer++; user_len--; } if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { acb->acb_flags &= ~ACB_F_MESSAGE_WQBUFFER_CLEARED; arcmsr_post_ioctldata2iop(acb); } } else { /* has error report sensedata */ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)cmd->sense_buffer; sensebuffer->ErrorCode = 0x70; sensebuffer->SenseKey = ILLEGAL_REQUEST; sensebuffer->AdditionalSenseLength = 0x0A; sensebuffer->AdditionalSenseCode = 0x20; sensebuffer->Valid = 1; retvalue = ARCMSR_MESSAGE_FAIL; } } pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { uint8_t *pQbuffer = acb->rqbuffer; if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; arcmsr_iop_message_read(acb); } acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; acb->rqbuf_firstindex = 0; acb->rqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { uint8_t *pQbuffer = acb->wqbuffer; if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; arcmsr_iop_message_read(acb); } acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); acb->wqbuf_firstindex = 0; acb->wqbuf_lastindex = 0; memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { uint8_t *pQbuffer; if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; arcmsr_iop_message_read(acb); } acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); acb->rqbuf_firstindex = 0; acb->rqbuf_lastindex = 0; acb->wqbuf_firstindex = 0; acb->wqbuf_lastindex = 0; pQbuffer = acb->rqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); pQbuffer = acb->wqbuffer; memset(pQbuffer, 0, sizeof(struct QBUFFER)); pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; case ARCMSR_MESSAGE_RETURN_CODE_3F: { pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; } break; case ARCMSR_MESSAGE_SAY_HELLO: { int8_t *hello_string = "Hello! I am ARCMSR"; memcpy(pcmdmessagefld->messagedatabuffer, hello_string , (int16_t)strlen(hello_string)); pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; case ARCMSR_MESSAGE_SAY_GOODBYE: arcmsr_iop_parking(acb); break; case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: arcmsr_flush_adapter_cache(acb); break; default: retvalue = ARCMSR_MESSAGE_FAIL; } message_out: sg = scsi_sglist(cmd); kunmap_atomic(buffer - sg->offset, KM_IRQ0); return retvalue;}static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb){ struct list_head *head = &acb->ccb_free_list; struct CommandControlBlock *ccb = NULL; if (!list_empty(head)) { ccb = list_entry(head->next, struct CommandControlBlock, list); list_del(head->next); } return ccb;}static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd){ switch (cmd->cmnd[0]) { case INQUIRY: { unsigned char inqdata[36]; char *buffer; struct scatterlist *sg; if (cmd->device->lun) { cmd->result = (DID_TIME_OUT << 16); cmd->scsi_done(cmd); return; } inqdata[0] = TYPE_PROCESSOR; /* Periph Qualifier & Periph Dev Type */ inqdata[1] = 0; /* rem media bit & Dev Type Modifier */ inqdata[2] = 0; /* ISO, ECMA, & ANSI versions */ inqdata[4] = 31; /* length of additional data */ strncpy(&inqdata[8], "Areca ", 8); /* Vendor Identification */ strncpy(&inqdata[16], "RAID controller ", 16); /* Product Identification */ strncpy(&inqdata[32], "R001", 4); /* Product Revision */ sg = scsi_sglist(cmd); buffer = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset; memcpy(buffer, inqdata, sizeof(inqdata)); sg = scsi_sglist(cmd); kunmap_atomic(buffer - sg->offset, KM_IRQ0); cmd->scsi_done(cmd); } break; case WRITE_BUFFER: case READ_BUFFER: { if (arcmsr_iop_message_xfer(acb, cmd)) cmd->result = (DID_ERROR << 16); cmd->scsi_done(cmd); } break; default: cmd->scsi_done(cmd); }}static int arcmsr_queue_command(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)){ struct Scsi_Host *host = cmd->device->host; struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; struct CommandControlBlock *ccb; int target = cmd->device->id; int lun = cmd->device->lun; cmd->scsi_done = done; cmd->host_scribble = NULL; cmd->result = 0; if (acb->acb_flags & ACB_F_BUS_RESET) { printk(KERN_NOTICE "arcmsr%d: bus reset" " and return busy \n" , acb->host->host_no); return SCSI_MLQUEUE_HOST_BUSY; } if (target == 16) { /* virtual device for iop message transfer */ arcmsr_handle_virtual_command(acb, cmd); return 0; } if (acb->devstate[target][lun] == ARECA_RAID_GONE) { uint8_t block_cmd; block_cmd = cmd->cmnd[0] & 0x0f; if (block_cmd == 0x08 || block_cmd == 0x0a) { printk(KERN_NOTICE "arcmsr%d: block 'read/write'" "command with gone raid volume" " Cmd = %2x, TargetId = %d, Lun = %d \n" , acb->host->host_no , cmd->cmnd[0] , target, lun); cmd->result = (DID_NO_CONNECT << 16); cmd->scsi_done(cmd); return 0; } } if (atomic_read(&acb->ccboutstandingcount) >= ARCMSR_MAX_OUTSTANDING_CMD) return SCSI_MLQUEUE_HOST_BUSY; ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; arcmsr_build_ccb(acb, ccb, cmd); arcmsr_post_ccb(acb, ccb); return 0;}static void arcmsr_get_hba_config(struct AdapterControlBlock *acb){ struct MessageUnit_A __iomem *reg = acb->pmuA; char *acb_firm_model = acb->firm_model; char *acb_firm_version = acb->firm_version; char __iomem *iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); int count; writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); if (arcmsr_hba_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); } count = 8; while (count) { *acb_firm_model = readb(iop_firm_model); acb_firm_model++; iop_firm_model++; count--; } count = 16; while (count) { *acb_firm_version = readb(iop_firm_version); acb_firm_version++; iop_firm_version++; count--; } printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" , acb->host->host_no , acb->firm_version); acb->firm_request_len = readl(®->message_rwbuffer[1]); acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); acb->firm_sdram_size = readl(®->message_rwbuffer[3]); acb->firm_hd_channels = readl(®->message_rwbuffer[4]);}static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb){ struct MessageUnit_B *reg = acb->pmuB; uint32_t __iomem *lrwbuffer = reg->msgcode_rwbuffer_reg; char *acb_firm_model = acb->firm_model; char *acb_firm_version = acb->firm_version; char __iomem *iop_firm_model = (char __iomem *)(&lrwbuffer[15]); /*firm_model,15,60-67*/ char __iomem *iop_firm_version = (char __iomem *)(&lrwbuffer[17]); /*firm_version,17,68-83*/ int count; writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg); if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ miscellaneous data' timeout \n", acb->host->host_no); } count = 8; while (count) { *acb_firm_model = readb(iop_firm_model); acb_firm_model++; iop_firm_model++; count--; } count = 16; while (count) { *acb_firm_version = readb(iop_firm_version); acb_firm_version++; iop_firm_version++; count--; } printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", acb->host->host_no, acb->firm_version); lrwbuffer++; acb->firm_request_len = readl(lrwbuffer++); /*firm_request_len,1,04-07*/ acb->firm_numbers_queue = readl(lrwbuffer++); /*firm_numbers_queue,2,08-11*/ acb->firm_sdram_size = readl(lrwbuffer++); /*firm_sdram_size,3,12-15*/ acb->firm_hd_channels = readl(lrwbuffer); /*firm_ide_channels,4,16-19*/}static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb){ switch (acb->adapter_type) { case ACB_ADAPTER_TYPE_A: { arcmsr_get_hba_config(acb); } break; case ACB_ADAPTER_TYPE_B: { arcmsr_get_hbb_config(acb); } break; }}static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb){ struct MessageUnit_A __iomem *reg = acb->pmuA; struct CommandControlBlock *ccb; uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; polling_hba_ccb_retry: poll_count++; outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ while (1) { if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { if (poll_ccb_done) break; else { msleep(25); if (poll_count > 100) break; goto polling_hba_ccb_retry; } }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?