Refine the detach/attach code.

Proberly fail outstanding bio requests on devices that are detached.

This makes it possible to change between disk/cdrom/dvd/whathaveyou
in a notebook, just by suspending it, changing the device in the
bay (or what you model calls it), unsuspend and the ATA driver
will figure out what disappeared and properly fail those, and attach
any new devices found.
This commit is contained in:
sos 2001-03-14 12:05:44 +00:00
parent 045a83cd92
commit 4659caa469
12 changed files with 349 additions and 198 deletions

View File

@ -69,21 +69,25 @@ static struct intr_config_hook *ata_delayed_attach = NULL;
static char ata_conf[256];
static MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer");
/* misc defines */
#define MASTER 0
#define SLAVE 1
int
ata_probe(device_t dev)
{
struct ata_softc *scp = device_get_softc(dev);
struct ata_softc *scp;
int rid;
int mask = 0;
u_int8_t status0, status1;
if (!scp || scp->flags & ATA_ATTACHED)
if (!dev)
return ENXIO;
scp = device_get_softc(dev);
if (!scp || scp->devices)
return ENXIO;
/* initialize the softc basics */
scp->active = ATA_IDLE;
scp->dev = dev;
scp->devices = 0;
rid = ATA_IOADDR_RID;
scp->r_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
@ -107,28 +111,7 @@ ata_probe(device_t dev)
(int)rman_get_start(scp->r_altio),
(scp->r_bmio) ? (int)rman_get_start(scp->r_bmio) : 0);
/* do we have any signs of ATA/ATAPI HW being present ? */
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(1);
status0 = ATA_INB(scp->r_io, ATA_STATUS);
if ((status0 & 0xf8) != 0xf8 && status0 != 0xa5)
mask |= 0x01;
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
DELAY(1);
status1 = ATA_INB(scp->r_io, ATA_STATUS);
if ((status1 & 0xf8) != 0xf8 && status1 != 0xa5)
mask |= 0x02;
if (bootverbose)
ata_printf(scp, -1, "mask=%02x status0=%02x status1=%02x\n",
mask, status0, status1);
if (!mask)
goto failure;
ata_reset(scp, &mask);
if (!mask)
goto failure;
ata_reset(scp);
TAILQ_INIT(&scp->ata_queue);
TAILQ_INIT(&scp->atapi_queue);
@ -149,10 +132,13 @@ ata_probe(device_t dev)
int
ata_attach(device_t dev)
{
struct ata_softc *scp = device_get_softc(dev);
struct ata_softc *scp;
int error, rid;
if (!scp || scp->flags & ATA_ATTACHED)
if (!dev)
return ENXIO;
scp = device_get_softc(dev);
if (!scp)
return ENXIO;
rid = ATA_IRQ_RID;
@ -197,19 +183,26 @@ ata_attach(device_t dev)
atapi_attach(scp, ATA_SLAVE);
#endif
}
scp->flags |= ATA_ATTACHED;
return 0;
}
int
ata_detach(device_t dev)
{
struct ata_softc *scp = device_get_softc(dev);
struct ata_softc *scp;
int s;
if (!scp || !(scp->flags & ATA_ATTACHED))
if (!dev)
return ENXIO;
scp = device_get_softc(dev);
if (!scp || !scp->devices)
return ENXIO;
/* make sure device is not busy SOS XXX */
/* make sure channel is not busy SOS XXX */
s = splbio();
while (!atomic_cmpset_int(&scp->active, ATA_IDLE, ATA_ACTIVE))
tsleep((caddr_t)&s, PRIBIO, "atachm", hz/4);
splx(s);
/* disable interrupts on devices */
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
@ -218,30 +211,31 @@ ata_detach(device_t dev)
ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_4BIT);
#ifdef DEV_ATADISK
if (scp->devices & ATA_ATA_MASTER)
ad_detach(scp->dev_softc[0]);
if (scp->devices & ATA_ATA_SLAVE)
ad_detach(scp->dev_softc[1]);
if (scp->devices & ATA_ATA_MASTER && scp->dev_softc[MASTER])
ad_detach(scp->dev_softc[MASTER]);
if (scp->devices & ATA_ATA_SLAVE && scp->dev_softc[SLAVE])
ad_detach(scp->dev_softc[SLAVE]);
#endif
#if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST)
if (scp->devices & ATA_ATAPI_MASTER)
atapi_detach(scp->dev_softc[0]);
if (scp->devices & ATA_ATAPI_SLAVE)
atapi_detach(scp->dev_softc[1]);
if (scp->devices & ATA_ATAPI_MASTER && scp->dev_softc[MASTER])
atapi_detach(scp->dev_softc[MASTER]);
if (scp->devices & ATA_ATAPI_SLAVE && scp->dev_softc[SLAVE])
atapi_detach(scp->dev_softc[SLAVE]);
#endif
if (scp->dev_param[ATA_DEV(ATA_MASTER)]) {
free(scp->dev_param[ATA_DEV(ATA_MASTER)], M_ATA);
scp->dev_param[ATA_DEV(ATA_MASTER)] = NULL;
if (scp->dev_param[MASTER]) {
free(scp->dev_param[MASTER], M_ATA);
scp->dev_param[MASTER] = NULL;
}
if (scp->dev_param[ATA_DEV(ATA_SLAVE)]) {
free(scp->dev_param[ATA_DEV(ATA_SLAVE)], M_ATA);
scp->dev_param[ATA_DEV(ATA_SLAVE)] = NULL;
if (scp->dev_param[SLAVE]) {
free(scp->dev_param[SLAVE], M_ATA);
scp->dev_param[SLAVE] = NULL;
}
scp->dev_softc[ATA_DEV(ATA_MASTER)] = NULL;
scp->dev_softc[ATA_DEV(ATA_SLAVE)] = NULL;
scp->mode[ATA_DEV(ATA_MASTER)] = ATA_PIO;
scp->mode[ATA_DEV(ATA_SLAVE)] = ATA_PIO;
scp->dev_softc[MASTER] = NULL;
scp->dev_softc[SLAVE] = NULL;
scp->mode[MASTER] = ATA_PIO;
scp->mode[SLAVE] = ATA_PIO;
scp->devices = 0;
bus_teardown_intr(dev, scp->r_irq, scp->ih);
bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, scp->r_irq);
@ -249,7 +243,7 @@ ata_detach(device_t dev)
bus_release_resource(dev, SYS_RES_IOPORT, ATA_BMADDR_RID, scp->r_bmio);
bus_release_resource(dev, SYS_RES_IOPORT, ATA_ALTADDR_RID, scp->r_altio);
bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, scp->r_io);
scp->flags &= ~ATA_ATTACHED;
scp->active = ATA_IDLE;
return 0;
}
@ -336,7 +330,7 @@ ata_boot_attach(void)
if (ata_getparam(scp, ATA_MASTER, ATA_C_ATA_IDENTIFY))
scp->devices &= ~ATA_ATA_MASTER;
if (scp->devices & ATA_ATAPI_MASTER)
if (ata_getparam(scp, ATA_MASTER,ATA_C_ATAPI_IDENTIFY))
if (ata_getparam(scp, ATA_MASTER, ATA_C_ATAPI_IDENTIFY))
scp->devices &= ~ATA_ATAPI_MASTER;
}
@ -407,15 +401,14 @@ ata_intr(void *data)
break;
#endif
case ATA_WAIT_INTR:
case ATA_WAIT_INTR | ATA_REINITING:
wakeup((caddr_t)scp);
break;
case ATA_WAIT_READY:
case ATA_WAIT_READY | ATA_REINITING:
break;
case ATA_REINITING:
return;
case ATA_IDLE:
if (scp->flags & ATA_QUEUED) {
scp->active = ATA_ACTIVE; /* XXX */
@ -435,7 +428,9 @@ ata_intr(void *data)
}
#endif
}
scp->active = ATA_IDLE;
scp->active &= ATA_REINITING;
if (scp->active & ATA_REINITING)
return;
scp->running = NULL;
ata_start(scp);
return;
@ -457,10 +452,10 @@ ata_start(struct ata_softc *scp)
#ifdef DEV_ATADISK
/* find & call the responsible driver if anything on the ATA queue */
if (TAILQ_EMPTY(&scp->ata_queue)) {
if (scp->devices & (ATA_ATA_MASTER) && scp->dev_softc[0])
ad_start((struct ad_softc *)scp->dev_softc[0]);
if (scp->devices & (ATA_ATA_SLAVE) && scp->dev_softc[1])
ad_start((struct ad_softc *)scp->dev_softc[1]);
if (scp->devices & (ATA_ATA_MASTER) && scp->dev_softc[MASTER])
ad_start((struct ad_softc *)scp->dev_softc[MASTER]);
if (scp->devices & (ATA_ATA_SLAVE) && scp->dev_softc[SLAVE])
ad_start((struct ad_softc *)scp->dev_softc[SLAVE]);
}
if ((ad_request = TAILQ_FIRST(&scp->ata_queue))) {
TAILQ_REMOVE(&scp->ata_queue, ad_request, chain);
@ -474,10 +469,10 @@ ata_start(struct ata_softc *scp)
#if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST)
/* find & call the responsible driver if anything on the ATAPI queue */
if (TAILQ_EMPTY(&scp->atapi_queue)) {
if (scp->devices & (ATA_ATAPI_MASTER) && scp->dev_softc[0])
atapi_start((struct atapi_softc *)scp->dev_softc[0]);
if (scp->devices & (ATA_ATAPI_SLAVE) && scp->dev_softc[1])
atapi_start((struct atapi_softc *)scp->dev_softc[1]);
if (scp->devices & (ATA_ATAPI_MASTER) && scp->dev_softc[MASTER])
atapi_start((struct atapi_softc *)scp->dev_softc[MASTER]);
if (scp->devices & (ATA_ATAPI_SLAVE) && scp->dev_softc[SLAVE])
atapi_start((struct atapi_softc *)scp->dev_softc[SLAVE]);
}
if ((atapi_request = TAILQ_FIRST(&scp->atapi_queue))) {
TAILQ_REMOVE(&scp->atapi_queue, atapi_request, chain);
@ -491,27 +486,35 @@ ata_start(struct ata_softc *scp)
}
void
ata_reset(struct ata_softc *scp, int *mask)
ata_reset(struct ata_softc *scp)
{
int timeout;
u_int8_t a, b, ostat0, ostat1;
u_int8_t status0 = ATA_S_BUSY, status1 = ATA_S_BUSY;
u_int8_t lsb, msb, ostat0, ostat1;
u_int8_t stat0 = ATA_S_BUSY, stat1 = ATA_S_BUSY;
int mask = 0, timeout;
/* get the current status of the devices */
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
DELAY(10);
ostat1 = ATA_INB(scp->r_io, ATA_STATUS);
/* do we have any signs of ATA/ATAPI HW being present ? */
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(10);
DELAY(1);
ostat0 = ATA_INB(scp->r_io, ATA_STATUS);
if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5)
mask |= 0x01;
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
DELAY(1);
ostat1 = ATA_INB(scp->r_io, ATA_STATUS);
if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5)
mask |= 0x02;
scp->devices = 0;
if (!mask)
return;
/* in some setups we dont want to test for a slave */
if (scp->flags & ATA_NO_SLAVE)
*mask &= ~0x02;
mask &= ~0x02;
if (bootverbose)
ata_printf(scp, -1, "mask=%02x ostat0=%02x ostat2=%02x\n",
*mask, ostat0, ostat1);
mask, ostat0, ostat1);
/* reset channel */
ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
@ -519,86 +522,85 @@ ata_reset(struct ata_softc *scp, int *mask)
ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_IDS);
DELAY(100000);
ATA_INB(scp->r_io, ATA_ERROR);
scp->devices = 0;
/* wait for BUSY to go inactive */
for (timeout = 0; timeout < 310000; timeout++) {
if (status0 & ATA_S_BUSY) {
if (stat0 & ATA_S_BUSY) {
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(10);
status0 = ATA_INB(scp->r_io, ATA_STATUS);
if (!(status0 & ATA_S_BUSY)) {
stat0 = ATA_INB(scp->r_io, ATA_STATUS);
if (!(stat0 & ATA_S_BUSY)) {
/* check for ATAPI signature while its still there */
a = ATA_INB(scp->r_io, ATA_CYL_LSB);
b = ATA_INB(scp->r_io, ATA_CYL_MSB);
lsb = ATA_INB(scp->r_io, ATA_CYL_LSB);
msb = ATA_INB(scp->r_io, ATA_CYL_MSB);
if (bootverbose)
ata_printf(scp, ATA_MASTER,
"ATAPI probe a=%02x b=%02x\n", a, b);
if (a == ATAPI_MAGIC_LSB && b == ATAPI_MAGIC_MSB)
"ATAPI probe %02x %02x\n", lsb, msb);
if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
scp->devices |= ATA_ATAPI_MASTER;
}
}
if (status1 & ATA_S_BUSY) {
if (stat1 & ATA_S_BUSY) {
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
DELAY(10);
status1 = ATA_INB(scp->r_io, ATA_STATUS);
if (!(status1 & ATA_S_BUSY)) {
stat1 = ATA_INB(scp->r_io, ATA_STATUS);
if (!(stat1 & ATA_S_BUSY)) {
/* check for ATAPI signature while its still there */
a = ATA_INB(scp->r_io, ATA_CYL_LSB);
b = ATA_INB(scp->r_io, ATA_CYL_MSB);
lsb = ATA_INB(scp->r_io, ATA_CYL_LSB);
msb = ATA_INB(scp->r_io, ATA_CYL_MSB);
if (bootverbose)
ata_printf(scp, ATA_SLAVE,
"ATAPI probe a=%02x b=%02x\n", a, b);
if (a == ATAPI_MAGIC_LSB && b == ATAPI_MAGIC_MSB)
"ATAPI probe %02x %02x\n", lsb, msb);
if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
scp->devices |= ATA_ATAPI_SLAVE;
}
}
if (*mask == 0x01) /* wait for master only */
if (!(status0 & ATA_S_BUSY))
if (mask == 0x01) /* wait for master only */
if (!(stat0 & ATA_S_BUSY))
break;
if (*mask == 0x02) /* wait for slave only */
if (!(status1 & ATA_S_BUSY))
if (mask == 0x02) /* wait for slave only */
if (!(stat1 & ATA_S_BUSY))
break;
if (*mask == 0x03) /* wait for both master & slave */
if (!(status0 & ATA_S_BUSY) && !(status1 & ATA_S_BUSY))
if (mask == 0x03) /* wait for both master & slave */
if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
break;
DELAY(100);
}
DELAY(10);
ATA_OUTB(scp->r_altio, ATA_ALTSTAT, ATA_A_4BIT);
if (status0 & ATA_S_BUSY)
*mask &= ~0x01;
if (status1 & ATA_S_BUSY)
*mask &= ~0x02;
if (stat0 & ATA_S_BUSY)
mask &= ~0x01;
if (stat1 & ATA_S_BUSY)
mask &= ~0x02;
if (bootverbose)
ata_printf(scp, -1, "mask=%02x status0=%02x status1=%02x\n",
*mask, status0, status1);
if (!*mask)
ata_printf(scp, -1, "mask=%02x stat0=%02x stat1=%02x\n",
mask, stat0, stat1);
if (!mask)
return;
if (*mask & 0x01 && ostat0 != 0x00 && !(scp->devices & ATA_ATAPI_MASTER)) {
if (mask & 0x01 && ostat0 != 0x00 && !(scp->devices & ATA_ATAPI_MASTER)) {
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
DELAY(10);
ATA_OUTB(scp->r_io, ATA_ERROR, 0x58);
ATA_OUTB(scp->r_io, ATA_CYL_LSB, 0xa5);
a = ATA_INB(scp->r_io, ATA_ERROR);
b = ATA_INB(scp->r_io, ATA_CYL_LSB);
lsb = ATA_INB(scp->r_io, ATA_ERROR);
msb = ATA_INB(scp->r_io, ATA_CYL_LSB);
if (bootverbose)
ata_printf(scp, ATA_MASTER, "ATA probe a=%02x b=%02x\n", a, b);
if (a != 0x58 && b == 0xa5)
ata_printf(scp, ATA_MASTER, "ATA probe %02x %02x\n", lsb, msb);
if (lsb != 0x58 && msb == 0xa5)
scp->devices |= ATA_ATA_MASTER;
}
if (*mask & 0x02 && ostat1 != 0x00 && !(scp->devices & ATA_ATAPI_SLAVE)) {
if (mask & 0x02 && ostat1 != 0x00 && !(scp->devices & ATA_ATAPI_SLAVE)) {
ATA_OUTB(scp->r_io, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
DELAY(10);
ATA_OUTB(scp->r_io, ATA_ERROR, 0x58);
ATA_OUTB(scp->r_io, ATA_CYL_LSB, 0xa5);
a = ATA_INB(scp->r_io, ATA_ERROR);
b = ATA_INB(scp->r_io, ATA_CYL_LSB);
lsb = ATA_INB(scp->r_io, ATA_ERROR);
msb = ATA_INB(scp->r_io, ATA_CYL_LSB);
if (bootverbose)
ata_printf(scp, ATA_SLAVE, "ATA probe a=%02x b=%02x\n", a, b);
if (a != 0x58 && b == 0xa5)
ata_printf(scp, ATA_SLAVE, "ATA probe %02x %02x\n", lsb, msb);
if (lsb != 0x58 && msb == 0xa5)
scp->devices |= ATA_ATA_SLAVE;
}
if (bootverbose)
@ -608,36 +610,74 @@ ata_reset(struct ata_softc *scp, int *mask)
int
ata_reinit(struct ata_softc *scp)
{
int mask = 0, odevices;
int devices, misdev, newdev;
scp->active = ATA_REINITING;
scp->running = NULL;
if (scp->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER))
mask |= 0x01;
if (scp->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE))
mask |= 0x02;
if (mask) {
odevices = scp->devices;
ata_printf(scp, -1, "resetting devices .. ");
ata_reset(scp, &mask);
if (odevices != scp->devices)
printf(" device dissapeared! 0x%02x ", odevices & ~scp->devices);
devices = scp->devices;
ata_printf(scp, -1, "resetting devices .. ");
ata_reset(scp);
if ((misdev = devices & ~scp->devices)) {
printf("\ndevice(s) disappeared! 0x%02x\n", misdev);
#ifdef DEV_ATADISK
if (scp->devices & (ATA_ATA_MASTER) && scp->dev_softc[0])
ad_reinit((struct ad_softc *)scp->dev_softc[0]);
if (scp->devices & (ATA_ATA_SLAVE) && scp->dev_softc[1])
ad_reinit((struct ad_softc *)scp->dev_softc[1]);
if (misdev & ATA_ATA_MASTER && scp->dev_softc[MASTER])
ad_detach(scp->dev_softc[MASTER]);
if (misdev & ATA_ATA_SLAVE && scp->dev_softc[SLAVE])
ad_detach(scp->dev_softc[SLAVE]);
#endif
#if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST)
if (scp->devices & (ATA_ATAPI_MASTER) && scp->dev_softc[0])
atapi_reinit((struct atapi_softc *)scp->dev_softc[0]);
if (scp->devices & (ATA_ATAPI_SLAVE) && scp->dev_softc[1])
atapi_reinit((struct atapi_softc *)scp->dev_softc[1]);
if (misdev & ATA_ATAPI_MASTER && scp->dev_softc[MASTER])
atapi_detach(scp->dev_softc[MASTER]);
if (misdev & ATA_ATAPI_SLAVE && scp->dev_softc[SLAVE])
atapi_detach(scp->dev_softc[SLAVE]);
#endif
printf("done\n");
if (misdev & ATA_ATA_MASTER || misdev & ATA_ATAPI_MASTER) {
free(scp->dev_param[MASTER], M_ATA);
scp->dev_param[MASTER] = NULL;
}
if (misdev & ATA_ATA_SLAVE || misdev & ATA_ATAPI_SLAVE) {
free(scp->dev_param[SLAVE], M_ATA);
scp->dev_param[SLAVE] = NULL;
}
}
if ((newdev = ~devices & scp->devices)) {
printf("\ndevice(s) appeared! 0x%02x\n", newdev);
if (newdev & ATA_ATA_MASTER)
if (ata_getparam(scp, ATA_MASTER, ATA_C_ATA_IDENTIFY))
newdev &= ~ATA_ATA_MASTER;
if (newdev & ATA_ATA_SLAVE)
if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATA_IDENTIFY))
newdev &= ~ATA_ATA_SLAVE;
if (newdev & ATA_ATAPI_MASTER)
if (ata_getparam(scp, ATA_MASTER, ATA_C_ATAPI_IDENTIFY))
newdev &= ~ATA_ATAPI_MASTER;
if (newdev & ATA_ATAPI_SLAVE)
if (ata_getparam(scp, ATA_SLAVE, ATA_C_ATAPI_IDENTIFY))
newdev &= ~ATA_ATAPI_SLAVE;
}
scp->active = ATA_IDLE;
#ifdef DEV_ATADISK
if (newdev & ATA_ATA_MASTER && !scp->dev_softc[MASTER])
ad_attach(scp, ATA_MASTER);
else if (scp->devices & ATA_ATA_MASTER && scp->dev_softc[MASTER])
ad_reinit((struct ad_softc *)scp->dev_softc[MASTER]);
if (newdev & ATA_ATA_SLAVE && !scp->dev_softc[SLAVE])
ad_attach(scp, ATA_SLAVE);
else if (scp->devices & (ATA_ATA_SLAVE) && scp->dev_softc[SLAVE])
ad_reinit((struct ad_softc *)scp->dev_softc[SLAVE]);
#endif
#if defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || defined(DEV_ATAPIST)
if (newdev & ATA_ATAPI_MASTER && !scp->dev_softc[MASTER])
atapi_attach(scp, ATA_MASTER);
else if (scp->devices & (ATA_ATAPI_MASTER) && scp->dev_softc[MASTER])
atapi_reinit((struct atapi_softc *)scp->dev_softc[MASTER]);
if (newdev & ATA_ATAPI_SLAVE && !scp->dev_softc[SLAVE])
atapi_attach(scp, ATA_SLAVE);
else if (scp->devices & (ATA_ATAPI_SLAVE) && scp->dev_softc[SLAVE])
atapi_reinit((struct atapi_softc *)scp->dev_softc[SLAVE]);
#endif
printf("done\n");
ata_start(scp);
return 0;
}
@ -651,12 +691,12 @@ ata_service(struct ata_softc *scp)
ata_dmastatus(scp) | ATA_BMSTAT_INTERRUPT);
#ifdef DEV_ATADISK
if ((ATA_INB(scp->r_io, ATA_DRIVE) & ATA_SLAVE) == ATA_MASTER) {
if ((scp->devices & ATA_ATA_MASTER) && scp->dev_softc[0])
return ad_service((struct ad_softc *)scp->dev_softc[0], 0);
if ((scp->devices & ATA_ATA_MASTER) && scp->dev_softc[MASTER])
return ad_service((struct ad_softc *)scp->dev_softc[MASTER], 0);
}
else {
if ((scp->devices & ATA_ATA_SLAVE) && scp->dev_softc[1])
return ad_service((struct ad_softc *)scp->dev_softc[1], 0);
if ((scp->devices & ATA_ATA_SLAVE) && scp->dev_softc[SLAVE])
return ad_service((struct ad_softc *)scp->dev_softc[SLAVE], 0);
}
#endif
}
@ -751,7 +791,7 @@ ata_command(struct ata_softc *scp, int device, u_int8_t command,
switch (flags) {
case ATA_WAIT_INTR:
scp->active = ATA_WAIT_INTR;
scp->active |= ATA_WAIT_INTR;
asleep((caddr_t)scp, PRIBIO, "atacmd", 10 * hz);
ATA_OUTB(scp->r_io, ATA_CMD, command);
@ -761,14 +801,13 @@ ata_command(struct ata_softc *scp, int device, u_int8_t command,
if (await(PRIBIO, 10 * hz)) {
ata_printf(scp, device, "ata_command: timeout waiting for intr\n");
scp->active = ATA_IDLE;
scp->active &= ~ATA_WAIT_INTR;
error = -1;
}
break;
case ATA_WAIT_READY:
if (scp->active != ATA_REINITING)
scp->active = ATA_WAIT_READY;
scp->active |= ATA_WAIT_READY;
ATA_OUTB(scp->r_io, ATA_CMD, command);
if (ata_wait(scp, device, ATA_S_READY) < 0) {
ata_printf(scp, device,
@ -776,8 +815,7 @@ ata_command(struct ata_softc *scp, int device, u_int8_t command,
command, scp->status, scp->error);
error = -1;
}
if (scp->active != ATA_REINITING)
scp->active = ATA_IDLE;
scp->active &= ~ATA_WAIT_READY;
break;
case ATA_IMMEDIATE:

View File

@ -312,8 +312,7 @@ struct ata_softc {
#define ATA_ATAPI_DMA_RO 0x02
#define ATA_USE_16BIT 0x04
#define ATA_NO_SLAVE 0x08
#define ATA_ATTACHED 0x10
#define ATA_QUEUED 0x20
#define ATA_QUEUED 0x10
int devices; /* what is present */
#define ATA_ATA_MASTER 0x01
@ -324,14 +323,14 @@ struct ata_softc {
u_int8_t status; /* last controller status */
u_int8_t error; /* last controller error */
int active; /* active processing request */
#define ATA_IDLE 0x0
#define ATA_IMMEDIATE 0x1
#define ATA_WAIT_INTR 0x2
#define ATA_WAIT_READY 0x3
#define ATA_ACTIVE 0x4
#define ATA_ACTIVE_ATA 0x5
#define ATA_ACTIVE_ATAPI 0x6
#define ATA_REINITING 0x7
#define ATA_IDLE 0x0000
#define ATA_IMMEDIATE 0x0001
#define ATA_WAIT_INTR 0x0002
#define ATA_WAIT_READY 0x0004
#define ATA_ACTIVE 0x0008
#define ATA_ACTIVE_ATA 0x0010
#define ATA_ACTIVE_ATAPI 0x0020
#define ATA_REINITING 0x0040
TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */
TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */
@ -348,7 +347,7 @@ int ata_detach(device_t);
int ata_resume(device_t);
void ata_start(struct ata_softc *);
void ata_reset(struct ata_softc *, int *);
void ata_reset(struct ata_softc *);
int ata_reinit(struct ata_softc *);
int ata_wait(struct ata_softc *, int, u_int8_t);
int ata_command(struct ata_softc *, int, u_int8_t, u_int16_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t, int);
@ -370,6 +369,7 @@ void ata_dmastart(struct ata_softc *, int, struct ata_dmaentry *, int);
int ata_dmastatus(struct ata_softc *);
int ata_dmadone(struct ata_softc *);
/* macros to hide busspace uglyness */
#define ATA_INB(res, offset) \
bus_space_read_1(rman_get_bustag((res)), \
rman_get_bushandle((res)), (offset))

View File

@ -96,12 +96,10 @@ ad_attach(struct ata_softc *scp, int device)
dev_t dev;
int secsperint;
if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) {
ata_printf(scp, device, "failed to allocate driver storage\n");
return;
}
scp->dev_softc[ATA_DEV(device)] = adp;
adp->controller = scp;
adp->unit = device;
#ifdef ATA_STATIC_ID
@ -169,7 +167,6 @@ ad_attach(struct ata_softc *scp, int device)
dev->si_drv1 = adp;
dev->si_iosize_max = 256 * DEV_BSIZE;
adp->dev = dev;
bioq_init(&adp->queue);
if (bootverbose) {
@ -204,15 +201,40 @@ ad_attach(struct ata_softc *scp, int device)
(adp->unit == ATA_MASTER) ? "master" : "slave",
(adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
ata_mode2str(adp->controller->mode[ATA_DEV(adp->unit)]));
/* store our softc signalling we are ready to go */
scp->dev_softc[ATA_DEV(device)] = adp;
}
void
ad_detach(struct ad_softc *adp)
{
struct ad_request *request;
struct bio *bp;
adp->flags |= AD_F_DETACHING;
TAILQ_FOREACH(request, &adp->controller->ata_queue, chain) {
if (request->device != adp)
continue;
TAILQ_REMOVE(&adp->controller->ata_queue, request, chain);
request->bp->bio_error = ENXIO;
request->bp->bio_flags |= BIO_ERROR;
biodone(request->bp);
ad_free(request);
}
while ((bp = bioq_first(&adp->queue))) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
}
disk_invalidate(&adp->disk);
disk_destroy(adp->dev);
devstat_remove_entry(&adp->stats);
if (ata_command(adp->controller, adp->unit, ATA_C_FLUSHCACHE,
0, 0, 0, 0, 0, ATA_WAIT_INTR))
printf("ad%d: flushing cache on detach failed\n", adp->lun);
ata_free_lun(&adp_lun_map, adp->lun);
adp->controller->dev_softc[ATA_DEV(adp->unit)] = NULL;
free(adp, M_AD);
}
@ -239,6 +261,13 @@ adstrategy(struct bio *bp)
struct ad_softc *adp = bp->bio_dev->si_drv1;
int s;
if (adp->flags & AD_F_DETACHING) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
return;
}
/* if it's a null transfer, return immediatly. */
if (bp->bio_bcount == 0) {
bp->bio_resid = 0;
@ -876,7 +905,7 @@ ad_reinit(struct ad_softc *adp)
/* reinit disk parameters */
ad_invalidatequeue(adp, NULL);
ata_command(adp->controller, adp->unit, ATA_C_SET_MULTI, 0, 0, 0,
adp->transfersize / DEV_BSIZE, 0, ATA_WAIT_READY);
adp->transfersize / DEV_BSIZE, 0, ATA_WAIT_INTR);
if (adp->controller->mode[ATA_DEV(adp->unit)] >= ATA_DMA)
ata_dmainit(adp->controller, adp->unit, ata_pmode(AD_PARAM),
ata_wmode(AD_PARAM), ata_umode(AD_PARAM));

View File

@ -68,6 +68,7 @@ struct ad_softc {
#define AD_F_LBA_ENABLED 0x0002
#define AD_F_32B_ENABLED 0x0004
#define AD_F_TAG_ENABLED 0x0008
#define AD_F_DETACHING 0x0010
struct ad_request *tags[32]; /* tag array of requests */
int outstanding; /* tags not serviced yet */

View File

@ -35,6 +35,7 @@
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/bio.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <dev/ata/ata-all.h>
@ -114,13 +115,18 @@ atapi_attach(struct ata_softc *scp, int device)
free(atp, M_ATAPI);
atp = NULL;
}
/* store our softc */
/* store our softc signalling we are ready to go */
scp->dev_softc[ATA_DEV(device)] = atp;
}
void
atapi_detach(struct atapi_softc *atp)
{
struct atapi_request *request;
atp->flags |= ATAPI_F_DETACHING;
switch (ATP_PARAM->device_type) {
#ifdef DEV_ATAPICD
case ATAPI_TYPE_CDROM:
@ -140,6 +146,21 @@ atapi_detach(struct atapi_softc *atp)
default:
return;
}
TAILQ_FOREACH(request, &atp->controller->atapi_queue, chain) {
if (request->device != atp)
continue;
TAILQ_REMOVE(&atp->controller->atapi_queue, request, chain);
if (request->driver) {
struct bio *bp = (struct bio *) request->driver;
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
}
if (request->dmatab)
free(request->dmatab, M_DEVBUF);
free(request, M_ATAPI);
}
atp->controller->dev_softc[ATA_DEV(atp->unit)] = NULL;
free(atp, M_ATAPI);
}

View File

@ -150,7 +150,7 @@ struct atapi_softc {
u_int8_t cmd; /* last cmd executed */
int flags; /* drive flags */
#define ATAPI_F_MEDIA_CHANGED 0x0001
#define ATAPI_F_DETACHING 0x0002
};
typedef int atapi_callback_t(struct atapi_request *);

View File

@ -98,6 +98,7 @@ static int acd_set_speed(struct acd_softc *cdp, int);
/* internal vars */
static u_int32_t acd_lun_map = 0;
static eventhandler_tag acd_tag;
static MALLOC_DEFINE(M_ACD, "ACD driver", "ATAPI CD driver buffers");
int
@ -110,7 +111,7 @@ acdattach(struct atapi_softc *atp)
if (!acd_cdev_done) {
cdevsw_add(&acd_cdevsw);
EVENTHANDLER_REGISTER(dev_clone, acd_clone, 0, 1000);
acd_tag = EVENTHANDLER_REGISTER(dev_clone, acd_clone, 0, 1000);
acd_cdev_done++;
}
@ -213,13 +214,36 @@ void
acddetach(struct atapi_softc *atp)
{
struct acd_softc *cdp = atp->driver;
struct bio *bp;
int subdev;
destroy_dev(cdp->dev1);
destroy_dev(cdp->dev2);
if (cdp->changer_info) {
/* should free all cdp's here, not possible yet SOS XXX */
for (subdev = 0; subdev < cdp->changer_info->slots; subdev++) {
if (cdp->driver[subdev] == cdp)
continue;
while ((bp = bioq_first(&cdp->driver[subdev]->queue))) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
}
destroy_dev(cdp->dev1);
destroy_dev(cdp->dev2);
devstat_remove_entry(cdp->stats);
free(cdp->stats, M_ACD);
free(cdp->atp->devname, M_ACD);
ata_free_lun(&acd_lun_map, cdp->lun);
free(cdp, M_ACD);
}
free(cdp->driver, M_ACD);
free(cdp->changer_info, M_ACD);
}
while ((bp = bioq_first(&cdp->queue))) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
}
destroy_dev(cdp->dev1);
destroy_dev(cdp->dev2);
devstat_remove_entry(cdp->stats);
free(cdp->stats, M_ACD);
free(cdp->atp->devname, M_ACD);
@ -234,7 +258,7 @@ acd_init_lun(struct atapi_softc *atp, struct devstat *stats)
if (!(cdp = malloc(sizeof(struct acd_softc), M_ACD, M_NOWAIT | M_ZERO)))
return NULL;
bioq_init(&cdp->bio_queue);
bioq_init(&cdp->queue);
cdp->atp = atp;
cdp->lun = ata_get_lun(&acd_lun_map);
cdp->block_size = 2048;
@ -1097,6 +1121,13 @@ acdstrategy(struct bio *bp)
struct acd_softc *cdp = bp->bio_dev->si_drv1;
int s;
if (cdp->atp->flags & ATAPI_F_DETACHING) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
return;
}
/* if it's a null transfer, return immediatly. */
if (bp->bio_bcount == 0) {
bp->bio_resid = 0;
@ -1108,7 +1139,7 @@ acdstrategy(struct bio *bp)
bp->bio_resid = bp->bio_bcount;
s = splbio();
bioqdisksort(&cdp->bio_queue, bp);
bioqdisksort(&cdp->queue, bp);
ata_start(cdp->atp->controller);
splx(s);
}
@ -1117,7 +1148,7 @@ void
acd_start(struct atapi_softc *atp)
{
struct acd_softc *cdp = atp->driver;
struct bio *bp = bioq_first(&cdp->bio_queue);
struct bio *bp = bioq_first(&cdp->queue);
u_int32_t lba, lastlba, count;
int8_t ccb[16];
int track, blocksize;
@ -1126,13 +1157,13 @@ acd_start(struct atapi_softc *atp)
int i;
cdp = cdp->driver[cdp->changer_info->current_slot];
bp = bioq_first(&cdp->bio_queue);
bp = bioq_first(&cdp->queue);
/* check for work pending on any other slot */
for (i = 0; i < cdp->changer_info->slots; i++) {
if (i == cdp->changer_info->current_slot)
continue;
if (bioq_first(&(cdp->driver[i]->bio_queue))) {
if (bioq_first(&(cdp->driver[i]->queue))) {
if (!bp || time_second > (cdp->timestamp + 10)) {
acd_select_slot(cdp->driver[i]);
return;
@ -1142,7 +1173,7 @@ acd_start(struct atapi_softc *atp)
}
if (!bp)
return;
bioq_remove(&cdp->bio_queue, bp);
bioq_remove(&cdp->queue, bp);
/* reject all queued entries if media changed */
if (cdp->atp->flags & ATAPI_F_MEDIA_CHANGED) {

View File

@ -167,6 +167,8 @@ struct cappage {
u_int8_t :3;
u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */
u_int16_t cur_write_speed; /* current data rate in bytes/1000 */
u_int16_t copy_protect_rev;
u_int16_t reserved4;
};
/* CDROM Changer mechanism status structure */
@ -298,7 +300,7 @@ struct acd_softc {
int flags; /* device state flags */
#define F_LOCKED 0x0001 /* this unit is locked */
struct bio_queue_head bio_queue; /* Queue of i/o requests */
struct bio_queue_head queue; /* queue of i/o requests */
struct toc toc; /* table of disc contents */
struct {
u_int32_t volsize; /* volume size in blocks */

View File

@ -89,7 +89,7 @@ afdattach(struct atapi_softc *atp)
printf("afd: out of memory\n");
return -1;
}
bioq_init(&fdp->bio_queue);
bioq_init(&fdp->queue);
fdp->atp = atp;
fdp->lun = ata_get_lun(&afd_lun_map);
@ -122,7 +122,13 @@ void
afddetach(struct atapi_softc *atp)
{
struct afd_softc *fdp = atp->driver;
struct bio *bp;
while ((bp = bioq_first(&fdp->queue))) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
}
disk_invalidate(&fdp->disk);
disk_destroy(fdp->dev);
devstat_remove_entry(&fdp->stats);
@ -181,25 +187,27 @@ afd_describe(struct afd_softc *fdp)
printf(" transfer limit %d blks,", fdp->transfersize);
printf(" %s\n", ata_mode2str(fdp->atp->controller->mode[
ATA_DEV(fdp->atp->unit)]));
printf("afd%d: Medium: ", fdp->lun);
switch (fdp->header.medium_type) {
case MFD_2DD:
printf("720KB DD disk"); break;
if (fdp->header.medium_type) {
printf("afd%d: Medium: ", fdp->lun);
switch (fdp->header.medium_type) {
case MFD_2DD:
printf("720KB DD disk"); break;
case MFD_HD_12:
printf("1.2MB HD disk"); break;
case MFD_HD_12:
printf("1.2MB HD disk"); break;
case MFD_HD_144:
printf("1.44MB HD disk"); break;
case MFD_HD_144:
printf("1.44MB HD disk"); break;
case MFD_UHD:
printf("120MB UHD disk"); break;
case MFD_UHD:
printf("120MB UHD disk"); break;
default:
printf("Unknown media (0x%x)", fdp->header.medium_type);
default:
printf("Unknown (0x%x)", fdp->header.medium_type);
}
if (fdp->header.wp) printf(", writeprotected");
}
if (fdp->header.wp) printf(", writeprotected");
printf("\n");
printf("\n");
}
else {
printf("afd%d: %luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
@ -277,6 +285,13 @@ afdstrategy(struct bio *bp)
struct afd_softc *fdp = bp->bio_dev->si_drv1;
int s;
if (fdp->atp->flags & ATAPI_F_DETACHING) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
return;
}
/* if it's a null transfer, return immediatly. */
if (bp->bio_bcount == 0) {
bp->bio_resid = 0;
@ -285,7 +300,7 @@ afdstrategy(struct bio *bp)
}
s = splbio();
bioqdisksort(&fdp->bio_queue, bp);
bioqdisksort(&fdp->queue, bp);
ata_start(fdp->atp->controller);
splx(s);
}
@ -294,7 +309,7 @@ void
afd_start(struct atapi_softc *atp)
{
struct afd_softc *fdp = atp->driver;
struct bio *bp = bioq_first(&fdp->bio_queue);
struct bio *bp = bioq_first(&fdp->queue);
u_int32_t lba;
u_int16_t count;
int8_t ccb[16];
@ -303,7 +318,7 @@ afd_start(struct atapi_softc *atp)
if (!bp)
return;
bioq_remove(&fdp->bio_queue, bp);
bioq_remove(&fdp->queue, bp);
/* should reject all queued entries if media have changed. */
if (fdp->atp->flags & ATAPI_F_MEDIA_CHANGED) {
@ -353,7 +368,8 @@ afd_start(struct atapi_softc *atp)
ccb[8] = count;
atapi_queue_cmd(fdp->atp, ccb, data_ptr, count * fdp->cap.sector_size,
(bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0, 30, afd_done, bp);
(bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0, 30,
afd_done, bp);
}
static int
@ -423,5 +439,5 @@ afd_prevent_allow(struct afd_softc *fdp, int lock)
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
return atapi_queue_cmd(fdp->atp, ccb, NULL, 0, 0,30, NULL, NULL);
return atapi_queue_cmd(fdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL);
}

View File

@ -74,7 +74,7 @@ struct afd_softc {
struct atapi_softc *atp; /* controller structure */
int lun; /* logical device unit */
int transfersize; /* max size of each transfer */
struct bio_queue_head bio_queue; /* queue of i/o requests */
struct bio_queue_head queue; /* queue of i/o requests */
struct afd_header header; /* capabilities page info */
struct afd_cappage cap; /* capabilities page info */
struct disk disk; /* virtual drives */

View File

@ -101,7 +101,7 @@ astattach(struct atapi_softc *atp)
printf("ast: out of memory\n");
return -1;
}
bioq_init(&stp->bio_queue);
bioq_init(&stp->queue);
stp->atp = atp;
stp->lun = ata_get_lun(&ast_lun_map);
if (ast_sense(stp)) {
@ -151,7 +151,13 @@ void
astdetach(struct atapi_softc *atp)
{
struct ast_softc *stp = atp->driver;
struct bio *bp;
while ((bp = bioq_first(&stp->queue))) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
}
destroy_dev(stp->dev1);
destroy_dev(stp->dev2);
devstat_remove_entry(&stp->stats);
@ -414,6 +420,13 @@ aststrategy(struct bio *bp)
struct ast_softc *stp = bp->bio_dev->si_drv1;
int s;
if (stp->atp->flags & ATAPI_F_DETACHING) {
bp->bio_error = ENXIO;
bp->bio_flags |= BIO_ERROR;
biodone(bp);
return;
}
/* if it's a null transfer, return immediatly. */
if (bp->bio_bcount == 0) {
bp->bio_resid = 0;
@ -447,7 +460,7 @@ aststrategy(struct bio *bp)
}
s = splbio();
bioq_insert_tail(&stp->bio_queue, bp);
bioq_insert_tail(&stp->queue, bp);
ata_start(stp->atp->controller);
splx(s);
}
@ -456,7 +469,7 @@ void
ast_start(struct atapi_softc *atp)
{
struct ast_softc *stp = atp->driver;
struct bio *bp = bioq_first(&stp->bio_queue);
struct bio *bp = bioq_first(&stp->queue);
u_int32_t blkcount;
int8_t ccb[16];
@ -470,7 +483,7 @@ ast_start(struct atapi_softc *atp)
else
ccb[0] = ATAPI_WRITE;
bioq_remove(&stp->bio_queue, bp);
bioq_remove(&stp->queue, bp);
blkcount = bp->bio_bcount / stp->blksize;
ccb[1] = 1;

View File

@ -154,7 +154,7 @@ struct ast_softc {
#define F_ONSTREAM 0x0100 /* OnStream ADR device */
int blksize; /* block size (512 | 1024) */
struct bio_queue_head bio_queue; /* queue of i/o requests */
struct bio_queue_head queue; /* queue of i/o requests */
struct atapi_params *param; /* drive parameters table */
struct ast_cappage cap; /* capabilities page info */
struct devstat stats; /* devstat entry */