arcmsr_hba.c

来自「linux 内核源代码」· C语言 代码 · 共 2,271 行 · 第 1/5 页

C
2,271
字号
		ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5));		poll_ccb_done = (ccb == poll_ccb) ? 1:0;		if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {			if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) {				printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'"					" poll command abort successfully \n"					, acb->host->host_no					, ccb->pcmd->device->id					, ccb->pcmd->device->lun					, ccb);				ccb->pcmd->result = DID_ABORT << 16;				arcmsr_ccb_complete(ccb, 1);				poll_ccb_done = 1;				continue;			}			printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"				" command done ccb = '0x%p'"				"ccboutstandingcount = %d \n"				, acb->host->host_no				, ccb				, atomic_read(&acb->ccboutstandingcount));			continue;		}		arcmsr_report_ccb_state(acb, ccb, flag_ccb);	}}static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \					struct CommandControlBlock *poll_ccb){		struct MessageUnit_B *reg = acb->pmuB;		struct CommandControlBlock *ccb;		uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0;		int index;	polling_hbb_ccb_retry:		poll_count++;		/* clear doorbell interrupt */		writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);		while (1) {			index = reg->doneq_index;			if ((flag_ccb = readl(&reg->done_qbuffer[index])) == 0) {				if (poll_ccb_done)					break;				else {					msleep(25);					if (poll_count > 100)						break;					goto polling_hbb_ccb_retry;				}			}			writel(0, &reg->done_qbuffer[index]);			index++;			/*if last index number set it to 0 */			index %= ARCMSR_MAX_HBB_POSTQUEUE;			reg->doneq_index = index;			/* check ifcommand done with no error*/			ccb = (struct CommandControlBlock *)\      (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/			poll_ccb_done = (ccb == poll_ccb) ? 1:0;			if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) {				if (ccb->startdone == ARCMSR_CCB_ABORTED) {					printk(KERN_NOTICE "arcmsr%d: \		scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n"						,acb->host->host_no						,ccb->pcmd->device->id						,ccb->pcmd->device->lun						,ccb);					ccb->pcmd->result = DID_ABORT << 16;					arcmsr_ccb_complete(ccb, 1);					continue;				}				printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb"					" command done ccb = '0x%p'"					"ccboutstandingcount = %d \n"					, acb->host->host_no					, ccb					, atomic_read(&acb->ccboutstandingcount));				continue;			}			arcmsr_report_ccb_state(acb, ccb, flag_ccb);		}	/*drain reply FIFO*/}static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \					struct CommandControlBlock *poll_ccb){	switch (acb->adapter_type) {	case ACB_ADAPTER_TYPE_A: {		arcmsr_polling_hba_ccbdone(acb,poll_ccb);		}		break;	case ACB_ADAPTER_TYPE_B: {		arcmsr_polling_hbb_ccbdone(acb,poll_ccb);		}	}}static int arcmsr_iop_confirm(struct AdapterControlBlock *acb){	uint32_t cdb_phyaddr, ccb_phyaddr_hi32;	dma_addr_t dma_coherent_handle;	/*	********************************************************************	** here we need to tell iop 331 our freeccb.HighPart	** if freeccb.HighPart is not zero	********************************************************************	*/	dma_coherent_handle = acb->dma_coherent_handle;	cdb_phyaddr = (uint32_t)(dma_coherent_handle);	ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16);	/*	***********************************************************************	**    if adapter type B, set window of "post command Q"	***********************************************************************	*/	switch (acb->adapter_type) {	case ACB_ADAPTER_TYPE_A: {		if (ccb_phyaddr_hi32 != 0) {			struct MessageUnit_A __iomem *reg = acb->pmuA;			uint32_t intmask_org;			intmask_org = arcmsr_disable_outbound_ints(acb);			writel(ARCMSR_SIGNATURE_SET_CONFIG, \						&reg->message_rwbuffer[0]);			writel(ccb_phyaddr_hi32, &reg->message_rwbuffer[1]);			writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \							&reg->inbound_msgaddr0);			if (arcmsr_hba_wait_msgint_ready(acb)) {				printk(KERN_NOTICE "arcmsr%d: ""set ccb high \				part physical address timeout\n",				acb->host->host_no);				return 1;			}			arcmsr_enable_outbound_ints(acb, intmask_org);		}		}		break;	case ACB_ADAPTER_TYPE_B: {		unsigned long post_queue_phyaddr;		uint32_t __iomem *rwbuffer;		struct MessageUnit_B *reg = acb->pmuB;		uint32_t intmask_org;		intmask_org = arcmsr_disable_outbound_ints(acb);		reg->postq_index = 0;		reg->doneq_index = 0;		writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg);		if (arcmsr_hbb_wait_msgint_ready(acb)) {			printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \				acb->host->host_no);			return 1;		}		post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \		sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ;		rwbuffer = reg->msgcode_rwbuffer_reg;		/* driver "set config" signature */		writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++);		/* normal should be zero */		writel(ccb_phyaddr_hi32, rwbuffer++);		/* postQ size (256 + 8)*4	 */		writel(post_queue_phyaddr, rwbuffer++);		/* doneQ size (256 + 8)*4	 */		writel(post_queue_phyaddr + 1056, rwbuffer++);		/* ccb maxQ size must be --> [(256 + 8)*4]*/		writel(1056, rwbuffer);		writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg);		if (arcmsr_hbb_wait_msgint_ready(acb)) {			printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \			timeout \n",acb->host->host_no);			return 1;		}		writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg);		if (arcmsr_hbb_wait_msgint_ready(acb)) {			printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\			,acb->host->host_no);			return 1;		}		arcmsr_enable_outbound_ints(acb, intmask_org);		}		break;	}	return 0;}static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb){	uint32_t firmware_state = 0;	switch (acb->adapter_type) {	case ACB_ADAPTER_TYPE_A: {		struct MessageUnit_A __iomem *reg = acb->pmuA;		do {			firmware_state = readl(&reg->outbound_msgaddr1);		} while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0);		}		break;	case ACB_ADAPTER_TYPE_B: {		struct MessageUnit_B *reg = acb->pmuB;		do {			firmware_state = readl(reg->iop2drv_doorbell_reg);		} while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0);		}		break;	}}static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb){	struct MessageUnit_A __iomem *reg = acb->pmuA;	acb->acb_flags |= ACB_F_MSG_START_BGRB;	writel(ARCMSR_INBOUND_MESG0_START_BGRB, &reg->inbound_msgaddr0);	if (arcmsr_hba_wait_msgint_ready(acb)) {		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \				rebulid' timeout \n", acb->host->host_no);	}}static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb){	struct MessageUnit_B *reg = acb->pmuB;	acb->acb_flags |= ACB_F_MSG_START_BGRB;	writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg);	if (arcmsr_hbb_wait_msgint_ready(acb)) {		printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \				rebulid' timeout \n",acb->host->host_no);	}}static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb){	switch (acb->adapter_type) {	case ACB_ADAPTER_TYPE_A:		arcmsr_start_hba_bgrb(acb);		break;	case ACB_ADAPTER_TYPE_B:		arcmsr_start_hbb_bgrb(acb);		break;	}}static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb){	switch (acb->adapter_type) {	case ACB_ADAPTER_TYPE_A: {		struct MessageUnit_A __iomem *reg = acb->pmuA;		uint32_t outbound_doorbell;		/* empty doorbell Qbuffer if door bell ringed */		outbound_doorbell = readl(&reg->outbound_doorbell);		/*clear doorbell interrupt */		writel(outbound_doorbell, &reg->outbound_doorbell);		writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, &reg->inbound_doorbell);		}		break;	case ACB_ADAPTER_TYPE_B: {		struct MessageUnit_B *reg = acb->pmuB;		/*clear interrupt and message state*/		writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg);		writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg);		/* let IOP know data has been read */		}		break;	}}static void arcmsr_iop_init(struct AdapterControlBlock *acb){	uint32_t intmask_org;	arcmsr_wait_firmware_ready(acb);	arcmsr_iop_confirm(acb);       /* disable all outbound interrupt */       intmask_org = arcmsr_disable_outbound_ints(acb);	arcmsr_get_firmware_spec(acb);	/*start background rebuild*/	arcmsr_start_adapter_bgrb(acb);	/* empty doorbell Qbuffer if door bell ringed */	arcmsr_clear_doorbell_queue_buffer(acb);	/* enable outbound Post Queue,outbound doorbell Interrupt */	arcmsr_enable_outbound_ints(acb, intmask_org);	acb->acb_flags |= ACB_F_IOP_INITED;}static void arcmsr_iop_reset(struct AdapterControlBlock *acb){	struct CommandControlBlock *ccb;	uint32_t intmask_org;	int i = 0;	if (atomic_read(&acb->ccboutstandingcount) != 0) {		/* talk to iop 331 outstanding command aborted */		arcmsr_abort_allcmd(acb);		/* wait for 3 sec for all command aborted*/		ssleep(3);		/* disable all outbound interrupt */		intmask_org = arcmsr_disable_outbound_ints(acb);		/* clear all outbound posted Q */		arcmsr_done4abort_postqueue(acb);		for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {			ccb = acb->pccb_pool[i];			if (ccb->startdone == ARCMSR_CCB_START) {				ccb->startdone = ARCMSR_CCB_ABORTED;				arcmsr_ccb_complete(ccb, 1);			}		}		/* enable all outbound interrupt */		arcmsr_enable_outbound_ints(acb, intmask_org);	}}static int arcmsr_bus_reset(struct scsi_cmnd *cmd){	struct AdapterControlBlock *acb =		(struct AdapterControlBlock *)cmd->device->host->hostdata;	int i;	acb->num_resets++;	acb->acb_flags |= ACB_F_BUS_RESET;	for (i = 0; i < 400; i++) {		if (!atomic_read(&acb->ccboutstandingcount))			break;		arcmsr_interrupt(acb);/* FIXME: need spinlock */		msleep(25);	}	arcmsr_iop_reset(acb);	acb->acb_flags &= ~ACB_F_BUS_RESET;	return SUCCESS;}static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb,		struct CommandControlBlock *ccb){	u32 intmask;	ccb->startdone = ARCMSR_CCB_ABORTED;	/*	** Wait for 3 sec for all command done.	*/	ssleep(3);	intmask = arcmsr_disable_outbound_ints(acb);	arcmsr_polling_ccbdone(acb, ccb);	arcmsr_enable_outbound_ints(acb, intmask);}static int arcmsr_abort(struct scsi_cmnd *cmd){	struct AdapterControlBlock *acb =		(struct AdapterControlBlock *)cmd->device->host->hostdata;	int i = 0;	printk(KERN_NOTICE		"arcmsr%d: abort device command of scsi id = %d lun = %d \n",		acb->host->host_no, cmd->device->id, cmd->device->lun);	acb->num_aborts++;	/*	************************************************	** the all interrupt service routine is locked	** we need to handle it as soon as possible and exit	************************************************	*/	if (!atomic_read(&acb->ccboutstandingcount))		return SUCCESS;	for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) {		struct CommandControlBlock *ccb = acb->pccb_pool[i];		if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) {			arcmsr_abort_one_cmd(acb, ccb);			break;		}	}	return SUCCESS;}static const char *arcmsr_info(struct Scsi_Host *host){	struct AdapterControlBlock *acb =		(struct AdapterControlBlock *) host->hostdata;	static char buf[256];	char *type;	int raid6 = 1;	switch (acb->pdev->device) {	case PCI_DEVICE_ID_ARECA_1110:	case PCI_DEVICE_ID_ARECA_1200:	case PCI_DEVICE_ID_ARECA_1202:	case PCI_DEVICE_ID_ARECA_1210:		raid6 = 0;		/*FALLTHRU*/	case PCI_DEVICE_ID_ARECA_1120:	case PCI_DEVICE_ID_ARECA_1130:	case PCI_DEVICE_ID_ARECA_1160:	case PCI_DEVICE_ID_ARECA_1170:	case PCI_DEVICE_ID_ARECA_1201:	case PCI_DEVICE_ID_ARECA_1220:	case PCI_DEVICE_ID_ARECA_1230:	case PCI_DEVICE_ID_ARECA_1260:	case PCI_DEVICE_ID_ARECA_1270:	case PCI_DEVICE_ID_ARECA_1280:		type = "SATA";		break;	case PCI_DEVICE_ID_ARECA_1380:	case PCI_DEVICE_ID_ARECA_1381:	case PCI_DEVICE_ID_ARECA_1680:	case PCI_DEVICE_ID_ARECA_1681:		type = "SAS";		break;	default:		type = "X-TYPE";		break;	}	sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s",			type, raid6 ? "( RAID6 capable)" : "",			ARCMSR_DRIVER_VERSION);	return buf;}#ifdef CONFIG_SCSI_ARCMSR_AERstatic pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev){	struct Scsi_Host *host = pci_get_drvdata(pdev);	struct AdapterControlBlock *acb =		(struct AdapterControlBlock *) host->hostdata;	uint32_t intmask_org;	int i, j;	if (pci_enable_device(pdev)) {		return PCI_ERS_RESULT_DISCONNECT;	}	pci_set_master(pdev);	intmask_org = arcmsr_disable_outbound_ints(acb);	acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED |			   ACB_F_MESSAGE_RQBUFFER_CLEARED |			   ACB_F_MESSAGE_WQBUFFER_READED);	acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER;	for (i = 0; i < ARCMSR_MAX_TARGETID; i++)		for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++)			acb->devstate[i][j] = ARECA_RAID_GONE;	arcmsr_wait_firmware_r

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?