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

📄 acornscsi.c.2

📁 arm平台上的uclinux系统全部源代码
💻 2
📖 第 1 页 / 共 5 页
字号:
	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 *//* * 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, 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, MASKREG, MASK_ON);    if (direction == DMA_OUT) {#if (DEBUG & DEBUG_NO_WRITE)	if (NO_WRITE & (1 << host->SCpnt->target)) {	    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 (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, TXCNTLO, length);	dmac_write (host->dma.io_port, TXCNTHI, length >> 8);	dmac_write (host->dma.io_port, TXADRLO, address);	dmac_write (host->dma.io_port, TXADRMD, address >> 8);	dmac_write (host->dma.io_port, TXADRHI, 0);	dmac_write (host->dma.io_port, MODECON, mode);	dmac_write (host->dma.io_port, 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, 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, "clup"));#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);    }}/* * 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, 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 buffer size     */    length = min (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, TXCNTLO, length);	dmac_write (host->dma.io_port, TXCNTHI, length >> 8);	dmac_write (host->dma.io_port, TXADRLO, address);	dmac_write (host->dma.io_port, TXADRMD, address >> 8);	dmac_write (host->dma.io_port, TXADRHI, 0);	dmac_write (host->dma.io_port, 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, STATUS) & STATUS_RQ0) {	    acornscsi_abortcmd (host, host->SCpnt->tag);	    dmac_write (host->dma.io_port, TXCNTLO, 0);	    dmac_write (host->dma.io_port, TXCNTHI, 0);	    dmac_write (host->dma.io_port, TXADRLO, 0);	    dmac_write (host->dma.io_port, TXADRMD, 0);	    dmac_write (host->dma.io_port, TXADRHI, 0);	    dmac_write (host->dma.io_port, 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 transfered 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.have_data_in 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.have_data_in	 *		   - host->dma.transferred	 */	transferred = host->scsi.SCp.have_data_in - 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, TXADRLO, transferred);	    dmac_write (host->dma.io_port, TXADRMD, transferred >> 8);	    dmac_write (host->dma.io_port, TXADRHI, transferred >> 16);#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))	    DBG(host->SCpnt, acornscsi_dumpdma (host, "adjo"));#endif	}			        }}/* ========================================================================================= * Data I/O *//* * Function: void acornscsi_sendcommand (AS_Host *host) * Purpose : send a command to a target * Params  : host - host which is connected to target */staticvoid acornscsi_sendcommand (AS_Host *host){    Scsi_Cmnd *SCpnt = host->SCpnt;    unsigned int asr;    unsigned char *cmdptr, *cmdend;    sbic_arm_write (host->scsi.io_port, 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);    sbic_arm_write (host->scsi.io_port, CMND, CMND_XFERINFO);    cmdptr = SCpnt->cmnd + host->scsi.SCp.sent_command;    cmdend = SCpnt->cmnd + SCpnt->cmd_len;    while (cmdptr < cmdend) {	asr = sbic_arm_read (host->scsi.io_port, ASR);	if (asr & ASR_DBR)	    sbic_arm_write (host->scsi.io_port, DATA, *cmdptr++);	else if (asr & ASR_INT)	    break;    }    if (cmdptr >= cmdend)	host->scsi.SCp.sent_command = cmdptr - SCpnt->cmnd;    host->scsi.phase = PHASE_COMMAND;}staticvoid acornscsi_sendmessage (AS_Host *host){    unsigned int message_length = msgqueue_msglength (&host->scsi.msgs);    int msglen;    char *msg;#if (DEBUG & DEBUG_MESSAGES)	printk ("scsi%d.%c: sending message ",		host->host->host_no, acornscsi_target (host));#endif    switch (message_length) {    case 0:	sbic_arm_write (host->scsi.io_port, CMND, CMND_XFERINFO | CMND_SBT);	while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);	sbic_arm_write (host->scsi.io_port, DATA, NOP);	host->scsi.last_message = NOP;#if (DEBUG & DEBUG_MESSAGES)	printk ("NOP");#endif	break;    case 1:	sbic_arm_write (host->scsi.io_port, CMND, CMND_XFERINFO | CMND_SBT);	msg = msgqueue_getnextmsg (&host->scsi.msgs, &msglen);	while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);	sbic_arm_write (host->scsi.io_port, DATA, msg[0]);	host->scsi.last_message = msg[0];#if (DEBUG & DEBUG_MESSAGES)	print_msg (msg);#endif	break;    default:	/*	 * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14)	 * 'When a target sends this (MESSAGE_REJECT) message, it	 *  shall change to MESSAGE IN phase and send this message	 *  prior to requesting additional message bytes from the	 *  initiator.  This provides an interlock so that the	 *  initiator can determine which message byte is rejected.	 */	sbic_arm_write (host->scsi.io_port, TRANSCNTH, 0);	sbic_arm_writenext (host->scsi.io_port, 0);	sbic_arm_writenext (host->scsi.io_port, message_length);	sbic_arm_write (host->scsi.io_port, CMND, CMND_XFERINFO);	while ((msg = msgqueue_getnextmsg (&host->scsi.msgs, &msglen)) != NULL) {	    unsigned int asr, i;#if (DEBUG & DEBUG_MESSAGES)	    print_msg (msg);#endif	    for (i = 0; i < msglen;) {		asr = sbic_arm_read (host->scsi.io_port, ASR);		if (asr & ASR_DBR)		    sbic_arm_write (host->scsi.io_port, DATA, msg[i++]);		if (asr & ASR_INT)		    break;	    }	    host->scsi.last_message = msg[0];	    if (msg[0] == EXTENDED_MESSAGE)		host->scsi.last_message |= msg[2] << 8;	    if (asr & ASR_INT)		break;	}	break;    }#if (DEBUG & DEBUG_MESSAGES)    printk ("\n");#endif}/* * Function: void acornscsi_readstatusbyte (AS_Host *host) * Purpose : Read status byte from connected target * Params  : host - host connected to target */staticvoid acornscsi_readstatusbyte (AS_Host *host){    sbic_arm_write (host->scsi.io_port, CMND, CMND_XFERINFO|CMND_SBT);    while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);    host->scsi.SCp.Status = sbic_arm_read (host->scsi.io_port, DATA);    host->scsi.phase = PHASE_STATUSIN;}/* * Function: unsigned char acornscsi_readmessagebyte (AS_Host *host) * Purpose : Read one message byte from connected target * Params  : host - host connected to target */staticunsigned char acornscsi_readmessagebyte (AS_Host *host){    unsigned char message;    sbic_arm_write (host->scsi.io_port, CMND, CMND_XFERINFO | CMND_SBT);    while ((sbic_arm_read (host->scsi.io_port, ASR) & ASR_DBR) == 0);    message = sbic_arm_read (host->scsi.io_port, DATA);

⌨️ 快捷键说明

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