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

📄 ncr5380.c

📁 LINUX 1.0 内核c源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif

    /* 
     * The SCSI specification calls for a 250 ms timeout for the actual 
     * selection.
     */

    timeout = jiffies + 25; 

    /* 
     * XXX very interesting - we're seeing a bounce where the BSY we 
     * asserted is being reflected / still asserted (propogation delay?)
     * and it's detecting as true.  Sigh.
     */

    while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));

    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);

    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
	cmd->result = DID_BAD_TARGET << 16;
	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
	return 0;
    } 

    /*
     * 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 queing 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 queing but fail when more than
     *	     some number of commands are issued at once.
     */

    /* Wait for start of REQ/ACK handshake */
    while (!(NCR5380_read(STATUS_REG) & SR_REQ));

#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 (scsi_devices[cmd->index].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 (scsi_devices[cmd->index].current_tag == 0)
		scsi_devices[cmd->index].current_tag = 1;

	    cmd->tag = scsi_devices[cmd->index].current_tag;
	    scsi_devices[cmd->index].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 (!scsi_devices[cmd->index].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 enterred without transfering
 *	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);

    /* 
     * 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

	if (!(p == PHASE_MSGOUT && c > 1))
	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
	else
	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
    } 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;
}

#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 enterred without transfering
 *	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 occured 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
    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
#endif /* def REAL_DMA */

#if (NDEBUG & NDEBUG_DMA) & 0
    printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG));
#endif

    if (p & SR_IO)
	NCR5380_write(START_DMA_INITIATOR_RECIEVE_REG, 0);
    else {
	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
	NCR5380_write(START_DMA_SEND_REG, 0);
    }

#if defined(REAL_DMA_POLL)
    do {
	tmp = NCR5380_read(BUS_AND_STATUS_REG);
    } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | 
	BASR_END_DMA_TRANSFER)));

/*
  At this point, either we've completed DMA, or we have a phase mismatch,
  or we've unexpectedly lost BUSY (which is a real error).

  For write DMAs, we want to wait until the last byte has been
  transferred out over the bus before we turn off DMA mode.  Alas, there
  seems to be no terribly good way of doing this on a 5380 under all
  conditions.  For non-scatter-gather operations, we can wait until REQ
  and ACK both go false, or until a phase mismatch occurs.  Gather-writes
  are nastier, since the device will be expecting more data than we
  are prepared to send it, and REQ will remain asserted.  On a 53C8[01] we
  could test LAST BIT SENT to assure transfer (I imagine this is precisely
  why this signal was added to the newer chips) but on the older 538[01]
  this signal does not exist.  The workaround for this lack is a watchdog;
  we bail out of the wait-loop after a modest amount of wait-time if
  the usual exit conditions are not met.  Not a terribly clean or
  correct solution :-%

  Reads are equally tricky due to a nasty characteristic of the NCR5380.
  If the chip is in DMA mode for an READ, it will respond to a target's
  REQ by latching the SCSI data into the INPUT DATA register and asserting
  ACK, even if it has _already_ been notified by the DMA controller that
  the current DMA transfer has completed!  If the NCR5380 is then taken
  out of DMA mode, this already-acknowledged byte is lost.

  This is not a problem for "one DMA transfer per command" reads, because
  the situation will never arise... either all of the data is DMA'ed
  properly, or the target switches to MESSAGE IN phase to signal a
  disconnection (either operation bringing the DMA to a clean halt).
  However, in order to handle scatter-reads, we must work around the
  problem.  The chosen fix is to DMA N-2 bytes, then check for the
  condition before taking the NCR5380 out of DMA mode.  One or two extra
  bytes are tranferred via PIO as necessary to fill out the original
  request.
*/

    if (p & SR_IO) {
#ifdef READ_OVERRUNS
      udelay(10);
      if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) ==
           (BASR_PHASE_MATCH | BASR_ACK))) {
        saved_data = NCR5380_read(INPUT_DATA_REGISTER);
        overrun = 1;
      }
#endif
    } else {
      int limit = 100;
      while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) ||
            (NCR5380_read(STATUS_REG) & SR_REQ)) {
        if (!(tmp & BASR_PHASE_MATCH)) break;
        if (--limit < 0) break;
      }
    }


#if (NDEBUG & NDEBUG_DMA)
    printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n",
	   instance->host_no, tmp, NCR5380_read(STATUS_REG));
#endif

    NCR5380_write(MODE_REG, MR_BASE);
    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);

    residue = NCR5380_dma_residual(instance);
    c -= residue;
    *count -= c;
    *data += c;
    *phase = NCR5380_read(STATUS_REG) & PHASE_MASK;

#ifdef READ_OVERRUNS
    if (*phase == p && (p & SR_IO) && residue == 0) {
      if (overrun) {
#if (NDEBUG & NDEBUG_DMA)
        printk("Got an input overrun, using saved byte\n");
#endif
        **data = saved_data;
        *data += 1;
        *count -= 1;
        cnt = toPIO = 1;

⌨️ 快捷键说明

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