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,			&reg->inbound_queueport);		else {				writel(cdb_shifted_phyaddr, &reg->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, &reg->post_qbuffer[ending_index]);		if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) {			writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\						 &reg->post_qbuffer[index]);		}		else {			writel(cdb_shifted_phyaddr, &reg->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, &reg->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, &reg->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, &reg->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 *)&reg->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 *) &reg->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(&reg->outbound_doorbell);	writel(outbound_doorbell, &reg->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(&reg->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(&reg->done_qbuffer[index])) != 0) {		writel(0, &reg->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(&reg->outbound_intstatus) & \							acb->outbound_int_enable;	if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT))	{		return 1;	}	writel(outbound_intstatus, &reg->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 + -
显示快捷键?