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 + -
显示快捷键?