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 *)(&reg->message_rwbuffer[15]);	char __iomem *iop_firm_version = (char __iomem *)(&reg->message_rwbuffer[17]);	int count;	writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, &reg->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(&reg->message_rwbuffer[1]);	acb->firm_numbers_queue = readl(&reg->message_rwbuffer[2]);	acb->firm_sdram_size = readl(&reg->message_rwbuffer[3]);	acb->firm_hd_channels = readl(&reg->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(&reg->outbound_intstatus) & acb->outbound_int_enable;	writel(outbound_intstatus, &reg->outbound_intstatus);/*clear interrupt*/	while (1) {		if ((flag_ccb = readl(&reg->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 + -
显示快捷键?