summaryrefslogtreecommitdiffstats
path: root/sys/dev/ata/atapi-cd.c
diff options
context:
space:
mode:
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