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

📄 ncr5380.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
     * No less than two deskew delays after the initiator detects the      * BSY signal is true, it shall release the SEL signal and may      * change the DATA BUS.                                     -wingel     */    udelay(1);    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);	if (hostdata->targets_present & (1 << cmd->target)) {	    printk("scsi%d : weirdness\n", instance->host_no);	    if (hostdata->restart_select)		printk("\trestart select\n");#ifdef NDEBUG	    NCR5380_print (instance);#endif	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);	    return -1;	}	cmd->result = DID_BAD_TARGET << 16;#ifdef NCR5380_STATS	collect_stats(hostdata, cmd);#endif	cmd->scsi_done(cmd);	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);#if (NDEBUG & NDEBUG_SELECTION)	printk("scsi%d : target did not respond within 250ms\n", 	    instance->host_no);#endif	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);	return 0;    }     hostdata->targets_present |= (1 << cmd->target);    /*     * Since we followed the SCSI spec, and raised ATN while SEL      * was true but before BSY was false during selection, the information     * transfer phase should be a MESSAGE OUT phase so that we can send the     * IDENTIFY message.     *      * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG     * message (2 bytes) with a tag ID that we increment with every command     * until it wraps back to 0.     *     * XXX - it turns out that there are some broken SCSI-II devices,     *	     which claim to support tagged queuing but fail when more than     *	     some number of commands are issued at once.     */    /* Wait for start of REQ/ACK handshake */#ifdef NCR_TIMEOUT    {      unsigned long timeout = jiffies + NCR_TIMEOUT;       while (!(NCR5380_read(STATUS_REG) & SR_REQ) && jiffies < timeout);      if (jiffies >= timeout) {        printk("scsi%d: timeout at NCR5380.c:%d\n", __LINE__);        NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);        return -1;      }    }#else /* NCR_TIMEOUT */    while (!(NCR5380_read(STATUS_REG) & SR_REQ));#endif /* def NCR_TIMEOUT */#if (NDEBUG & NDEBUG_SELECTION)    printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n",	instance->host_no, cmd->target);#endif    tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun);#ifdef SCSI2    if (cmd->device->tagged_queue && (tag != TAG_NONE)) {	tmp[1] = SIMPLE_QUEUE_TAG;	if (tag == TAG_NEXT) {	    /* 0 is TAG_NONE, used to imply no tag for this command */	    if (cmd->device->current_tag == 0)		cmd->device->current_tag = 1;	    cmd->tag = cmd->device->current_tag;	    cmd->device->current_tag++;	} else  	    cmd->tag = (unsigned char) tag;	tmp[2] = cmd->tag;	hostdata->last_message = SIMPLE_QUEUE_TAG;	len = 3;    } else #endif /* def SCSI2 */    {	len = 1;	cmd->tag=0;    }    /* Send message(s) */    data = tmp;    phase = PHASE_MSGOUT;    NCR5380_transfer_pio(instance, &phase, &len, &data);#if (NDEBUG & NDEBUG_SELECTION)    printk("scsi%d : nexus established.\n", instance->host_no);#endif    /* XXX need to handle errors here */    hostdata->connected = cmd;#ifdef SCSI2    if (!cmd->device->tagged_queue)#endif    	hostdata->busy[cmd->target] |= (1 << cmd->lun);    initialize_SCp(cmd);    return 0;}/*  * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,  *      unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using polled I/O * * Inputs : instance - instance of driver, *phase - pointer to  *	what phase is expected, *count - pointer to number of  *	bytes to transfer, **data - pointer to data pointer. *  * Returns : -1 when different phase is entered without transferring *	maximum number of bytes, 0 if all bytes or transfered or exit *	is in same phase. * * 	Also, *phase, *count, *data are modified in place. * * XXX Note : handling for bus free may be useful. *//* * Note : this code is not as quick as it could be, however it  * IS 100% reliable, and for the actual data transfer where speed * counts, we will always do a pseudo DMA or DMA transfer. */static int NCR5380_transfer_pio (struct Scsi_Host *instance, 	unsigned char *phase, int *count, unsigned char **data) {    NCR5380_local_declare();    register unsigned char p = *phase, tmp;    register int c = *count;    register unsigned char *d = *data;    NCR5380_setup(instance);#if (NDEBUG & NDEBUG_PIO)    if (!(p & SR_IO))      printk("scsi%d : pio write %d bytes\n", instance->host_no, c);    else      printk("scsi%d : pio read %d bytes\n", instance->host_no, c);#endif    /*      * The NCR5380 chip will only drive the SCSI bus when the      * phase specified in the appropriate bits of the TARGET COMMAND     * REGISTER match the STATUS REGISTER     */    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));    do {	/* 	 * Wait for assertion of REQ, after which the phase bits will be 	 * valid 	 */	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));#if (NDEBUG & NDEBUG_HANDSHAKE)	printk("scsi%d : REQ detected\n", instance->host_no);#endif	/* Check for phase mismatch */		if ((tmp & PHASE_MASK) != p) {#if (NDEBUG & NDEBUG_PIO)	    printk("scsi%d : phase mismatch\n", instance->host_no);	    NCR5380_print_phase(instance);#endif	    break;	}	/* Do actual transfer from SCSI bus to / from memory */	if (!(p & SR_IO)) 	    NCR5380_write(OUTPUT_DATA_REG, *d);	else 	    *d = NCR5380_read(CURRENT_SCSI_DATA_REG);	++d;	/* 	 * The SCSI standard suggests that in MSGOUT phase, the initiator	 * should drop ATN on the last byte of the message phase	 * after REQ has been asserted for the handshake but before	 * the initiator raises ACK.	 */	if (!(p & SR_IO)) {	    if (!((p & SR_MSG) && c > 1)) {		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 		    ICR_ASSERT_DATA);#if (NDEBUG & NDEBUG_PIO)	NCR5380_print(instance);#endif		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 			ICR_ASSERT_DATA | ICR_ASSERT_ACK);	    } else {		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);#if (NDEBUG & NDEBUG_PIO)	NCR5380_print(instance);#endif		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);	    }	} else {#if (NDEBUG & NDEBUG_PIO)	NCR5380_print(instance);#endif	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);	}	while (NCR5380_read(STATUS_REG) & SR_REQ);#if (NDEBUG & NDEBUG_HANDSHAKE)	    printk("scsi%d : req false, handshake complete\n", instance->host_no);#endif/* * We have several special cases to consider during REQ/ACK handshaking :  * 1.  We were in MSGOUT phase, and we are on the last byte of the  *	message.  ATN must be dropped as ACK is dropped. * * 2.  We are in a MSGIN phase, and we are on the last byte of the   *	message.  We must exit with ACK asserted, so that the calling *	code may raise ATN before dropping ACK to reject the message. * * 3.  ACK and ATN are clear and the target may proceed as normal. */	if (!(p == PHASE_MSGIN && c == 1)) {  	    if (p == PHASE_MSGOUT && c > 1)		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);	    else		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);	}     } while (--c);#if (NDEBUG & NDEBUG_PIO)     printk("scsi%d : residual %d\n", instance->host_no, c);#endif    *count = c;    *data = d;    tmp = NCR5380_read(STATUS_REG);    if (tmp & SR_REQ)	*phase = tmp & PHASE_MASK;    else 	*phase = PHASE_UNKNOWN;    if (!c || (*phase == p))	return 0;    else 	return -1;}static void do_reset (struct Scsi_Host *host) {    NCR5380_local_declare();    NCR5380_setup(host);    cli();    NCR5380_write(TARGET_COMMAND_REG, 	PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);    udelay(25);    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);    sti();}/* * Function : do_abort (Scsi_Host *host) *  * Purpose : abort the currently established nexus.  Should only be  * 	called from a routine which can drop into a  *  * Returns : 0 on success, -1 on failure. */static int do_abort (struct Scsi_Host *host) {    NCR5380_local_declare();    unsigned char tmp, *msgptr, phase;    int len;    NCR5380_setup(host);    /* Request message out phase */    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);    /*      * Wait for the target to indicate a valid phase by asserting      * REQ.  Once this happens, we'll have either a MSGOUT phase      * and can immediately send the ABORT message, or we'll have some      * other phase and will have to source/sink data.     *      * We really don't care what value was on the bus or what value     * the target sees, so we just handshake.     */        while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));    if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 	    ICR_ASSERT_ACK);	while (NCR5380_read(STATUS_REG) & SR_REQ);	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);    }       tmp = ABORT;    msgptr = &tmp;    len = 1;    phase = PHASE_MSGOUT;    NCR5380_transfer_pio (host, &phase, &len, &msgptr);    /*     * If we got here, and the command completed successfully,     * we're about to go into bus free state.     */    return len ? -1 : 0;}#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)/*  * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,  *      unsigned char *phase, int *count, unsigned char **data) * * Purpose : transfers data in given phase using either real *	or pseudo DMA. * * Inputs : instance - instance of driver, *phase - pointer to  *	what phase is expected, *count - pointer to number of  *	bytes to transfer, **data - pointer to data pointer. *  * Returns : -1 when different phase is entered without transferring *	maximum number of bytes, 0 if all bytes or transfered or exit *	is in same phase. * * 	Also, *phase, *count, *data are modified in place. * */static int NCR5380_transfer_dma (struct Scsi_Host *instance,     unsigned char *phase, int *count, unsigned char **data) {    NCR5380_local_declare();    register int c = *count;    register unsigned char p = *phase;    register unsigned char *d = *data;    unsigned char tmp;    int foo;#if defined(REAL_DMA_POLL)    int cnt, toPIO;    unsigned char saved_data = 0, overrun = 0, residue;#endif    struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) 	instance->hostdata;    NCR5380_setup(instance);    if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {	*phase = tmp;	return -1;    }#if defined(REAL_DMA) || defined(REAL_DMA_POLL) #ifdef READ_OVERRUNS     if (p & SR_IO) {       c -= 2;     }#endif#if (NDEBUG & NDEBUG_DMA)    printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n",	instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" :	"writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);#endif    hostdata->dma_len = (p & SR_IO) ?	NCR5380_dma_read_setup(instance, d, c) : 	NCR5380_dma_write_setup(instance, d, c);#endif    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));#ifdef REAL_DMA    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);#elif defined(REAL_DMA_POLL)    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);#else    /*     * Note : on my sample board, watch-dog timeouts occurred when interrupts     * were not disabled for the duration of a single DMA transfer, from      * before the setting of DMA mode to after transfer of the last byte.     */#if defined(PSEUDO_DMA) && !defined(UNSAFE)    cli();#endif    /* KLL May need eop and parity in 53c400 */    if (hostdata->flags & FLAG_NCR53C400)	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK	| MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE	| MR_MONITOR_BSY);    else	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);#endif /* def REAL_DMA */#if (NDEBUG & 

⌨️ 快捷键说明

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