diff options
author | sos <sos@FreeBSD.org> | 2001-03-14 12:05:44 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2001-03-14 12:05:44 +0000 |
commit | 4659caa469c2dedd9d5063417c8da7cc4e37d7aa (patch) | |
tree | 871c965e909b58c956ea34692b952d392b3c58c1 /sys/dev/ata/ata-disk.c | |
parent | 045a83cd9229e8ab1171e7adf872e072644f8945 (diff) | |
download | FreeBSD-src-4659caa469c2dedd9d5063417c8da7cc4e37d7aa.zip FreeBSD-src-4659caa469c2dedd9d5063417c8da7cc4e37d7aa.tar.gz |
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.
Diffstat (limited to 'sys/dev/ata/ata-disk.c')
-rw-r--r-- | sys/dev/ata/ata-disk.c | 37 |
1 files changed, 33 insertions, 4 deletions
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c index d834b95..359681b 100644 --- a/sys/dev/ata/ata-disk.c +++ b/sys/dev/ata/ata-disk.c @@ -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)); |