Make ATAPI CD changer devices work, hopefully better than before.
This commit is contained in:
parent
da862b0d61
commit
3326256bf0
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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)) {
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user