diff options
author | sos <sos@FreeBSD.org> | 2000-03-21 13:26:54 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2000-03-21 13:26:54 +0000 |
commit | 3326256bf03e795dff052bf0fd8db5cdf670f414 (patch) | |
tree | a185b13729282e7c2ea9a3a2008ad8b51ab74b60 | |
parent | da862b0d617e5f9a1807469a83448df6609fcebb (diff) | |
download | FreeBSD-src-3326256bf03e795dff052bf0fd8db5cdf670f414.zip FreeBSD-src-3326256bf03e795dff052bf0fd8db5cdf670f414.tar.gz |
Make ATAPI CD changer devices work, hopefully better than before.
-rw-r--r-- | sys/dev/ata/atapi-all.c | 22 | ||||
-rw-r--r-- | sys/dev/ata/atapi-all.h | 5 | ||||
-rw-r--r-- | sys/dev/ata/atapi-cd.c | 133 | ||||
-rw-r--r-- | sys/dev/ata/atapi-cd.h | 4 | ||||
-rw-r--r-- | sys/dev/ata/atapi-fd.c | 4 | ||||
-rw-r--r-- | sys/dev/ata/atapi-tape.c | 2 |
6 files changed, 112 insertions, 58 deletions
diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c index 075081d..5700a9a 100644 --- a/sys/dev/ata/atapi-all.c +++ b/sys/dev/ata/atapi-all.c @@ -150,7 +150,7 @@ atapi_detach(struct atapi_softc *atp) int32_t atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data, int32_t count, int32_t flags, int32_t timeout, - atapi_callback_t callback, struct buf *bp) + atapi_callback_t callback, void *driver) { struct atapi_request *request; int32_t error, s; @@ -168,7 +168,7 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data, bcopy(ccb, request->ccb, request->ccbsize); if (callback) { request->callback = callback; - request->bp = bp; + request->driver = driver; } s = splbio(); @@ -178,7 +178,15 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data, asleep((caddr_t)request, PRIBIO, "atprq", 0); /* append onto controller queue and try to start controller */ - TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain); +#ifdef ATAPI_DEBUG + printf("%s: queueing %s ", + request->device->devname, atapi_cmd2str(request->ccb[0])); + atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb)); +#endif + if (flags & ATPR_F_AT_HEAD) + TAILQ_INSERT_HEAD(&atp->controller->atapi_queue, request, chain); + else + TAILQ_INSERT_TAIL(&atp->controller->atapi_queue, request, chain); ata_start(atp->controller); /* if callback used, then just return, gets called from interrupt context */ @@ -191,6 +199,10 @@ atapi_queue_cmd(struct atapi_softc *atp, int8_t *ccb, void *data, await(PRIBIO, 0); splx(s); error = request->error; +#ifdef ATAPI_DEBUG + printf("%s: finished %s\n", + request->device->devname, atapi_cmd2str(request->ccb[0])); +#endif free(request, M_ATAPI); return error; } @@ -425,6 +437,10 @@ op_finished: } } if (request->callback) { +#ifdef ATAPI_DEBUG + printf("%s: finished %s (callback)\n", + request->device->devname, atapi_cmd2str(request->ccb[0])); +#endif if (!((request->callback)(request))) free(request, M_ATAPI); } diff --git a/sys/dev/ata/atapi-all.h b/sys/dev/ata/atapi-all.h index b3e5091..6223f5d 100644 --- a/sys/dev/ata/atapi-all.h +++ b/sys/dev/ata/atapi-all.h @@ -169,10 +169,11 @@ struct atapi_request { int32_t flags; #define ATPR_F_READ 0x0001 #define ATPR_F_DMA_USED 0x0002 +#define ATPR_F_AT_HEAD 0x0004 int8_t *data; /* pointer to data buf */ - struct buf *bp; /* associated buf ptr */ atapi_callback_t *callback; /* ptr to callback func */ + void *driver; /* driver specific */ TAILQ_ENTRY(atapi_request) chain; /* list management */ }; @@ -181,7 +182,7 @@ void atapi_detach(struct atapi_softc *); void atapi_start(struct atapi_softc *); void atapi_transfer(struct atapi_request *); int32_t atapi_interrupt(struct atapi_request *); -int32_t atapi_queue_cmd(struct atapi_softc *, int8_t [], void *, int32_t, int32_t, int32_t, atapi_callback_t, struct buf *); +int32_t atapi_queue_cmd(struct atapi_softc *, int8_t [], void *, int32_t, int32_t, int32_t, atapi_callback_t, void *); void atapi_reinit(struct atapi_softc *); int32_t atapi_test_ready(struct atapi_softc *); int32_t atapi_wait_ready(struct atapi_softc *, int32_t); diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index a20cb4c..b34a899 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -76,7 +76,7 @@ static void acd_describe(struct acd_softc *); static void lba2msf(int32_t, u_int8_t *, u_int8_t *, u_int8_t *); static int32_t msf2lba(u_int8_t, u_int8_t, u_int8_t); static int32_t acd_done(struct atapi_request *); -static int32_t acd_read_toc(struct acd_softc *); +static void acd_read_toc(struct acd_softc *); static void acd_construct_label(struct acd_softc *); static int32_t acd_setchan(struct acd_softc *, u_int8_t, u_int8_t, u_int8_t, u_int8_t); static void acd_select_slot(struct acd_softc *); @@ -153,10 +153,16 @@ acdattach(struct atapi_softc *atp) if (!error) { struct acd_softc *tmpcdp = cdp; + struct acd_softc **cdparr; int32_t count; int8_t string[16]; chp->table_length = htons(chp->table_length); + if (!(cdparr = malloc(sizeof(struct acd_softc) * chp->slots, + M_ACD, M_NOWAIT))) { + printf("acd: out of memory\n"); + return -1; + } for (count = 0; count < chp->slots; count++) { if (count > 0) { tmpcdp = acd_init_lun(atp, cdp->stats); @@ -165,27 +171,36 @@ acdattach(struct atapi_softc *atp) return -1; } } + cdparr[count] = tmpcdp; + tmpcdp->driver = cdparr; tmpcdp->slot = count; tmpcdp->changer_info = chp; if (bootverbose) printf("acd%d: changer slot %d %s\n", tmpcdp->lun, count, (chp->slot[count].present ? "CD present" : "empty")); + acd_make_dev(tmpcdp); } - sprintf(string, "acd%d-", cdp->lun); + sprintf(string, "acd%d-%d", cdp->lun, + cdp->lun + cdp->changer_info->slots - 1); devstat_add_entry(cdp->stats, string, tmpcdp->lun, DEV_BSIZE, DEVSTAT_NO_ORDERED_TAGS, DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_CD); - acd_make_dev(cdp); + if ((cdp->atp->devname = malloc(8, M_ACD, M_NOWAIT))) + sprintf(cdp->atp->devname, "acd%d-%d", cdp->lun, + cdp->lun + cdp->changer_info->slots - 1); } } else { + acd_make_dev(cdp); devstat_add_entry(cdp->stats, "acd", cdp->lun, DEV_BSIZE, DEVSTAT_NO_ORDERED_TAGS, DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE, DEVSTAT_PRIORITY_CD); - acd_make_dev(cdp); + if ((cdp->atp->devname = malloc(8, M_ACD, M_NOWAIT))) + sprintf(cdp->atp->devname, "acd%d", cdp->lun); } + cdp->atp->driver = cdp; acd_describe(cdp); return 0; } @@ -232,7 +247,6 @@ acd_init_lun(struct atapi_softc *atp, struct devstat *stats) } else cdp->stats = stats; - return cdp; } @@ -254,9 +268,6 @@ acd_make_dev(struct acd_softc *cdp) dev->si_bsize_phys = 2048; /* XXX SOS */ cdp->dev2 = dev; cdp->atp->flags |= ATAPI_F_MEDIA_CHANGED; - cdp->atp->driver = cdp; - if ((cdp->atp->devname = malloc(8, M_ACD, M_NOWAIT))) - sprintf(cdp->atp->devname, "acd%d", cdp->lun); } static void @@ -483,6 +494,10 @@ acdopen(dev_t dev, int32_t flags, int32_t fmt, struct proc *p) return EBUSY; } if (count_dev(dev) == 1) { + if (cdp->slot != cdp->changer_info->current_slot) { + acd_select_slot(cdp); + tsleep(&cdp->changer_info, PRIBIO, "acdopn", 0); + } acd_prevent_allow(cdp, 1); cdp->flags |= F_LOCKED; if (!(flags & O_NONBLOCK) && !(flags & FWRITE)) @@ -499,9 +514,13 @@ acdclose(dev_t dev, int32_t flags, int32_t fmt, struct proc *p) { struct acd_softc *cdp = dev->si_drv1; - if (count_dev(dev) == 1) + if (count_dev(dev) == 1) { + if (cdp->slot != cdp->changer_info->current_slot) { + acd_select_slot(cdp); + tsleep(&cdp->changer_info, PRIBIO, "acdclo", 0); + } acd_prevent_allow(cdp, 0); - + } cdp->flags &= ~F_LOCKED; return 0; } @@ -512,6 +531,10 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flags, struct proc *p) struct acd_softc *cdp = dev->si_drv1; int32_t error = 0; + if (cdp->slot != cdp->changer_info->current_slot) { + acd_select_slot(cdp); + tsleep(&cdp->changer_info, PRIBIO, "acdctl", 0); + } if (cdp->atp->flags & ATAPI_F_MEDIA_CHANGED) switch (cmd) { case CDIOCRESET: @@ -543,13 +566,11 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flags, struct proc *p) break; case CDIOCALLOW: - acd_select_slot(cdp); cdp->flags &= ~F_LOCKED; error = acd_prevent_allow(cdp, 0); break; case CDIOCPREVENT: - acd_select_slot(cdp); cdp->flags |= F_LOCKED; error = acd_prevent_allow(cdp, 1); break; @@ -1093,9 +1114,26 @@ acd_start(struct atapi_softc *atp) u_int32_t lba, count; int8_t ccb[16]; + if (cdp->changer_info) { + int i; + + cdp = cdp->driver[cdp->changer_info->current_slot]; + bp = bufq_first(&cdp->buf_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 (bufq_first(&(cdp->driver[i]->buf_queue))) { + if (!bp || time_second > (cdp->timestamp + 10)) { + acd_select_slot(cdp->driver[i]); + return; + } + } + } + } if (!bp) return; - bufq_remove(&cdp->buf_queue, bp); /* reject all queued entries if media changed */ @@ -1106,7 +1144,6 @@ acd_start(struct atapi_softc *atp) return; } - acd_select_slot(cdp); bzero(ccb, sizeof(ccb)); count = (bp->b_bcount + (cdp->block_size - 1)) / cdp->block_size; if (bp->b_flags & B_PHYS) @@ -1128,7 +1165,7 @@ acd_start(struct atapi_softc *atp) ccb[0] = ATAPI_READ_BIG; else { ccb[0] = ATAPI_READ_CD; - ccb[9] = 0xf8; + ccb[9] = 0x10; } } else @@ -1151,7 +1188,7 @@ acd_start(struct atapi_softc *atp) static int32_t acd_done(struct atapi_request *request) { - struct buf *bp = request->bp; + struct buf *bp = request->driver; struct acd_softc *cdp = request->device->driver; if (request->error) { @@ -1168,7 +1205,7 @@ acd_done(struct atapi_request *request) return 0; } -static int32_t +static void acd_read_toc(struct acd_softc *cdp) { int32_t ntracks, len; @@ -1179,7 +1216,6 @@ acd_read_toc(struct acd_softc *cdp) bzero(ccb, sizeof(ccb)); atapi_test_ready(cdp->atp); - acd_select_slot(cdp); if (cdp->atp->flags & ATAPI_F_MEDIA_CHANGED) cdp->flags &= ~(F_WRITTEN | F_DISK_OPEN | F_TRACK_OPEN); @@ -1193,12 +1229,12 @@ acd_read_toc(struct acd_softc *cdp) if (atapi_queue_cmd(cdp->atp, ccb, &cdp->toc, len, ATPR_F_READ, 30, NULL, NULL)) { bzero(&cdp->toc, sizeof(cdp->toc)); - return 0; + return; } ntracks = cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1; if (ntracks <= 0 || ntracks > MAXTRK) { bzero(&cdp->toc, sizeof(cdp->toc)); - return 0; + return; } len = sizeof(struct ioc_toc_header)+(ntracks+1)*sizeof(struct cd_toc_entry); @@ -1209,7 +1245,7 @@ acd_read_toc(struct acd_softc *cdp) if (atapi_queue_cmd(cdp->atp, ccb, &cdp->toc, len, ATPR_F_READ, 30, NULL, NULL)) { bzero(&cdp->toc, sizeof(cdp->toc)); - return 0; + return; } cdp->toc.hdr.len = ntohs(cdp->toc.hdr.len); @@ -1236,7 +1272,7 @@ acd_read_toc(struct acd_softc *cdp) cdp->toc.hdr.ending_track - cdp->toc.hdr.starting_track + 1); } #endif - return 0; + return; } static void @@ -1287,39 +1323,39 @@ acd_setchan(struct acd_softc *cdp, return acd_mode_select(cdp, &cdp->au, sizeof(cdp->au)); } -static void -acd_select_slot(struct acd_softc *cdp) +static int32_t +acd_select_done1(struct atapi_request *request) { - int8_t ccb[16]; - - if (cdp->slot < 0 || cdp->changer_info->current_slot == cdp->slot) - return; - - /* unlock (might not be needed but its cheaper than asking) */ - acd_prevent_allow(cdp, 0); + struct acd_softc *cdp = request->driver; + cdp->changer_info->current_slot = cdp->slot; + cdp->driver[cdp->changer_info->current_slot]->timestamp = time_second; + wakeup(&cdp->changer_info); + return 0; +} - /* unload the current media from player */ - bzero(ccb, sizeof(ccb)); - ccb[0] = ATAPI_LOAD_UNLOAD; - ccb[4] = 2; - ccb[8] = cdp->changer_info->current_slot; - atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 30, NULL, NULL); +static int32_t +acd_select_done(struct atapi_request *request) +{ + struct acd_softc *cdp = request->driver; + int8_t ccb[16] = { ATAPI_LOAD_UNLOAD, 0, 0, 0, 3, 0, 0, 0, + cdp->slot, 0, 0, 0, 0, 0, 0, 0 }; /* load the wanted slot */ - bzero(ccb, sizeof(ccb)); - ccb[0] = ATAPI_LOAD_UNLOAD; - ccb[1] = 0x01; - ccb[4] = 3; - ccb[8] = cdp->slot; - atapi_queue_cmd(cdp->atp, ccb, NULL, 0, 0, 10, NULL, NULL); - atapi_wait_ready(cdp->atp, 30); + atapi_queue_cmd(cdp->atp, ccb, NULL, 0, ATPR_F_AT_HEAD, 30, + acd_select_done1, cdp); + return 0; +} - cdp->changer_info->current_slot = cdp->slot; +static void +acd_select_slot(struct acd_softc *cdp) +{ + int8_t ccb[16] = { ATAPI_LOAD_UNLOAD, 0, 0, 0, 2, 0, 0, 0, + cdp->changer_info->current_slot, 0, 0, 0, 0, 0, 0, 0 }; - /* lock the media if needed */ - if (cdp->flags & F_LOCKED) - acd_prevent_allow(cdp, 1); + /* unload the current media from player */ + atapi_queue_cmd(cdp->atp, ccb, NULL, 0, ATPR_F_AT_HEAD, 30, + acd_select_done, cdp); } static int32_t @@ -1695,7 +1731,6 @@ acd_eject(struct acd_softc *cdp, int32_t close) { int32_t error; - acd_select_slot(cdp); if ((error = acd_start_stop(cdp, 0)) == EBUSY) { if (!close) return 0; diff --git a/sys/dev/ata/atapi-cd.h b/sys/dev/ata/atapi-cd.h index 5e46b91..eed3647 100644 --- a/sys/dev/ata/atapi-cd.h +++ b/sys/dev/ata/atapi-cd.h @@ -337,7 +337,9 @@ struct acd_softc { u_int32_t rellba; } subchan; struct changer *changer_info; /* changer info */ - int32_t slot; /* this lun's slot number */ + struct acd_softc **driver; /* softc's of changer slots */ + int32_t slot; /* this instance slot number */ + time_t timestamp; /* this instance timestamp */ u_int32_t block_size; /* blocksize currently used */ struct disklabel disklabel; /* fake disk label */ struct devstat *stats; /* devstat entry */ diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c index 6588684..c0a8cc4 100644 --- a/sys/dev/ata/atapi-fd.c +++ b/sys/dev/ata/atapi-fd.c @@ -360,7 +360,7 @@ afd_start(struct atapi_softc *atp) static int32_t afd_partial_done(struct atapi_request *request) { - struct buf *bp = request->bp; + struct buf *bp = request->driver; if (request->error) { bp->b_error = request->error; @@ -373,7 +373,7 @@ afd_partial_done(struct atapi_request *request) static int32_t afd_done(struct atapi_request *request) { - struct buf *bp = request->bp; + struct buf *bp = request->driver; struct afd_softc *fdp = request->device->driver; if (request->error || (bp->b_flags & B_ERROR)) { diff --git a/sys/dev/ata/atapi-tape.c b/sys/dev/ata/atapi-tape.c index 3d08eba..fc7bee4 100644 --- a/sys/dev/ata/atapi-tape.c +++ b/sys/dev/ata/atapi-tape.c @@ -488,7 +488,7 @@ ast_start(struct atapi_softc *atp) static int32_t ast_done(struct atapi_request *request) { - struct buf *bp = request->bp; + struct buf *bp = request->driver; struct ast_softc *stp = request->device->driver; if (request->error) { |