summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2000-03-21 13:26:54 +0000
committersos <sos@FreeBSD.org>2000-03-21 13:26:54 +0000
commit3326256bf03e795dff052bf0fd8db5cdf670f414 (patch)
treea185b13729282e7c2ea9a3a2008ad8b51ab74b60 /sys
parentda862b0d617e5f9a1807469a83448df6609fcebb (diff)
downloadFreeBSD-src-3326256bf03e795dff052bf0fd8db5cdf670f414.zip
FreeBSD-src-3326256bf03e795dff052bf0fd8db5cdf670f414.tar.gz
Make ATAPI CD changer devices work, hopefully better than before.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/ata/atapi-all.c22
-rw-r--r--sys/dev/ata/atapi-all.h5
-rw-r--r--sys/dev/ata/atapi-cd.c133
-rw-r--r--sys/dev/ata/atapi-cd.h4
-rw-r--r--sys/dev/ata/atapi-fd.c4
-rw-r--r--sys/dev/ata/atapi-tape.c2
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) {
OpenPOWER on IntegriCloud