Ejemplo n.º 1
0
static u_int32_t
ata_siiprb_softreset(device_t dev, int port)
{
    struct ata_pci_controller *ctlr = device_get_softc(device_get_parent(dev));
    struct ata_channel *ch = device_get_softc(dev);
    struct ata_siiprb_command *prb = (struct ata_siiprb_command *)ch->dma.work;
    u_int32_t signature;
    int offset = ch->unit * 0x2000;

    /* setup the workspace for a soft reset command */
    bzero(prb, sizeof(struct ata_siiprb_command));
    prb->control = htole16(0x0080);
    prb->fis[1] = port & 0x0f;

    /* issue soft reset */
    if (ata_siiprb_issue_cmd(dev))
	return -1;

    ata_udelay(150000);

    /* get possible signature */
    prb = (struct ata_siiprb_command *)
	((u_int8_t *)rman_get_virtual(ctlr->r_res2) + offset);
    signature=prb->fis[12]|(prb->fis[4]<<8)|(prb->fis[5]<<16)|(prb->fis[6]<<24);

    /* clear error bits/interrupt */
    ATA_IDX_OUTL(ch, ATA_SERROR, 0xffffffff);

    return signature;
}
Ejemplo n.º 2
0
int
ata_sata_phy_reset(device_t dev, int port, int quick)
{
    struct ata_channel *ch = device_get_softc(dev);
    int loop, retry;
    uint32_t val;

    if (quick) {
	if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
	    return (0);
	if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE)
	    return ata_sata_connect(ch, port);
    }

    if (bootverbose) {
	if (port < 0) {
	    device_printf(dev, "hardware reset ...\n");
	} else {
	    device_printf(dev, "p%d: hardware reset ...\n", port);
	}
    }
    for (retry = 0; retry < 10; retry++) {
	for (loop = 0; loop < 10; loop++) {
	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET))
		return (0);
	    ata_udelay(100);
	    if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
		return (0);
	    if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_RESET)
		break;
	}
	ata_udelay(5000);
	for (loop = 0; loop < 10; loop++) {
	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL,
		    ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 :
		    ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)))
		return (0);
	    ata_udelay(100);
	    if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
		return (0);
	    if ((val & ATA_SC_DET_MASK) == 0)
		return ata_sata_connect(ch, port);
	}
    }
    return 0;
}
Ejemplo n.º 3
0
static int
ata_sata_connect(struct ata_channel *ch, int port, int quick)
{
    u_int32_t status;
    int timeout, t;

    /* wait up to 1 second for "connect well" */
    timeout = (quick == 2) ? 0 : 100;
    t = 0;
    while (1) {
	if (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status))
	    return (0);
	if (((status & ATA_SS_DET_MASK) == ATA_SS_DET_PHY_ONLINE) &&
	    ((status & ATA_SS_SPD_MASK) != ATA_SS_SPD_NO_SPEED) &&
	    ((status & ATA_SS_IPM_MASK) == ATA_SS_IPM_ACTIVE))
	    break;
	if (++t > timeout)
	    break;
	ata_udelay(10000);
    }
    if (bootverbose) {
	if (t > timeout) {
	    if (port < 0) {
		device_printf(ch->dev, "SATA connect timeout status=%08x\n",
		    status);
	    } else {
		device_printf(ch->dev, "p%d: SATA connect timeout status=%08x\n",
		    port, status);
	    }
	} else if (port < 0) {
	    device_printf(ch->dev, "SATA connect time=%dms status=%08x\n",
		t * 10, status);
	} else {
	    device_printf(ch->dev, "p%d: SATA connect time=%dms status=%08x\n",
		port, t * 10, status);
	}
    }

    /* clear SATA error register */
    ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff);

    return ((t > timeout) ? 0 : 1);
}
Ejemplo n.º 4
0
static int
ata_sata_connect(struct ata_channel *ch, int port)
{
    u_int32_t status;
    int timeout;

    /* wait up to 1 second for "connect well" */
    for (timeout = 0; timeout < 100 ; timeout++) {
	if (ata_sata_scr_read(ch, port, ATA_SSTATUS, &status))
	    return (0);
	if ((status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN1 ||
	    (status & ATA_SS_CONWELL_MASK) == ATA_SS_CONWELL_GEN2)
	    break;
	ata_udelay(10000);
    }
    if (timeout >= 100) {
	if (bootverbose) {
	    if (port < 0) {
		device_printf(ch->dev, "SATA connect timeout status=%08x\n",
		    status);
	    } else {
		device_printf(ch->dev, "p%d: SATA connect timeout status=%08x\n",
		    port, status);
	    }
	}
	return 0;
    }
    if (bootverbose) {
	if (port < 0) {
	    device_printf(ch->dev, "SATA connect time=%dms status=%08x\n",
		timeout * 10, status);
	} else {
	    device_printf(ch->dev, "p%d: SATA connect time=%dms status=%08x\n",
		port, timeout * 10, status);
	}
    }

    /* clear SATA error register */
    ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff);

    return 1;
}
Ejemplo n.º 5
0
/* must be called with ATA channel locked and state_mtx held */
void
ata_generic_reset(device_t dev)
{
    struct ata_channel *ch = device_get_softc(dev);

    u_int8_t ostat0 = 0, stat0 = 0, ostat1 = 0, stat1 = 0;
    u_int8_t err = 0, lsb = 0, msb = 0;
    int mask = 0, timeout;

    /* do we have any signs of ATA/ATAPI HW being present ? */
    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER));
    DELAY(10);
    ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
    if (((ostat0 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) &&
	    ostat0 != 0xa5) {
	stat0 = ATA_S_BUSY;
	mask |= 0x01;
    }

    /* in some setups we dont want to test for a slave */
    if (!(ch->flags & ATA_NO_SLAVE)) {
	ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_SLAVE));
	DELAY(10);      
	ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
	if (((ostat1 & 0xf8) != 0xf8 || (ch->flags & ATA_KNOWN_PRESENCE)) &&
		ostat1 != 0xa5) {
	    stat1 = ATA_S_BUSY;
	    mask |= 0x02;
	}
    }

    if (bootverbose)
	device_printf(dev, "reset tp1 mask=%02x ostat0=%02x ostat1=%02x\n",
		      mask, ostat0, ostat1);

    /* if nothing showed up there is no need to get any further */
    /* XXX SOS is that too strong?, we just might loose devices here */
    ch->devices = 0;
    if (!mask)
	return;

    /* reset (both) devices on this channel */
    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_D_LBA | ATA_DEV(ATA_MASTER));
    DELAY(10);
    ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS | ATA_A_RESET);
    ata_udelay(10000); 
    ATA_IDX_OUTB(ch, ATA_CONTROL, ATA_A_IDS);
    ata_udelay(100000);
    ATA_IDX_INB(ch, ATA_ERROR);

    /* wait for BUSY to go inactive */
    for (timeout = 0; timeout < 310; timeout++) {
	if ((mask & 0x01) && (stat0 & ATA_S_BUSY)) {
	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_MASTER));
	    DELAY(10);
	    if (ch->flags & ATA_STATUS_IS_LONG)
		    stat0 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff;
	    else
		    stat0 = ATA_IDX_INB(ch, ATA_STATUS);
	    err = ATA_IDX_INB(ch, ATA_ERROR);
	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
	    if (bootverbose)
		device_printf(dev,
			      "stat0=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
			      stat0, err, lsb, msb);
	    if (stat0 == err && lsb == err && msb == err &&
		timeout > (stat0 & ATA_S_BUSY ? 100 : 10))
		mask &= ~0x01;
	    if (!(stat0 & ATA_S_BUSY)) {
		if ((err & 0x7f) == ATA_E_ILI) {
		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
			ch->devices |= ATA_ATAPI_MASTER;
		    }
		    else if (lsb == 0 && msb == 0 && (stat0 & ATA_S_READY)) {
			ch->devices |= ATA_ATA_MASTER;
		    }
		}
		else if ((stat0 & 0x0f) && err == lsb && err == msb) {
		    stat0 |= ATA_S_BUSY;
		}
	    }
	}

	if ((mask & 0x02) && (stat1 & ATA_S_BUSY) &&
	    !((mask & 0x01) && (stat0 & ATA_S_BUSY))) {
	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_DEV(ATA_SLAVE));
	    DELAY(10);
	    if (ch->flags & ATA_STATUS_IS_LONG)
		    stat1 = ATA_IDX_INL(ch, ATA_STATUS) & 0xff;
	    else
		    stat1 = ATA_IDX_INB(ch, ATA_STATUS);
	    err = ATA_IDX_INB(ch, ATA_ERROR);
	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
	    if (bootverbose)
		device_printf(dev,
			      "stat1=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
			      stat1, err, lsb, msb);
	    if (stat1 == err && lsb == err && msb == err &&
		timeout > (stat1 & ATA_S_BUSY ? 100 : 10))
		mask &= ~0x02;
	    if (!(stat1 & ATA_S_BUSY)) {
		if ((err & 0x7f) == ATA_E_ILI) {
		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
			ch->devices |= ATA_ATAPI_SLAVE;
		    }
		    else if (lsb == 0 && msb == 0 && (stat1 & ATA_S_READY)) {
			ch->devices |= ATA_ATA_SLAVE;
		    }
		}
		else if ((stat1 & 0x0f) && err == lsb && err == msb) {
		    stat1 |= ATA_S_BUSY;
		}
	    }
	}

	if ((ch->flags & ATA_KNOWN_PRESENCE) == 0 &&
	    timeout > ((mask == 0x03) ? 20 : 10)) {
		if ((mask & 0x01) && stat0 == 0xff)
			mask &= ~0x01;
		if ((mask & 0x02) && stat1 == 0xff)
			mask &= ~0x02;
	}
	if (((mask & 0x01) == 0 || !(stat0 & ATA_S_BUSY)) &&
	    ((mask & 0x02) == 0 || !(stat1 & ATA_S_BUSY)))
		break;
	ata_udelay(100000);
    }

    if (bootverbose)
	device_printf(dev, "reset tp2 stat0=%02x stat1=%02x devices=0x%x\n",
		      stat0, stat1, ch->devices);
}
Ejemplo n.º 6
0
int
ata_sata_phy_reset(device_t dev, int port, int quick)
{
    struct ata_channel *ch = device_get_softc(dev);
    int loop, retry, sata_rev;
    uint32_t val, val1;

#ifdef ATA_CAM
    sata_rev = ch->user[port < 0 ? 0 : port].revision;
    if (sata_rev > 0)
	quick = 0;
#else
    sata_rev = 0;
#endif

    if (quick) {
	if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
	    return (0);
	if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_IDLE) {
	    ata_sata_scr_write(ch, port, ATA_SCONTROL,
		ATA_SC_DET_IDLE | ((ch->pm_level > 0) ? 0 :
		ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER));
	    return ata_sata_connect(ch, port, quick);
	}
    }

    if (bootverbose) {
	if (port < 0) {
	    device_printf(dev, "hard reset ...\n");
	} else {
	    device_printf(dev, "p%d: hard reset ...\n", port);
	}
    }
    if (sata_rev == 1)
	val1 = ATA_SC_SPD_SPEED_GEN1;
    else if (sata_rev == 2)
	val1 = ATA_SC_SPD_SPEED_GEN2;
    else if (sata_rev == 3)
	val1 = ATA_SC_SPD_SPEED_GEN3;
    else
	val1 = 0;
    for (retry = 0; retry < 10; retry++) {
	for (loop = 0; loop < 10; loop++) {
	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL, ATA_SC_DET_RESET |
		    val1 | ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER))
		goto fail;
	    ata_udelay(100);
	    if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
		goto fail;
	    if ((val & ATA_SC_DET_MASK) == ATA_SC_DET_RESET)
		break;
	}
	ata_udelay(5000);
	for (loop = 0; loop < 10; loop++) {
	    if (ata_sata_scr_write(ch, port, ATA_SCONTROL,
		    ATA_SC_DET_IDLE | val1 | ((ch->pm_level > 0) ? 0 :
		    ATA_SC_IPM_DIS_PARTIAL | ATA_SC_IPM_DIS_SLUMBER)))
		goto fail;
	    ata_udelay(100);
	    if (ata_sata_scr_read(ch, port, ATA_SCONTROL, &val))
		goto fail;
	    if ((val & ATA_SC_DET_MASK) == 0)
		return ata_sata_connect(ch, port, 0);
	}
    }
fail:
    /* Clear SATA error register. */
    ata_sata_scr_write(ch, port, ATA_SERROR, 0xffffffff);

    if (bootverbose) {
	if (port < 0) {
	    device_printf(dev, "hard reset failed\n");
	} else {
	    device_printf(dev, "p%d: hard reset failed\n", port);
	}
    }
    return (0);
}
Ejemplo n.º 7
0
/* must be called with ATA channel locked */
static void
ata_generic_reset(struct ata_channel *ch)
{
    u_int8_t err = 0, lsb = 0, msb = 0, ostat0, ostat1;
    u_int8_t stat0 = 0, stat1 = 0;
    int mask = 0, timeout;

    /* if DMA functionality present stop it  */
    if (ch->dma) {
        if (ch->dma->stop)
            ch->dma->stop(ch);
        if (ch->dma->flags & ATA_DMA_LOADED)
            ch->dma->unload(ch);
    }

    /* reset host end of channel (if supported) */
    if (ch->reset)
	ch->reset(ch);

    /* do we have any signs of ATA/ATAPI HW being present ? */
    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
    DELAY(10);
    ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
    if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
	stat0 = ATA_S_BUSY;
	mask |= 0x01;
    }

    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
    DELAY(10);	
    ostat1 = ATA_IDX_INB(ch, ATA_STATUS);

    /* in some setups we dont want to test for a slave */
    if (!(ch->flags & ATA_NO_SLAVE)) {
	if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
	    stat1 = ATA_S_BUSY;
	    mask |= 0x02;
	}
    }

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

    /* if nothing showed up there is no need to get any further */
    /* SOS is that too strong?, we just might loose devices here XXX */
    ch->devices = 0;
    if (!mask)
	return;

    /* reset (both) devices on this channel */
    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
    DELAY(10);
    ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
    ata_udelay(10000); 
    ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS);
    ata_udelay(100000);
    ATA_IDX_INB(ch, ATA_ERROR);

    /* wait for BUSY to go inactive */
    for (timeout = 0; timeout < 310; timeout++) {
	if (stat0 & ATA_S_BUSY) {
	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
	    DELAY(10);
    	    err = ATA_IDX_INB(ch, ATA_ERROR);
	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
	    stat0 = ATA_IDX_INB(ch, ATA_STATUS);
	    if (bootverbose)
		ata_printf(ch, ATA_MASTER,
			   "stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
			   stat0, err, lsb, msb);
	    if (!(stat0 & ATA_S_BUSY)) {
		if ((err & 0x7f) == ATA_E_ILI) {
		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
			ch->devices |= ATA_ATAPI_MASTER;
		    }
		    else if (stat0 & ATA_S_READY) {
			ch->devices |= ATA_ATA_MASTER;
		    }
		}
		else if ((stat0 & 0x4f) && err == lsb && err == msb) {
		    stat0 |= ATA_S_BUSY;
		}
	    }
	}
	if (!((mask == 0x03) && (stat0 & ATA_S_BUSY)) && (stat1 & ATA_S_BUSY)) {
	    ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
	    DELAY(10);
    	    err = ATA_IDX_INB(ch, ATA_ERROR);
	    lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
	    msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
	    stat1 = ATA_IDX_INB(ch, ATA_STATUS);
	    if (bootverbose)
		ata_printf(ch, ATA_SLAVE,
			   " stat=0x%02x err=0x%02x lsb=0x%02x msb=0x%02x\n",
			   stat1, err, lsb, msb);
	    if (!(stat1 & ATA_S_BUSY)) {
		if ((err & 0x7f) == ATA_E_ILI) {
		    if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB) {
			ch->devices |= ATA_ATAPI_SLAVE;
		    }
		    else if (stat1 & ATA_S_READY) {
			ch->devices |= ATA_ATA_SLAVE;
		    }
		}
		else if ((stat1 & 0x4f) && err == lsb && err == msb) {
		    stat1 |= ATA_S_BUSY;
		}
	    }
	}
	if (mask == 0x01)	/* wait for master only */
	    if (!(stat0 & ATA_S_BUSY) || (stat0 == 0xff && timeout > 5) ||
		(stat0 == err && lsb == err && msb == err && timeout > 5))
		break;
	if (mask == 0x02)	/* wait for slave only */
	    if (!(stat1 & ATA_S_BUSY) || (stat1 == 0xff && timeout > 5) ||
		(stat1 == err && lsb == err && msb == err && timeout > 5))
		break;
	if (mask == 0x03) {	/* wait for both master & slave */
	    if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
		break;
	    if ((stat0 == 0xff && timeout > 5) ||
		(stat0 == err && lsb == err && msb == err && timeout > 5))
		mask &= ~0x01;
	    if ((stat1 == 0xff && timeout > 5) ||
		(stat1 == err && lsb == err && msb == err && timeout > 5))
		mask &= ~0x02;
	}
	if (mask == 0 && !(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
	    break;

	ata_udelay(100000);
    }

    if (bootverbose)
	ata_printf(ch, -1,
		   "reset tp2 stat0=%02x stat1=%02x devices=0x%b\n",
		   stat0, stat1, ch->devices,
		   "\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
}