⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 acornscsi.c

📁 h内核
💻 C
📖 第 1 页 / 共 5 页
字号:
 * Notes    : this will only be one SG entry or less */staticvoid acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length){    SCp->ptr += length;    SCp->this_residual -= length;    if (SCp->this_residual == 0 && next_SCp(SCp) == 0)	host->dma.xfer_done = 1;}/* * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr, *				unsigned int start_addr, unsigned int length) * Purpose  : read data from DMA RAM * Params   : host - host to transfer from *	      ptr  - DRAM address *	      start_addr - host mem address *	      length - number of bytes to transfer * Notes    : this will only be one SG entry or less */staticvoid acornscsi_data_read(AS_Host *host, char *ptr,				 unsigned int start_addr, unsigned int length){    extern void __acornscsi_in(int port, char *buf, int len);    unsigned int page, offset, len = length;    page = (start_addr >> 12);    offset = start_addr & ((1 << 12) - 1);    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);    while (len > 0) {	unsigned int this_len;	if (len + offset > (1 << 12))	    this_len = (1 << 12) - offset;	else	    this_len = len;	__acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len);	offset += this_len;	ptr += this_len;	len -= this_len;	if (offset == (1 << 12)) {	    offset = 0;	    page ++;	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);	}    }    outb(host->card.page_reg, host->card.io_page);}/* * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr, *				unsigned int start_addr, unsigned int length) * Purpose  : write data to DMA RAM * Params   : host - host to transfer from *	      ptr  - DRAM address *	      start_addr - host mem address *	      length - number of bytes to transfer * Notes    : this will only be one SG entry or less */staticvoid acornscsi_data_write(AS_Host *host, char *ptr,				 unsigned int start_addr, unsigned int length){    extern void __acornscsi_out(int port, char *buf, int len);    unsigned int page, offset, len = length;    page = (start_addr >> 12);    offset = start_addr & ((1 << 12) - 1);    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);    while (len > 0) {	unsigned int this_len;	if (len + offset > (1 << 12))	    this_len = (1 << 12) - offset;	else	    this_len = len;	__acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len);	offset += this_len;	ptr += this_len;	len -= this_len;	if (offset == (1 << 12)) {	    offset = 0;	    page ++;	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);	}    }    outb(host->card.page_reg, host->card.io_page);}/* ========================================================================================= * On-board DMA routines */#ifdef USE_DMAC/* * Prototype: void acornscsi_dmastop(AS_Host *host) * Purpose  : stop all DMA * Params   : host - host on which to stop DMA * Notes    : This is called when leaving DATA IN/OUT phase, *	      or when interface is RESET */static inlinevoid acornscsi_dma_stop(AS_Host *host){    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);    dmac_clearintr(host->dma.io_intr_clear);#if (DEBUG & DEBUG_DMA)    DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));#endif}/* * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) * Purpose : setup DMA controller for data transfer * Params  : host - host to setup *	     direction - data transfer direction * Notes   : This is called when entering DATA I/O phase, not *	     while we're in a DATA I/O phase */staticvoid acornscsi_dma_setup(AS_Host *host, dmadir_t direction){    unsigned int address, length, mode;    host->dma.direction = direction;    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);    if (direction == DMA_OUT) {#if (DEBUG & DEBUG_NO_WRITE)	if (NO_WRITE & (1 << host->SCpnt->device->id)) {	    printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",		    host->host->host_no, acornscsi_target(host));	    return;	}#endif	mode = DMAC_WRITE;    } else	mode = DMAC_READ;    /*     * Allocate some buffer space, limited to half the buffer size     */    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);    if (length) {	host->dma.start_addr = address = host->dma.free_addr;	host->dma.free_addr = (host->dma.free_addr + length) &				(DMAC_BUFFER_SIZE - 1);	/*	 * Transfer data to DMA memory	 */	if (direction == DMA_OUT)	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,				length);	length -= 1;	dmac_write(host->dma.io_port, DMAC_TXCNTLO, length);	dmac_write(host->dma.io_port, DMAC_TXCNTHI, length >> 8);	dmac_write(host->dma.io_port, DMAC_TXADRLO, address);	dmac_write(host->dma.io_port, DMAC_TXADRMD, address >> 8);	dmac_write(host->dma.io_port, DMAC_TXADRHI, 0);	dmac_write(host->dma.io_port, DMAC_MODECON, mode);	dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_OFF);#if (DEBUG & DEBUG_DMA)	DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));#endif	host->dma.xfer_setup = 1;    }}/* * Function: void acornscsi_dma_cleanup(AS_Host *host) * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct * Params  : host - host to finish * Notes   : This is called when a command is: *		terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT *	   : This must not return until all transfers are completed. */staticvoid acornscsi_dma_cleanup(AS_Host *host){    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);    dmac_clearintr(host->dma.io_intr_clear);    /*     * Check for a pending transfer     */    if (host->dma.xfer_required) {	host->dma.xfer_required = 0;	if (host->dma.direction == DMA_IN)	    acornscsi_data_read(host, host->dma.xfer_ptr,				 host->dma.xfer_start, host->dma.xfer_length);    }    /*     * Has a transfer been setup?     */    if (host->dma.xfer_setup) {	unsigned int transferred;	host->dma.xfer_setup = 0;#if (DEBUG & DEBUG_DMA)	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupi"));#endif	/*	 * Calculate number of bytes transferred from DMA.	 */	transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;	host->dma.transferred += transferred;	if (host->dma.direction == DMA_IN)	    acornscsi_data_read(host, host->scsi.SCp.ptr,				 host->dma.start_addr, transferred);	/*	 * Update SCSI pointers	 */	acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);#if (DEBUG & DEBUG_DMA)	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));#endif    }}/* * Function: void acornscsi_dmacintr(AS_Host *host) * Purpose : handle interrupts from DMAC device * Params  : host - host to process * Notes   : If reading, we schedule the read to main memory & *	     allow the transfer to continue. *	   : If writing, we fill the onboard DMA memory from main *	     memory. *	   : Called whenever DMAC finished it's current transfer. */staticvoid acornscsi_dma_intr(AS_Host *host){    unsigned int address, length, transferred;#if (DEBUG & DEBUG_DMA)    DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));#endif    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);    dmac_clearintr(host->dma.io_intr_clear);    /*     * Calculate amount transferred via DMA     */    transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;    host->dma.transferred += transferred;    /*     * Schedule DMA transfer off board     */    if (host->dma.direction == DMA_IN) {	host->dma.xfer_start = host->dma.start_addr;	host->dma.xfer_length = transferred;	host->dma.xfer_ptr = host->scsi.SCp.ptr;	host->dma.xfer_required = 1;    }    acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);    /*     * Allocate some buffer space, limited to half the on-board RAM size     */    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);    if (length) {	host->dma.start_addr = address = host->dma.free_addr;	host->dma.free_addr = (host->dma.free_addr + length) &				(DMAC_BUFFER_SIZE - 1);	/*	 * Transfer data to DMA memory	 */	if (host->dma.direction == DMA_OUT)	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,				length);	length -= 1;	dmac_write(host->dma.io_port, DMAC_TXCNTLO, length);	dmac_write(host->dma.io_port, DMAC_TXCNTHI, length >> 8);	dmac_write(host->dma.io_port, DMAC_TXADRLO, address);	dmac_write(host->dma.io_port, DMAC_TXADRMD, address >> 8);	dmac_write(host->dma.io_port, DMAC_TXADRHI, 0);	dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_OFF);#if (DEBUG & DEBUG_DMA)	DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));#endif    } else {	host->dma.xfer_setup = 0;#if 0	/*	 * If the interface still wants more, then this is an error.	 * We give it another byte, but we also attempt to raise an	 * attention condition.  We continue giving one byte until	 * the device recognises the attention.	 */	if (dmac_read(host->dma.io_port, DMAC_STATUS) & STATUS_RQ0) {	    acornscsi_abortcmd(host, host->SCpnt->tag);	    dmac_write(host->dma.io_port, DMAC_TXCNTLO, 0);	    dmac_write(host->dma.io_port, DMAC_TXCNTHI, 0);	    dmac_write(host->dma.io_port, DMAC_TXADRLO, 0);	    dmac_write(host->dma.io_port, DMAC_TXADRMD, 0);	    dmac_write(host->dma.io_port, DMAC_TXADRHI, 0);	    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_OFF);	}#endif    }}/* * Function: void acornscsi_dma_xfer(AS_Host *host) * Purpose : transfer data between AcornSCSI and memory * Params  : host - host to process */staticvoid acornscsi_dma_xfer(AS_Host *host){    host->dma.xfer_required = 0;    if (host->dma.direction == DMA_IN)	acornscsi_data_read(host, host->dma.xfer_ptr,				host->dma.xfer_start, host->dma.xfer_length);}/* * Function: void acornscsi_dma_adjust(AS_Host *host) * Purpose : adjust DMA pointers & count for bytes transferred to *	     SBIC but not SCSI bus. * Params  : host - host to adjust DMA count for */staticvoid acornscsi_dma_adjust(AS_Host *host){    if (host->dma.xfer_setup) {	signed long transferred;#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))	DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));#endif	/*	 * Calculate correct DMA address - DMA is ahead of SCSI bus while	 * writing.	 *  host->scsi.SCp.scsi_xferred is the number of bytes	 *  actually transferred to/from the SCSI bus.	 *  host->dma.transferred is the number of bytes transferred	 *  over DMA since host->dma.start_addr was last set.	 *	 * real_dma_addr = host->dma.start_addr + host->scsi.SCp.scsi_xferred	 *		   - host->dma.transferred	 */	transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;	if (transferred < 0)	    printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",		    host->host->host_no, acornscsi_target(host), transferred);	else if (transferred == 0)	    host->dma.xfer_setup = 0;	else {	    transferred += host->dma.start_addr;	    dmac_write(host->dma.io_port, DMAC_TXADRLO, transferred);	    dmac_write(host->dma.io_port, DMAC_TXADRMD, transferred >> 8);	    dmac_write(host->dma.io_port, DMAC_TXADRHI, transferred >> 16);#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))	    DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));#endif	}    }}#endif/* ========================================================================================= * Data I/O */static intacornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout){	unsigned int asr, timeout = max_timeout;	int my_ptr = *ptr;	while (my_ptr < len) {		asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);		if (asr & ASR_DBR) {			timeout = max_timeout;			sbic_arm_write(host->scsi.io_port, SBIC_DATA, bytes[my_ptr++]);		} else if (asr & ASR_INT)			break;		else if (--timeout == 0)			break;		udelay(1);	}	*ptr = my_ptr;	return (timeout == 0) ? -1 : 0;}/* * Function: void acornscsi_sendcommand(AS_Host *host) * Purpose : send a command to a target * Params  : host - host which is connected to target */static voidacornscsi_sendcommand(AS_Host *host){    Scsi_Cmnd *SCpnt = host->SCpnt;    sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);    sbic_arm_writenext(host->scsi.io_port, 0);    sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);    if (acornscsi_write_pio(host, SCpnt->cmnd,	(int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))	printk("scsi%d: timeout while sending command\n", host->host->host_no);    host->scsi.phase = PHASE_COMMAND;}staticvoid acornscsi_sendmessage(AS_Host *host){    unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);    unsigned int msgnr;    struct message *msg;

⌨️ 快捷键说明

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