Make ATAPI CD changer devices work, hopefully better than before.

This commit is contained in:
sos 2000-03-21 13:26:54 +00:00
parent da862b0d61
commit 3326256bf0
6 changed files with 115 additions and 61 deletions

View File

@ -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 @@ atapi_interrupt(struct atapi_request *request)
}
}
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);
}

View File

@ -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);

View File

@ -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);
/* 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);
/* 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);
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;
}
/* lock the media if needed */
if (cdp->flags & F_LOCKED)
acd_prevent_allow(cdp, 1);
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 */
atapi_queue_cmd(cdp->atp, ccb, NULL, 0, ATPR_F_AT_HEAD, 30,
acd_select_done1, cdp);
return 0;
}
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 };
/* 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;

View File

@ -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 */

View File

@ -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)) {

View File

@ -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) {