Beispiel #1
0
int
ata_wait(struct ata_device *atadev, u_int8_t mask)
{
    int timeout = 0;
    
    DELAY(1);
    while (timeout < 5000000) { /* timeout 5 secs */
	atadev->channel->status = ATA_INB(atadev->channel->r_io, ATA_STATUS);

	/* if drive fails status, reselect the drive just to be sure */
	if (atadev->channel->status == 0xff) {
	    ata_prtdev(atadev, "no status, reselecting device\n");
	    ATA_OUTB(atadev->channel->r_io, ATA_DRIVE, ATA_D_IBM|atadev->unit);
	    DELAY(10);
	    atadev->channel->status = ATA_INB(atadev->channel->r_io,ATA_STATUS);
	    if (atadev->channel->status == 0xff)
		return -1;
	}

	/* are we done ? */
	if (!(atadev->channel->status & ATA_S_BUSY))
	    break;	      

	if (timeout > 1000) {
	    timeout += 1000;
	    DELAY(1000);
	}
	else {
	    timeout += 10;
	    DELAY(10);
	}
    }	 
    if (atadev->channel->status & ATA_S_ERROR)
	atadev->channel->error = ATA_INB(atadev->channel->r_io, ATA_ERROR);
    if (timeout >= 5000000)	 
	return -1;	    
    if (!mask)	   
	return (atadev->channel->status & ATA_S_ERROR);	 
    
    /* Wait 50 msec for bits wanted. */	   
    timeout = 5000;
    while (timeout--) {	  
	atadev->channel->status = ATA_INB(atadev->channel->r_io, ATA_STATUS);
	if ((atadev->channel->status & mask) == mask) {
	    if (atadev->channel->status & ATA_S_ERROR)
		atadev->channel->error=ATA_INB(atadev->channel->r_io,ATA_ERROR);
	    return (atadev->channel->status & ATA_S_ERROR);	      
	}
	DELAY (10);	   
    }	  
    return -1;	    
}   
Beispiel #2
0
static int 
ata_nvidia_status(device_t dev)
{
    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
    struct ata_channel *ch = device_get_softc(dev);
    int offset = ctlr->chip->cfg1 & NV4 ? 0x0440 : 0x0010;
    int shift = ch->unit << (ctlr->chip->cfg1 & NVQ ? 4 : 2);
    u_int32_t istatus;

    /* get interrupt status */
    if (ctlr->chip->cfg1 & NVQ)
	istatus = ATA_INL(ctlr->r_res2, offset);
    else
	istatus = ATA_INB(ctlr->r_res2, offset);

    /* do we have any PHY events ? */
    if (istatus & (0x0c << shift))
	ata_sata_phy_check_events(dev, -1);

    /* clear interrupt(s) */
    if (ctlr->chip->cfg1 & NVQ)
	ATA_OUTL(ctlr->r_res2, offset, (0x0f << shift) | 0x00f000f0);
    else
	ATA_OUTB(ctlr->r_res2, offset, (0x0f << shift));

    /* do we have any device action ? */
    return (istatus & (0x01 << shift));
}
Beispiel #3
0
static int
ata_service(struct ata_channel *ch)
{
    /* do we have a SERVICE request from the drive ? */
    if ((ch->status & (ATA_S_SERVICE|ATA_S_ERROR|ATA_S_DRQ)) == ATA_S_SERVICE) {
	ATA_OUTB(ch->r_bmio, ATA_BMSTAT_PORT,
		 ata_dmastatus(ch) | ATA_BMSTAT_INTERRUPT);
#if NATADISK > 0
	if ((ATA_INB(ch->r_io, ATA_DRIVE) & ATA_SLAVE) == ATA_MASTER) {
	    if ((ch->devices & ATA_ATA_MASTER) && ch->device[MASTER].driver)
		return ad_service((struct ad_softc *)
				  ch->device[MASTER].driver, 0);
	}
	else {
	    if ((ch->devices & ATA_ATA_SLAVE) && ch->device[SLAVE].driver)
		return ad_service((struct ad_softc *)
				  ch->device[SLAVE].driver, 0);
	}
#endif
    }
    return ATA_OP_FINISHED;
}
Beispiel #4
0
void
ata_reset(struct ata_channel *ch)
{
    u_int8_t lsb, msb, ostat0, ostat1;
    u_int8_t stat0 = 0, stat1 = 0;
    int mask = 0, timeout;

    /* do we have any signs of ATA/ATAPI HW being present ? */
    ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
    DELAY(10);
    ostat0 = ATA_INB(ch->r_io, ATA_STATUS);
    if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
	stat0 = ATA_S_BUSY;
	mask |= 0x01;
    }
    ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
    DELAY(10);	
    ostat1 = ATA_INB(ch->r_io, ATA_STATUS);
    if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
	stat1 = ATA_S_BUSY;
	mask |= 0x02;
    }

    ch->devices = 0;
    if (!mask)
	return;

    /* in some setups we dont want to test for a slave */
    if (ch->flags & ATA_NO_SLAVE) {
	stat1 = 0x0;
	mask &= ~0x02;
    }

    if (bootverbose)
	ata_printf(ch, -1, "mask=%02x ostat0=%02x ostat2=%02x\n",
		   mask, ostat0, ostat1);

    /* reset channel */
    ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
    DELAY(10);
    ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
    DELAY(10000); 
    ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_IDS);
    DELAY(100000);
    ATA_INB(ch->r_io, ATA_ERROR);

    /* wait for BUSY to go inactive */
    for (timeout = 0; timeout < 310000; timeout++) {
	if (stat0 & ATA_S_BUSY) {
	    ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
	    DELAY(10);

	    /* check for ATAPI signature while its still there */
	    lsb = ATA_INB(ch->r_io, ATA_CYL_LSB);
	    msb = ATA_INB(ch->r_io, ATA_CYL_MSB);
	    stat0 = ATA_INB(ch->r_io, ATA_STATUS);
	    if (!(stat0 & ATA_S_BUSY)) {
		if (bootverbose)
		    ata_printf(ch, ATA_MASTER, "ATAPI %02x %02x\n", lsb, msb);
		if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
		    ch->devices |= ATA_ATAPI_MASTER;
	    }
	}
	if (stat1 & ATA_S_BUSY) {
	    ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
	    DELAY(10);

	    /* check for ATAPI signature while its still there */
	    lsb = ATA_INB(ch->r_io, ATA_CYL_LSB);
	    msb = ATA_INB(ch->r_io, ATA_CYL_MSB);
	    stat1 = ATA_INB(ch->r_io, ATA_STATUS);
	    if (!(stat1 & ATA_S_BUSY)) {
		if (bootverbose)
		    ata_printf(ch, ATA_SLAVE, "ATAPI %02x %02x\n", lsb, msb);
		if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
		    ch->devices |= ATA_ATAPI_SLAVE;
	    }
	}
	if (mask == 0x01)      /* wait for master only */
	    if (!(stat0 & ATA_S_BUSY))
		break;
	if (mask == 0x02)      /* wait for slave only */
	    if (!(stat1 & ATA_S_BUSY))
		break;
	if (mask == 0x03)      /* wait for both master & slave */
	    if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
		break;
	DELAY(100);
    }	
    DELAY(10);
    ATA_OUTB(ch->r_altio, ATA_ALTSTAT, ATA_A_4BIT);

    if (stat0 & ATA_S_BUSY)
	mask &= ~0x01;
    if (stat1 & ATA_S_BUSY)
	mask &= ~0x02;
    if (bootverbose)
	ata_printf(ch, -1, "mask=%02x stat0=%02x stat1=%02x\n", 
		   mask, stat0, stat1);
    if (!mask)
	return;

    if (mask & 0x01 && ostat0 != 0x00 && !(ch->devices & ATA_ATAPI_MASTER)) {
	ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
	DELAY(10);
	ATA_OUTB(ch->r_io, ATA_ERROR, 0x58);
	ATA_OUTB(ch->r_io, ATA_CYL_LSB, 0xa5);
	lsb = ATA_INB(ch->r_io, ATA_ERROR);
	msb = ATA_INB(ch->r_io, ATA_CYL_LSB);
	if (bootverbose)
	    ata_printf(ch, ATA_MASTER, "ATA %02x %02x\n", lsb, msb);
	if (lsb != 0x58 && msb == 0xa5)
	    ch->devices |= ATA_ATA_MASTER;
    }
    if (mask & 0x02 && ostat1 != 0x00 && !(ch->devices & ATA_ATAPI_SLAVE)) {
	ATA_OUTB(ch->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
	DELAY(10);
	ATA_OUTB(ch->r_io, ATA_ERROR, 0x58);
	ATA_OUTB(ch->r_io, ATA_CYL_LSB, 0xa5);
	lsb = ATA_INB(ch->r_io, ATA_ERROR);
	msb = ATA_INB(ch->r_io, ATA_CYL_LSB);
	if (bootverbose)
	    ata_printf(ch, ATA_SLAVE, "ATA %02x %02x\n", lsb, msb);
	if (lsb != 0x58 && msb == 0xa5)
	    ch->devices |= ATA_ATA_SLAVE;
    }
    if (bootverbose)
	ata_printf(ch, -1, "devices=%02x\n", ch->devices);
}
Beispiel #5
0
static void
ata_intr(void *data)
{
    struct ata_channel *ch = (struct ata_channel *)data;
    /* 
     * on PCI systems we might share an interrupt line with another
     * device or our twin ATA channel, so call ch->intr_func to figure 
     * out if it is really an interrupt we should process here
     */
    if (ch->intr_func && ch->intr_func(ch))
	return;

    /* if drive is busy it didn't interrupt */
    if (ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_BUSY) {
	DELAY(100);
	if (!(ATA_INB(ch->r_altio, ATA_ALTSTAT) & ATA_S_DRQ))
	    return;
    }

    /* clear interrupt and get status */
    ch->status = ATA_INB(ch->r_io, ATA_STATUS);

    if (ch->status & ATA_S_ERROR)
	ch->error = ATA_INB(ch->r_io, ATA_ERROR);

    /* find & call the responsible driver to process this interrupt */
    switch (ch->active) {
#if NATADISK > 0
    case ATA_ACTIVE_ATA:
	if (!ch->running || ad_interrupt(ch->running) == ATA_OP_CONTINUES)
	    return;
	break;
#endif
#if DEV_ATAPIALL
    case ATA_ACTIVE_ATAPI:
	if (!ch->running || atapi_interrupt(ch->running) == ATA_OP_CONTINUES)
	    return;
	break;
#endif
    case ATA_WAIT_INTR:
    case ATA_WAIT_INTR | ATA_CONTROL:
	wakeup((caddr_t)ch);
	break;

    case ATA_WAIT_READY:
    case ATA_WAIT_READY | ATA_CONTROL:
	break;

    case ATA_IDLE:
	if (ch->flags & ATA_QUEUED) {
	    ch->active = ATA_ACTIVE;
	    if (ata_service(ch) == ATA_OP_CONTINUES)
		return;
	}
	/* FALLTHROUGH */

    default:
#ifdef ATA_DEBUG
    {
	static int intr_count = 0;

	if (intr_count++ < 10)
	    ata_printf(ch, -1, "unwanted interrupt #%d active=%02x s=%02x\n",
		       intr_count, ch->active, ch->status);
    }
#endif
	break;
    }
    ch->active &= ATA_CONTROL;
    if (ch->active & ATA_CONTROL)
	return;
    ch->running = NULL;
    ata_start(ch);
    return;
}