hba_mod.c
来自「6440linuxDriver的源代码」· C语言 代码 · 共 1,621 行 · 第 1/3 页
C
1,621 行
/* * module management module - module of the modules * * */#include "hba_header.h"#include "linux_main.h"#include "linux_iface.h"#include "hba_timer.h"#include "hba_mod.h"#include "res_mgmt.h"#include "hba_exp.h"static void __dump_hex(const unsigned char *buf, int len){ int i; for (i = 0; i < len; i++) { if (i && !(i % 8)) printk(YELLOW(" :")); if (i && !(i % 16)) printk("\n"); printk(" %02X", buf[i]); } printk("\n");}void __hba_dump_req_info(MV_U32 id, PMV_Request preq){ unsigned long lba =0; char *buf; struct scsi_cmnd *scmd = NULL; struct scatterlist *sg = NULL; switch (preq->Cdb[0]) { case SCSI_CMD_READ_10: case SCSI_CMD_WRITE_10: lba = preq->Cdb[2]<<24 | preq->Cdb[3]<<16 | preq->Cdb[4]<<8 | \ preq->Cdb[5]; break; case SCSI_CMD_INQUIRY: if (REQ_STATUS_SUCCESS != preq->Scsi_Status) break; scmd = (struct scsi_cmnd *) preq->Org_Req; sg = (struct scatterlist *) scmd->request_buffer; /* ignored */ break; buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; MV_DBG(DMSG_SCSI, BLUE("%s : -- inquiry dump starts -- ")"\n", mv_product_name); __dump_hex((unsigned char *)buf, scmd->request_bufflen); MV_DBG(DMSG_SCSI, "%s : -- inquiry dump ends -- \n", mv_product_name); kunmap_atomic(buf, KM_IRQ0); break; default: lba = 0; break; } MV_DBG(DMSG_FREQ, "(%u) req "RED("%p") " dev %d : cmd %2X : lba %lu - %lu : length %d.\n", id, preq, preq->Device_Id, preq->Cdb[0], lba, lba + preq->Data_Transfer_Length/512, preq->Data_Transfer_Length);}static void generate_sg_table(struct hba_extension *phba, struct scsi_cmnd *scmd, PMV_SG_Table sg_table){ struct scatterlist *sg; unsigned int sg_count = 0; unsigned int length; BUS_ADDRESS busaddr = 0; int i; MV_DBG(DMSG_FREQ,"%s : in %s.\n", mv_product_name, __FUNCTION__); if (scmd->request_bufflen > (mv_scmd_host(scmd)->max_sectors << 9)) { MV_DBG(DMSG_SCSI, "ERROR: request length exceeds " "the maximum alowed value.\n"); } if (0 == scmd->request_bufflen) return ; if (scmd->use_sg) { MV_DBG(DMSG_SCSI_FREQ, "%s : map %d sg entries.\n", mv_product_name, scmd->use_sg); sg = (struct scatterlist *) scmd->request_buffer; sg_count = pci_map_sg(phba->dev, sg, scmd->use_sg, scmd->sc_data_direction); if (sg_count != scmd->use_sg) { MV_PRINT("WARNING sg_count(%d) != scmd->use_sg(%d)\n", (unsigned int) sg_count, scmd->use_sg); } for (i = 0; i < sg_count; i++) { busaddr = sg_dma_address(&sg[i]); length = sg_dma_len(&sg[i]); sgdt_append_pctx(sg_table, LO_BUSADDR(busaddr), HI_BUSADDR(busaddr), length, sg + i); } } else { MV_DBG(DMSG_SCSI_FREQ, "%s : map kernel addr into bus addr.\n", mv_product_name); scmd->SCp.dma_handle = pci_map_single(phba->dev, scmd->request_buffer, scmd->request_bufflen, scmd->sc_data_direction); sgdt_append_vp(sg_table, scmd->request_buffer, scmd->request_bufflen, LO_BUSADDR(scmd->SCp.dma_handle), HI_BUSADDR(scmd->SCp.dma_handle)); }}static void mv_complete_request(struct hba_extension *phba, struct scsi_cmnd *scmd, PMV_Request pReq){ PMV_Sense_Data senseBuffer = (PMV_Sense_Data) scmd->sense_buffer; MV_POKE(); __hba_dump_req_info(phba->desc->module_id, pReq); if (scmd->request_bufflen) { MV_DBG(DMSG_SCSI_FREQ, "%s : unmap %d bytes.\n", mv_product_name, scmd->request_bufflen); if (scmd->use_sg) { pci_unmap_sg(phba->dev, scmd->request_buffer, scmd->use_sg, scmd->sc_data_direction); } else { pci_unmap_single(phba->dev, scmd->SCp.dma_handle, scmd->request_bufflen, scmd->sc_data_direction); } } MV_DBG(DMSG_SCSI_FREQ, "%s : %s - pReq->Scsi_Status = %x pcmd = %p.\n", mv_product_name, __FUNCTION__, pReq->Scsi_Status, scmd); switch (pReq->Scsi_Status) { case REQ_STATUS_SUCCESS: scmd->result = (DID_OK << 16); break; case REQ_STATUS_MEDIA_ERROR: scmd->result = (DID_BAD_TARGET << 16); break; case REQ_STATUS_BUSY: scmd->result = (DID_BUS_BUSY << 16); break; case REQ_STATUS_NO_DEVICE: scmd->result = (DID_NO_CONNECT << 16); break; case REQ_STATUS_HAS_SENSE: /* Sense buffer data is valid already. */ scmd->result = (DRIVER_SENSE << 24) | (DID_OK << 16); senseBuffer->Valid = 1; MV_DBG(DMSG_SCSI, "MV Sense: response %x SK %s length %x " "ASC %x ASCQ %x.\n", ((MV_PU8) senseBuffer)[0], MV_DumpSenseKey(((MV_PU8) senseBuffer)[2]), ((MV_PU8) senseBuffer)[7], ((MV_PU8) senseBuffer)[12], ((MV_PU8) senseBuffer)[13]); break; default: scmd->result = (DRIVER_INVALID | SUGGEST_ABORT) << 24; scmd->result |= DID_ABORT << 16; break; } scmd->scsi_done(scmd);}/* This should be the _only_ os request exit point. */static void hba_req_callback(MV_PVOID This, PMV_Request pReq){ struct hba_extension *phba = (struct hba_extension *)This; struct scsi_cmnd *scmd = (struct scsi_cmnd *)pReq->Org_Req; /* Return this request to OS. */ mv_complete_request(phba, scmd, pReq); phba->Io_Count--; res_free_req_to_pool(phba->req_pool, pReq);}static int scsi_cmd_to_req_conv(struct hba_extension *phba, struct scsi_cmnd *scmd, PMV_Request pReq){ /* * Set three flags: CMD_FLAG_NON_DATA * CMD_FLAG_DATA_IN * CMD_FLAG_DMA * currently data in/out all go thru DMA */ pReq->Cmd_Flag = 0; switch (scmd->sc_data_direction) { case DMA_NONE: pReq->Cmd_Flag |= CMD_FLAG_NON_DATA; break; case DMA_FROM_DEVICE: pReq->Cmd_Flag |= CMD_FLAG_DATA_IN; case DMA_TO_DEVICE: pReq->Cmd_Flag |= CMD_FLAG_DMA; break; case DMA_BIDIRECTIONAL : MV_DBG(DMSG_SCSI, "%s : unexpected DMA_BIDIRECTIONAL.\n", mv_product_name); break; default: break; } /* handling of specific cmds */ memset(pReq->Cdb, 0, MAX_CDB_SIZE); switch (scmd->cmnd[0]){ case READ_TOC: pReq->Cdb[0] = READ_TOC; pReq->Cdb[1] = scmd->cmnd[1]; pReq->Cdb[2] = scmd->cmnd[9]>>6; pReq->Cdb[6] = scmd->cmnd[6]; pReq->Cdb[7] = scmd->cmnd[7]; pReq->Cdb[8] = scmd->cmnd[8]; break; case FORMAT_UNIT: pReq->Cdb[0] = 0x24; /* ATAPI opcodes */ break; case READ_CAPACITY: //TBD pReq->Cdb[0] = scmd->cmnd[0]; break; case TEST_UNIT_READY: //TBD pReq->Cdb[0] = scmd->cmnd[0]; break; default: memcpy(pReq->Cdb, scmd->cmnd, MAX_CDB_SIZE); break; } pReq->Data_Buffer = scmd->request_buffer; pReq->Data_Transfer_Length = scmd->request_bufflen; pReq->Sense_Info_Buffer = scmd->sense_buffer; pReq->Sense_Info_Buffer_Length = SCSI_SENSE_BUFFERSIZE; SGTable_Init(&pReq->SG_Table, 0); generate_sg_table(phba, scmd, &pReq->SG_Table); MV_SetLBAandSectorCount(pReq); pReq->Req_Type = REQ_TYPE_OS; pReq->Org_Req = scmd; pReq->Tag = scmd->tag; pReq->Scsi_Status = REQ_STATUS_PENDING; pReq->Completion = hba_req_callback; pReq->Cmd_Initiator = phba; pReq->Scsi_Status = REQ_STATUS_INVALID_REQUEST; pReq->Device_Id = __MAKE_DEV_ID(mv_scmd_target(scmd), mv_scmd_lun(scmd));#ifdef __AC_REQ_TRACE__ MV_DBG(DMSG_FREQ, "_MV_ OS REQ : "); __hba_dump_req_info(phba->desc->module_id, pReq);#endif /* __AC_REQ_TRACE__ */ return 0;}static void hba_shutdown_req_cb(MV_PVOID this, PMV_Request req){ struct hba_extension *phba = (struct hba_extension *) this; res_free_req_to_pool(phba->req_pool, req); phba->Io_Count--;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) atomic_set(&phba->hba_sync, 0);#else complete(&phba->cmpl);#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) */}#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11)/* will wait for atomic value atomic to become zero until timed out *//* return how much 'timeout' is left or 0 if already timed out */int __hba_wait_for_atomic_timeout(atomic_t *atomic, unsigned long timeout){ unsigned intv = HZ/20; while (timeout) { if (0 == atomic_read(atomic)) break; if (timeout < intv) intv = timeout; set_current_state(TASK_INTERRUPTIBLE); timeout -= (intv - schedule_timeout(intv)); } return timeout;}#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) */void hba_send_shutdown_req(struct hba_extension *phba){ unsigned long flags; PMV_Request pReq; pReq = res_get_req_from_pool(phba->req_pool); if (NULL == pReq) { printk("%s : cannot allocate memory for req.\n", mv_product_name); return; } pReq->Cmd_Initiator = phba; pReq->Org_Req = pReq; pReq->Req_Type = REQ_TYPE_INTERNAL; pReq->Scsi_Status = REQ_STATUS_INVALID_REQUEST; pReq->Completion = hba_shutdown_req_cb; #ifdef RAID_DRIVER pReq->Cdb[0] = APICDB0_LD; pReq->Cdb[1] = APICDB1_LD_SHUTDOWN;#else pReq->Device_Id = 0; pReq->Cmd_Flag = 0; pReq->Cmd_Flag |= CMD_FLAG_NON_DATA; pReq->Sense_Info_Buffer_Length = 0; pReq->Data_Transfer_Length = 0; pReq->Data_Buffer = NULL; pReq->Sense_Info_Buffer = NULL; SGTable_Init(&pReq->SG_Table, 0); pReq->Cdb[0] = SCSI_CMD_MARVELL_SPECIFIC; pReq->Cdb[1] = CDB_CORE_MODULE; pReq->Cdb[2] = CDB_CORE_SHUTDOWN; pReq->LBA.value = 0; pReq->Sector_Count = 0; pReq->Scsi_Status = REQ_STATUS_PENDING;#endif spin_lock_irqsave(&phba->irq_lock, flags); phba->Io_Count++;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) atomic_set(&phba->hba_sync, 1);#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) */ phba->desc->ops->module_sendrequest(phba->desc->extension, pReq); spin_unlock_irqrestore(&phba->irq_lock, flags);#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) __hba_wait_for_atomic_timeout(&phba->hba_sync, 10*HZ);#else wait_for_completion_timeout(&phba->cmpl, 10*HZ);#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 11) */}#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 7)static enum scsi_eh_timer_return mv_linux_timed_out(struct scsi_cmnd *cmd){ MV_BOOLEAN ret = MV_FALSE; MV_DBG(DMSG_SCSI, "scsi cmd timed out : %p.\n", cmd); return (ret)?EH_RESET_TIMER:EH_NOT_HANDLED;}#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 7) */static int mv_linux_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)){ struct Scsi_Host *host = mv_scmd_host(scmd); struct hba_extension *hba = *((struct hba_extension * *) host->hostdata); PMV_Request req; unsigned long flags;#ifdef __AC_QCMD_PROF__ cycles_t tick; static unsigned long tick_mean; static unsigned long num;#endif /* __AC_PROF__ */ if (done == NULL) { MV_PRINT( ": in queuecommand, done function can't be NULL\n"); return 0; } MV_DBG(DMSG_SCSI_FREQ, "mv_linux_queue_command %p (%d/%d/%d/%d cdb=(%x-%x-%x))\n", scmd, host->host_no, mv_scmd_channel(scmd), mv_scmd_target(scmd), mv_scmd_lun(scmd), *(scmd->cmnd), *(scmd->cmnd+1), *(scmd->cmnd+2)); scmd->result = 0; scmd->scsi_done = done; if (mv_scmd_channel(scmd)) { scmd->result = DID_BAD_TARGET << 16; goto done; } /* * Get mv_request resource and translate the scsi_cmnd request * to mv_request. */ req = res_get_req_from_pool(hba->req_pool); if (req == NULL) return SCSI_MLQUEUE_HOST_BUSY; if (scsi_cmd_to_req_conv(hba, scmd, req)) { /* * Even TranslateOSRequest failed, * it still should set some of the variables to the MV_Request * especially MV_Request.Org_Req and MV_Request.Scsi_Status; */ MV_DBG(DMSG_HBA, "ERROR - Translation from OS Request failed.\n"); hba_req_callback(hba, req); return 0; } spin_lock_irqsave(&hba->irq_lock, flags); hba->Io_Count++;#ifdef __AC_QCMD_PROF__ tick = get_cycles();#endif /* __AC_PROF__ */ if (hba->State != DRIVER_STATUS_STARTED) { MV_ASSERT(0); /*if ( hba->State==DRIVER_STATUS_IDLE ) { hba->State = DRIVER_STATUS_STARTING; Module_StartAll(module_manage, MODULE_CORE); }*/ } else { hba->desc->ops->module_sendrequest(hba->desc->extension, req); } spin_unlock_irqrestore(&hba->irq_lock, flags);#ifdef __AC_QCMD_PROF__ tick = (get_cycles() - tick); num++; tick_mean = (tick + (num-1)*tick_mean) / num; MV_DBG(DMSG_PROF_FREQ, "_MV_ cmd took "CYAN("%llu (%lu)")" us to process.\n", tick*1000/cpu_khz, tick_mean*100/cpu_khz);#endif /* __AC_PROF__ */ return 0;done: scmd->scsi_done(scmd); return 0;}#if 0static void ac_dump_info(struct scsi_cmnd *cmd){ return;}static int mv_linux_abort(struct scsi_cmnd *cmd){ struct Scsi_Host *host; struct hba_extension *phba; int ret = FAILED; MV_PRINT("__MV__ abort command %p.\n", cmd); return ret;}#endif /* 0 */#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)static irqreturn_t mv_intr_handler(int irq, void *dev_id, struct pt_regs *regs)#elsestatic irqreturn_t mv_intr_handler(int irq, void *dev_id)#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) */{ /* MV_FALSE should be equal to IRQ_NONE (0) */ irqreturn_t retval = MV_FALSE; unsigned long flags;#ifdef __AC_PROF__ cycles_t tick; static cycles_t start; static unsigned int num_irq; unsigned int data_len =0; static unsigned long tick_mean; static unsigned long data_mean; static unsigned long num; struct hba_extension *hba = (struct hba_extension *)dev_id; spin_lock_irqsave(hba->irq_lock, flags); pcore = module_manage->resource[MODULE_CORE].module_extension; tick = get_cycles(); num_irq++; if ( 0 == start ) start = tick; retval = Core_InterruptServiceRoutine(pcore, &data_len); tick = (get_cycles() - tick); if ((get_cycles() - start) > cpu_khz * 1000) { MV_DBG(DMSG_PROF_FREQ, "_MV_ "YELLOW("%u")" irqs in a sec.\n", num_irq); start = 0; num_irq = 0; } /* compute the mean transfer time */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?