summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/atapi-cd.c
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2001-03-14 12:05:44 +0000
committersos <sos@FreeBSD.org>2001-03-14 12:05:44 +0000
commit4659caa469c2dedd9d5063417c8da7cc4e37d7aa (patch)
tree871c965e909b58c956ea34692b952d392b3c58c1 /sys/dev/ata/atapi-cd.c
parent045a83cd9229e8ab1171e7adf872e072644f8945 (diff)
downloadFreeBSD-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/atapi-cd.c')
-rw-r--r--sys/dev/ata/atapi-cd.c51
1 files changed, 41 insertions, 10 deletions
diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c
index 41c922f..7f7e6e5 100644
--- a/sys/dev/ata/atapi-cd.c
+++ b/sys/dev/ata/atapi-cd.c
@@ -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) {
OpenPOWER on IntegriCloud