summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ata/ata-all.c1581
-rw-r--r--sys/dev/ata/ata-all.h250
-rw-r--r--sys/dev/ata/ata-card.c5
-rw-r--r--sys/dev/ata/ata-cbus.c1
-rw-r--r--sys/dev/ata/ata-chipset.c487
-rw-r--r--sys/dev/ata/ata-commands.h127
-rw-r--r--sys/dev/ata/ata-disk.c785
-rw-r--r--sys/dev/ata/ata-disk.h37
-rw-r--r--sys/dev/ata/ata-dma.c37
-rw-r--r--sys/dev/ata/ata-isa.c9
-rw-r--r--sys/dev/ata/ata-lowlevel.c787
-rw-r--r--sys/dev/ata/ata-pci.c17
-rw-r--r--sys/dev/ata/ata-pci.h9
-rw-r--r--sys/dev/ata/ata-queue.c471
-rw-r--r--sys/dev/ata/ata-raid.c68
-rw-r--r--sys/dev/ata/ata-raid.h2
-rw-r--r--sys/dev/ata/atapi-all.c699
-rw-r--r--sys/dev/ata/atapi-all.h196
-rw-r--r--sys/dev/ata/atapi-cam.c228
-rw-r--r--sys/dev/ata/atapi-cd.c562
-rw-r--r--sys/dev/ata/atapi-cd.h182
-rw-r--r--sys/dev/ata/atapi-fd.c198
-rw-r--r--sys/dev/ata/atapi-fd.h1
-rw-r--r--sys/dev/ata/atapi-tape.c257
-rw-r--r--sys/dev/ata/atapi-tape.h1
25 files changed, 3336 insertions, 3661 deletions
diff --git a/sys/dev/ata/ata-all.c b/sys/dev/ata/ata-all.c
index cb77622..8d0923a 100644
--- a/sys/dev/ata/ata-all.c
+++ b/sys/dev/ata/ata-all.c
@@ -33,12 +33,14 @@
#include <sys/systm.h>
#include <sys/ata.h>
#include <sys/kernel.h>
+#include <sys/endian.h>
#include <sys/conf.h>
-#include <sys/module.h>
#include <sys/bus.h>
#include <sys/bio.h>
#include <sys/malloc.h>
+#include <sys/mutex.h>
#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
#include <machine/stdarg.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -50,33 +52,35 @@
#include <dev/ata/ata-all.h>
#include <dev/ata/ata-disk.h>
#include <dev/ata/ata-raid.h>
-#include <dev/ata/atapi-all.h>
/* device structures */
-static d_ioctl_t ataioctl;
+static d_ioctl_t ata_ioctl;
static struct cdevsw ata_cdevsw = {
.d_open = nullopen,
.d_close = nullclose,
- .d_ioctl = ataioctl,
+ .d_ioctl = ata_ioctl,
.d_name = "ata",
.d_maj = 159,
};
/* prototypes */
+static void ata_shutdown(void *arg, int howto);
+static int ata_getparam(struct ata_device *atadev, u_int8_t command);
+static void ata_identify_devices(struct ata_channel *ch);
static void ata_boot_attach(void);
-static void ata_intr(void *);
-static int ata_getparam(struct ata_device *, u_int8_t);
-static int ata_service(struct ata_channel *);
-static void ata_flush(struct ata_device *);
-static void bswap(int8_t *, int);
-static void btrim(int8_t *, int);
-static void bpack(int8_t *, int8_t *, int);
-static void ata_change_mode(struct ata_device *, int);
-static u_int8_t ata_enclosure_sensor(struct ata_device *, int, u_int8_t, u_int8_t);
-static int ata_enclosure_status(struct ata_device *, int *, int *, int *, int *);
+static void bswap(int8_t *buf, int len);
+static void btrim(int8_t *buf, int len);
+static void bpack(int8_t *src, int8_t *dst, int len);
+static void ata_init(void);
/* sysctl vars */
SYSCTL_NODE(_hw, OID_AUTO, ata, CTLFLAG_RD, 0, "ATA driver parameters");
+TUNABLE_INT("hw.ata.ata_dma", &ata_dma);
+TUNABLE_INT("hw.ata.wc", &ata_wc);
+TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma);
+int ata_dma = 1;
+int ata_wc = 1;
+int atapi_dma = 0;
/* global vars */
struct intr_config_hook *ata_delayed_attach = NULL;
@@ -85,10 +89,9 @@ devclass_t ata_devclass;
/* local vars */
static MALLOC_DEFINE(M_ATA, "ATA generic", "ATA driver generic layer");
-/* misc defines */
-#define DEV_ATAPIALL defined(DEV_ATAPICD) || defined(DEV_ATAPIFD) || \
- defined(DEV_ATAPIST) || defined(DEV_ATAPICAM)
-
+/*
+ * newbus device interface related functions
+ */
int
ata_probe(device_t dev)
{
@@ -101,20 +104,22 @@ ata_probe(device_t dev)
return EEXIST;
/* initialize the softc basics */
- ch->active = ATA_IDLE;
- ch->dev = dev;
+ ata_generic_hw(ch);
ch->device[MASTER].channel = ch;
ch->device[MASTER].unit = ATA_MASTER;
ch->device[MASTER].mode = ATA_PIO;
ch->device[SLAVE].channel = ch;
ch->device[SLAVE].unit = ATA_SLAVE;
ch->device[SLAVE].mode = ATA_PIO;
+ ch->dev = dev;
+ ch->state = ATA_IDLE;
+ bzero(&ch->queue_mtx, sizeof(struct mtx));
+ mtx_init(&ch->queue_mtx, "ATA queue lock", MTX_DEF, 0);
TAILQ_INIT(&ch->ata_queue);
- TAILQ_INIT(&ch->atapi_queue);
/* initialise device(s) on this channel */
ch->locking(ch, ATA_LF_LOCK);
- ata_reset(ch);
+ ch->hw.reset(ch);
ch->locking(ch, ATA_LF_UNLOCK);
return 0;
}
@@ -135,8 +140,8 @@ ata_attach(device_t dev)
ata_printf(ch, -1, "unable to allocate interrupt\n");
return ENXIO;
}
- if ((error = bus_setup_intr(dev, ch->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
- ata_intr, ch, &ch->ih))) {
+ if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS,
+ ch->hw.interrupt, ch, &ch->ih))) {
ata_printf(ch, -1, "unable to setup interrupt\n");
return error;
}
@@ -144,42 +149,19 @@ ata_attach(device_t dev)
if (ch->dma)
ch->dma->alloc(ch);
- /*
- * do not attach devices if we are in early boot, this is done later
- * when interrupts are enabled by a hook into the boot process.
- * otherwise attach what the probe has found in ch->devices.
- */
- if (!ata_delayed_attach) {
- ch->locking(ch, ATA_LF_LOCK);
- if (ch->devices & ATA_ATA_SLAVE)
- if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY))
- ch->devices &= ~ATA_ATA_SLAVE;
- if (ch->devices & ATA_ATAPI_SLAVE)
- if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY))
- ch->devices &= ~ATA_ATAPI_SLAVE;
- if (ch->devices & ATA_ATA_MASTER)
- if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY))
- ch->devices &= ~ATA_ATA_MASTER;
- if (ch->devices & ATA_ATAPI_MASTER)
- if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY))
- ch->devices &= ~ATA_ATAPI_MASTER;
-#ifdef DEV_ATADISK
- if (ch->devices & ATA_ATA_MASTER)
- ad_attach(&ch->device[MASTER]);
- if (ch->devices & ATA_ATA_SLAVE)
- ad_attach(&ch->device[SLAVE]);
-#endif
-#if DEV_ATAPIALL
- if (ch->devices & ATA_ATAPI_MASTER)
- atapi_attach(&ch->device[MASTER]);
- if (ch->devices & ATA_ATAPI_SLAVE)
- atapi_attach(&ch->device[SLAVE]);
-#endif
+ /* do not attach devices if we are in early boot */
+ if (ata_delayed_attach)
+ return 0;
+
+ ata_identify_devices(ch);
+
+ if (ch->device[MASTER].attach)
+ ch->device[MASTER].attach(&ch->device[MASTER]);
+ if (ch->device[SLAVE].attach)
+ ch->device[SLAVE].attach(&ch->device[SLAVE]);
#ifdef DEV_ATAPICAM
- atapi_cam_attach_bus(ch);
+ atapi_cam_attach_bus(ch);
#endif
- ch->locking(ch, ATA_LF_UNLOCK);
- }
return 0;
}
@@ -187,56 +169,97 @@ int
ata_detach(device_t dev)
{
struct ata_channel *ch;
- int s;
+ struct ata_request *request;
if (!dev || !(ch = device_get_softc(dev)) || !ch->r_irq)
return ENXIO;
- /* make sure channel is not busy */
- ch->locking(ch, ATA_LF_LOCK);
- ATA_SLEEPLOCK_CH(ch, ATA_CONTROL);
-
- s = splbio();
-#ifdef DEV_ATADISK
- if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver)
- ad_detach(&ch->device[MASTER]);
- if (ch->devices & ATA_ATA_SLAVE && ch->device[SLAVE].driver)
- ad_detach(&ch->device[SLAVE]);
-#endif
-#if DEV_ATAPIALL
- if (ch->devices & ATA_ATAPI_MASTER && ch->device[MASTER].driver)
- atapi_detach(&ch->device[MASTER]);
- if (ch->devices & ATA_ATAPI_SLAVE && ch->device[SLAVE].driver)
- atapi_detach(&ch->device[SLAVE]);
-#endif
+ /* detach devices on this channel */
+ if (ch->device[MASTER].detach)
+ ch->device[MASTER].detach(&ch->device[MASTER]);
+ if (ch->device[SLAVE].detach)
+ ch->device[SLAVE].detach(&ch->device[SLAVE]);
#ifdef DEV_ATAPICAM
atapi_cam_detach_bus(ch);
#endif
- splx(s);
+
+ /* fail outstanding requests on this channel */
+ mtx_lock(&ch->queue_mtx);
+ while ((request = TAILQ_FIRST(&ch->ata_queue))) {
+ TAILQ_REMOVE(&ch->ata_queue, request, chain);
+ request->status = ATA_S_ERROR;
+ mtx_unlock(&ch->queue_mtx);
+ ata_finish(request);
+ mtx_lock(&ch->queue_mtx);
+ }
+ mtx_unlock(&ch->queue_mtx);
if (ch->device[MASTER].param) {
- ata_flush(&ch->device[MASTER]);
+ ata_controlcmd(&ch->device[MASTER], ATA_FLUSHCACHE, 0, 0, 0);
free(ch->device[MASTER].param, M_ATA);
ch->device[MASTER].param = NULL;
}
if (ch->device[SLAVE].param) {
- ata_flush(&ch->device[SLAVE]);
+ ata_controlcmd(&ch->device[SLAVE], ATA_FLUSHCACHE, 0, 0, 0);
free(ch->device[SLAVE].param, M_ATA);
ch->device[SLAVE].param = NULL;
}
- ch->device[MASTER].driver = NULL;
- ch->device[SLAVE].driver = NULL;
ch->device[MASTER].mode = ATA_PIO;
ch->device[SLAVE].mode = ATA_PIO;
ch->devices = 0;
+
if (ch->dma)
ch->dma->free(ch);
bus_teardown_intr(dev, ch->r_irq, ch->ih);
bus_release_resource(dev, SYS_RES_IRQ, ATA_IRQ_RID, ch->r_irq);
ch->r_irq = NULL;
+ return 0;
+}
+
+int
+ata_reinit(struct ata_channel *ch)
+{
+ int devices, misdev, newdev;
+
+ if (!ch->r_irq)
+ return ENXIO;
+
+ /* reset the HW */
+ ata_printf(ch, -1, "resetting devices ..\n");
+ ATA_FORCELOCK_CH(ch, ATA_CONTROL);
+ ch->running = NULL;
+ devices = ch->devices;
+ ch->hw.reset(ch);
ATA_UNLOCK_CH(ch);
- ch->locking(ch, ATA_LF_UNLOCK);
+
+ /* detach what left the channel during reset */
+ if ((misdev = devices & ~ch->devices)) {
+ if ((misdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) &&
+ ch->device[MASTER].detach)
+ ch->device[MASTER].detach(&ch->device[MASTER]);
+ if ((misdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) &&
+ ch->device[SLAVE].detach)
+ ch->device[SLAVE].detach(&ch->device[SLAVE]);
+ }
+
+ /* identify whats present on this channel now */
+ ata_identify_devices(ch);
+
+ /* attach new devices that appeared during reset */
+ if ((newdev = ~devices & ch->devices)) {
+ if ((newdev & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) &&
+ ch->device[MASTER].attach)
+ ch->device[MASTER].attach(&ch->device[MASTER]);
+ if ((newdev & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) &&
+ ch->device[SLAVE].attach)
+ ch->device[SLAVE].attach(&ch->device[SLAVE]);
+ }
+#ifdef DEV_ATAPICAM
+ atapi_cam_reinit_bus(ch);
+#endif
+
+ printf("done\n");
return 0;
}
@@ -265,1094 +288,428 @@ ata_resume(device_t dev)
ch->locking(ch, ATA_LF_LOCK);
error = ata_reinit(ch);
ch->locking(ch, ATA_LF_UNLOCK);
+ ata_start(ch);
return error;
}
-static int
-ataioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td)
+static void
+ata_shutdown(void *arg, int howto)
{
- struct ata_cmd *iocmd = (struct ata_cmd *)addr;
struct ata_channel *ch;
- device_t device = devclass_get_device(ata_devclass, iocmd->channel);
- int error;
+ int ctlr;
- if (cmd != IOCATA)
- return ENOTTY;
-
- if (iocmd->cmd == ATAGMAXCHANNEL) {
- iocmd->u.maxchan = devclass_get_maxunit(ata_devclass);
- return 0;
+ /* flush cache on all devices */
+ for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
+ if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
+ continue;
+ if (ch->device[MASTER].param)
+ ata_controlcmd(&ch->device[MASTER], ATA_FLUSHCACHE, 0, 0, 0);
+ if (ch->device[SLAVE].param)
+ ata_controlcmd(&ch->device[SLAVE], ATA_FLUSHCACHE, 0, 0, 0);
}
+}
- if (iocmd->channel < -1 || iocmd->device < -1 || iocmd->device > SLAVE)
- return ENXIO;
+/*
+ * device related interfaces
+ */
+static int
+ata_ioctl(dev_t dev, u_long cmd, caddr_t addr, int32_t flag, struct thread *td)
+{
+ struct ata_cmd *iocmd = (struct ata_cmd *)addr;
+ device_t device = devclass_get_device(ata_devclass, iocmd->channel);
+ struct ata_channel *ch;
+ struct ata_device *atadev;
+ struct ata_request *request;
+ caddr_t buf;
+ int error = ENOTTY;
+ DROP_GIANT();
switch (iocmd->cmd) {
- case ATAATTACH:
- /* should enable channel HW on controller that can SOS XXX */
- error = ata_probe(device);
- if (!error)
- error = ata_attach(device);
- return error;
-
- case ATADETACH:
- error = ata_detach(device);
- /* should disable channel HW on controller that can SOS XXX */
- return error;
-
- case ATAREINIT:
- if (!device || !(ch = device_get_softc(device)))
- return ENXIO;
- ch->locking(ch, ATA_LF_LOCK);
- ATA_SLEEPLOCK_CH(ch, ATA_ACTIVE);
- error = ata_reinit(ch);
- ch->locking(ch, ATA_LF_UNLOCK);
- return error;
-
- case ATAGMODE:
- if (!device || !(ch = device_get_softc(device)))
- return ENXIO;
-
- if ((iocmd->device == MASTER || iocmd->device == -1) &&
- ch->device[MASTER].driver)
- iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode;
- else
- iocmd->u.mode.mode[MASTER] = -1;
-
- if ((iocmd->device == SLAVE || iocmd->device == -1) &&
- ch->device[SLAVE].param)
- iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode;
- else
- iocmd->u.mode.mode[SLAVE] = -1;
- return 0;
-
- case ATASMODE:
- if (!device || !(ch = device_get_softc(device)))
- return ENXIO;
-
- ch->locking(ch, ATA_LF_LOCK);
- if ((iocmd->device == MASTER || iocmd->device == -1) &&
- iocmd->u.mode.mode[MASTER] >= 0 && ch->device[MASTER].param) {
- ata_change_mode(&ch->device[MASTER],iocmd->u.mode.mode[MASTER]);
- iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode;
- }
- else
- iocmd->u.mode.mode[MASTER] = -1;
-
- if ((iocmd->device == SLAVE || iocmd->device == -1) &&
- iocmd->u.mode.mode[SLAVE] >= 0 && ch->device[SLAVE].param) {
- ata_change_mode(&ch->device[SLAVE], iocmd->u.mode.mode[SLAVE]);
- iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode;
- }
- else
- iocmd->u.mode.mode[SLAVE] = -1;
- ch->locking(ch, ATA_LF_UNLOCK);
- return 0;
-
- case ATAGPARM:
- if (!device || !(ch = device_get_softc(device)))
- return ENXIO;
-
- iocmd->u.param.type[MASTER] =
- ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER);
- iocmd->u.param.type[SLAVE] =
- ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE);
-
- if (ch->device[MASTER].name)
- strcpy(iocmd->u.param.name[MASTER], ch->device[MASTER].name);
- if (ch->device[SLAVE].name)
- strcpy(iocmd->u.param.name[SLAVE], ch->device[SLAVE].name);
-
- if (ch->device[MASTER].param)
- bcopy(ch->device[MASTER].param, &iocmd->u.param.params[MASTER],
- sizeof(struct ata_params));
- if (ch->device[SLAVE].param)
- bcopy(ch->device[SLAVE].param, &iocmd->u.param.params[SLAVE],
- sizeof(struct ata_params));
- return 0;
-
- case ATAENCSTAT: {
- struct ata_device *atadev;
-
- if (!device || !(ch = device_get_softc(device)))
- return ENXIO;
-
- if (iocmd->device == SLAVE)
- atadev = &ch->device[SLAVE];
- else
- atadev = &ch->device[MASTER];
+ case ATAGMAXCHANNEL:
+ iocmd->u.maxchan = devclass_get_maxunit(ata_devclass);
+ error = 0;
+ break;
- return ata_enclosure_status(atadev,
- &iocmd->u.enclosure.fan,
- &iocmd->u.enclosure.temp,
- &iocmd->u.enclosure.v05,
- &iocmd->u.enclosure.v12);
+ case ATAGPARM:
+ if (!device || !(ch = device_get_softc(device))) {
+ error = ENXIO;
+ break;
}
+ iocmd->u.param.type[MASTER] =
+ ch->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER);
+ iocmd->u.param.type[SLAVE] =
+ ch->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE);
+ if (ch->device[MASTER].name)
+ strcpy(iocmd->u.param.name[MASTER], ch->device[MASTER].name);
+ if (ch->device[SLAVE].name)
+ strcpy(iocmd->u.param.name[SLAVE], ch->device[SLAVE].name);
+ if (ch->device[MASTER].param)
+ bcopy(ch->device[MASTER].param, &iocmd->u.param.params[MASTER],
+ sizeof(struct ata_params));
+ if (ch->device[SLAVE].param)
+ bcopy(ch->device[SLAVE].param, &iocmd->u.param.params[SLAVE],
+ sizeof(struct ata_params));
+ error = 0;
+ break;
-#ifdef DEV_ATADISK
- case ATARAIDREBUILD:
- return ata_raid_rebuild(iocmd->channel);
-
- case ATARAIDCREATE:
- return ata_raid_create(&iocmd->u.raid_setup);
-
- case ATARAIDDELETE:
- return ata_raid_delete(iocmd->channel);
+ case ATAGMODE:
+ if (!device || !(ch = device_get_softc(device))) {
+ error = ENXIO;
+ break;
+ }
+ iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode;
+ iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode;
+ error = 0;
+ break;
- case ATARAIDADDSPARE:
- return ata_raid_addspare(iocmd->channel, iocmd->u.raid_spare.disk);
+ case ATASMODE:
+ if (!device || !(ch = device_get_softc(device))) {
+ error = ENXIO;
+ break;
+ }
+ if (iocmd->u.mode.mode[MASTER] >= 0 && ch->device[MASTER].param)
+ ch->device[MASTER].setmode(&ch->device[MASTER],
+ iocmd->u.mode.mode[MASTER]);
+ iocmd->u.mode.mode[MASTER] = ch->device[MASTER].mode;
+ if (iocmd->u.mode.mode[SLAVE] >= 0 && ch->device[SLAVE].param)
+ ch->device[SLAVE].setmode(&ch->device[SLAVE],
+ iocmd->u.mode.mode[SLAVE]);
+ iocmd->u.mode.mode[SLAVE] = ch->device[SLAVE].mode;
+ error = 0;
+ break;
- case ATARAIDSTATUS:
- return ata_raid_status(iocmd->channel, &iocmd->u.raid_status);
-#endif
-#if DEV_ATAPIALL
- case ATAPICMD: {
- struct ata_device *atadev;
- caddr_t buf;
-
- if (!device || !(ch = device_get_softc(device)))
- return ENXIO;
-
- if (!(atadev = &ch->device[iocmd->device]) ||
- !(ch->devices & (iocmd->device == MASTER ?
- ATA_ATAPI_MASTER : ATA_ATAPI_SLAVE)))
- return ENODEV;
-
- if (!(buf = malloc(iocmd->u.atapi.count, M_ATA, M_NOWAIT)))
- return ENOMEM;
-
- if (iocmd->u.atapi.flags & ATAPI_CMD_WRITE) {
- error = copyin(iocmd->u.atapi.data, buf, iocmd->u.atapi.count);
- if (error) {
- free(buf, M_ATA);
- return error;
- }
- }
- error = atapi_queue_cmd(atadev, iocmd->u.atapi.ccb,
- buf, iocmd->u.atapi.count,
- (iocmd->u.atapi.flags == ATAPI_CMD_READ ?
- ATPR_F_READ : 0) | ATPR_F_QUIET,
- iocmd->u.atapi.timeout, NULL, NULL);
+ case ATAREQUEST:
+ if (!device || !(ch = device_get_softc(device))) {
+ error = ENXIO;
+ break;
+ }
+ if (!(atadev = &ch->device[iocmd->device])) {
+ error = ENODEV;
+ break;
+ }
+ if (!(buf = malloc(iocmd->u.request.count, M_ATA, M_NOWAIT))) {
+ error = ENOMEM;
+ break;
+ }
+ if (!(request = ata_alloc_request())) {
+ error = ENOMEM;
+ free(buf, M_ATA);
+ break;
+ }
+ if (iocmd->u.request.flags & ATA_CMD_WRITE) {
+ error = copyin(iocmd->u.request.data, buf, iocmd->u.request.count);
if (error) {
- iocmd->u.atapi.error = error;
- bcopy(&atadev->result, iocmd->u.atapi.sense_data,
- sizeof(struct atapi_reqsense));
- error = 0;
+ free(buf, M_ATA);
+ ata_free_request(request);
+ break;
}
- else if (iocmd->u.atapi.flags & ATAPI_CMD_READ)
- error = copyout(buf, iocmd->u.atapi.data, iocmd->u.atapi.count);
-
- free(buf, M_ATA);
- return error;
}
-#endif
- default:
- break;
- }
- return ENOTTY;
-}
-
-static int
-ata_getparam(struct ata_device *atadev, u_int8_t command)
-{
- struct ata_params *ata_parm;
- int retry = 0;
-
- if (!(ata_parm = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT))) {
- ata_prtdev(atadev, "malloc for identify data failed\n");
- return -1;
- }
+
+ request->device = atadev;
- /* apparently some devices needs this repeated */
- do {
- if (ata_command(atadev, command, 0, 0, 0,
- dumping ? ATA_WAIT_READY : ATA_WAIT_INTR)) {
- ata_prtdev(atadev, "%s identify failed\n",
- command == ATA_C_ATAPI_IDENTIFY ? "ATAPI" : "ATA");
- free(ata_parm, M_ATA);
- return -1;
+ if (iocmd->u.request.flags & ATA_CMD_ATAPI) {
+ request->flags = ATA_R_ATAPI;
+ bcopy(iocmd->u.request.u.atapi.ccb, request->u.atapi.ccb, 16);
}
- if (retry++ > 4) {
- ata_prtdev(atadev, "%s identify retries exceeded\n",
- command == ATA_C_ATAPI_IDENTIFY ? "ATAPI" : "ATA");
- free(ata_parm, M_ATA);
- return -1;
+ else {
+ request->u.ata.command = iocmd->u.request.u.ata.command;
+ request->u.ata.feature = iocmd->u.request.u.ata.feature;
+ request->u.ata.lba = iocmd->u.request.u.ata.lba;
+ request->u.ata.count = iocmd->u.request.u.ata.count;
}
- } while (ata_wait(atadev, ((command == ATA_C_ATAPI_IDENTIFY) ?
- ATA_S_DRQ : (ATA_S_READY|ATA_S_DSC|ATA_S_DRQ))));
- ATA_IDX_INSW(atadev->channel, ATA_DATA, (int16_t *)ata_parm,
- sizeof(struct ata_params)/sizeof(int16_t));
-
- if (command == ATA_C_ATA_IDENTIFY ||
- !((ata_parm->model[0] == 'N' && ata_parm->model[1] == 'E') ||
- (ata_parm->model[0] == 'F' && ata_parm->model[1] == 'X') ||
- (ata_parm->model[0] == 'P' && ata_parm->model[1] == 'i')))
- bswap(ata_parm->model, sizeof(ata_parm->model));
- btrim(ata_parm->model, sizeof(ata_parm->model));
- bpack(ata_parm->model, ata_parm->model, sizeof(ata_parm->model));
- bswap(ata_parm->revision, sizeof(ata_parm->revision));
- btrim(ata_parm->revision, sizeof(ata_parm->revision));
- bpack(ata_parm->revision, ata_parm->revision, sizeof(ata_parm->revision));
- bswap(ata_parm->serial, sizeof(ata_parm->serial));
- btrim(ata_parm->serial, sizeof(ata_parm->serial));
- bpack(ata_parm->serial, ata_parm->serial, sizeof(ata_parm->serial));
- atadev->param = ata_parm;
- return 0;
-}
-static void
-ata_boot_attach(void)
-{
- struct ata_channel *ch;
- int ctlr;
+ request->timeout = iocmd->u.request.timeout;
+ request->data = buf;
+ request->bytecount = iocmd->u.request.count;
+ request->transfersize = request->bytecount;
- /*
- * run through all ata devices and look for real ATA & ATAPI devices
- * using the hints we found in the early probe, this avoids some of
- * the delays probing of non-exsistent devices can cause.
- */
- for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
- if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
- continue;
- ch->locking(ch, ATA_LF_LOCK);
- if (ch->devices & ATA_ATA_SLAVE)
- if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY))
- ch->devices &= ~ATA_ATA_SLAVE;
- if (ch->devices & ATA_ATAPI_SLAVE)
- if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY))
- ch->devices &= ~ATA_ATAPI_SLAVE;
- if (ch->devices & ATA_ATA_MASTER)
- if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY))
- ch->devices &= ~ATA_ATA_MASTER;
- if (ch->devices & ATA_ATAPI_MASTER)
- if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY))
- ch->devices &= ~ATA_ATAPI_MASTER;
- ch->locking(ch, ATA_LF_UNLOCK);
- }
-#ifdef DEV_ATADISK
- /* now we know whats there, do the real attach, first the ATA disks */
- for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
- if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
- continue;
- ch->locking(ch, ATA_LF_LOCK);
- if (ch->devices & ATA_ATA_MASTER)
- ad_attach(&ch->device[MASTER]);
- if (ch->devices & ATA_ATA_SLAVE)
- ad_attach(&ch->device[SLAVE]);
- ch->locking(ch, ATA_LF_UNLOCK);
- }
-#endif
- /* then the atapi devices */
- for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
- if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
- continue;
- ch->locking(ch, ATA_LF_LOCK);
-#if DEV_ATAPIALL
- if (ch->devices & ATA_ATAPI_MASTER)
- atapi_attach(&ch->device[MASTER]);
- if (ch->devices & ATA_ATAPI_SLAVE)
- atapi_attach(&ch->device[SLAVE]);
-#endif
-#ifdef DEV_ATAPICAM
- atapi_cam_attach_bus(ch);
-#endif
- ch->locking(ch, ATA_LF_UNLOCK);
- }
- if (ata_delayed_attach) {
- config_intrhook_disestablish(ata_delayed_attach);
- free(ata_delayed_attach, M_TEMP);
- ata_delayed_attach = NULL;
- }
-#ifdef DEV_ATADISK
- ata_raid_attach();
-#endif
-}
+ if (iocmd->u.request.flags & ATA_CMD_CONTROL)
+ request->flags |= ATA_R_CONTROL;
+ if (iocmd->u.request.flags & ATA_CMD_READ)
+ request->flags |= ATA_R_READ;
+ if (iocmd->u.request.flags & ATA_CMD_WRITE)
+ request->flags |= ATA_R_WRITE;
-static void
-ata_intr(void *data)
-{
- struct ata_channel *ch = (struct ata_channel *)data;
+ ata_queue_request(request);
- /* if device is busy it didn't interrupt */
- if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
- DELAY(100);
- if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DRQ))
- return;
- }
+ if (request->error)
+ iocmd->u.request.error = request->error;
+ else {
+ if (iocmd->u.request.flags & ATA_CMD_READ)
+ error = copyout(buf,
+ iocmd->u.request.data, iocmd->u.request.count);
+ else
+ error = 0;
+ }
+ free(buf, M_ATA);
+ ata_free_request(request);
+ break;
- /* clear interrupt and get status */
- ch->status = ATA_IDX_INB(ch, ATA_STATUS);
+ case ATAREINIT:
+ if (!device || !(ch = device_get_softc(device)))
+ return ENXIO;
+ error = ata_reinit(ch);
+ ata_start(ch);
+ break;
- if (ch->status & ATA_S_ERROR)
- ch->error = ATA_IDX_INB(ch, ATA_ERROR);
+ case ATAATTACH:
+ if (!device) {
+ error = ENXIO;
+ break;
+ }
+ /* SOS should enable channel HW on controller XXX */
+ error = ata_probe(device);
+ if (!error)
+ error = ata_attach(device);
+ break;
- /* find & call the responsible driver to process this interrupt */
- switch (ch->active) {
-#ifdef DEV_ATADISK
- case ATA_ACTIVE_ATA:
- if (!ch->running || ad_interrupt(ch->running) == ATA_OP_CONTINUES)
- return;
+ case ATADETACH:
+ if (!device) {
+ error = ENXIO;
+ break;
+ }
+ error = ata_detach(device);
+ /* SOS should disable channel HW on controller XXX */
break;
-#endif
-#if DEV_ATAPIALL
- case ATA_ACTIVE_ATAPI:
- if (!ch->running || atapi_interrupt(ch->running) == ATA_OP_CONTINUES)
- return;
+
+
+#ifdef DEV_ATARAID
+ case ATARAIDCREATE:
+ error = ata_raid_create(&iocmd->u.raid_setup);
+ break;
+
+ case ATARAIDDELETE:
+ error = ata_raid_delete(iocmd->channel);
+ break;
+
+ case ATARAIDSTATUS:
+ error = ata_raid_status(iocmd->channel, &iocmd->u.raid_status);
+ break;
+
+ case ATARAIDADDSPARE:
+ error = ata_raid_addspare(iocmd->channel, iocmd->u.raid_spare.disk);
+ break;
+
+ case ATARAIDREBUILD:
+ error = ata_raid_rebuild(iocmd->channel);
break;
#endif
- default:
- if (ch->active & ATA_WAIT_INTR)
- wakeup(ch);
}
-
- if (ch->active & ATA_CONTROL) {
- ATA_FORCELOCK_CH(ch, ATA_CONTROL);
- return;
- }
-
- if (ch->active & ATA_WAIT_INTR) {
- ATA_UNLOCK_CH(ch);
- return;
- }
-
- if ((ch->flags & ATA_QUEUED) &&
- ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_SERVICE) {
- ATA_FORCELOCK_CH(ch, ATA_ACTIVE);
- if (ata_service(ch) == ATA_OP_CONTINUES)
- return;
- }
- ch->running = NULL;
- ATA_UNLOCK_CH(ch);
- ch->locking(ch, ATA_LF_UNLOCK);
- ata_start(ch);
- return;
+ PICKUP_GIANT();
+ return error;
}
-void
-ata_start(struct ata_channel *ch)
+/*
+ * device probe functions
+ */
+static int
+ata_getparam(struct ata_device *atadev, u_int8_t command)
{
-#ifdef DEV_ATADISK
- struct ad_request *ad_request;
-#endif
-#if DEV_ATAPIALL
- struct atapi_request *atapi_request;
-#endif
- int s;
+ struct ata_params *atacap;
+ struct ata_request *request;
+ int error = ENOMEM;
- ch->locking(ch, ATA_LF_LOCK);
- if (!ATA_LOCK_CH(ch, ATA_ACTIVE))
- return;
-
- s = splbio();
-#ifdef DEV_ATADISK
- /* find & call the responsible driver if anything on the ATA queue */
- if (TAILQ_EMPTY(&ch->ata_queue)) {
- if (ch->devices & (ATA_ATA_MASTER) && ch->device[MASTER].driver)
- ad_start(&ch->device[MASTER]);
- if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver)
- ad_start(&ch->device[SLAVE]);
- }
- if ((ad_request = TAILQ_FIRST(&ch->ata_queue))) {
- TAILQ_REMOVE(&ch->ata_queue, ad_request, chain);
- ch->active = ATA_ACTIVE_ATA;
- ch->running = ad_request;
- if (ad_transfer(ad_request) == ATA_OP_CONTINUES) {
- splx(s);
- return;
+ if (atadev->param)
+ atacap = atadev->param;
+ else
+ atacap = malloc(sizeof(struct ata_params), M_ATA, M_NOWAIT);
+ if (atacap) {
+ request = ata_alloc_request();
+ if (request) {
+ request->device = atadev;
+ request->u.ata.command = command;
+ request->flags = ATA_R_READ;
+ request->data = (caddr_t)atacap;
+ request->timeout = 2;
+ request->retries = 2;
+ request->bytecount = sizeof(struct ata_params);
+ request->transfersize = DEV_BSIZE;
+ ata_queue_request(request);
+ error = request->result;
+ ata_free_request(request);
}
- }
+ if (error) {
+ atadev->param = NULL;
+ free(atacap, M_ATA);
+ }
+ else {
+#if BYTE_ORDER == BIG_ENDIAN
+ int16_t *ptr;
+ for (ptr = (int16_t *)atacap;
+ ptr < (int16_t *)atacap + sizeof(struct ata_params)/2; ptr++) {
+ *ptr = bswap16(*ptr);
+ }
#endif
-#if DEV_ATAPIALL
- /* find & call the responsible driver if anything on the ATAPI queue */
- if (TAILQ_EMPTY(&ch->atapi_queue)) {
- if (ch->devices & (ATA_ATAPI_MASTER) && ch->device[MASTER].driver)
- atapi_start(&ch->device[MASTER]);
- if (ch->devices & (ATA_ATAPI_SLAVE) && ch->device[SLAVE].driver)
- atapi_start(&ch->device[SLAVE]);
- }
- if ((atapi_request = TAILQ_FIRST(&ch->atapi_queue))) {
- TAILQ_REMOVE(&ch->atapi_queue, atapi_request, chain);
- ch->active = ATA_ACTIVE_ATAPI;
- ch->running = atapi_request;
- if (atapi_transfer(atapi_request) == ATA_OP_CONTINUES) {
- splx(s);
- return;
+ if (!((atacap->model[0] == 'N' && atacap->model[1] == 'E') ||
+ (atacap->model[0] == 'F' && atacap->model[1] == 'X') ||
+ (atacap->model[0] == 'P' && atacap->model[1] == 'i')))
+ bswap(atacap->model, sizeof(atacap->model));
+ btrim(atacap->model, sizeof(atacap->model));
+ bpack(atacap->model, atacap->model, sizeof(atacap->model));
+ bswap(atacap->revision, sizeof(atacap->revision));
+ btrim(atacap->revision, sizeof(atacap->revision));
+ bpack(atacap->revision, atacap->revision, sizeof(atacap->revision));
+ bswap(atacap->serial, sizeof(atacap->serial));
+ btrim(atacap->serial, sizeof(atacap->serial));
+ bpack(atacap->serial, atacap->serial, sizeof(atacap->serial));
+ atadev->param = atacap;
+ if (bootverbose)
+ ata_prtdev(atadev,
+ "pio=0x%02x wdma=0x%02x udma=0x%02x cable=%spin\n",
+ ata_pmode(atacap), ata_wmode(atacap),
+ ata_umode(atacap),
+ (atacap->hwres & ATA_CABLE_ID) ? "80":"40");
}
}
-#endif
- ATA_UNLOCK_CH(ch);
- ch->locking(ch, ATA_LF_UNLOCK);
- splx(s);
+ return error;
}
-void
-ata_reset(struct ata_channel *ch)
+static void
+ata_identify_devices(struct ata_channel *ch)
{
- u_int8_t lsb, msb, ostat0, ostat1;
- u_int8_t stat0 = 0, stat1 = 0;
- int mask = 0, timeout;
-
- /* do we have any signs of ATA/ATAPI HW being present ? */
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
- ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
- if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
- stat0 = ATA_S_BUSY;
- mask |= 0x01;
- }
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
- DELAY(10);
- ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
- if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
- stat1 = ATA_S_BUSY;
- mask |= 0x02;
- }
-
- ch->devices = 0;
- if (!mask)
- return;
-
- /* in some setups we dont want to test for a slave */
- if (ch->flags & ATA_NO_SLAVE) {
- stat1 = 0x0;
- mask &= ~0x02;
+ if (ch->devices & ATA_ATA_SLAVE) {
+ if (ata_getparam(&ch->device[SLAVE], ATA_ATA_IDENTIFY))
+ ch->devices &= ~ATA_ATA_SLAVE;
+#ifdef DEV_ATADISK
+ else
+ ch->device[SLAVE].attach = ad_attach;
+#endif
}
-
- if (bootverbose)
- ata_printf(ch, -1, "pre reset mask=%02x ostat0=%02x ostat2=%02x\n",
- mask, ostat0, ostat1);
-
- /* reset channel */
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
- ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
- DELAY(10000);
- ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS);
- DELAY(100000);
- ATA_IDX_INB(ch, ATA_ERROR);
-
- /* wait for BUSY to go inactive */
- for (timeout = 0; timeout < 310000; timeout++) {
- if (stat0 & ATA_S_BUSY) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
-
- /* check for ATAPI signature while its still there */
- lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
- stat0 = ATA_IDX_INB(ch, ATA_STATUS);
- if (!(stat0 & ATA_S_BUSY)) {
- if (bootverbose)
- ata_printf(ch, ATA_MASTER, "ATAPI %02x %02x\n", lsb, msb);
- if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
- ch->devices |= ATA_ATAPI_MASTER;
- }
- }
- if (stat1 & ATA_S_BUSY) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
- DELAY(10);
-
- /* check for ATAPI signature while its still there */
- lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
- stat1 = ATA_IDX_INB(ch, ATA_STATUS);
- if (!(stat1 & ATA_S_BUSY)) {
- if (bootverbose)
- ata_printf(ch, ATA_SLAVE, "ATAPI %02x %02x\n", lsb, msb);
- if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
- ch->devices |= ATA_ATAPI_SLAVE;
- }
- }
- if (mask == 0x01) /* wait for master only */
- if (!(stat0 & ATA_S_BUSY))
- break;
- if (mask == 0x02) /* wait for slave only */
- if (!(stat1 & ATA_S_BUSY))
+ if (ch->devices & ATA_ATAPI_SLAVE) {
+ if (ata_getparam(&ch->device[SLAVE], ATA_ATAPI_IDENTIFY))
+ ch->devices &= ~ATA_ATAPI_SLAVE;
+ else {
+ switch (ch->device[SLAVE].param->config & ATA_ATAPI_TYPE_MASK) {
+#ifdef DEV_ATAPICD
+ case ATA_ATAPI_TYPE_CDROM:
+ ch->device[SLAVE].attach = acd_attach;
break;
- if (mask == 0x03) /* wait for both master & slave */
- if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
+#endif
+#ifdef DEV_ATAPIFD
+ case ATA_ATAPI_TYPE_DIRECT:
+ ch->device[SLAVE].attach = afd_attach;
break;
- DELAY(100);
- }
- DELAY(10);
- ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT);
-
- if (stat0 & ATA_S_BUSY)
- mask &= ~0x01;
- if (stat1 & ATA_S_BUSY)
- mask &= ~0x02;
- if (bootverbose)
- ata_printf(ch, -1, "after reset mask=%02x stat0=%02x stat1=%02x\n",
- mask, stat0, stat1);
- if (!mask)
- return;
-
- if (mask & 0x01 && ostat0 != 0x00 && !(ch->devices & ATA_ATAPI_MASTER)) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
- DELAY(10);
- ATA_IDX_OUTB(ch, ATA_ERROR, 0x58);
- ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5);
- lsb = ATA_IDX_INB(ch, ATA_ERROR);
- msb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- if (bootverbose)
- ata_printf(ch, ATA_MASTER, "ATA %02x %02x\n", lsb, msb);
- if (lsb != 0x58 && msb == 0xa5)
- ch->devices |= ATA_ATA_MASTER;
- }
- if (mask & 0x02 && ostat1 != 0x00 && !(ch->devices & ATA_ATAPI_SLAVE)) {
- ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
- DELAY(10);
- ATA_IDX_OUTB(ch, ATA_ERROR, 0x58);
- ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5);
- lsb = ATA_IDX_INB(ch, ATA_ERROR);
- msb = ATA_IDX_INB(ch, ATA_CYL_LSB);
- if (bootverbose)
- ata_printf(ch, ATA_SLAVE, "ATA %02x %02x\n", lsb, msb);
- if (lsb != 0x58 && msb == 0xa5)
- ch->devices |= ATA_ATA_SLAVE;
- }
- if (bootverbose)
- ata_printf(ch, -1, "devices=%02x\n", ch->devices);
-}
-
-int
-ata_reinit(struct ata_channel *ch)
-{
- int devices, misdev, newdev;
-
-
- if (!ch->r_irq)
- return ENXIO;
-
- ATA_FORCELOCK_CH(ch, ATA_CONTROL);
- ch->running = NULL;
- devices = ch->devices;
- ata_printf(ch, -1, "resetting devices ..\n");
- ata_reset(ch);
-
- if ((misdev = devices & ~ch->devices)) {
-#ifdef DEV_ATADISK
- if (misdev & ATA_ATA_MASTER && ch->device[MASTER].driver)
- ad_detach(&ch->device[MASTER]);
- if (misdev & ATA_ATA_SLAVE && ch->device[SLAVE].driver)
- ad_detach(&ch->device[SLAVE]);
#endif
-#if DEV_ATAPIALL
- if (misdev & ATA_ATAPI_MASTER && ch->device[MASTER].driver)
- atapi_detach(&ch->device[MASTER]);
- if (misdev & ATA_ATAPI_SLAVE && ch->device[SLAVE].driver)
- atapi_detach(&ch->device[SLAVE]);
+#ifdef DEV_ATAPIST
+ case ATA_ATAPI_TYPE_TAPE:
+ ch->device[SLAVE].attach = ast_attach;
+ break;
#endif
- if (misdev & ATA_ATA_MASTER || misdev & ATA_ATAPI_MASTER) {
- if (ch->device[MASTER].param)
- free(ch->device[MASTER].param, M_ATA);
- ch->device[MASTER].param = NULL;
- }
- if (misdev & ATA_ATA_SLAVE || misdev & ATA_ATAPI_SLAVE) {
- if (ch->device[SLAVE].param)
- free(ch->device[SLAVE].param, M_ATA);
- ch->device[SLAVE].param = NULL;
+ }
}
}
- if ((newdev = ~devices & ch->devices)) {
- if (newdev & ATA_ATA_MASTER)
- if (ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY))
- ch->devices &= ~ATA_ATA_MASTER;
- if (newdev & ATA_ATA_SLAVE)
- if (ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY))
- ch->devices &= ~ATA_ATA_SLAVE;
- if (newdev & ATA_ATAPI_MASTER)
- if (ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY))
- ch->devices &= ~ATA_ATAPI_MASTER;
- if (newdev & ATA_ATAPI_SLAVE)
- if (ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY))
- ch->devices &= ~ATA_ATAPI_SLAVE;
- }
- newdev = ~devices & ch->devices;
+ if (ch->devices & ATA_ATA_MASTER) {
+ if (ata_getparam(&ch->device[MASTER], ATA_ATA_IDENTIFY))
+ ch->devices &= ~ATA_ATA_MASTER;
#ifdef DEV_ATADISK
- if (newdev & ATA_ATA_SLAVE && !ch->device[SLAVE].driver) {
- ATA_UNLOCK_CH(ch);
- ad_attach(&ch->device[SLAVE]);
- ATA_SLEEPLOCK_CH(ch, ATA_CONTROL);
- }
- else if (ch->devices & (ATA_ATA_SLAVE) && ch->device[SLAVE].driver) {
- ata_getparam(&ch->device[SLAVE], ATA_C_ATA_IDENTIFY);
- ad_reinit(&ch->device[SLAVE]);
- }
- if (newdev & ATA_ATA_MASTER && !ch->device[MASTER].driver) {
- ATA_UNLOCK_CH(ch);
- ad_attach(&ch->device[MASTER]);
- ATA_SLEEPLOCK_CH(ch, ATA_CONTROL);
- }
- else if (ch->devices & ATA_ATA_MASTER && ch->device[MASTER].driver) {
- ata_getparam(&ch->device[MASTER], ATA_C_ATA_IDENTIFY);
- ad_reinit(&ch->device[MASTER]);
- }
+ else
+ ch->device[MASTER].attach = ad_attach;
#endif
-#if DEV_ATAPIALL
- if (newdev & ATA_ATAPI_SLAVE && !ch->device[SLAVE].driver) {
- ATA_UNLOCK_CH(ch);
- atapi_attach(&ch->device[SLAVE]);
- ATA_SLEEPLOCK_CH(ch, ATA_CONTROL);
- }
- else if (ch->devices & (ATA_ATAPI_SLAVE) && ch->device[SLAVE].driver) {
- ata_getparam(&ch->device[SLAVE], ATA_C_ATAPI_IDENTIFY);
- atapi_reinit(&ch->device[SLAVE]);
- }
- if (newdev & ATA_ATAPI_MASTER && !ch->device[MASTER].driver) {
- ATA_UNLOCK_CH(ch);
- atapi_attach(&ch->device[MASTER]);
- ATA_SLEEPLOCK_CH(ch, ATA_CONTROL);
- }
- else if (ch->devices & (ATA_ATAPI_MASTER) && ch->device[MASTER].driver) {
- ata_getparam(&ch->device[MASTER], ATA_C_ATAPI_IDENTIFY);
- atapi_reinit(&ch->device[MASTER]);
}
+ if (ch->devices & ATA_ATAPI_MASTER) {
+ if (ata_getparam(&ch->device[MASTER], ATA_ATAPI_IDENTIFY))
+ ch->devices &= ~ATA_ATAPI_MASTER;
+ else {
+ switch (ch->device[MASTER].param->config & ATA_ATAPI_TYPE_MASK) {
+#ifdef DEV_ATAPICD
+ case ATA_ATAPI_TYPE_CDROM:
+ ch->device[MASTER].attach = acd_attach;
+ break;
#endif
-#ifdef DEV_ATAPICAM
- atapi_cam_reinit_bus(ch);
+#ifdef DEV_ATAPIFD
+ case ATA_ATAPI_TYPE_DIRECT:
+ ch->device[MASTER].attach = afd_attach;
+ break;
#endif
- printf("done\n");
- ATA_UNLOCK_CH(ch);
- ata_start(ch);
- return 0;
-}
-
-static int
-ata_service(struct ata_channel *ch)
-{
- /* do we have a SERVICE request from the drive ? */
- if ((ch->status & (ATA_S_SERVICE|ATA_S_ERROR|ATA_S_DRQ)) == ATA_S_SERVICE) {
-#if 0 /* XXX */
- ATA_IDX_OUTB(ch->r_bmio, ATA_BMSTAT_PORT,
- ch->dma->status(ch) | ATA_BMSTAT_INTERRUPT);
+#ifdef DEV_ATAPIST
+ case ATA_ATAPI_TYPE_TAPE:
+ ch->device[MASTER].attach = ast_attach;
+ break;
#endif
-#ifdef DEV_ATADISK
- if ((ATA_IDX_INB(ch, ATA_DRIVE) & ATA_SLAVE) == ATA_MASTER) {
- if ((ch->devices & ATA_ATA_MASTER) && ch->device[MASTER].driver)
- return ad_service((struct ad_softc *)
- ch->device[MASTER].driver, 0);
- }
- else {
- if ((ch->devices & ATA_ATA_SLAVE) && ch->device[SLAVE].driver)
- return ad_service((struct ad_softc *)
- ch->device[SLAVE].driver, 0);
+ }
}
-#endif
}
- return ATA_OP_FINISHED;
}
-static void
-ata_flush(struct ata_device *atadev)
-{
- if (ata_command(atadev, ATA_C_FLUSHCACHE, 0, 0, 0, ATA_WAIT_READY))
- ata_prtdev(atadev, "flushing device failed\n");
-}
-
-static void
-ata_shutdown(void *arg, int howto)
+static void
+ata_boot_attach(void)
{
struct ata_channel *ch;
int ctlr;
- /* flush cache on all devices */
- for (ctlr = 0; ctlr < devclass_get_maxunit(ata_devclass); ctlr++) {
+ /*
+ * run through all ata devices and look for real ATA & ATAPI devices
+ * using the hints we found in the early probe, this avoids some of
+ * the delays probing of non-exsistent devices can cause.
+ */
+ for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
continue;
- ch->locking(ch, ATA_LF_LOCK);
- if (ch->device[MASTER].param)
- ata_flush(&ch->device[MASTER]);
- if (ch->device[SLAVE].param)
- ata_flush(&ch->device[SLAVE]);
- ch->locking(ch, ATA_LF_UNLOCK);
- }
-}
-
-int
-ata_wait(struct ata_device *atadev, u_int8_t mask)
-{
- int timeout = 0;
-
- DELAY(1);
- while (timeout < 5000000) { /* timeout 5 secs */
- atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
-
- /* if drive fails status, reselect the drive just to be sure */
- if (atadev->channel->status == 0xff) {
- ata_prtdev(atadev, "no status, reselecting device\n");
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM|atadev->unit);
- DELAY(10);
- atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
- if (atadev->channel->status == 0xff)
- return -1;
- }
-
- /* are we done ? */
- if (!(atadev->channel->status & ATA_S_BUSY))
- break;
-
- if (timeout > 1000) {
- timeout += 1000;
- DELAY(1000);
- }
- else {
- timeout += 10;
- DELAY(10);
- }
- }
- if (atadev->channel->status & ATA_S_ERROR)
- atadev->channel->error = ATA_IDX_INB(atadev->channel, ATA_ERROR);
- if (timeout >= 5000000)
- return -1;
- if (!mask)
- return (atadev->channel->status & ATA_S_ERROR);
-
- /* Wait 50 msec for bits wanted. */
- timeout = 5000;
- while (timeout--) {
- atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
- if ((atadev->channel->status & mask) == mask) {
- if (atadev->channel->status & ATA_S_ERROR)
- atadev->channel->error=ATA_IDX_INB(atadev->channel, ATA_ERROR);
- return (atadev->channel->status & ATA_S_ERROR);
- }
- DELAY (10);
- }
- return -1;
-}
-
-int
-ata_command(struct ata_device *atadev, u_int8_t command,
- u_int64_t lba, u_int16_t count, u_int16_t feature, int flags)
-{
- int error = 0;
-#ifdef ATA_DEBUG
- ata_prtdev(atadev, "ata_command: addr=%04lx, cmd=%02x, "
- "lba=%jd, count=%d, feature=%d, flags=%02x\n",
- rman_get_start(atadev->channel->r_io[ATA_DATA].res),
- command, (intmax_t)lba, count, feature, flags);
+ ata_identify_devices(ch);
+ if (ch->device[MASTER].attach)
+ ch->device[MASTER].attach(&ch->device[MASTER]);
+ if (ch->device[SLAVE].attach)
+ ch->device[SLAVE].attach(&ch->device[SLAVE]);
+#ifdef DEV_ATAPICAM
+ atapi_cam_attach_bus(ch);
#endif
-
- /* select device */
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
-
- /* disable interrupt from device */
- if (atadev->channel->flags & ATA_QUEUED)
- ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_IDS | ATA_A_4BIT);
-
- /* ready to issue command ? */
- if (ata_wait(atadev, 0) < 0) {
- ata_prtdev(atadev, "timeout sending command=%02x s=%02x e=%02x\n",
- command, atadev->channel->status, atadev->channel->error);
- return -1;
}
-
- /* only use 48bit addressing if needed because of the overhead */
- if ((lba > 268435455 || count > 256) && atadev->param &&
- atadev->param->support.address48) {
- ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature);
- ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit);
-
- /* translate command into 48bit version */
- switch (command) {
- case ATA_C_READ:
- command = ATA_C_READ48; break;
- case ATA_C_READ_MUL:
- command = ATA_C_READ_MUL48; break;
- case ATA_C_READ_DMA:
- command = ATA_C_READ_DMA48; break;
- case ATA_C_READ_DMA_QUEUED:
- command = ATA_C_READ_DMA_QUEUED48; break;
- case ATA_C_WRITE:
- command = ATA_C_WRITE48; break;
- case ATA_C_WRITE_MUL:
- command = ATA_C_WRITE_MUL48; break;
- case ATA_C_WRITE_DMA:
- command = ATA_C_WRITE_DMA48; break;
- case ATA_C_WRITE_DMA_QUEUED:
- command = ATA_C_WRITE_DMA_QUEUED48; break;
- case ATA_C_FLUSHCACHE:
- command = ATA_C_FLUSHCACHE48; break;
- default:
- ata_prtdev(atadev, "can't translate cmd to 48bit version\n");
- return -1;
- }
- atadev->channel->flags |= ATA_48BIT_ACTIVE;
- }
- else {
- ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature);
- ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
- ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
- if (atadev->flags & ATA_D_USE_CHS)
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
- ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf));
- else
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
- ATA_D_IBM | ATA_D_LBA | atadev->unit | ((lba>>24) &0xf));
- atadev->channel->flags &= ~ATA_48BIT_ACTIVE;
- }
-
- switch (flags & ATA_WAIT_MASK) {
- case ATA_IMMEDIATE:
- ATA_IDX_OUTB(atadev->channel, ATA_CMD, command);
-
- /* enable interrupt */
- if (atadev->channel->flags & ATA_QUEUED)
- ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT);
- break;
-
- case ATA_WAIT_INTR:
- atadev->channel->active |= ATA_WAIT_INTR;
- ATA_IDX_OUTB(atadev->channel, ATA_CMD, command);
-
- /* enable interrupt */
- if (atadev->channel->flags & ATA_QUEUED)
- ATA_IDX_OUTB(atadev->channel, ATA_ALTSTAT, ATA_A_4BIT);
-
- if (tsleep(atadev->channel, PRIBIO, "atacmd", 10 * hz)) {
- ata_prtdev(atadev, "timeout waiting for interrupt\n");
- atadev->channel->active &= ~ATA_WAIT_INTR;
- error = -1;
- }
- break;
-
- case ATA_WAIT_READY:
- atadev->channel->active |= ATA_WAIT_READY;
- ATA_IDX_OUTB(atadev->channel, ATA_CMD, command);
- if (ata_wait(atadev, ATA_S_READY) < 0) {
- ata_prtdev(atadev, "timeout waiting for cmd=%02x s=%02x e=%02x\n",
- command, atadev->channel->status,atadev->channel->error);
- error = -1;
- }
- atadev->channel->active &= ~ATA_WAIT_READY;
- break;
+#ifdef DEV_ATARAID
+ ata_raid_attach();
+#endif
+ if (ata_delayed_attach) {
+ config_intrhook_disestablish(ata_delayed_attach);
+ free(ata_delayed_attach, M_TEMP);
+ ata_delayed_attach = NULL;
}
- return error;
-}
-
-static void
-ata_enclosure_start(struct ata_device *atadev)
-{
- ATA_IDX_INB(atadev->channel, ATA_DRIVE);
- DELAY(1);
- ATA_IDX_INB(atadev->channel, ATA_DRIVE);
- DELAY(1);
- ATA_IDX_INB(atadev->channel, ATA_CMD);
- DELAY(1);
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
- DELAY(1);
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
- DELAY(1);
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
- DELAY(1);
- ATA_IDX_INB(atadev->channel, ATA_COUNT);
- DELAY(1);
- ATA_IDX_INB(atadev->channel, ATA_DRIVE);
- DELAY(1);
-}
-
-static void
-ata_enclosure_end(struct ata_device *atadev)
-{
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
- DELAY(1);
}
+/*
+ * misc support functions
+ */
static void
-ata_enclosure_chip_start(struct ata_device *atadev)
+bswap(int8_t *buf, int len)
{
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0b);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0a);
- DELAY(25);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08);
+ u_int16_t *ptr = (u_int16_t*)(buf + len);
+
+ while (--ptr >= (u_int16_t*)buf)
+ *ptr = ntohs(*ptr);
}
static void
-ata_enclosure_chip_end(struct ata_device *atadev)
-{
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08);
- DELAY(64);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0a);
- DELAY(25);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x0b);
- DELAY(64);
-}
+btrim(int8_t *buf, int len)
+{
+ int8_t *ptr;
-static u_int8_t
-ata_enclosure_chip_rdbit(struct ata_device *atadev)
-{
- u_int8_t val;
-
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0);
- DELAY(64);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x02);
- DELAY(25);
- val = ATA_IDX_INB(atadev->channel, ATA_SECTOR) & 0x01;
- DELAY(38);
- return val;
+ for (ptr = buf; ptr < buf+len; ++ptr)
+ if (!*ptr)
+ *ptr = ' ';
+ for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
+ *ptr = 0;
}
static void
-ata_enclosure_chip_wrbit(struct ata_device *atadev, u_int8_t data)
-{
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08 | (data & 0x01));
- DELAY(64);
- ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, 0x08 | 0x02 | (data & 0x01));
- DELAY(64);
-}
-
-static u_int8_t
-ata_enclosure_chip_rw(struct ata_device *atadev, int rw, u_int8_t val)
-{
- int i;
-
- if (rw) {
- for (i = 0; i < 8; i++)
- ata_enclosure_chip_wrbit(atadev, (val & (0x80 >> i)) ? 1 : 0);
- }
- else {
- for (i = 0; i < 8; i++)
- val = (val << 1) | ata_enclosure_chip_rdbit(atadev);
- }
- ata_enclosure_chip_wrbit(atadev, 0);
- return val;
-}
-
-static u_int8_t
-ata_enclosure_sensor(struct ata_device *atadev,
- int rw, u_int8_t idx, u_int8_t data)
+bpack(int8_t *src, int8_t *dst, int len)
{
- ata_enclosure_start(atadev);
- ata_enclosure_chip_start(atadev);
- ata_enclosure_chip_rw(atadev, 1, 0x5a);
- ata_enclosure_chip_rw(atadev, 1, idx);
- if (rw) {
- ata_enclosure_chip_rw(atadev, 1, data);
- }
- else {
- ata_enclosure_chip_end(atadev);
- ata_enclosure_chip_start(atadev);
- ata_enclosure_chip_rw(atadev, 1, 0x5b);
- data = ata_enclosure_chip_rw(atadev, 0, 0);
- }
- ata_enclosure_chip_end(atadev);
- ata_enclosure_end(atadev);
- return data;
-}
+ int i, j, blank;
-static int
-ata_enclosure_status(struct ata_device *atadev,
- int *fan, int *temp, int *v05, int *v12)
-{
- u_int8_t id1, id2, cnt, div;
- int error = ENXIO;
-
- if (atadev->flags & ATA_D_ENC_PRESENT) {
- atadev->channel->locking(atadev->channel, ATA_LF_LOCK);
- ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL);
- ata_enclosure_sensor(atadev, 1, 0x4e, 0);
- id1 = ata_enclosure_sensor(atadev, 0, 0x4f, 0);
- ata_enclosure_sensor(atadev, 1, 0x4e, 0x80);
- id2 = ata_enclosure_sensor(atadev, 0, 0x4f, 0);
- if (id1 == 0xa3 && id2 == 0x5c) {
- div = 1 << (((ata_enclosure_sensor(atadev, 0, 0x5d, 0)&0x20)>>3)+
- ((ata_enclosure_sensor(atadev, 0, 0x47, 0)&0x30)>>4)+1);
- cnt = ata_enclosure_sensor(atadev, 0, 0x28, 0);
- if (cnt == 0xff)
- *fan = 0;
- else
- *fan = 1350000 / cnt / div;
- ata_enclosure_sensor(atadev, 1, 0x4e, 0x01);
- *temp = (ata_enclosure_sensor(atadev, 0, 0x50, 0) * 10) +
- (ata_enclosure_sensor(atadev, 0, 0x50, 0) & 0x80 ? 5 : 0);
- *v05 = ata_enclosure_sensor(atadev, 0, 0x23, 0) * 27;
- *v12 = ata_enclosure_sensor(atadev, 0, 0x24, 0) * 61;
- error = 0;
+ for (i = j = blank = 0 ; i < len; i++) {
+ if (blank && src[i] == ' ') continue;
+ if (blank && src[i] != ' ') {
+ dst[j++] = src[i];
+ blank = 0;
+ continue;
}
- ATA_UNLOCK_CH(atadev->channel);
- atadev->channel->locking(atadev->channel, ATA_LF_UNLOCK);
- }
- return error;
-}
-
-void
-ata_enclosure_print(struct ata_device *atadev)
-{
- u_int8_t id, st;
- int fan, temp, v05, v12;
-
- atadev->channel->locking(atadev->channel, ATA_LF_LOCK);
- ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL);
- ata_enclosure_start(atadev);
- id = ATA_IDX_INB(atadev->channel, ATA_DRIVE);
- DELAY(1);
- st = ATA_IDX_INB(atadev->channel, ATA_COUNT);
- DELAY(1);
- ata_enclosure_end(atadev);
- ATA_UNLOCK_CH(atadev->channel);
- atadev->channel->locking(atadev->channel, ATA_LF_UNLOCK);
-
- switch (id & 0x93) {
- case 0x00:
- ata_prtdev(atadev, "Universal enclosure");
- break;
- case 0x01:
- ata_prtdev(atadev, "FastSwap enclosure");
- break;
- case 0x10:
- case 0x11:
- ata_prtdev(atadev, "SuperSwap enclosure");
- break;
- default:
- atadev->flags &= ~ATA_D_ENC_PRESENT;
- return;
- }
- atadev->flags |= ATA_D_ENC_PRESENT;
-
- ata_enclosure_leds(atadev, ATA_LED_GREEN);
- if (ata_enclosure_status(atadev, &fan, &temp, &v05, &v12))
- printf(" detected\n");
- else
- printf(" [FAN:%drpm TEMP:%d.%01dC %d.%03dV %d.%03dV]\n",
- fan, temp/10, temp%10, v05/1000, v05%1000, v12/1000, v12%1000);
-}
-
-void
-ata_enclosure_leds(struct ata_device *atadev, u_int8_t color)
-{
- if (atadev->flags & ATA_D_ENC_PRESENT) {
- u_int8_t reg;
-
- ata_enclosure_start(atadev);
- reg = ATA_IDX_INB(atadev->channel, ATA_COUNT);
- DELAY(1);
- ATA_IDX_OUTB(atadev->channel, ATA_COUNT,
- (color & ATA_LED_MASK) | (reg & ~ATA_LED_MASK));
- DELAY(1);
- ata_enclosure_end(atadev);
+ if (src[i] == ' ') {
+ blank = 1;
+ if (i == 0)
+ continue;
+ }
+ dst[j++] = src[i];
}
-}
-
-static void
-ata_change_mode(struct ata_device *atadev, int mode)
-{
- ATA_SLEEPLOCK_CH(atadev->channel, ATA_ACTIVE);
- atadev->setmode(atadev, mode);
- ATA_UNLOCK_CH(atadev->channel);
- ata_start(atadev->channel);
+ if (j < len)
+ dst[j] = 0x00;
}
int
@@ -1465,13 +822,13 @@ ata_pmode(struct ata_params *ap)
if (ap->apiomodes & 0x01)
return ATA_PIO3;
}
- if (ap->retired_piomode == 2)
+ if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 2)
return ATA_PIO2;
- if (ap->retired_piomode == 1)
+ if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 1)
return ATA_PIO1;
- if (ap->retired_piomode == 0)
+ if ((ap->retired_piomode & ATA_RETIRED_PIO_MASK) == 0)
return ATA_PIO0;
- if (ap->support_dma)
+ if (ap->capabilities1 & ATA_SUPPORT_DMA)
return ATA_PIO4;
return ATA_PIO0;
}
@@ -1485,7 +842,7 @@ ata_wmode(struct ata_params *ap)
return ATA_WDMA1;
if (ap->mwdmamodes & 0x01)
return ATA_WDMA0;
- if (ap->support_dma)
+ if (ap->capabilities1 & ATA_SUPPORT_DMA)
return ATA_WDMA2;
return -1;
}
@@ -1531,50 +888,6 @@ ata_limit_mode(struct ata_device *atadev, int mode, int maxmode)
}
static void
-bswap(int8_t *buf, int len)
-{
- u_int16_t *ptr = (u_int16_t*)(buf + len);
-
- while (--ptr >= (u_int16_t*)buf)
- *ptr = ntohs(*ptr);
-}
-
-static void
-btrim(int8_t *buf, int len)
-{
- int8_t *ptr;
-
- for (ptr = buf; ptr < buf+len; ++ptr)
- if (!*ptr)
- *ptr = ' ';
- for (ptr = buf + len - 1; ptr >= buf && *ptr == ' '; --ptr)
- *ptr = 0;
-}
-
-static void
-bpack(int8_t *src, int8_t *dst, int len)
-{
- int i, j, blank;
-
- for (i = j = blank = 0 ; i < len; i++) {
- if (blank && src[i] == ' ') continue;
- if (blank && src[i] != ' ') {
- dst[j++] = src[i];
- blank = 0;
- continue;
- }
- if (src[i] == ' ') {
- blank = 1;
- if (i == 0)
- continue;
- }
- dst[j++] = src[i];
- }
- if (j < len)
- dst[j] = 0x00;
-}
-
-static void
ata_init(void)
{
/* register controlling device */
diff --git a/sys/dev/ata/ata-all.h b/sys/dev/ata/ata-all.h
index 44cb042..99ec220 100644
--- a/sys/dev/ata/ata-all.h
+++ b/sys/dev/ata/ata-all.h
@@ -30,7 +30,9 @@
/* ATA register defines */
#define ATA_DATA 0x00 /* data register */
+
#define ATA_ERROR 0x01 /* (R) error register */
+#define ATA_E_ILI 0x01 /* illegal length */
#define ATA_E_NM 0x02 /* no media */
#define ATA_E_ABORT 0x04 /* command aborted */
#define ATA_E_MCR 0x08 /* media change request */
@@ -38,6 +40,24 @@
#define ATA_E_MC 0x20 /* media changed */
#define ATA_E_UNC 0x40 /* uncorrectable data */
#define ATA_E_ICRC 0x80 /* UDMA crc error */
+#define ATA_E_MASK 0x0f /* error mask */
+#define ATA_SK_MASK 0xf0 /* sense key mask */
+#define ATA_SK_NO_SENSE 0x00 /* no specific sense key info */
+#define ATA_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */
+#define ATA_SK_NOT_READY 0x20 /* no access to drive */
+#define ATA_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */
+#define ATA_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */
+#define ATA_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */
+#define ATA_SK_UNIT_ATTENTION 0x60 /* media changed */
+#define ATA_SK_DATA_PROTECT 0x70 /* write protect */
+#define ATA_SK_BLANK_CHECK 0x80 /* blank check */
+#define ATA_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */
+#define ATA_SK_COPY_ABORTED 0xa0 /* copy aborted */
+#define ATA_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */
+#define ATA_SK_EQUAL 0xc0 /* equal */
+#define ATA_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */
+#define ATA_SK_MISCOMPARE 0xe0 /* data dont match the medium */
+#define ATA_SK_RESERVED 0xf0
#define ATA_FEATURE 0x01 /* (W) feature register */
#define ATA_F_DMA 0x01 /* enable DMA */
@@ -58,44 +78,6 @@
#define ATA_D_IBM 0xa0 /* 512 byte sectors, ECC */
#define ATA_CMD 0x07 /* command register */
-#define ATA_C_NOP 0x00 /* NOP command */
-#define ATA_C_F_FLUSHQUEUE 0x00 /* flush queued cmd's */
-#define ATA_C_F_AUTOPOLL 0x01 /* start autopoll function */
-#define ATA_C_ATAPI_RESET 0x08 /* reset ATAPI device */
-#define ATA_C_READ 0x20 /* read command */
-#define ATA_C_READ48 0x24 /* read command */
-#define ATA_C_READ_DMA48 0x25 /* read w/DMA command */
-#define ATA_C_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */
-#define ATA_C_READ_MUL48 0x29 /* read multi command */
-#define ATA_C_WRITE 0x30 /* write command */
-#define ATA_C_WRITE48 0x34 /* write command */
-#define ATA_C_WRITE_DMA48 0x35 /* write w/DMA command */
-#define ATA_C_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */
-#define ATA_C_WRITE_MUL48 0x39 /* write multi command */
-#define ATA_C_PACKET_CMD 0xa0 /* packet command */
-#define ATA_C_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/
-#define ATA_C_SERVICE 0xa2 /* service command */
-#define ATA_C_READ_MUL 0xc4 /* read multi command */
-#define ATA_C_WRITE_MUL 0xc5 /* write multi command */
-#define ATA_C_SET_MULTI 0xc6 /* set multi size command */
-#define ATA_C_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */
-#define ATA_C_READ_DMA 0xc8 /* read w/DMA command */
-#define ATA_C_WRITE_DMA 0xca /* write w/DMA command */
-#define ATA_C_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */
-#define ATA_C_SLEEP 0xe6 /* sleep command */
-#define ATA_C_FLUSHCACHE 0xe7 /* flush cache to disk */
-#define ATA_C_FLUSHCACHE48 0xea /* flush cache to disk */
-#define ATA_C_ATA_IDENTIFY 0xec /* get ATA params */
-#define ATA_C_SETFEATURES 0xef /* features command */
-#define ATA_C_F_SETXFER 0x03 /* set transfer mode */
-#define ATA_C_F_ENAB_WCACHE 0x02 /* enable write cache */
-#define ATA_C_F_DIS_WCACHE 0x82 /* disable write cache */
-#define ATA_C_F_ENAB_RCACHE 0xaa /* enable readahead cache */
-#define ATA_C_F_DIS_RCACHE 0x55 /* disable readahead cache */
-#define ATA_C_F_ENAB_RELIRQ 0x5d /* enable release interrupt */
-#define ATA_C_F_DIS_RELIRQ 0xdd /* disable release interrupt */
-#define ATA_C_F_ENAB_SRVIRQ 0x5e /* enable service interrupt */
-#define ATA_C_F_DIS_SRVIRQ 0xde /* disable service interrupt */
#define ATA_STATUS 0x07 /* status register */
#define ATA_S_ERROR 0x01 /* error */
@@ -117,6 +99,16 @@
#define ATA_A_RESET 0x04 /* RESET controller */
#define ATA_A_4BIT 0x08 /* 4 head bits */
+/* ATAPI misc defines */
+#define ATAPI_MAGIC_LSB 0x14
+#define ATAPI_MAGIC_MSB 0xeb
+#define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN)
+#define ATAPI_P_WRITE (ATA_S_DRQ)
+#define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD)
+#define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN)
+#define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN)
+#define ATAPI_P_ABORT 0
+
/* misc defines */
#define ATA_PRIMARY 0x1f0
#define ATA_SECONDARY 0x170
@@ -126,8 +118,6 @@
#define ATA_ALTIOSIZE 0x01
#define ATA_BMIOSIZE 0x08
#define ATA_PC98_BANKIOSIZE 0x01
-#define ATA_OP_FINISHED 0x00
-#define ATA_OP_CONTINUES 0x01
#define ATA_IOADDR_RID 0
#define ATA_ALTADDR_RID 1
#define ATA_BMADDR_RID 0x20
@@ -163,22 +153,72 @@
#define ATA_IDX_DATA 0x0f
#define ATA_MAX_RES 0x10
-/* structure for holding DMA address data */
-struct ata_dmaentry {
- u_int32_t base;
- u_int32_t count;
-};
+#define ATA_INTR_FLAGS (INTR_MPSAFE|INTR_TYPE_BIO|INTR_ENTROPY)
+#define ATA_OP_CONTINUES 0
+#define ATA_OP_FINISHED 1
+
+struct ata_request {
+ struct ata_device *device; /* ptr to device softc */
+ void *driver; /* driver specific */
+
+ union {
+ struct {
+ u_int8_t command; /* command reg */
+ u_int8_t feature; /* feature reg */
+ u_int64_t lba; /* lba reg */
+ u_int16_t count; /* count reg */
+ } ata;
+ struct {
+ u_int8_t ccb[16]; /* ATAPI command block */
+ } atapi;
+ } u;
+
+ u_int8_t status; /* ATA status */
+ u_int8_t error; /* ATA error */
+ u_int8_t dmastat; /* DMA status */
+
+ u_int32_t bytecount; /* bytes to transfer */
+ u_int32_t transfersize; /* bytes pr transfer */
+ u_int32_t donecount; /* bytes transferred */
+ caddr_t data; /* pointer to data buf */
+ int flags;
+#define ATA_R_DONE 0x0001
+#define ATA_R_CONTROL 0x0002
+#define ATA_R_READ 0x0004
+#define ATA_R_WRITE 0x0008
+
+#define ATA_R_ATAPI 0x0010
+#define ATA_R_QUIET 0x0020
+#define ATA_R_DMA 0x0040
+
+#define ATA_R_ORDERED 0x0100
+#define ATA_R_AT_HEAD 0x0200
+#define ATA_R_REQUEUE 0x0400
+#define ATA_R_SKIPSTART 0x0800
+
+ void (*callback)(struct ata_request *);
+ int retries; /* retry count */
+ int timeout; /* timeout for this cmd */
+ struct callout_handle timeout_handle; /* handle for untimeout */
+ int result; /* result error code */
+ struct task task; /* task management */
+ TAILQ_ENTRY(ata_request) sequence; /* sequence management */
+ TAILQ_ENTRY(ata_request) chain; /* list management */
+};
/* structure describing an ATA/ATAPI device */
struct ata_device {
struct ata_channel *channel;
int unit; /* unit number */
-#define ATA_MASTER 0x00
-#define ATA_SLAVE 0x10
+#define ATA_MASTER 0x00
+#define ATA_SLAVE 0x10
char *name; /* device name */
struct ata_params *param; /* ata param structure */
- void *driver; /* ptr to driver for device */
+ void *softc; /* ptr to softc for device */
+ void (*attach)(struct ata_device *);
+ void (*detach)(struct ata_device *);
+ void (*start)(struct ata_device *);
int flags;
#define ATA_D_USE_CHS 0x0001
#define ATA_D_DETACHING 0x0002
@@ -186,13 +226,18 @@ struct ata_device {
#define ATA_D_ENC_PRESENT 0x0008
int cmd; /* last cmd executed */
- void *result; /* misc data */
int mode; /* transfermode */
void (*setmode)(struct ata_device *, int);
};
+/* structure for holding DMA address data */
+struct ata_dmaentry {
+ u_int32_t base;
+ u_int32_t count;
+};
+
/* structure holding DMA related information */
-struct ata_dma_data {
+struct ata_dma {
bus_dma_tag_t dmatag; /* parent DMA tag */
bus_dma_tag_t cdmatag; /* control DMA tag */
bus_dmamap_t cdmamap; /* control DMA map */
@@ -200,7 +245,8 @@ struct ata_dma_data {
bus_dmamap_t ddmamap; /* data DMA map */
struct ata_dmaentry *dmatab; /* DMA transfer table */
bus_addr_t mdmatab; /* bus address of dmatab */
- u_int32_t alignment; /* DMA engine alignment */
+ u_int32_t alignment; /* DMA engine alignment */
+ u_int32_t max_iosize; /* DMA engine max IO size */
int flags;
#define ATA_DMA_ACTIVE 0x01 /* DMA transfer in progress */
#define ATA_DMA_READ 0x02 /* transaction is a read */
@@ -212,6 +258,13 @@ struct ata_dma_data {
int (*stop)(struct ata_channel *);
};
+/* structure holding lowlevel functions */
+struct ata_lowlevel {
+ void (*reset)(struct ata_channel *);
+ int (*transaction)(struct ata_request *);
+ void (*interrupt)(void *);
+};
+
/* structure holding resources for an ATA channel */
struct ata_resource {
struct resource *res;
@@ -225,15 +278,14 @@ struct ata_channel {
struct ata_resource r_io[ATA_MAX_RES];/* I/O resources */
struct resource *r_irq; /* interrupt of this channel */
void *ih; /* interrupt handle */
- struct ata_dma_data *dma; /* DMA data / functions */
- u_int32_t chiptype; /* controller chip PCI id */
+ struct ata_lowlevel hw; /* lowlevel HW functions */
+ struct ata_dma *dma; /* DMA data / functions */
int flags; /* channel flags */
#define ATA_NO_SLAVE 0x01
#define ATA_USE_16BIT 0x02
#define ATA_USE_PC98GEOM 0x04
#define ATA_ATAPI_DMA_RO 0x08
-#define ATA_QUEUED 0x10
-#define ATA_48BIT_ACTIVE 0x20
+#define ATA_48BIT_ACTIVE 0x10
struct ata_device device[2]; /* devices on this channel */
#define MASTER 0x00
@@ -245,28 +297,42 @@ struct ata_channel {
#define ATA_ATAPI_MASTER 0x04
#define ATA_ATAPI_SLAVE 0x08
- u_int8_t status; /* last controller status */
- u_int8_t error; /* last controller error */
- int active; /* ATA channel state control */
+ int state; /* ATA channel state control */
#define ATA_IDLE 0x0000
-#define ATA_IMMEDIATE 0x0001
-#define ATA_WAIT_INTR 0x0002
-#define ATA_WAIT_READY 0x0004
-#define ATA_WAIT_MASK 0x0007
-#define ATA_ACTIVE 0x0010
-#define ATA_ACTIVE_ATA 0x0020
-#define ATA_ACTIVE_ATAPI 0x0040
-#define ATA_CONTROL 0x0080
+#define ATA_ACTIVE 0x0001
+#define ATA_CONTROL 0x0002
void (*locking)(struct ata_channel *, int);
#define ATA_LF_LOCK 0x0001
#define ATA_LF_UNLOCK 0x0002
- TAILQ_HEAD(, ad_request) ata_queue; /* head of ATA queue */
- TAILQ_HEAD(, atapi_request) atapi_queue; /* head of ATAPI queue */
+ struct mtx queue_mtx;
+ TAILQ_HEAD(, ata_request) ata_queue; /* head of ATA queue */
void *running; /* currently running request */
};
+/* ATAPI request sense structure */
+struct atapi_sense {
+ u_int8_t error_code :7; /* current or deferred errors */
+ u_int8_t valid :1; /* follows ATAPI spec */
+ u_int8_t segment; /* Segment number */
+ u_int8_t sense_key :4; /* sense key */
+ u_int8_t reserved2_4 :1; /* reserved */
+ u_int8_t ili :1; /* incorrect length indicator */
+ u_int8_t eom :1; /* end of medium */
+ u_int8_t filemark :1; /* filemark */
+ u_int32_t cmd_info __packed; /* cmd information */
+ u_int8_t sense_length; /* additional sense len (n-7) */
+ u_int32_t cmd_specific_info __packed; /* additional cmd spec info */
+ u_int8_t asc; /* additional sense code */
+ u_int8_t ascq; /* additional sense code qual */
+ u_int8_t replaceable_unit_code; /* replaceable unit code */
+ u_int8_t sk_specific :7; /* sense key specific */
+ u_int8_t sksv :1; /* sense key specific info OK */
+ u_int8_t sk_specific1; /* sense key specific */
+ u_int8_t sk_specific2; /* sense key specific */
+};
+
/* disk bay/enclosure related */
#define ATA_LED_OFF 0x00
#define ATA_LED_RED 0x01
@@ -277,20 +343,15 @@ struct ata_channel {
/* externs */
extern devclass_t ata_devclass;
extern struct intr_config_hook *ata_delayed_attach;
+extern int ata_dma, ata_wc, atapi_dma;
/* public prototypes */
+/* ata-all.c: */
int ata_probe(device_t);
int ata_attach(device_t);
int ata_detach(device_t);
int ata_suspend(device_t);
int ata_resume(device_t);
-void ata_start(struct ata_channel *);
-void ata_reset(struct ata_channel *);
-int ata_reinit(struct ata_channel *);
-int ata_wait(struct ata_device *, u_int8_t);
-int ata_command(struct ata_device *, u_int8_t, u_int64_t, u_int16_t, u_int16_t, int);
-void ata_enclosure_leds(struct ata_device *, u_int8_t);
-void ata_enclosure_print(struct ata_device *);
int ata_printf(struct ata_channel *, int, const char *, ...) __printflike(3, 4);
int ata_prtdev(struct ata_device *, const char *, ...) __printflike(2, 3);
void ata_set_name(struct ata_device *, char *, int);
@@ -299,22 +360,45 @@ int ata_get_lun(u_int32_t *);
int ata_test_lun(u_int32_t *, int);
void ata_free_lun(u_int32_t *, int);
char *ata_mode2str(int);
-int ata_pmode(struct ata_params *);
-int ata_wmode(struct ata_params *);
-int ata_umode(struct ata_params *);
-int ata_limit_mode(struct ata_device *, int, int);
+int ata_pmode(struct ata_params *ap);
+int ata_wmode(struct ata_params *ap);
+int ata_umode(struct ata_params *ap);
+int ata_limit_mode(struct ata_device *atadev, int mode, int maxmode);
+
+/* ata-queue.c: */
+int ata_reinit(struct ata_channel *ch);
+void ata_start(struct ata_channel *ch);
+struct ata_request *ata_alloc_request(void);
+void ata_free_request(struct ata_request *request);
+int ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature, u_int64_t lba, u_int16_t count);
+int ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data, int count, int flags, int timeout);
+void ata_queue_request(struct ata_request *request);
+void ata_finish(struct ata_request *request);
+char *ata_cmd2str(struct ata_request *request);
+
+/* ata-lowlevel.c: */
+void ata_generic_hw(struct ata_channel *ch);
+
+/* subdrivers */
+void ad_attach(struct ata_device *);
+void acd_attach(struct ata_device *);
+void afd_attach(struct ata_device *);
+void ast_attach(struct ata_device *);
+void atapi_cam_attach_bus(struct ata_channel *);
+void atapi_cam_detach_bus(struct ata_channel *);
+void atapi_cam_reinit_bus(struct ata_channel *);
/* macros for locking a channel */
#define ATA_LOCK_CH(ch, value) \
- atomic_cmpset_acq_int(&(ch)->active, ATA_IDLE, (value))
+ atomic_cmpset_acq_int(&(ch)->state, ATA_IDLE, (value))
#define ATA_SLEEPLOCK_CH(ch, value) \
- while (!atomic_cmpset_acq_int(&(ch)->active, ATA_IDLE, (value))) \
+ while (!atomic_cmpset_acq_int(&(ch)->state, ATA_IDLE, (value))) \
tsleep((caddr_t)&(ch), PRIBIO, "atalck", 1);
-#define ATA_FORCELOCK_CH(ch, value) atomic_store_rel_int(&(ch)->active, (value))
+#define ATA_FORCELOCK_CH(ch, value) atomic_store_rel_int(&(ch)->state, (value))
-#define ATA_UNLOCK_CH(ch) atomic_store_rel_int(&(ch)->active, ATA_IDLE)
+#define ATA_UNLOCK_CH(ch) atomic_store_rel_int(&(ch)->state, ATA_IDLE)
/* macros to hide busspace uglyness */
#define ATA_INB(res, offset) \
diff --git a/sys/dev/ata/ata-card.c b/sys/dev/ata/ata-card.c
index 1f4ba3a..198992a 100644
--- a/sys/dev/ata/ata-card.c
+++ b/sys/dev/ata/ata-card.c
@@ -35,6 +35,7 @@
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/malloc.h>
+#include <sys/taskqueue.h>
#include <machine/stdarg.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -45,8 +46,6 @@
#include <dev/pccard/pccarddevs.h>
static const struct pccard_product ata_pccard_products[] = {
- /* NetBSD has a few others that need to migrate into pccarddevs */
- /* XXX */
PCMCIA_CARD(FREECOM, PCCARDIDE, 0),
PCMCIA_CARD(EXP, EXPMULTIMEDIA, 0),
PCMCIA_CARD(IODATA, CBIDE2, 0),
@@ -72,7 +71,7 @@ ata_pccard_match(device_t dev)
if (fcn == PCCARD_FUNCTION_DISK)
return (0);
- /* Match other devices here, primarily cdrom/dvd rom */
+ /* match other devices here, primarily cdrom/dvd rom */
if ((pp = pccard_product_lookup(dev, ata_pccard_products,
sizeof(ata_pccard_products[0]), NULL)) != NULL) {
if (pp->pp_name)
diff --git a/sys/dev/ata/ata-cbus.c b/sys/dev/ata/ata-cbus.c
index 0bca3ab..ae4411d 100644
--- a/sys/dev/ata/ata-cbus.c
+++ b/sys/dev/ata/ata-cbus.c
@@ -35,6 +35,7 @@
#include <sys/ata.h>
#include <sys/bus.h>
#include <sys/malloc.h>
+#include <sys/taskqueue.h>
#include <machine/resource.h>
#include <machine/bus.h>
#include <sys/rman.h>
diff --git a/sys/dev/ata/ata-chipset.c b/sys/dev/ata/ata-chipset.c
index add97ea..ac96d82 100644
--- a/sys/dev/ata/ata-chipset.c
+++ b/sys/dev/ata/ata-chipset.c
@@ -35,6 +35,7 @@
#include <sys/ata.h>
#include <sys/bus.h>
#include <sys/malloc.h>
+#include <sys/taskqueue.h>
#include <machine/stdarg.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -74,6 +75,8 @@ static int ata_highpoint_check_80pin(struct ata_device *, int);
static int ata_intel_chipinit(device_t);
static void ata_intel_old_setmode(struct ata_device *, int);
static void ata_intel_new_setmode(struct ata_device *, int);
+static int ata_national_chipinit(device_t);
+static void ata_national_setmode(struct ata_device *, int);
static int ata_nvidia_chipinit(device_t);
static int ata_via_chipinit(device_t);
static void ata_via_family_setmode(struct ata_device *, int);
@@ -100,12 +103,12 @@ static void ata_sii_setmode(struct ata_device *, int);
static void ata_cmd_setmode(struct ata_device *, int);
static int ata_sis_chipinit(device_t);
static void ata_sis_setmode(struct ata_device *, int);
-static int ata_mode2idx(int);
static int ata_check_80pin(struct ata_device *, int);
static struct ata_chip_id *ata_find_chip(device_t, struct ata_chip_id *, int);
static struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *);
-static int ata_default_interrupt(device_t);
-static void ata_pci_serialize(struct ata_channel *, int);
+static int ata_setup_interrupt(device_t);
+static void ata_serialize(struct ata_channel *, int);
+static int ata_mode2idx(int);
/* generic or unknown ATA chipset init code */
int
@@ -123,7 +126,7 @@ ata_generic_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
ctlr->setmode = ata_generic_setmode;
return 0;
@@ -155,11 +158,9 @@ ata_generic_intr(void *data)
static void
ata_generic_setmode(struct ata_device *atadev, int mode)
{
- if (mode >= ATA_DMA)
- atadev->mode = ATA_DMA;
- else
- atadev->mode = ATA_PIO;
- return;
+ mode = ata_check_80pin(atadev, mode);
+ if (!ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode))
+ atadev->mode = mode;
}
/*
@@ -200,14 +201,14 @@ ata_acard_chipinit(device_t dev)
device_printf(dev, "unable to map interrupt\n");
return ENXIO;
}
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ata_acard_intr, ctlr, &ctlr->handle))) {
device_printf(dev, "unable to setup interrupt\n");
return ENXIO;
}
if (ctlr->chip->cfg1 == ATPOLD) {
ctlr->setmode = ata_acard_850_setmode;
- ctlr->locking = ata_pci_serialize;
+ ctlr->locking = ata_serialize;
}
else
ctlr->setmode = ata_acard_86X_setmode;
@@ -254,11 +255,10 @@ ata_acard_850_setmode(struct ata_device *atadev, int mode)
/* XXX missing WDMA0+1 + PIO modes */
if (mode >= ATA_WDMA2) {
- error = ata_command(atadev, ATA_C_SETFEATURES, 0,
- mode, ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode);
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (!error) {
u_int8_t reg54 = pci_read_config(parent, 0x54, 1);
@@ -292,11 +292,10 @@ ata_acard_86X_setmode(struct ata_device *atadev, int mode)
/* XXX missing WDMA0+1 + PIO modes */
if (mode >= ATA_WDMA2) {
- error = ata_command(atadev, ATA_C_SETFEATURES, 0,
- mode, ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode);
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (!error) {
u_int16_t reg44 = pci_read_config(parent, 0x44, 2);
@@ -345,7 +344,7 @@ ata_ali_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
/* deactivate the ATAPI FIFO and enable ATAPI UDMA */
@@ -390,11 +389,11 @@ ata_ali_setmode(struct ata_device *atadev, int mode)
}
}
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (!error) {
if (mode >= ATA_UDMA0) {
@@ -452,7 +451,7 @@ ata_amd_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
/* set prefetch, postwrite */
@@ -486,7 +485,7 @@ ata_cyrix_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
if (ctlr->r_io1)
@@ -510,11 +509,11 @@ ata_cyrix_setmode(struct ata_device *atadev, int mode)
mode = ata_limit_mode(atadev, mode, ATA_UDMA2);
atadev->channel->dma->alignment = 16;
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on Cyrix chip\n",
- (error) ? "failed" : "success", ata_mode2str(mode));
+ ata_prtdev(atadev, "%ssetting %s on Cyrix chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode));
if (!error) {
if (mode >= ATA_UDMA0) {
ATA_OUTL(ch->r_io[ATA_BMCMD_PORT].res,
@@ -562,7 +561,7 @@ ata_cypress_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
ctlr->setmode = ata_cypress_setmode;
@@ -579,11 +578,10 @@ ata_cypress_setmode(struct ata_device *atadev, int mode)
/* XXX missing WDMA0+1 + PIO modes */
if (mode == ATA_WDMA2) {
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0,mode);
if (bootverbose)
- ata_prtdev(atadev, "%s setting WDMA2 on Cypress chip\n",
- error ? "failed" : "success");
+ ata_prtdev(atadev, "%ssetting WDMA2 on Cypress chip\n",
+ error ? "FAILURE " : "");
if (!error) {
pci_write_config(parent, atadev->channel->unit?0x4e:0x4c,0x2020,2);
atadev->mode = mode;
@@ -641,7 +639,7 @@ ata_highpoint_chipinit(device_t dev)
device_printf(dev, "unable to map interrupt\n");
return ENXIO;
}
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ata_highpoint_intr, ctlr, &ctlr->handle))) {
device_printf(dev, "unable to setup interrupt\n");
return ENXIO;
@@ -724,11 +722,11 @@ ata_highpoint_setmode(struct ata_device *atadev, int mode)
mode = ata_highpoint_check_80pin(atadev, mode);
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on HighPoint chip\n",
- (error) ? "failed" : "success", ata_mode2str(mode));
+ ata_prtdev(atadev, "%ssetting %s on HighPoint chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode));
if (!error)
pci_write_config(parent, 0x40 + (devno << 2),
timings33[ata_mode2idx(mode)][ctlr->chip->cfg1], 4);
@@ -805,7 +803,7 @@ ata_intel_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
if (ctlr->chip->chipid == ATA_I82371FB)
@@ -845,11 +843,11 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode)
mode = ATA_UDMA2;
}
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (error)
return;
@@ -899,6 +897,92 @@ ata_intel_new_setmode(struct ata_device *atadev, int mode)
}
/*
+ * National chipset support functions
+ */
+int
+ata_national_ident(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+
+ /* this chip is a clone of the Cyrix chip, bugs and all */
+ if (pci_get_devid(dev) == ATA_SC1100) {
+ device_set_desc(dev, "National Geode SC1100 ATA33 controller");
+ ctlr->chipinit = ata_national_chipinit;
+ return 0;
+ }
+ return ENXIO;
+}
+
+static device_t nat_host = NULL;
+
+static int
+ata_national_chipinit(device_t dev)
+{
+ struct ata_pci_controller *ctlr = device_get_softc(dev);
+ device_t *children;
+ int nchildren, i;
+
+ if (ata_setup_interrupt(dev))
+ return ENXIO;
+
+ /* locate the ISA part in the southbridge and enable UDMA33 */
+ if (!device_get_children(device_get_parent(dev), &children,&nchildren)){
+ for (i = 0; i < nchildren; i++) {
+ if (pci_get_devid(children[i]) == 0x0510100b) {
+ nat_host = children[i];
+ break;
+ }
+ }
+ free(children, M_TEMP);
+ }
+ ctlr->setmode = ata_national_setmode;
+ return 0;
+}
+
+static void
+ata_national_setmode(struct ata_device *atadev, int mode)
+{
+ device_t parent = device_get_parent(atadev->channel->dev);
+ int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit);
+ u_int32_t piotiming[] =
+ { 0x9172d132, 0x21717121, 0x00803020, 0x20102010, 0x00100010,
+ 0x00803020, 0x20102010, 0x00100010,
+ 0x00100010, 0x00100010, 0x00100010 };
+ u_int32_t dmatiming[] = { 0x80077771, 0x80012121, 0x80002020 };
+ u_int32_t udmatiming[] = { 0x80921250, 0x80911140, 0x80911030 };
+ int error;
+
+ atadev->channel->dma->alignment = 4;
+ atadev->channel->dma->max_iosize = 63 * 1024;
+
+ mode = ata_limit_mode(atadev, mode, ATA_UDMA2);
+
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
+ if (bootverbose)
+ ata_prtdev(atadev, "%s setting %s on National chip\n",
+ (error) ? "failed" : "success", ata_mode2str(mode));
+ if (!error) {
+ if (mode >= ATA_UDMA0) {
+ pci_write_config(parent, 0x44 + (devno << 3),
+ udmatiming[mode & ATA_MODE_MASK], 4);
+ }
+ else if (mode >= ATA_WDMA0) {
+ pci_write_config(parent, 0x44 + (devno << 3),
+ dmatiming[mode & ATA_MODE_MASK], 4);
+ }
+ else {
+ pci_write_config(parent, 0x44 + (devno << 3),
+ pci_read_config(parent, 0x44 + (devno << 3), 4) |
+ 0x80000000, 4);
+ }
+ pci_write_config(parent, 0x40 + (devno << 3),
+ piotiming[ata_mode2idx(mode)], 4);
+ atadev->mode = mode;
+ }
+}
+
+/*
* nVidia chipset support functions
*/
int
@@ -927,7 +1011,7 @@ ata_nvidia_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
/* set prefetch, postwrite */
@@ -954,25 +1038,25 @@ ata_promise_ident(device_t dev)
{ ATA_PDC20263, 0, PRNEW, 0x00, ATA_UDMA4, "Promise PDC20263" },
{ ATA_PDC20265, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20265" },
{ ATA_PDC20267, 0, PRNEW, 0x00, ATA_UDMA5, "Promise PDC20267" },
- { ATA_PDC20268, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20268" },
- { ATA_PDC20269, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20269" },
- { ATA_PDC20270, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20270" },
- { ATA_PDC20271, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20271" },
- { ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20275" },
- { ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "Promise PDC20276" },
- { ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20277" },
- { ATA_PDC20318, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20318" },
- { ATA_PDC20319, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20319" },
- { ATA_PDC20371, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20371" },
- { ATA_PDC20375, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20375" },
- { ATA_PDC20376, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20376" },
- { ATA_PDC20377, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20377" },
- { ATA_PDC20378, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20378" },
- { ATA_PDC20379, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20379" },
- { ATA_PDC20617, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20617" },
- { ATA_PDC20618, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20618" },
- { ATA_PDC20619, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20619" },
- { ATA_PDC20620, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20620" },
+ { ATA_PDC20268, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20268" },
+ { ATA_PDC20269, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20269" },
+ { ATA_PDC20270, 0, PRTX, PRTX4, ATA_UDMA5, "Promise PDC20270" },
+ { ATA_PDC20271, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20271" },
+ { ATA_PDC20275, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20275" },
+ { ATA_PDC20276, 0, PRTX, PRSX6K, ATA_UDMA6, "Promise PDC20276" },
+ { ATA_PDC20277, 0, PRTX, 0x00, ATA_UDMA6, "Promise PDC20277" },
+ { ATA_PDC20318, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20318" },
+ { ATA_PDC20319, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20319" },
+ { ATA_PDC20371, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20371" },
+ { ATA_PDC20375, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20375" },
+ { ATA_PDC20376, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20376" },
+ { ATA_PDC20377, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20377" },
+ { ATA_PDC20378, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20378" },
+ { ATA_PDC20379, 0, PRMIO, PRSATA, ATA_SA150, "Promise PDC20379" },
+ { ATA_PDC20617, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20617" },
+ { ATA_PDC20618, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20618" },
+ { ATA_PDC20619, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20619" },
+ { ATA_PDC20620, 0, PRMIO, PRDUAL, ATA_UDMA6, "Promise PDC20620" },
{ 0, 0, 0, 0, 0, 0}};
char buffer[64];
uintptr_t devid = 0;
@@ -1039,7 +1123,7 @@ ata_promise_chipinit(device_t dev)
/* enable burst mode */
ATA_OUTB(ctlr->r_io1, 0x1f, ATA_INB(ctlr->r_io1, 0x1f) | 0x01);
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ata_promise_old_intr, ctlr, &ctlr->handle))) {
device_printf(dev, "unable to setup interrupt\n");
return ENXIO;
@@ -1047,7 +1131,7 @@ ata_promise_chipinit(device_t dev)
break;
case PRTX:
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ata_promise_tx2_intr, ctlr, &ctlr->handle))) {
device_printf(dev, "unable to setup interrupt\n");
return ENXIO;
@@ -1074,7 +1158,7 @@ ata_promise_chipinit(device_t dev)
else
ctlr->channels = 4;
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ata_promise_mio_intr, ctlr, &ctlr->handle))) {
device_printf(dev, "unable to setup interrupt\n");
return ENXIO;
@@ -1109,7 +1193,7 @@ ata_promise_mio_allocate(device_t dev, struct ata_channel *ch)
(ATA_IDX_INL(ch, ATA_BMCMD_PORT) & ~0x00000f8f) | ch->unit);
ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_0, 0x00000001);
- ch->flags |= ATA_NO_SLAVE;
+ ch->flags |= (ATA_NO_SLAVE | ATA_USE_16BIT);
ctlr->dmainit(ch);
return 0;
}
@@ -1171,13 +1255,13 @@ ata_promise_mio_intr(void *data)
struct ata_pci_controller *ctlr = data;
struct ata_channel *ch;
u_int32_t irq_vector;
- int unit;
+ int unit;
irq_vector = ATA_INL(ctlr->r_io2, 0x0040);
for (unit = 0; unit < ctlr->channels; unit++) {
if (irq_vector & (1 << unit)) {
if ((ch = ctlr->interrupt[unit].argument)) {
- ctlr->interrupt[unit].function(ch);
+ ctlr->interrupt[unit].function(ch);
ATA_IDX_OUTL(ch, ATA_BMDEVSPEC_0, 0x00000001);
}
}
@@ -1235,7 +1319,7 @@ ata_promise_setmode(struct ata_device *atadev, int mode)
break;
case PRMIO:
- if (mode > ATA_UDMA2 &&
+ if (mode > ATA_UDMA2 &&
(ATA_IDX_INL(atadev->channel, ATA_BMCTL_PORT) & 0x01000000)) {
ata_prtdev(atadev,
"DMA limited to UDMA33, non-ATA66 cable or device\n");
@@ -1244,16 +1328,15 @@ ata_promise_setmode(struct ata_device *atadev, int mode)
break;
}
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (!error) {
if (ctlr->chip->cfg1 < PRTX)
- pci_write_config(device_get_parent(atadev->channel->dev),
- 0x60 + (devno << 2),
+ pci_write_config(parent, 0x60 + (devno << 2),
timings33[ctlr->chip->cfg1][ata_mode2idx(mode)],4);
atadev->mode = mode;
}
@@ -1290,12 +1373,11 @@ ata_promise_new_dmastart(struct ata_channel *ch,
ATA_OUTL(ctlr->r_io1, 0x20,
(dir ? 0x05000000 : 0x06000000) | (count >> 1));
}
- ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab);
- ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, dir ? ATA_BMCMD_WRITE_READ : 0);
ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) |
(ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR)));
+ ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab);
ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
- ATA_IDX_INB(ch, ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP);
+ (dir ? ATA_BMCMD_WRITE_READ : 0) | ATA_BMCMD_START_STOP);
return error;
}
@@ -1388,17 +1470,31 @@ ata_serverworks_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
- if (ctlr->chip->cfg1 > SWKS33)
+ if (ctlr->chip->cfg1 == SWKS33) {
+ device_t *children;
+ int nchildren, i;
+
+ /* locate the ISA part in the southbridge and enable UDMA33 */
+ if (!device_get_children(device_get_parent(dev), &children,&nchildren)){
+ for (i = 0; i < nchildren; i++) {
+ if (pci_get_devid(children[i]) == ATA_ROSB4_ISA) {
+ pci_write_config(children[i], 0x64,
+ (pci_read_config(children[i], 0x64, 4) &
+ ~0x00002000) | 0x00004000, 4);
+ break;
+ }
+ }
+ free(children, M_TEMP);
+ }
+ }
+ else {
pci_write_config(dev, 0x5a,
(pci_read_config(dev, 0x5a, 1) & ~0x40) |
(ctlr->chip->cfg1 == SWKS100) ? 0x03 : 0x02, 1);
- else
- pci_write_config(dev, 0x64,
- (pci_read_config(dev, 0x64, 4) & ~0x00002000) |
- 0x00004000, 4);
+ }
ctlr->setmode = ata_serverworks_setmode;
return 0;
}
@@ -1411,35 +1507,50 @@ ata_serverworks_setmode(struct ata_device *atadev, int mode)
int devno = (atadev->channel->unit << 1) + ATA_DEV(atadev->unit);
int offset = devno ^ 0x01;
int error;
- u_int8_t timings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
- 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ u_int8_t piotimings[] = { 0x5d, 0x47, 0x34, 0x22, 0x20, 0x34, 0x22, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
+ u_int8_t dmatimings[] = { 0x77, 0x21, 0x20 };
mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma);
mode = ata_check_80pin(atadev, mode);
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (!error) {
if (mode >= ATA_UDMA0) {
- pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) |
- (0x01 << devno), 1);
pci_write_config(parent, 0x56,
(pci_read_config(parent, 0x56, 2) &
~(0xf << (devno << 2))) |
((mode & ATA_MODE_MASK) << (devno << 2)), 2);
+
+ pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) |
+ (0x01 << devno), 1);
+ pci_write_config(parent, 0x44,
+ (pci_read_config(parent, 0x44, 4) &
+ ~(0xff << (offset << 8))) |
+ (dmatimings[2] << (offset << 8)), 4);
+ }
+ else if (mode >= ATA_WDMA0) {
+ pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) &
+ ~(0x01 << devno), 1);
+ pci_write_config(parent, 0x44,
+ (pci_read_config(parent, 0x44, 4) &
+ ~(0xff << (offset << 8))) |
+ (dmatimings[mode & ATA_MODE_MASK]<<(offset<<8)),4);
}
else
- pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) |
+ pci_write_config(parent, 0x54, pci_read_config(parent, 0x54, 1) &
~(0x01 << devno), 1);
- pci_write_config(parent, 0x44,
- (pci_read_config(parent, 0x44, 4) &
+
+ pci_write_config(parent, 0x40,
+ (pci_read_config(parent, 0x40, 4) &
~(0xff << (offset << 8))) |
- (timings[ata_mode2idx(mode)] << (offset << 8)), 4);
+ (piotimings[ata_mode2idx(mode)] << (offset << 8)), 4);
atadev->mode = mode;
}
}
@@ -1453,12 +1564,12 @@ ata_sii_ident(device_t dev)
struct ata_pci_controller *ctlr = device_get_softc(dev);
struct ata_chip_id *idx;
static struct ata_chip_id ids[] =
- {{ ATA_SII3112, 0x00, SIIMEMIO, 0, ATA_SA150, "SiI 3112" },
+ {{ ATA_SII3112, 0x00, SIIMEMIO, 0, ATA_SA150, "SiI 3112" },
{ ATA_SII0680, 0x00, SIIMEMIO, SIISETCLK, ATA_UDMA6, "SiI 0680" },
- { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" },
- { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" },
- { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" },
- { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" },
+ { ATA_CMD649, 0x00, 0, SIIINTR, ATA_UDMA5, "CMD 649" },
+ { ATA_CMD648, 0x00, 0, SIIINTR, ATA_UDMA4, "CMD 648" },
+ { ATA_CMD646, 0x07, 0, 0, ATA_UDMA2, "CMD 646U2" },
+ { ATA_CMD646, 0x00, 0, 0, ATA_WDMA2, "CMD 646" },
{ 0, 0, 0, 0, 0, 0}};
char buffer[64];
@@ -1485,7 +1596,7 @@ ata_sii_chipinit(device_t dev)
}
if (ctlr->chip->cfg1 == SIIMEMIO) {
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ata_sii_intr, ctlr, &ctlr->handle))) {
device_printf(dev, "unable to setup interrupt\n");
return ENXIO;
@@ -1507,7 +1618,7 @@ ata_sii_chipinit(device_t dev)
ctlr->setmode = ata_sii_setmode;
}
else {
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ctlr->chip->cfg2 & SIIINTR ?
ata_cmd_intr : ata_generic_intr,
ctlr, &ctlr->handle))) {
@@ -1523,7 +1634,7 @@ ata_sii_chipinit(device_t dev)
/* enable interrupt as BIOS might not */
pci_write_config(dev, 0x71, 0x01, 1);
- ctlr->setmode = ata_cmd_setmode;
+ ctlr->setmode = ata_cmd_setmode;
}
return 0;
}
@@ -1586,18 +1697,18 @@ ata_cmd_intr(void *data)
{
struct ata_pci_controller *ctlr = data;
struct ata_channel *ch;
- u_int8_t dmastat;
+ u_int8_t dmastat, reg71;
int unit;
/* implement this as a toggle instead to balance load XXX */
for (unit = 0; unit < 2; unit++) {
if (!(ch = ctlr->interrupt[unit].argument))
continue;
- if (!(pci_read_config(device_get_parent(ch->dev), 0x71, 1) &
+ if (!((reg71 = pci_read_config(device_get_parent(ch->dev), 0x71, 1)) &
(ch->unit ? 0x08 : 0x04)))
continue;
pci_write_config(device_get_parent(ch->dev), 0x71,
- (ch->unit ? 0x08 : 0x04), 1);
+ reg71 & ~(ch->unit ? 0x04 : 0x08), 1);
if (ch->dma->flags & ATA_DMA_ACTIVE) {
if (!((dmastat = (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) &
ATA_BMSTAT_MASK)) & ATA_BMSTAT_INTERRUPT))
@@ -1617,24 +1728,34 @@ ata_sii_setmode(struct ata_device *atadev, int mode)
int rego = (atadev->channel->unit << 4) + (ATA_DEV(atadev->unit) << 1);
int mreg = atadev->channel->unit ? 0x84 : 0x80;
int mask = 0x03 << (ATA_DEV(atadev->unit) << 2);
- int mval = pci_read_config(parent, mreg, 1) & ~mask;
+ int mval;
int error;
mode = ata_limit_mode(atadev, mode, ctlr->chip->max_dma);
- if (ctlr->chip->max_dma < ATA_SA150)
+ if (ctlr->chip->max_dma < ATA_UDMA2) {
mode = ata_check_80pin(atadev, mode);
+ }
+ else if (ctlr->chip->max_dma < ATA_SA150 && mode > ATA_UDMA2 &&
+ (pci_read_config(parent, 0x79, 1) &
+ (atadev->channel->unit ? 0x02 : 0x01))) {
+ ata_prtdev(atadev,
+ "DMA limited to UDMA33, non-ATA66 cable or device\n");
+ mode = ATA_UDMA2;
+ }
+
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (error)
return;
+ mval = pci_read_config(parent, mreg, 1) & ~mask;
+
if (ctlr->chip->max_dma < ATA_SA150) {
if (mode >= ATA_UDMA0) {
u_int8_t udmatimings[] = { 0xf, 0xb, 0x7, 0x5, 0x3, 0x2, 0x1 };
@@ -1680,11 +1801,11 @@ ata_cmd_setmode(struct ata_device *atadev, int mode)
mode = ata_check_80pin(atadev, mode);
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (!error) {
int treg = 0x54 + (devno < 3) ? (devno << 1) : 7;
@@ -1730,35 +1851,35 @@ ata_sis_ident(device_t dev)
struct ata_pci_controller *ctlr = device_get_softc(dev);
struct ata_chip_id *idx;
static struct ata_chip_id ids[] =
- {{ ATA_SIS963, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 963" }, /* south */
- { ATA_SIS962, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 962" }, /* south */
-
- { ATA_SIS755, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 755" }, /* ext south */
- { ATA_SIS752, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 752" }, /* unknown */
- { ATA_SIS751, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 751" }, /* unknown */
- { ATA_SIS750, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 750" }, /* unknown */
- { ATA_SIS748, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 748" }, /* unknown */
- { ATA_SIS746, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 746" }, /* ext south */
- { ATA_SIS745, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 745" }, /* 1chip */
- { ATA_SIS740, 0x00, SIS_SOUTH, 0, ATA_UDMA5, "SiS 740" }, /* ext south */
- { ATA_SIS735, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 735" }, /* 1chip */
- { ATA_SIS733, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 733" }, /* 1chip */
- { ATA_SIS730, 0x00, SIS100OLD, 0, ATA_UDMA5, "SiS 730" }, /* 1chip */
-
- { ATA_SIS658, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 658" }, /* ext south */
- { ATA_SIS655, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 655" }, /* ext south */
- { ATA_SIS652, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 652" }, /* unknown */
- { ATA_SIS651, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 651" }, /* ext south */
- { ATA_SIS650, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 650" }, /* ext south */
- { ATA_SIS648, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 648" }, /* ext south */
+ {{ ATA_SIS963, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 963" }, /* south */
+ { ATA_SIS962, 0x00, SIS133NEW, 0, ATA_UDMA6, "SiS 962" }, /* south */
+
+ { ATA_SIS755, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 755" }, /* ext south */
+ { ATA_SIS752, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 752" }, /* unknown */
+ { ATA_SIS751, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 751" }, /* unknown */
+ { ATA_SIS750, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 750" }, /* unknown */
+ { ATA_SIS748, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 748" }, /* unknown */
+ { ATA_SIS746, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 746" }, /* ext south */
+ { ATA_SIS745, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 745" }, /* 1chip */
+ { ATA_SIS740, 0x00, SIS_SOUTH, 0, ATA_UDMA5, "SiS 740" }, /* ext south */
+ { ATA_SIS735, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 735" }, /* 1chip */
+ { ATA_SIS733, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 733" }, /* 1chip */
+ { ATA_SIS730, 0x00, SIS100OLD, 0, ATA_UDMA5, "SiS 730" }, /* 1chip */
+
+ { ATA_SIS658, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 658" }, /* ext south */
+ { ATA_SIS655, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 655" }, /* ext south */
+ { ATA_SIS652, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 652" }, /* unknown */
+ { ATA_SIS651, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 651" }, /* ext south */
+ { ATA_SIS650, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 650" }, /* ext south */
+ { ATA_SIS648, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 648" }, /* ext south */
{ ATA_SIS646, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 645DX"},/* ext south */
- { ATA_SIS645, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 645" }, /* ext south */
- { ATA_SIS640, 0x00, SIS_SOUTH, 0, ATA_UDMA4, "SiS 640" }, /* ext south */
- { ATA_SIS635, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 635" }, /* 1chip */
- { ATA_SIS633, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 633" }, /* unknown */
+ { ATA_SIS645, 0x00, SIS_SOUTH, 0, ATA_UDMA6, "SiS 645" }, /* ext south */
+ { ATA_SIS640, 0x00, SIS_SOUTH, 0, ATA_UDMA4, "SiS 640" }, /* ext south */
+ { ATA_SIS635, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 635" }, /* 1chip */
+ { ATA_SIS633, 0x00, SIS100NEW, 0, ATA_UDMA5, "SiS 633" }, /* unknown */
{ ATA_SIS630, 0x30, SIS100OLD, 0, ATA_UDMA5, "SiS 630S"}, /* 1chip */
- { ATA_SIS630, 0x00, SIS66, 0, ATA_UDMA4, "SiS 630" }, /* 1chip */
- { ATA_SIS620, 0x00, SIS66, 0, ATA_UDMA4, "SiS 620" }, /* 1chip */
+ { ATA_SIS630, 0x00, SIS66, 0, ATA_UDMA4, "SiS 630" }, /* 1chip */
+ { ATA_SIS620, 0x00, SIS66, 0, ATA_UDMA4, "SiS 620" }, /* 1chip */
{ ATA_SIS550, 0x00, SIS66, 0, ATA_UDMA5, "SiS 550" },
{ ATA_SIS540, 0x00, SIS66, 0, ATA_UDMA4, "SiS 540" },
@@ -1779,9 +1900,9 @@ ata_sis_ident(device_t dev)
sprintf(buffer, "SiS 96X %s controller",ata_mode2str(idx->max_dma));
}
else {
- struct ata_chip_id id[] =
- {{ ATA_SISSOUTH, 0x10, 0, 0, ATA_UDMA6, "SiS 961" },
- { 0, 0, 0, 0, 0, 0 }};
+ struct ata_chip_id id[] =
+ {{ ATA_SISSOUTH, 0x10, 0, 0, ATA_UDMA6, "SiS 961" },
+ { 0, 0, 0, 0, 0, 0 }};
if (ata_find_chip(dev, id, pci_get_slot(dev)))
idx->cfg1 = SIS133OLD;
@@ -1806,7 +1927,7 @@ ata_sis_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
switch (ctlr->chip->cfg1) {
@@ -1858,11 +1979,11 @@ ata_sis_setmode(struct ata_device *atadev, int mode)
}
}
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success",
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "",
ata_mode2str(mode), ctlr->chip->text);
if (!error) {
switch (ctlr->chip->cfg1) {
@@ -1949,7 +2070,7 @@ ata_via_chipinit(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
- if (ata_default_interrupt(dev))
+ if (ata_setup_interrupt(dev))
return ENXIO;
/* prepare for ATA-66 on the 82C686a and 82C596b */
@@ -2045,11 +2166,11 @@ ata_via_family_setmode(struct ata_device *atadev, int mode)
pci_write_config(parent, reg - 0x08, timings[ata_mode2idx(mode)], 1);
- error = ata_command(atadev, ATA_C_SETFEATURES, 0, mode,
- ATA_C_F_SETXFER, ATA_WAIT_READY);
+ error = ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_SETXFER, 0, mode);
+
if (bootverbose)
- ata_prtdev(atadev, "%s setting %s on %s chip\n",
- (error) ? "failed" : "success", ata_mode2str(mode),
+ ata_prtdev(atadev, "%ssetting %s on %s chip\n",
+ (error) ? "FAILURE " : "", ata_mode2str(mode),
ctlr->chip->text);
if (!error) {
if (mode >= ATA_UDMA0)
@@ -2062,26 +2183,6 @@ ata_via_family_setmode(struct ata_device *atadev, int mode)
}
/* misc functions */
-static int
-ata_mode2idx(int mode)
-{
- if ((mode & ATA_DMA_MASK) == ATA_UDMA0)
- return (mode & ATA_MODE_MASK) + 8;
- if ((mode & ATA_DMA_MASK) == ATA_WDMA0)
- return (mode & ATA_MODE_MASK) + 5;
- return (mode & ATA_MODE_MASK) - ATA_PIO0;
-}
-
-static int
-ata_check_80pin(struct ata_device *atadev, int mode)
-{
- if (mode > ATA_UDMA2 && !atadev->param->hwres_cblid) {
- ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n");
- mode = ATA_UDMA2;
- }
- return mode;
-}
-
static struct ata_chip_id *
ata_find_chip(device_t dev, struct ata_chip_id *index, int slot)
{
@@ -2119,7 +2220,7 @@ ata_match_chip(device_t dev, struct ata_chip_id *index)
}
static int
-ata_default_interrupt(device_t dev)
+ata_setup_interrupt(device_t dev)
{
struct ata_pci_controller *ctlr = device_get_softc(dev);
int rid = ATA_IRQ_RID;
@@ -2130,7 +2231,7 @@ ata_default_interrupt(device_t dev)
device_printf(dev, "unable to map interrupt\n");
return ENXIO;
}
- if ((bus_setup_intr(dev, ctlr->r_irq, INTR_TYPE_BIO | INTR_ENTROPY,
+ if ((bus_setup_intr(dev, ctlr->r_irq, ATA_INTR_FLAGS,
ata_generic_intr, ctlr, &ctlr->handle))) {
device_printf(dev, "unable to setup interrupt\n");
return ENXIO;
@@ -2140,7 +2241,7 @@ ata_default_interrupt(device_t dev)
}
static void
-ata_pci_serialize(struct ata_channel *ch, int flags)
+ata_serialize(struct ata_channel *ch, int flags)
{
struct ata_pci_controller *scp =
device_get_softc(device_get_parent(ch->dev));
@@ -2162,3 +2263,23 @@ ata_pci_serialize(struct ata_channel *ch, int flags)
}
return;
}
+
+static int
+ata_check_80pin(struct ata_device *atadev, int mode)
+{
+ if (mode > ATA_UDMA2 && !(atadev->param->hwres & ATA_CABLE_ID)) {
+ ata_prtdev(atadev,"DMA limited to UDMA33, non-ATA66 cable or device\n");
+ mode = ATA_UDMA2;
+ }
+ return mode;
+}
+
+static int
+ata_mode2idx(int mode)
+{
+ if ((mode & ATA_DMA_MASK) == ATA_UDMA0)
+ return (mode & ATA_MODE_MASK) + 8;
+ if ((mode & ATA_DMA_MASK) == ATA_WDMA0)
+ return (mode & ATA_MODE_MASK) + 5;
+ return (mode & ATA_MODE_MASK) - ATA_PIO0;
+}
diff --git a/sys/dev/ata/ata-commands.h b/sys/dev/ata/ata-commands.h
new file mode 100644
index 0000000..8b81b00
--- /dev/null
+++ b/sys/dev/ata/ata-commands.h
@@ -0,0 +1,127 @@
+/*-
+ * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/* ATA commands */
+#define ATA_NOP 0x00 /* NOP command */
+#define ATA_NF_FLUSHQUEUE 0x00 /* flush queued cmd's */
+#define ATA_NF_AUTOPOLL 0x01 /* start autopoll function */
+#define ATA_ATAPI_RESET 0x08 /* reset ATAPI device */
+#define ATA_READ 0x20 /* read command */
+#define ATA_READ48 0x24 /* read command */
+#define ATA_READ_DMA48 0x25 /* read w/DMA command */
+#define ATA_READ_DMA_QUEUED48 0x26 /* read w/DMA QUEUED command */
+#define ATA_READ_MUL48 0x29 /* read multi command */
+#define ATA_WRITE 0x30 /* write command */
+#define ATA_WRITE48 0x34 /* write command */
+#define ATA_WRITE_DMA48 0x35 /* write w/DMA command */
+#define ATA_WRITE_DMA_QUEUED48 0x36 /* write w/DMA QUEUED command */
+#define ATA_WRITE_MUL48 0x39 /* write multi command */
+#define ATA_PACKET_CMD 0xa0 /* packet command */
+#define ATA_ATAPI_IDENTIFY 0xa1 /* get ATAPI params*/
+#define ATA_SERVICE 0xa2 /* service command */
+#define ATA_READ_MUL 0xc4 /* read multi command */
+#define ATA_WRITE_MUL 0xc5 /* write multi command */
+#define ATA_SET_MULTI 0xc6 /* set multi size command */
+#define ATA_READ_DMA_QUEUED 0xc7 /* read w/DMA QUEUED command */
+#define ATA_READ_DMA 0xc8 /* read w/DMA command */
+#define ATA_WRITE_DMA 0xca /* write w/DMA command */
+#define ATA_WRITE_DMA_QUEUED 0xcc /* write w/DMA QUEUED command */
+#define ATA_SLEEP 0xe6 /* sleep command */
+#define ATA_FLUSHCACHE 0xe7 /* flush cache to disk */
+#define ATA_FLUSHCACHE48 0xea /* flush cache to disk */
+#define ATA_ATA_IDENTIFY 0xec /* get ATA params */
+#define ATA_SETFEATURES 0xef /* features command */
+#define ATA_SF_SETXFER 0x03 /* set transfer mode */
+#define ATA_SF_ENAB_WCACHE 0x02 /* enable write cache */
+#define ATA_SF_DIS_WCACHE 0x82 /* disable write cache */
+#define ATA_SF_ENAB_RCACHE 0xaa /* enable readahead cache */
+#define ATA_SF_DIS_RCACHE 0x55 /* disable readahead cache */
+#define ATA_SF_ENAB_RELIRQ 0x5d /* enable release interrupt */
+#define ATA_SF_DIS_RELIRQ 0xdd /* disable release interrupt */
+#define ATA_SF_ENAB_SRVIRQ 0x5e /* enable service interrupt */
+#define ATA_SF_DIS_SRVIRQ 0xde /* disable service interrupt */
+
+/* ATAPI commands */
+#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */
+#define ATAPI_REZERO 0x01 /* rewind */
+#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */
+#define ATAPI_FORMAT 0x04 /* format unit */
+#define ATAPI_READ 0x08 /* read data */
+#define ATAPI_WRITE 0x0a /* write data */
+#define ATAPI_WEOF 0x10 /* write filemark */
+#define ATAPI_WF_WRITE 0x01
+#define ATAPI_SPACE 0x11 /* space command */
+#define ATAPI_SP_FM 0x01
+#define ATAPI_SP_EOD 0x03
+#define ATAPI_MODE_SELECT 0x15 /* mode select */
+#define ATAPI_ERASE 0x19 /* erase */
+#define ATAPI_MODE_SENSE 0x1a /* mode sense */
+#define ATAPI_START_STOP 0x1b /* start/stop unit */
+#define ATAPI_SS_LOAD 0x01
+#define ATAPI_SS_RETENSION 0x02
+#define ATAPI_SS_EJECT 0x04
+#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */
+#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */
+#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
+#define ATAPI_READ_BIG 0x28 /* read data */
+#define ATAPI_WRITE_BIG 0x2a /* write data */
+#define ATAPI_LOCATE 0x2b /* locate to position */
+#define ATAPI_READ_POSITION 0x34 /* read position */
+#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */
+#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */
+#define ATAPI_READ_BUFFER 0x3c /* read device buffer */
+#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
+#define ATAPI_READ_TOC 0x43 /* get table of contents */
+#define ATAPI_PLAY_10 0x45 /* play by lba */
+#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */
+#define ATAPI_PLAY_TRACK 0x48 /* play by track number */
+#define ATAPI_PAUSE 0x4b /* pause audio operation */
+#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */
+#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */
+#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */
+#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */
+#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
+#define ATAPI_REPAIR_TRACK 0x58 /* repair track */
+#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */
+#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */
+#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */
+#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */
+#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */
+#define ATAPI_BLANK 0xa1 /* blank the media */
+#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */
+#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */
+#define ATAPI_PLAY_12 0xa5 /* play by lba */
+#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */
+#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */
+#define ATAPI_PLAY_CD 0xb4 /* universal play command */
+#define ATAPI_SET_SPEED 0xbb /* set drive speed */
+#define ATAPI_MECH_STATUS 0xbd /* get changer status */
+#define ATAPI_READ_CD 0xbe /* read data */
+#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */
diff --git a/sys/dev/ata/ata-disk.c b/sys/dev/ata/ata-disk.c
index b7b274d..8c2f5821 100644
--- a/sys/dev/ata/ata-disk.c
+++ b/sys/dev/ata/ata-disk.c
@@ -40,6 +40,7 @@
#include <sys/disk.h>
#include <sys/cons.h>
#include <sys/sysctl.h>
+#include <sys/taskqueue.h>
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/md_var.h>
@@ -52,27 +53,18 @@
#include <dev/ata/ata-raid.h>
/* prototypes */
+static void ad_detach(struct ata_device *atadev);
+static void ad_start(struct ata_device *atadev);
+static void ad_done(struct ata_request *request);
static disk_open_t adopen;
static disk_strategy_t adstrategy;
static dumper_t addump;
-static void ad_invalidatequeue(struct ad_softc *, struct ad_request *);
-static int ad_tagsupported(struct ad_softc *);
-static void ad_timeout(struct ad_request *);
-static void ad_free(struct ad_request *);
-static int ad_version(u_int16_t);
-
-/* misc defines */
-#define AD_MAX_RETRIES 3
+void ad_print(struct ad_softc *adp);
+static int ad_version(u_int16_t version);
/* internal vars */
-static u_int32_t adp_lun_map = 0;
-static int ata_dma = 1;
-static int ata_wc = 1;
-static int ata_tags = 0;
-TUNABLE_INT("hw.ata.ata_dma", &ata_dma);
-TUNABLE_INT("hw.ata.wc", &ata_wc);
-TUNABLE_INT("hw.ata.tags", &ata_tags);
static MALLOC_DEFINE(M_AD, "AD driver", "ATA disk driver");
+static u_int32_t adp_lun_map = 0;
/* sysctl vars */
SYSCTL_DECL(_hw_ata);
@@ -80,8 +72,6 @@ SYSCTL_INT(_hw_ata, OID_AUTO, ata_dma, CTLFLAG_RD, &ata_dma, 0,
"ATA disk DMA mode control");
SYSCTL_INT(_hw_ata, OID_AUTO, wc, CTLFLAG_RD, &ata_wc, 0,
"ATA disk write caching");
-SYSCTL_INT(_hw_ata, OID_AUTO, tags, CTLFLAG_RD, &ata_tags, 0,
- "ATA disk tagged queuing support");
void
ad_attach(struct ata_device *atadev)
@@ -91,7 +81,8 @@ ad_attach(struct ata_device *atadev)
u_int64_t lbasize48;
if (!(adp = malloc(sizeof(struct ad_softc), M_AD, M_NOWAIT | M_ZERO))) {
- ata_prtdev(atadev, "failed to allocate driver storage\n");
+ ata_prtdev(atadev, "FAILURE - could not allocate driver storage\n");
+ atadev->attach = NULL;
return;
}
adp->device = atadev;
@@ -104,12 +95,12 @@ ad_attach(struct ata_device *atadev)
adp->heads = atadev->param->heads;
adp->sectors = atadev->param->sectors;
adp->total_secs = atadev->param->cylinders * adp->heads * adp->sectors;
- adp->max_iosize = 256 * DEV_BSIZE;
if (adp->device->channel->flags & ATA_USE_PC98GEOM &&
adp->total_secs < 17 * 8 * 65536) {
adp->sectors = 17;
adp->heads = 8;
}
+ mtx_init(&adp->queue_mtx, "ATA disk bioqueue lock", MTX_DEF, 0);
bioq_init(&adp->queue);
lbasize = (u_int32_t)atadev->param->lba_size_1 |
@@ -118,7 +109,7 @@ ad_attach(struct ata_device *atadev)
/* does this device need oldstyle CHS addressing */
if (!ad_version(atadev->param->version_major) ||
!(atadev->param->atavalid & ATA_FLAG_54_58) || !lbasize)
- adp->flags |= AD_F_CHS_USED;
+ atadev->flags |= ATA_D_USE_CHS;
/* use the 28bit LBA size if valid or bigger than the CHS mapping */
if (atadev->param->cylinders == 16383 || adp->total_secs < lbasize)
@@ -130,106 +121,84 @@ ad_attach(struct ata_device *atadev)
((u_int64_t)atadev->param->lba_size48_4 << 48);
/* use the 48bit LBA size if valid */
- if (atadev->param->support.address48 && lbasize48 > 268435455)
+ if ((atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) &&
+ lbasize48 > 268435455)
adp->total_secs = lbasize48;
-
- ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL);
+
+ /* enable read caching */
+ ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_RCACHE, 0, 0);
+
+ /* enable write caching if enabled */
+ if (ata_wc)
+ ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_ENAB_WCACHE, 0, 0);
+ else
+ ata_controlcmd(atadev, ATA_SETFEATURES, ATA_SF_DIS_WCACHE, 0, 0);
/* use multiple sectors/interrupt if device supports it */
- adp->transfersize = DEV_BSIZE;
+ adp->max_iosize = DEV_BSIZE;
if (ad_version(atadev->param->version_major)) {
int secsperint = max(1, min(atadev->param->sectors_intr, 16));
- if (!ata_command(atadev, ATA_C_SET_MULTI, 0, secsperint,
- 0, ATA_WAIT_INTR) && !ata_wait(atadev, 0))
- adp->transfersize *= secsperint;
- }
-
- /* enable read caching if not default on device */
- if (ata_command(atadev, ATA_C_SETFEATURES,
- 0, 0, ATA_C_F_ENAB_RCACHE, ATA_WAIT_INTR))
- ata_prtdev(atadev, "enabling readahead cache failed\n");
-
- /* enable write caching if allowed and not default on device */
- if (ata_wc || (ata_tags && ad_tagsupported(adp))) {
- if (ata_command(atadev, ATA_C_SETFEATURES,
- 0, 0, ATA_C_F_ENAB_WCACHE, ATA_WAIT_INTR))
- ata_prtdev(atadev, "enabling write cache failed\n");
- }
- else {
- if (ata_command(atadev, ATA_C_SETFEATURES,
- 0, 0, ATA_C_F_DIS_WCACHE, ATA_WAIT_INTR))
- ata_prtdev(atadev, "disabling write cache failed\n");
+ if (!ata_controlcmd(atadev, ATA_SET_MULTI, 0, 0, secsperint))
+ adp->max_iosize = secsperint * DEV_BSIZE;
}
/* use DMA if allowed and if drive/controller supports it */
- if (ata_dma && atadev->channel->dma)
+ if (ata_dma && atadev->channel->dma)
atadev->setmode(atadev, ATA_DMA_MAX);
- else
+ else
atadev->setmode(atadev, ATA_PIO_MAX);
- /* use tagged queueing if allowed and supported */
-#if 0 /* disable tags for now */
- if (ata_tags && ad_tagsupported(adp)) {
- adp->num_tags = atadev->param->queuelen;
- adp->flags |= AD_F_TAG_ENABLED;
- adp->device->channel->flags |= ATA_QUEUED;
- if (ata_command(atadev, ATA_C_SETFEATURES,
- 0, 0, ATA_C_F_DIS_RELIRQ, ATA_WAIT_INTR))
- ata_prtdev(atadev, "disabling release interrupt failed\n");
- if (ata_command(atadev, ATA_C_SETFEATURES,
- 0, 0, ATA_C_F_DIS_SRVIRQ, ATA_WAIT_INTR))
- ata_prtdev(atadev, "disabling service interrupt failed\n");
- }
-#endif
- ATA_UNLOCK_CH(atadev->channel);
+ /* setup the function ptrs */
+ atadev->detach = ad_detach;
+ atadev->start = ad_start;
+ atadev->softc = adp;
+ /* lets create the disk device */
adp->disk.d_open = adopen;
adp->disk.d_strategy = adstrategy;
adp->disk.d_dump = addump;
adp->disk.d_name = "ad";
adp->disk.d_drv1 = adp;
- adp->disk.d_maxsize = adp->max_iosize;
+ if (atadev->channel->dma)
+ adp->disk.d_maxsize = atadev->channel->dma->max_iosize;
+ else
+ adp->disk.d_maxsize = DFLTPHYS;
adp->disk.d_sectorsize = DEV_BSIZE;
adp->disk.d_mediasize = DEV_BSIZE * (off_t)adp->total_secs;
adp->disk.d_fwsectors = adp->sectors;
adp->disk.d_fwheads = adp->heads;
- disk_create(adp->lun, &adp->disk, 0, NULL, NULL);
+ disk_create(adp->lun, &adp->disk, DISKFLAG_NOGIANT, NULL, NULL);
- atadev->driver = adp;
- atadev->flags = 0;
+ /* announce we are here */
+ ad_print(adp);
- ata_enclosure_print(atadev);
- if (atadev->driver)
- ad_print(adp);
+#ifdef DEV_ATARAID
ata_raiddisk_attach(adp);
+#endif
}
-void
+static void
ad_detach(struct ata_device *atadev)
{
- struct ad_softc *adp = atadev->driver;
- struct ad_request *request;
+ struct ad_softc *adp = atadev->softc;
atadev->flags |= ATA_D_DETACHING;
- ata_prtdev(atadev, "removed from configuration\n");
- ad_invalidatequeue(adp, NULL);
- TAILQ_FOREACH(request, &atadev->channel->ata_queue, chain) {
- if (request->softc != adp)
- continue;
- TAILQ_REMOVE(&atadev->channel->ata_queue, request, chain);
- biofinish(request->bp, NULL, ENXIO);
- ad_free(request);
- }
- bioq_flush(&adp->queue, NULL, ENXIO);
- disk_destroy(&adp->disk);
-
+#ifdef DEV_ATARAID
if (adp->flags & AD_F_RAID_SUBDISK)
ata_raiddisk_detach(adp);
-
+#endif
+ mtx_lock(&adp->queue_mtx);
+ bioq_flush(&adp->queue, NULL, ENXIO);
+ mtx_unlock(&adp->queue_mtx);
+ disk_destroy(&adp->disk);
+ ata_prtdev(atadev, "WARNING - removed from configuration\n");
ata_free_name(atadev);
ata_free_lun(&adp_lun_map, adp->lun);
- atadev->driver = NULL;
+ atadev->attach = NULL;
+ atadev->detach = NULL;
+ atadev->start = NULL;
+ atadev->softc = NULL;
atadev->flags = 0;
free(adp, M_AD);
}
@@ -239,12 +208,8 @@ adopen(struct disk *dp)
{
struct ad_softc *adp = dp->d_drv1;
- if (adp->flags & AD_F_RAID_SUBDISK)
- return EPERM;
-
- /* hold off access until we are fully attached */
- while (ata_delayed_attach)
- tsleep(&ata_delayed_attach, PRIBIO, "adopn", 1);
+ if (adp->device->flags & ATA_D_DETACHING)
+ return ENXIO;
return 0;
}
@@ -252,591 +217,145 @@ static void
adstrategy(struct bio *bp)
{
struct ad_softc *adp = bp->bio_disk->d_drv1;
- int s;
if (adp->device->flags & ATA_D_DETACHING) {
biofinish(bp, NULL, ENXIO);
return;
}
- s = splbio();
+ mtx_lock(&adp->queue_mtx);
bioq_disksort(&adp->queue, bp);
- splx(s);
+ mtx_unlock(&adp->queue_mtx);
ata_start(adp->device->channel);
}
-static int
-addump(void *arg, void *virtual, vm_offset_t physical,
- off_t offset, size_t length)
-{
- struct ad_softc *adp;
- struct ad_request request;
- static int once;
- struct disk *dp;
-
- dp = arg;
- adp = dp->d_drv1;
- if (!adp)
- return ENXIO;
-
- if (!once) {
- /* force PIO mode for dumps */
- adp->device->mode = ATA_PIO;
- adp->device->channel->locking(adp->device->channel, ATA_LF_LOCK);
- ata_reinit(adp->device->channel);
- adp->device->channel->locking(adp->device->channel, ATA_LF_UNLOCK);
- once = 1;
- }
-
- if (length > 0) {
- bzero(&request, sizeof(struct ad_request));
- request.softc = adp;
- request.blockaddr = offset / DEV_BSIZE;
- request.bytecount = length;
- request.data = virtual;
-
- while (request.bytecount > 0) {
- ad_transfer(&request);
- if (request.flags & ADR_F_ERROR)
- return EIO;
- request.donecount += request.currentsize;
- request.bytecount -= request.currentsize;
- DELAY(20);
- }
- } else {
- if (ata_wait(adp->device, ATA_S_READY | ATA_S_DSC) < 0)
- ata_prtdev(adp->device, "timeout waiting for final ready\n");
- }
- return 0;
-}
-
-void
+static void
ad_start(struct ata_device *atadev)
{
- struct ad_softc *adp = atadev->driver;
- struct bio *bp = bioq_first(&adp->queue);
- struct ad_request *request;
- int tag = 0;
+ struct ad_softc *adp = atadev->softc;
+ struct bio *bp;
+ struct ata_request *request;
- if (!bp)
+ /* remove request from drive queue */
+ mtx_lock(&adp->queue_mtx);
+ bp = bioq_first(&adp->queue);
+ if (!bp) {
+ mtx_unlock(&adp->queue_mtx);
return;
-
- /* if tagged queueing enabled get next free tag */
- if (adp->flags & AD_F_TAG_ENABLED) {
- while (tag <= adp->num_tags && adp->tags[tag])
- tag++;
- if (tag > adp->num_tags )
- return;
}
-
- /* remove request from drive queue */
bioq_remove(&adp->queue, bp);
+ mtx_unlock(&adp->queue_mtx);
- if (!(request = malloc(sizeof(struct ad_request), M_AD, M_NOWAIT|M_ZERO))) {
- ata_prtdev(atadev, "out of memory in start\n");
+ if (!(request = ata_alloc_request())) {
+ ata_prtdev(atadev, "FAILURE - out of memory in start\n");
biofinish(bp, NULL, ENOMEM);
return;
}
/* setup request */
- request->softc = adp;
- request->bp = bp;
- request->blockaddr = bp->bio_pblkno;
- request->bytecount = bp->bio_bcount;
+ request->device = atadev;
+ request->driver = bp;
+ request->callback = ad_done;
+ request->timeout = 5;
+ request->retries = 2;
request->data = bp->bio_data;
- request->tag = tag;
- if (bp->bio_cmd == BIO_READ)
- request->flags |= ADR_F_READ;
-
- if (adp->device->mode >= ATA_DMA && !atadev->channel->dma)
- adp->device->mode = ATA_PIO;
-
- /* insert in tag array */
- adp->tags[tag] = request;
-
- /* link onto controller queue */
- TAILQ_INSERT_TAIL(&atadev->channel->ata_queue, request, chain);
-}
-
-int
-ad_transfer(struct ad_request *request)
-{
- struct ad_softc *adp;
- u_int64_t lba;
- u_int32_t count;
- u_int8_t cmd;
- int flags = ATA_IMMEDIATE;
-
- /* get request params */
- adp = request->softc;
-
- /* calculate transfer details */
- lba = request->blockaddr + (request->donecount / DEV_BSIZE);
-
- /* start timeout for this transfer */
- if (!request->timeout_handle.callout && !dumping)
- request->timeout_handle =
- timeout((timeout_t*)ad_timeout, request, 10 * hz);
-
- if (request->donecount == 0) {
-
- /* check & setup transfer parameters */
- if (request->bytecount > adp->max_iosize) {
- ata_prtdev(adp->device,
- "%d byte transfers not supported\n", request->bytecount);
- count = howmany(adp->max_iosize, DEV_BSIZE);
- }
- else
- count = howmany(request->bytecount, DEV_BSIZE);
-
- if (count > (adp->device->param->support.address48 ? 65536 : 256)) {
- ata_prtdev(adp->device,
- "%d block transfers not supported\n", count);
- count = adp->device->param->support.address48 ? 65536 : 256;
- }
-
- if (adp->flags & AD_F_CHS_USED) {
- int sector = (lba % adp->sectors) + 1;
- int cylinder = lba / (adp->sectors * adp->heads);
- int head = (lba % (adp->sectors * adp->heads)) / adp->sectors;
-
- lba = (sector&0xff) | ((cylinder&0xffff)<<8) | ((head&0xf)<<24);
- adp->device->flags |= ATA_D_USE_CHS;
- }
-
- /* does this drive & transfer work with DMA ? */
- request->flags &= ~ADR_F_DMA_USED;
- if (adp->device->mode >= ATA_DMA &&
- !adp->device->channel->dma->setup(adp->device, request->data, request->bytecount)) {
- request->flags |= ADR_F_DMA_USED;
- request->currentsize = request->bytecount;
-
- /* do we have tags enabled ? */
- if (adp->flags & AD_F_TAG_ENABLED) {
- cmd = (request->flags & ADR_F_READ) ?
- ATA_C_READ_DMA_QUEUED : ATA_C_WRITE_DMA_QUEUED;
-
- if (ata_command(adp->device, cmd, lba,
- request->tag << 3, count, flags)) {
- ata_prtdev(adp->device, "error executing command");
- goto transfer_failed;
- }
- if (ata_wait(adp->device, ATA_S_READY)) {
- ata_prtdev(adp->device, "timeout waiting for READY\n");
- goto transfer_failed;
- }
- adp->outstanding++;
-
- /* if ATA bus RELEASE check for SERVICE */
- if (adp->flags & AD_F_TAG_ENABLED &&
- ATA_IDX_INB(adp->device->channel, ATA_IREASON) & ATA_I_RELEASE)
- return ad_service(adp, 1);
- }
- else {
- cmd = (request->flags & ADR_F_READ) ?
- ATA_C_READ_DMA : ATA_C_WRITE_DMA;
-
- if (ata_command(adp->device, cmd, lba, count, 0, flags)) {
- ata_prtdev(adp->device, "error executing command");
- goto transfer_failed;
- }
-#if 0
- /*
- * wait for data transfer phase
- *
- * well this should be here acording to specs, but older
- * promise controllers doesn't like it, they lockup!
- */
- if (ata_wait(adp->device, ATA_S_READY | ATA_S_DRQ)) {
- ata_prtdev(adp->device, "timeout waiting for data phase\n");
- goto transfer_failed;
- }
-#endif
- }
-
- /* start transfer, return and wait for interrupt */
- adp->device->channel->dma->start(adp->device->channel, request->data, request->bytecount,
- request->flags & ADR_F_READ);
- return ATA_OP_CONTINUES;
- }
-
- /* does this drive support multi sector transfers ? */
- if (adp->transfersize > DEV_BSIZE)
- cmd = request->flags&ADR_F_READ ? ATA_C_READ_MUL : ATA_C_WRITE_MUL;
+ request->bytecount = bp->bio_bcount;
- /* just plain old single sector transfer */
- else
- cmd = request->flags&ADR_F_READ ? ATA_C_READ : ATA_C_WRITE;
+ /* convert LBA contents if this is an old non-LBA device */
+ if (atadev->flags & ATA_D_USE_CHS) {
+ struct ata_params *param = atadev->param;
+ int sector = (bp->bio_pblkno % param->sectors) + 1;
+ int cylinder = bp->bio_pblkno / (param->sectors * param->heads);
+ int head = (bp->bio_pblkno %
+ (param->sectors * param->heads)) / param->sectors;
- if (ata_command(adp->device, cmd, lba, count, 0, flags)){
- ata_prtdev(adp->device, "error executing command");
- goto transfer_failed;
- }
- }
-
- /* calculate this transfer length */
- request->currentsize = min(request->bytecount, adp->transfersize);
-
- /* if this is a PIO read operation, return and wait for interrupt */
- if (request->flags & ADR_F_READ)
- return ATA_OP_CONTINUES;
-
- /* ready to write PIO data ? */
- if (ata_wait(adp->device, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
- ata_prtdev(adp->device, "timeout waiting for DRQ");
- goto transfer_failed;
+ request->u.ata.lba =
+ (sector & 0xff) | (cylinder & 0xffff) << 8 | (head & 0xf) << 24;
}
-
- /* output the data */
- if (adp->device->channel->flags & ATA_USE_16BIT)
- ATA_IDX_OUTSW_STRM(adp->device->channel, ATA_DATA,
- (void *)((uintptr_t)request->data + request->donecount),
- request->currentsize / sizeof(int16_t));
else
- ATA_IDX_OUTSL_STRM(adp->device->channel, ATA_DATA,
- (void *)((uintptr_t)request->data + request->donecount),
- request->currentsize / sizeof(int32_t));
- return ATA_OP_CONTINUES;
-
-transfer_failed:
- untimeout((timeout_t *)ad_timeout, request, request->timeout_handle);
- ad_invalidatequeue(adp, request);
-
- /* if retries still permit, reinject this request */
- if (request->retries++ < AD_MAX_RETRIES)
- TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain);
- else {
- /* retries all used up, return error */
- request->bp->bio_error = EIO;
- request->bp->bio_flags |= BIO_ERROR;
- request->bp->bio_resid = request->bytecount;
- biodone(request->bp);
- ad_free(request);
- }
- ata_reinit(adp->device->channel);
- return ATA_OP_CONTINUES;
-}
-
-int
-ad_interrupt(struct ad_request *request)
-{
- struct ad_softc *adp = request->softc;
- int dma_stat = 0;
-
- /* finish DMA transfer */
- if (request->flags & ADR_F_DMA_USED)
- dma_stat = adp->device->channel->dma->stop(adp->device->channel);
-
- /* do we have a corrected soft error ? */
- if (adp->device->channel->status & ATA_S_CORR)
- disk_err(request->bp, "soft error (ECC corrected)",
- request->donecount / DEV_BSIZE, 1);
-
- /* did any real errors happen ? */
- if ((adp->device->channel->status & ATA_S_ERROR) ||
- (request->flags & ADR_F_DMA_USED && dma_stat & ATA_BMSTAT_ERROR)) {
- adp->device->channel->error =
- ATA_IDX_INB(adp->device->channel, ATA_ERROR);
- disk_err(request->bp, (adp->device->channel->error & ATA_E_ICRC) ?
- "UDMA ICRC error" : "hard error",
- request->donecount / DEV_BSIZE, 0);
-
- /* if this is a UDMA CRC error, reinject request */
- if (request->flags & ADR_F_DMA_USED &&
- adp->device->channel->error & ATA_E_ICRC) {
- untimeout((timeout_t *)ad_timeout, request,request->timeout_handle);
- ad_invalidatequeue(adp, request);
-
- if (request->retries++ < AD_MAX_RETRIES)
- printf(" retrying\n");
- else {
- adp->device->setmode(adp->device, ATA_PIO_MAX);
- printf(" falling back to PIO mode\n");
- }
- TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain);
- return ATA_OP_FINISHED;
- }
-#if 0 /* XXX*/
- /* if using DMA, try once again in PIO mode */
- if (request->flags & ADR_F_DMA_USED) {
- untimeout((timeout_t *)ad_timeout, request,request->timeout_handle);
- ad_invalidatequeue(adp, request);
- adp->device->setmode(adp->device, ATA_PIO_MAX);
- request->flags |= ADR_F_FORCE_PIO;
- printf(" trying PIO mode\n");
- TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain);
- return ATA_OP_FINISHED;
- }
-#endif
- request->flags |= ADR_F_ERROR;
- printf(" status=%02x error=%02x\n",
- adp->device->channel->status, adp->device->channel->error);
- }
-
- /* if we arrived here with forced PIO mode, DMA doesn't work right */
- if (request->flags & ADR_F_FORCE_PIO && !(request->flags & ADR_F_ERROR))
- ata_prtdev(adp->device, "DMA problem fallback to PIO mode\n");
-
- /* if this was a PIO read operation, get the data */
- if (!(request->flags & ADR_F_DMA_USED) &&
- (request->flags & (ADR_F_READ | ADR_F_ERROR)) == ADR_F_READ) {
-
- /* ready to receive data? */
- if ((adp->device->channel->status & (ATA_S_READY|ATA_S_DSC|ATA_S_DRQ))
- != (ATA_S_READY|ATA_S_DSC|ATA_S_DRQ))
- ata_prtdev(adp->device, "read interrupt arrived early");
-
- if (ata_wait(adp->device, (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) != 0) {
- ata_prtdev(adp->device, "read error detected (too) late");
- request->flags |= ADR_F_ERROR;
- }
- else {
- /* data ready, read in */
- if (adp->device->channel->flags & ATA_USE_16BIT)
- ATA_IDX_INSW_STRM(adp->device->channel, ATA_DATA,
- (void*)((uintptr_t)request->data +
- request->donecount), request->currentsize /
- sizeof(int16_t));
- else
- ATA_IDX_INSL_STRM(adp->device->channel, ATA_DATA,
- (void*)((uintptr_t)request->data +
- request->donecount), request->currentsize /
- sizeof(int32_t));
- }
- }
-
- /* finish up transfer */
- if (request->flags & ADR_F_ERROR) {
- request->bp->bio_error = EIO;
- request->bp->bio_flags |= BIO_ERROR;
- }
- else {
- request->bytecount -= request->currentsize;
- request->donecount += request->currentsize;
- if (!(request->flags & ADR_F_DMA_USED) && request->bytecount > 0) {
- ad_transfer(request);
- return ATA_OP_CONTINUES;
- }
- }
-
- /* disarm timeout for this transfer */
- untimeout((timeout_t *)ad_timeout, request, request->timeout_handle);
-
- request->bp->bio_resid = request->bytecount;
-
- biodone(request->bp);
- ad_free(request);
- adp->outstanding--;
-
- /* check for SERVICE */
- return ad_service(adp, 1);
-}
+ request->u.ata.lba = bp->bio_pblkno;
-int
-ad_service(struct ad_softc *adp, int change)
-{
- /* do we have to check the other device on this channel ? */
- if (adp->device->channel->flags & ATA_QUEUED && change) {
- int device = adp->device->unit;
-
- if (adp->device->unit == ATA_MASTER) {
- if ((adp->device->channel->devices & ATA_ATA_SLAVE) &&
- (adp->device->channel->device[SLAVE].driver) &&
- ((struct ad_softc *) (adp->device->channel->
- device[SLAVE].driver))->flags & AD_F_TAG_ENABLED)
- device = ATA_SLAVE;
- }
- else {
- if ((adp->device->channel->devices & ATA_ATA_MASTER) &&
- (adp->device->channel->device[MASTER].driver) &&
- ((struct ad_softc *) (adp->device->channel->
- device[MASTER].driver))->flags & AD_F_TAG_ENABLED)
- device = ATA_MASTER;
- }
- if (device != adp->device->unit &&
- ((struct ad_softc *)
- (adp->device->channel->
- device[ATA_DEV(device)].driver))->outstanding > 0) {
- ATA_IDX_OUTB(adp->device->channel, ATA_DRIVE, ATA_D_IBM | device);
- adp = adp->device->channel->device[ATA_DEV(device)].driver;
- DELAY(1);
- }
- }
- adp->device->channel->status =
- ATA_IDX_INB(adp->device->channel, ATA_ALTSTAT);
-
- /* do we have a SERVICE request from the drive ? */
- if (adp->flags & AD_F_TAG_ENABLED &&
- adp->outstanding > 0 &&
- adp->device->channel->status & ATA_S_SERVICE) {
- struct ad_request *request;
- int tag;
-
- /* check for error */
- if (adp->device->channel->status & ATA_S_ERROR) {
- ata_prtdev(adp->device, "Oops! controller says s=0x%02x e=0x%02x\n",
- adp->device->channel->status,
- adp->device->channel->error);
- ad_invalidatequeue(adp, NULL);
- return ATA_OP_FINISHED;
- }
-
- /* issue SERVICE cmd */
- if (ata_command(adp->device, ATA_C_SERVICE, 0, 0, 0, ATA_IMMEDIATE)) {
- ata_prtdev(adp->device, "problem executing SERVICE cmd\n");
- ad_invalidatequeue(adp, NULL);
- return ATA_OP_FINISHED;
- }
+ request->u.ata.count = request->bytecount / DEV_BSIZE;
+ request->transfersize = min(bp->bio_bcount, adp->max_iosize);
- /* setup the transfer environment when ready */
- if (ata_wait(adp->device, ATA_S_READY)) {
- ata_prtdev(adp->device, "SERVICE timeout tag=%d s=%02x e=%02x\n",
- ATA_IDX_INB(adp->device->channel, ATA_COUNT) >> 3,
- adp->device->channel->status,
- adp->device->channel->error);
- ad_invalidatequeue(adp, NULL);
- return ATA_OP_FINISHED;
+ switch (bp->bio_cmd) {
+ case BIO_READ:
+ request->flags |= ATA_R_READ;
+ if (atadev->mode >= ATA_DMA) {
+ request->u.ata.command = ATA_READ_DMA;
+ request->flags |= ATA_R_DMA;
}
- tag = ATA_IDX_INB(adp->device->channel, ATA_COUNT) >> 3;
- if (!(request = adp->tags[tag])) {
- ata_prtdev(adp->device, "no request for tag=%d\n", tag);
- ad_invalidatequeue(adp, NULL);
- return ATA_OP_FINISHED;
- }
- ATA_FORCELOCK_CH(adp->device->channel, ATA_ACTIVE_ATA);
- adp->device->channel->running = request;
- request->serv++;
-
- /* start DMA transfer when ready */
- if (ata_wait(adp->device, ATA_S_READY | ATA_S_DRQ)) {
- ata_prtdev(adp->device, "timeout starting DMA s=%02x e=%02x\n",
- adp->device->channel->status,
- adp->device->channel->error);
- ad_invalidatequeue(adp, NULL);
- return ATA_OP_FINISHED;
+ else if (adp->max_iosize > DEV_BSIZE)
+ request->u.ata.command = ATA_READ_MUL;
+ else
+ request->u.ata.command = ATA_READ;
+
+ break;
+ case BIO_WRITE:
+ request->flags |= ATA_R_WRITE;
+ if (atadev->mode >= ATA_DMA) {
+ request->u.ata.command = ATA_WRITE_DMA;
+ request->flags |= ATA_R_DMA;
}
- adp->device->channel->dma->start(adp->device->channel, request->data, request->bytecount,
- request->flags & ADR_F_READ);
- return ATA_OP_CONTINUES;
+ else if (adp->max_iosize > DEV_BSIZE)
+ request->u.ata.command = ATA_WRITE_MUL;
+ else
+ request->u.ata.command = ATA_WRITE;
+ break;
+ default:
+ ata_prtdev(atadev, "FAILURE - unknown BIO operation\n");
+ ata_free_request(request);
+ biofinish(bp, NULL, EIO);
+ return;
}
- return ATA_OP_FINISHED;
+ request->flags |= ATA_R_SKIPSTART;
+ ata_queue_request(request);
}
static void
-ad_free(struct ad_request *request)
+ad_done(struct ata_request *request)
{
- request->softc->tags[request->tag] = NULL;
- free(request, M_AD);
-}
+ struct bio *bp = request->driver;
-static void
-ad_invalidatequeue(struct ad_softc *adp, struct ad_request *request)
-{
- /* if tags in use invalidate all other outstanding transfers */
- if (adp->flags & AD_F_TAG_ENABLED) {
- struct ad_request *tmpreq;
- int tag;
-
- ata_prtdev(adp->device, "invalidating queued requests\n");
- for (tag = 0; tag <= adp->num_tags; tag++) {
- tmpreq = adp->tags[tag];
- adp->tags[tag] = NULL;
- if (tmpreq == request || tmpreq == NULL)
- continue;
- untimeout((timeout_t *)ad_timeout, tmpreq, tmpreq->timeout_handle);
- TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, tmpreq, chain);
- }
- adp->outstanding = 0;
- if (ata_command(adp->device, ATA_C_NOP,
- 0, 0, ATA_C_F_FLUSHQUEUE, ATA_WAIT_READY))
- ata_prtdev(adp->device, "flush queue failed\n");
- }
+ /* finish up transfer */
+ if ((bp->bio_error = request->result))
+ bp->bio_flags |= BIO_ERROR;
+ bp->bio_resid = bp->bio_bcount - request->donecount;
+ biodone(bp);
+ ata_free_request(request);
}
static int
-ad_tagsupported(struct ad_softc *adp)
+addump(void *arg, void *virtual, vm_offset_t physical,
+ off_t offset, size_t length)
{
- /* check for controllers that we know doesn't support tags */
- switch (adp->device->channel->chiptype) {
- case ATA_PDC20265: case ATA_PDC20263: case ATA_PDC20267:
- case ATA_PDC20246: case ATA_PDC20262:
- return 0;
- }
-
- /* check that drive does DMA, has tags enabled, and is one we know works */
- if (adp->device->mode >= ATA_DMA && adp->device->param->support.queued &&
- adp->device->param->enabled.queued) {
-
- /* IBM DTTA series needs transfers <= 64K for tags to work properly */
- if (!strncmp(adp->device->param->model, "IBM-DTTA", 8)) {
- adp->max_iosize = 128 * DEV_BSIZE;
- return 1;
- }
+ struct ata_request request;
+ struct disk *dp = arg;
+ struct ad_softc *adp = dp->d_drv1;
- /* IBM DJNA series has broken tags, corrupts data */
- if (!strncmp(adp->device->param->model, "IBM-DJNA", 8))
- return 0;
+ if (!adp)
+ return ENXIO;
- /* IBM DPTA & IBM DTLA series supports tags */
- if (!strncmp(adp->device->param->model, "IBM-DPTA", 8) ||
- !strncmp(adp->device->param->model, "IBM-DTLA", 8))
- return 1;
+ bzero(&request, sizeof(struct ata_request));
+ request.data = virtual;
+ request.bytecount = length;
+ request.transfersize = min(length, adp->max_iosize);
- /* IBM IC series ATA drives supports tags */
- if (!strncmp(adp->device->param->model, "IC", 2) &&
- (!strncmp(adp->device->param->model + 8, "AT", 2) ||
- !strncmp(adp->device->param->model + 8, "AV", 2)))
- return 1;
+ request.flags |= ATA_R_WRITE;
+ if (adp->max_iosize > DEV_BSIZE)
+ request.u.ata.command = ATA_WRITE_MUL;
+ else
+ request.u.ata.command = ATA_WRITE;
+ request.u.ata.lba = offset / DEV_BSIZE;
+ request.u.ata.count = request.bytecount / DEV_BSIZE;
+
+ while (request.bytecount > request.donecount) {
+ if (adp->device->channel->hw.transaction(&request) == ATA_OP_FINISHED)
+ return EIO;
+ DELAY(20);
}
return 0;
}
-static void
-ad_timeout(struct ad_request *request)
-{
- struct ad_softc *adp = request->softc;
-
- adp->device->channel->running = NULL;
- request->timeout_handle.callout = NULL;
- ata_prtdev(adp->device, "%s command timeout tag=%d serv=%d - resetting\n",
- (request->flags & ADR_F_READ) ? "READ" : "WRITE",
- request->tag, request->serv);
-
- if (request->flags & ADR_F_DMA_USED) {
- adp->device->channel->dma->stop(adp->device->channel);
- ad_invalidatequeue(adp, request);
- if (request->retries == AD_MAX_RETRIES) {
- adp->device->setmode(adp->device, ATA_PIO_MAX);
- ata_prtdev(adp->device, "trying fallback to PIO mode\n");
- request->retries = 0;
- }
- }
-
- /* if retries still permit, reinject this request */
- if (request->retries++ < AD_MAX_RETRIES) {
- TAILQ_INSERT_HEAD(&adp->device->channel->ata_queue, request, chain);
- }
- else {
- /* retries all used up, return error */
- request->bp->bio_error = EIO;
- request->bp->bio_flags |= BIO_ERROR;
- biodone(request->bp);
- ad_free(request);
- }
- ata_reinit(adp->device->channel);
-}
-
-void
-ad_reinit(struct ata_device *atadev)
-{
- struct ad_softc *adp = atadev->driver;
-
- /* reinit disk parameters */
- ad_invalidatequeue(atadev->driver, NULL);
- ata_command(atadev, ATA_C_SET_MULTI, 0,
- adp->transfersize / DEV_BSIZE, 0, ATA_WAIT_READY);
- atadev->setmode(atadev, adp->device->mode);
-}
-
void
ad_print(struct ad_softc *adp)
{
@@ -857,15 +376,9 @@ ad_print(struct ad_softc *adp)
adp->heads, adp->sectors, DEV_BSIZE);
ata_prtdev(adp->device, "%d secs/int, %d depth queue, %s%s\n",
- adp->transfersize / DEV_BSIZE, adp->num_tags + 1,
+ adp->max_iosize / DEV_BSIZE, adp->num_tags + 1,
(adp->flags & AD_F_TAG_ENABLED) ? "tagged " : "",
ata_mode2str(adp->device->mode));
-
- ata_prtdev(adp->device, "piomode=%d dmamode=%d udmamode=%d cblid=%d\n",
- ata_pmode(adp->device->param), ata_wmode(adp->device->param),
- ata_umode(adp->device->param),
- adp->device->param->hwres_cblid);
-
}
else
ata_prtdev(adp->device,"%lluMB <%.40s> [%lld/%d/%d] at ata%d-%s %s%s\n",
diff --git a/sys/dev/ata/ata-disk.h b/sys/dev/ata/ata-disk.h
index 11d58c1..1373fd2 100644
--- a/sys/dev/ata/ata-disk.h
+++ b/sys/dev/ata/ata-disk.h
@@ -28,29 +28,6 @@
* $FreeBSD$
*/
-/* structure describing an ATA disk request */
-struct ad_request {
- struct ad_softc *softc; /* ptr to parent device */
- u_int32_t blockaddr; /* block number */
- u_int32_t bytecount; /* bytes to transfer */
- u_int32_t donecount; /* bytes transferred */
- u_int32_t currentsize; /* size of current transfer */
- struct callout_handle timeout_handle; /* handle for untimeout */
- int retries; /* retry count */
- int flags;
-#define ADR_F_READ 0x0001
-#define ADR_F_ERROR 0x0002
-#define ADR_F_DMA_USED 0x0004
-#define ADR_F_QUEUED 0x0008
-#define ADR_F_FORCE_PIO 0x0010
-
- caddr_t data; /* pointer to data buf */
- struct bio *bp; /* associated bio ptr */
- u_int8_t tag; /* tag ID of this request */
- int serv; /* request had service */
- TAILQ_ENTRY(ad_request) chain; /* list management */
-};
-
/* structure describing an ATA disk */
struct ad_softc {
struct ata_device *device; /* ptr to device softc */
@@ -60,7 +37,7 @@ struct ad_softc {
u_int8_t sectors;
u_int32_t transfersize; /* size of each transfer */
int num_tags; /* number of tags supported */
- int max_iosize; /* max size of transfer */
+ int max_iosize; /* max transfer HW supports */
int flags; /* drive flags */
#define AD_F_LABELLING 0x0001
#define AD_F_CHS_USED 0x0002
@@ -68,17 +45,7 @@ struct ad_softc {
#define AD_F_TAG_ENABLED 0x0008
#define AD_F_RAID_SUBDISK 0x0010
- struct ad_request *tags[32]; /* tag array of requests */
- int outstanding; /* tags not serviced yet */
+ struct mtx queue_mtx; /* queue lock */
struct bio_queue_head queue; /* head of request queue */
struct disk disk; /* disklabel/slice stuff */
};
-
-void ad_attach(struct ata_device *);
-void ad_detach(struct ata_device *);
-void ad_reinit(struct ata_device *);
-void ad_start(struct ata_device *);
-int ad_transfer(struct ad_request *);
-int ad_interrupt(struct ad_request *);
-int ad_service(struct ad_softc *, int);
-void ad_print(struct ad_softc *);
diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c
index 4dfff5a..a94bf18 100644
--- a/sys/dev/ata/ata-dma.c
+++ b/sys/dev/ata/ata-dma.c
@@ -36,10 +36,11 @@
#include <sys/malloc.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/taskqueue.h>
#include <sys/bus.h>
-#include <dev/pci/pcivar.h>
#include <machine/bus.h>
#include <sys/rman.h>
+#include <dev/pci/pcivar.h>
#include <dev/ata/ata-all.h>
#include <dev/ata/ata-pci.h>
@@ -67,7 +68,7 @@ int
ata_dmainit(struct ata_channel *ch)
{
if (!(ch->dma =
- malloc(sizeof(struct ata_dma_data), M_ATADMA, M_NOWAIT | M_ZERO)))
+ malloc(sizeof(struct ata_dma), M_ATADMA, M_NOWAIT | M_ZERO)))
return ENOMEM;
ch->dma->alloc = ata_dmaalloc;
ch->dma->free = ata_dmafree;
@@ -75,6 +76,7 @@ ata_dmainit(struct ata_channel *ch)
ch->dma->start = ata_dmastart;
ch->dma->stop = ata_dmastop;
ch->dma->alignment = 2;
+ ch->dma->max_iosize = 64*1024;
return 0;
}
@@ -98,9 +100,10 @@ ata_dmaalloc(struct ata_channel *ch)
if (bus_dma_tag_create(NULL, 1, 0,
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
NULL, NULL, MAXCTLDMASZ, ATA_DMA_ENTRIES,
- BUS_SPACE_MAXSIZE_32BIT, 0, busdma_lock_mutex,
- &Giant, &ch->dma->dmatag)) {
- printf("DMA tag allocation failed, disabling DMA\n");
+ BUS_SPACE_MAXSIZE_32BIT, 0, NULL, NULL,
+ &ch->dma->dmatag)) {
+ ata_printf(ch, -1,
+ "WARNING - DMA tag allocation failed, disabling DMA\n");
}
}
if (!ch->dma->cdmatag) {
@@ -108,8 +111,8 @@ ata_dmaalloc(struct ata_channel *ch)
BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL,
MAXTABSZ, 1, MAXTABSZ,
- BUS_DMA_ALLOCNOW, busdma_lock_mutex,
- &Giant, &ch->dma->cdmatag)))
+ BUS_DMA_ALLOCNOW, NULL, NULL,
+ &ch->dma->cdmatag)))
return error;
}
if (!ch->dma->ddmatag) {
@@ -117,8 +120,8 @@ ata_dmaalloc(struct ata_channel *ch)
BUS_SPACE_MAXADDR_32BIT,
BUS_SPACE_MAXADDR, NULL, NULL,
MAXPHYS, ATA_DMA_ENTRIES, MAXSEGSZ,
- BUS_DMA_ALLOCNOW, busdma_lock_mutex,
- &Giant, &ch->dma->ddmatag)))
+ BUS_DMA_ALLOCNOW, NULL, NULL,
+ &ch->dma->ddmatag)))
return error;
}
if (!ch->dma->mdmatab) {
@@ -211,12 +214,17 @@ ata_dmasetup(struct ata_device *atadev, caddr_t data, int32_t count)
if (((uintptr_t)data & (ch->dma->alignment - 1)) ||
(count & (ch->dma->alignment - 1))) {
- ata_prtdev(atadev, "non aligned DMA transfer attempted\n");
+ ata_prtdev(atadev, "FAILURE - non aligned DMA transfer attempted\n");
return -1;
}
-
if (!count) {
- ata_prtdev(atadev, "zero length DMA transfer attempted\n");
+ ata_prtdev(atadev, "FAILURE - zero length DMA transfer attempted\n");
+ return -1;
+ }
+ if (count > ch->dma->max_iosize) {
+ ata_prtdev(atadev,
+ "FAILURE - oversized DMA transfer attempted %d > %d\n",
+ count, ch->dma->max_iosize);
return -1;
}
return 0;
@@ -232,12 +240,10 @@ ata_dmastart(struct ata_channel *ch, caddr_t data, int32_t count, int dir)
cba.dmatab = ch->dma->dmatab;
bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_PREWRITE);
-
if (bus_dmamap_load(ch->dma->ddmatag, ch->dma->ddmamap, data, count,
ata_dmasetupd_cb, &cba, 0) || cba.error)
return -1;
- bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_POSTWRITE);
bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap,
dir ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
@@ -248,10 +254,13 @@ ata_dmastart(struct ata_channel *ch, caddr_t data, int32_t count, int dir)
int
ata_dmastop(struct ata_channel *ch)
{
+ bus_dmamap_sync(ch->dma->cdmatag, ch->dma->cdmamap, BUS_DMASYNC_POSTWRITE);
+
bus_dmamap_sync(ch->dma->ddmatag, ch->dma->ddmamap,
(ch->dma->flags & ATA_DMA_READ) != 0 ?
BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
bus_dmamap_unload(ch->dma->ddmatag, ch->dma->ddmamap);
+
ch->dma->flags = 0;
return 0;
}
diff --git a/sys/dev/ata/ata-isa.c b/sys/dev/ata/ata-isa.c
index 0f4688a..719c5e8 100644
--- a/sys/dev/ata/ata-isa.c
+++ b/sys/dev/ata/ata-isa.c
@@ -37,6 +37,7 @@
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/malloc.h>
+#include <sys/taskqueue.h>
#include <machine/stdarg.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -63,7 +64,7 @@ ata_isa_lock(struct ata_channel *ch, int type)
static void
ata_isa_setmode(struct ata_device *atadev, int mode)
{
- atadev->mode = ata_limit_mode(atadev, mode, ATA_PIO_MAX);
+ atadev->mode = min(mode, ATA_PIO_MAX);
}
static int
@@ -94,10 +95,10 @@ ata_isa_probe(device_t dev)
/* allocate the altport range */
rid = ATA_ALTADDR_RID;
altio = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0,
- ATA_ALTIOSIZE, RF_ACTIVE);
+ ATA_ALTIOSIZE, RF_ACTIVE);
if (!altio) {
- bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
- return ENXIO;
+ bus_release_resource(dev, SYS_RES_IOPORT, ATA_IOADDR_RID, io);
+ return ENXIO;
}
/* setup the resource vectors */
diff --git a/sys/dev/ata/ata-lowlevel.c b/sys/dev/ata/ata-lowlevel.c
new file mode 100644
index 0000000..d38037e
--- /dev/null
+++ b/sys/dev/ata/ata-lowlevel.c
@@ -0,0 +1,787 @@
+/*-
+ * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ata.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/ata/ata-all.h>
+
+/* prototypes */
+static int ata_transaction(struct ata_request *request);
+static void ata_interrupt(void *data);
+static void ata_reset(struct ata_channel *ch);
+static int ata_wait(struct ata_device *atadev, u_int8_t mask);
+static int ata_command(struct ata_device *atadev, u_int8_t command, u_int64_t lba, u_int16_t count, u_int16_t feature);
+static void ata_pio_read(struct ata_request *request, int length);
+static void ata_pio_write(struct ata_request *request, int length);
+
+/* local vars */
+static int atadebug = 0;
+
+/*
+ * low level ATA functions
+ */
+void
+ata_generic_hw(struct ata_channel *ch)
+{
+ ch->hw.reset = ata_reset;
+ ch->hw.transaction = ata_transaction;
+ ch->hw.interrupt = ata_interrupt;
+}
+
+/* must be called with ATA channel locked */
+static int
+ata_transaction(struct ata_request *request)
+{
+ /* record the request as running */
+ request->device->channel->running = request;
+
+ /* disable ATAPI DMA writes if HW doesn't support it */
+ if (request->flags & (ATA_R_ATAPI | ATA_R_DMA | ATA_R_WRITE) &&
+ request->device->channel->flags & ATA_ATAPI_DMA_RO)
+ request->flags &= ~ATA_R_DMA;
+
+ switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) {
+
+ /* ATA PIO data transfer and control commands */
+ default:
+ {
+ /* record command direction here as our request might be done later */
+ int write = (request->flags & ATA_R_WRITE);
+
+ /* issue command */
+ if (ata_command(request->device, request->u.ata.command,
+ request->u.ata.lba, request->u.ata.count,
+ request->u.ata.feature)) {
+ ata_prtdev(request->device, "error issueing PIO command\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* if write command output the data */
+ if (write) {
+ if (ata_wait(request->device,
+ (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
+ ata_prtdev(request->device,"timeout waiting for write DRQ");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+ ata_pio_write(request, request->transfersize);
+ }
+ }
+ /* return and wait for interrupt */
+ return ATA_OP_CONTINUES;
+
+ /* ATA DMA data transfer commands */
+ case ATA_R_DMA:
+ /* check sanity and setup DMA engine */
+ if (request->device->channel->dma->setup(request->device,
+ request->data,
+ request->bytecount)) {
+ ata_prtdev(request->device, "setting up DMA failed\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* issue command */
+ if (ata_command(request->device, request->u.ata.command,
+ request->u.ata.lba, request->u.ata.count,
+ request->u.ata.feature)) {
+ ata_prtdev(request->device, "error issuing DMA command\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* start DMA engine */
+ if (request->device->channel->dma->start(request->device->channel,
+ request->data,
+ request->bytecount,
+ request->flags & ATA_R_READ)) {
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+ /* return and wait for interrupt */
+ return ATA_OP_CONTINUES;
+
+ /* ATAPI PIO commands */
+ case ATA_R_ATAPI:
+ /* is this just a POLL DSC command ? */
+ if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
+ ATA_IDX_OUTB(request->device->channel, ATA_DRIVE,
+ ATA_D_IBM | request->device->unit);
+ DELAY(10);
+ if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC))
+ request->result = EBUSY;
+ return ATA_OP_FINISHED;
+ }
+
+ /* start ATAPI operation */
+ if (ata_command(request->device, ATA_PACKET_CMD,
+ request->transfersize << 8, 0, 0)) {
+ ata_prtdev(request->device, "error issuing ATA PACKET command\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* command interrupt device ? just return and wait for interrupt */
+ if ((request->device->param->config & ATA_DRQ_MASK) == ATA_DRQ_INTR)
+ return ATA_OP_CONTINUES;
+
+ /* wait for ready to write ATAPI command block */
+ {
+ int timeout = 5000; /* might be less for fast devices */
+ while (timeout--) {
+ int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON);
+ int status = ATA_IDX_INB(request->device->channel, ATA_STATUS);
+
+ if (((reason & (ATA_I_CMD | ATA_I_IN)) |
+ (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT)
+ break;
+ DELAY(20);
+ }
+ if (timeout <= 0) {
+ ata_prtdev(request->device,
+ "timeout waiting for ATAPI ready\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+ }
+
+ /* this seems to be needed for some (slow) devices */
+ DELAY(10);
+
+ /* output actual command block */
+ ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA,
+ (int16_t *)request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 6 : 8);
+
+ /* return and wait for interrupt */
+ return ATA_OP_CONTINUES;
+
+ case ATA_R_ATAPI|ATA_R_DMA:
+ /* is this just a POLL DSC command ? */
+ if (request->u.atapi.ccb[0] == ATAPI_POLL_DSC) {
+ ATA_IDX_OUTB(request->device->channel, ATA_DRIVE,
+ ATA_D_IBM | request->device->unit);
+ DELAY(10);
+ if (!(ATA_IDX_INB(request->device->channel, ATA_ALTSTAT)&ATA_S_DSC))
+ request->result = EBUSY;
+ return ATA_OP_FINISHED;
+ }
+
+ /* check sanity and setup DMA engine */
+ if (request->device->channel->dma->setup(request->device,
+ request->data,
+ request->bytecount)) {
+ ata_prtdev(request->device, "setting up DMA failed\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* start ATAPI operation */
+ if (ata_command(request->device, ATA_PACKET_CMD, 0, 0, ATA_F_DMA)) {
+ ata_prtdev(request->device, "error issuing ATAPI packet command\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* wait for ready to write ATAPI command block */
+ {
+ int timeout = 5000; /* might be less for fast devices */
+ while (timeout--) {
+ int reason = ATA_IDX_INB(request->device->channel, ATA_IREASON);
+ int status = ATA_IDX_INB(request->device->channel, ATA_STATUS);
+
+ if (((reason & (ATA_I_CMD | ATA_I_IN)) |
+ (status & (ATA_S_DRQ | ATA_S_BUSY))) == ATAPI_P_CMDOUT)
+ break;
+ DELAY(20);
+ }
+ if (timeout <= 0) {
+ ata_prtdev(request->device,
+ "timeout waiting for ATAPI ready\n");
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+ }
+
+ /* this seems to be needed for some (slow) devices */
+ DELAY(10);
+
+ /* output actual command block */
+ ATA_IDX_OUTSW_STRM(request->device->channel, ATA_DATA,
+ (int16_t *)request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 6 : 8);
+
+ /* start DMA engine */
+ if (request->device->channel->dma->start(request->device->channel,
+ request->data,
+ request->bytecount,
+ request->flags & ATA_R_READ)) {
+ request->result = EIO;
+ return ATA_OP_FINISHED;
+ }
+
+ /* return and wait for interrupt */
+ return ATA_OP_CONTINUES;
+ }
+}
+
+static void
+ata_interrupt(void *data)
+{
+ struct ata_channel *ch = (struct ata_channel *)data;
+ struct ata_request *request = ch->running;
+ int length;
+
+ /* if we dont have a running request shout and ignore this interrupt */
+ if (request == NULL) {
+ if (bootverbose) {
+ printf("ata%d: spurious interrupt - ", device_get_unit(ch->dev));
+ if (request)
+ printf("request OK - ");
+ printf("status=0x%02x error=0x%02x reason=0x%02x\n",
+ ATA_IDX_INB(ch, ATA_ALTSTAT), ATA_IDX_INB(ch, ATA_ERROR),
+ ATA_IDX_INB(ch, ATA_IREASON));
+ }
+ return;
+ }
+
+ /* if device is busy it didn't interrupt */
+ if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
+ DELAY(100);
+ if (!(ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_DRQ))
+ return;
+ }
+
+ /* clear interrupt and get status */
+ request->status = ATA_IDX_INB(ch, ATA_STATUS);
+
+ switch (request->flags & (ATA_R_ATAPI | ATA_R_DMA)) {
+
+ /* ATA PIO data transfer and control commands */
+ default:
+
+ /* if we got an error we are done with the HW */
+ if (request->status & ATA_S_ERROR) {
+ request->error = ATA_IDX_INB(ch, ATA_ERROR);
+ break;
+ }
+
+ /* if read data get it */
+ if (request->flags & ATA_R_READ)
+ ata_pio_read(request, request->transfersize);
+
+ /* update how far we've gotten */
+ request->donecount += request->transfersize;
+
+ /* do we need a scoop more ? */
+ if (request->bytecount > request->donecount) {
+
+ /* set this transfer size according to HW capabilities */
+ request->transfersize =
+ min((request->bytecount-request->donecount),
+ request->transfersize);
+
+ /* if data write command, output the data */
+ if (request->flags & ATA_R_WRITE) {
+ /* if we get an error here we are done with the HW */
+ if (ata_wait(request->device,
+ (ATA_S_READY | ATA_S_DSC | ATA_S_DRQ)) < 0) {
+ ata_prtdev(request->device,"timeout waiting for write DRQ");
+ request->status = ATA_IDX_INB(ch, ATA_STATUS);
+ break;
+ }
+ else {
+ /* output data and return waiting for new interrupt */
+ ata_pio_write(request, request->transfersize);
+ return;
+ }
+ }
+
+ /* if data read command, return & wait for interrupt */
+ else if (request->flags & ATA_R_READ) {
+ return;
+ }
+ else
+ ata_prtdev(request->device,
+ "FAILURE - %s shouldn't loop on control cmd\n",
+ ata_cmd2str(request));
+ }
+ /* done with HW */
+ break;
+
+ /* ATA DMA data transfer commands */
+ case ATA_R_DMA:
+ /* stop DMA engine and get status */
+ request->dmastat = ch->dma->stop(ch);
+
+ /* did we get error or data */
+ if (request->status & ATA_S_ERROR)
+ request->error = ATA_IDX_INB(ch, ATA_ERROR);
+ else if (request->dmastat & ATA_BMSTAT_ERROR)
+ request->status |= ATA_S_ERROR;
+ else
+ request->donecount = request->bytecount;
+
+ /* done with HW */
+ break;
+
+ /* ATAPI PIO commands */
+ case ATA_R_ATAPI:
+ length = ATA_IDX_INB(ch, ATA_CYL_LSB)|(ATA_IDX_INB(ch, ATA_CYL_MSB)<<8);
+
+ switch ((ATA_IDX_INB(ch, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) |
+ (request->status & ATA_S_DRQ)) {
+
+ case ATAPI_P_CMDOUT:
+ /* this seems to be needed for some (slow) devices */
+ DELAY(10);
+
+ if (!(request->status & ATA_S_DRQ)) {
+ ata_prtdev(request->device, "command interrupt without DRQ\n");
+ request->status = ATA_S_ERROR;
+ break;
+ }
+ ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (int16_t *)request->u.atapi.ccb,
+ (request->device->param->config &
+ ATA_PROTO_MASK)== ATA_PROTO_ATAPI_12 ? 6 : 8);
+ /* return wait for interrupt */
+ return;
+
+ case ATAPI_P_WRITE:
+ if (request->flags & ATA_R_READ) {
+ request->status = ATA_S_ERROR;
+ ata_prtdev(request->device,
+ "%s trying to write on read buffer\n",
+ ata_cmd2str(request));
+ break;
+ }
+ ata_pio_write(request, length);
+ request->donecount += length;
+
+ /* set next transfer size according to HW capabilities */
+ request->transfersize = min((request->bytecount-request->donecount),
+ request->transfersize);
+ /* return wait for interrupt */
+ return;
+
+ case ATAPI_P_READ:
+ if (request->flags & ATA_R_WRITE) {
+ request->status = ATA_S_ERROR;
+ ata_prtdev(request->device,
+ "%s trying to read on write buffer\n",
+ ata_cmd2str(request));
+ break;
+ }
+ ata_pio_read(request, length);
+ request->donecount += length;
+
+ /* set next transfer size according to HW capabilities */
+ request->transfersize = min((request->bytecount-request->donecount),
+ request->transfersize);
+ /* return wait for interrupt */
+ return;
+
+ case ATAPI_P_DONEDRQ:
+ ata_prtdev(request->device,
+ "WARNING - %s DONEDRQ non conformant device\n",
+ ata_cmd2str(request));
+ if (request->flags & ATA_R_READ) {
+ ata_pio_read(request, length);
+ request->donecount += length;
+ }
+ else if (request->flags & ATA_R_WRITE) {
+ ata_pio_write(request, length);
+ request->donecount += length;
+ }
+ else
+ request->status = ATA_S_ERROR;
+ /* FALLTHROUGH */
+
+ case ATAPI_P_ABORT:
+ case ATAPI_P_DONE:
+ if (request->status & (ATA_S_ERROR | ATA_S_DWF))
+ request->error = ATA_IDX_INB(ch, ATA_ERROR);
+ break;
+
+ default:
+ ata_prtdev(request->device, "unknown transfer phase\n");
+ request->status = ATA_S_ERROR;
+ }
+ /* done with HW */
+ break;
+
+ /* ATAPI DMA commands */
+ case ATA_R_ATAPI|ATA_R_DMA:
+
+ /* stop the engine and get engine status */
+ request->dmastat = ch->dma->stop(ch);
+
+ /* did we get error or data */
+ if (request->status & (ATA_S_ERROR | ATA_S_DWF))
+ request->error = ATA_IDX_INB(ch, ATA_ERROR);
+ else if (request->dmastat & ATA_BMSTAT_ERROR)
+ request->status |= ATA_S_ERROR;
+ else
+ request->donecount = request->bytecount;
+
+ /* done with HW */
+ break;
+ }
+
+ ata_finish(request);
+
+ /* unlock the ATA HW for new work */
+ ch->running = NULL;
+ ATA_UNLOCK_CH(ch);
+ ch->locking(ch, ATA_LF_UNLOCK);
+}
+
+/* must be called with ATA channel locked */
+static void
+ata_reset(struct ata_channel *ch)
+{
+ u_int8_t lsb, msb, ostat0, ostat1;
+ u_int8_t stat0 = 0, stat1 = 0;
+ int mask = 0, timeout;
+
+ /* do we have any signs of ATA/ATAPI HW being present ? */
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
+ DELAY(10);
+ ostat0 = ATA_IDX_INB(ch, ATA_STATUS);
+ if ((ostat0 & 0xf8) != 0xf8 && ostat0 != 0xa5) {
+ stat0 = ATA_S_BUSY;
+ mask |= 0x01;
+ }
+
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
+ DELAY(10);
+ ostat1 = ATA_IDX_INB(ch, ATA_STATUS);
+ /* in some setups we dont want to test for a slave */
+ if (!(ch->flags & ATA_NO_SLAVE)) {
+ if ((ostat1 & 0xf8) != 0xf8 && ostat1 != 0xa5) {
+ stat1 = ATA_S_BUSY;
+ mask |= 0x02;
+ }
+ }
+
+ /* if nothing showed up no need to get any further */
+ /* SOS is that too strong?, we just might loose devices here XXX */
+ ch->devices = 0;
+ if (!mask)
+ return;
+
+ if (bootverbose)
+ ata_printf(ch, -1, "pre reset mask=%02x ostat0=%02x ostat2=%02x\n",
+ mask, ostat0, ostat1);
+
+ /* reset channel */
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
+ DELAY(10);
+ ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS | ATA_A_RESET);
+ DELAY(10000);
+ ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_IDS);
+ DELAY(100000);
+ ATA_IDX_INB(ch, ATA_ERROR);
+
+ /* wait for BUSY to go inactive */
+ for (timeout = 0; timeout < 310000; timeout++) {
+ if (stat0 & ATA_S_BUSY) {
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
+ DELAY(10);
+
+ /* check for ATAPI signature while its still there */
+ lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
+ msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
+ stat0 = ATA_IDX_INB(ch, ATA_STATUS);
+ if (!(stat0 & ATA_S_BUSY)) {
+ if (bootverbose)
+ ata_printf(ch, ATA_MASTER, "ATAPI %02x %02x\n", lsb, msb);
+ if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
+ ch->devices |= ATA_ATAPI_MASTER;
+ }
+ }
+ if (stat1 & ATA_S_BUSY) {
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
+ DELAY(10);
+
+ /* check for ATAPI signature while its still there */
+ lsb = ATA_IDX_INB(ch, ATA_CYL_LSB);
+ msb = ATA_IDX_INB(ch, ATA_CYL_MSB);
+ stat1 = ATA_IDX_INB(ch, ATA_STATUS);
+ if (!(stat1 & ATA_S_BUSY)) {
+ if (bootverbose)
+ ata_printf(ch, ATA_SLAVE, "ATAPI %02x %02x\n", lsb, msb);
+ if (lsb == ATAPI_MAGIC_LSB && msb == ATAPI_MAGIC_MSB)
+ ch->devices |= ATA_ATAPI_SLAVE;
+ }
+ }
+ if (mask == 0x01) /* wait for master only */
+ if (!(stat0 & ATA_S_BUSY))
+ break;
+ if (mask == 0x02) /* wait for slave only */
+ if (!(stat1 & ATA_S_BUSY))
+ break;
+ if (mask == 0x03) /* wait for both master & slave */
+ if (!(stat0 & ATA_S_BUSY) && !(stat1 & ATA_S_BUSY))
+ break;
+ DELAY(100);
+ }
+ DELAY(10);
+ ATA_IDX_OUTB(ch, ATA_ALTSTAT, ATA_A_4BIT);
+
+ if (stat0 & ATA_S_BUSY)
+ mask &= ~0x01;
+ if (stat1 & ATA_S_BUSY)
+ mask &= ~0x02;
+ if (bootverbose)
+ ata_printf(ch, -1, "after reset mask=%02x stat0=%02x stat1=%02x\n",
+ mask, stat0, stat1);
+ if (!mask)
+ return;
+
+ if (mask & 0x01 && ostat0 != 0x00 && !(ch->devices & ATA_ATAPI_MASTER)) {
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_MASTER);
+ DELAY(10);
+ ATA_IDX_OUTB(ch, ATA_ERROR, 0x58);
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5);
+ lsb = ATA_IDX_INB(ch, ATA_ERROR);
+ msb = ATA_IDX_INB(ch, ATA_CYL_LSB);
+ if (bootverbose)
+ ata_printf(ch, ATA_MASTER, "ATA %02x %02x\n", lsb, msb);
+ if (lsb != 0x58 && msb == 0xa5)
+ ch->devices |= ATA_ATA_MASTER;
+ }
+ if (mask & 0x02 && ostat1 != 0x00 && !(ch->devices & ATA_ATAPI_SLAVE)) {
+ ATA_IDX_OUTB(ch, ATA_DRIVE, ATA_D_IBM | ATA_SLAVE);
+ DELAY(10);
+ ATA_IDX_OUTB(ch, ATA_ERROR, 0x58);
+ ATA_IDX_OUTB(ch, ATA_CYL_LSB, 0xa5);
+ lsb = ATA_IDX_INB(ch, ATA_ERROR);
+ msb = ATA_IDX_INB(ch, ATA_CYL_LSB);
+ if (bootverbose)
+ ata_printf(ch, ATA_SLAVE, "ATA %02x %02x\n", lsb, msb);
+ if (lsb != 0x58 && msb == 0xa5)
+ ch->devices |= ATA_ATA_SLAVE;
+ }
+ if (bootverbose)
+ ata_printf(ch, -1, "devices=%02x\n", ch->devices);
+}
+
+static int
+ata_wait(struct ata_device *atadev, u_int8_t mask)
+{
+ int timeout = 0;
+ u_int8_t status;
+
+ DELAY(1);
+ while (timeout < 5000000) { /* timeout 5 secs */
+ status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
+
+ /* if drive fails status, reselect the drive just to be sure */
+ if (status == 0xff) {
+ ata_prtdev(atadev, "WARNING no status, reselecting device\n");
+ ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
+ DELAY(10);
+ status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
+ if (status == 0xff)
+ return -1;
+ }
+
+ /* are we done ? */
+ if (!(status & ATA_S_BUSY))
+ break;
+
+ if (timeout > 1000) {
+ timeout += 1000;
+ DELAY(1000);
+ }
+ else {
+ timeout += 10;
+ DELAY(10);
+ }
+ }
+ if (timeout >= 5000000)
+ return -1;
+ if (!mask)
+ return (status & ATA_S_ERROR);
+
+ /* wait 50 msec for bits wanted. */
+ timeout = 5000;
+ while (timeout--) {
+ status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
+ if ((status & mask) == mask)
+ return (status & ATA_S_ERROR);
+ DELAY (10);
+ }
+ return -1;
+}
+
+static int
+ata_command(struct ata_device *atadev, u_int8_t command,
+ u_int64_t lba, u_int16_t count, u_int16_t feature)
+{
+ if (atadebug)
+ ata_prtdev(atadev, "ata_command: addr=%04lx, command=%02x, "
+ "lba=%jd, count=%d, feature=%d\n",
+ rman_get_start(atadev->channel->r_io[ATA_DATA].res),
+ command, (intmax_t)lba, count, feature);
+
+ /* select device */
+ ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
+
+ /* ready to issue command ? */
+ if (ata_wait(atadev, 0) < 0) {
+ ata_prtdev(atadev, "timeout sending command=%02x\n", command);
+ return -1;
+ }
+
+ /* only use 48bit addressing if needed (avoid bugs and overhead) */
+ if ((lba > 268435455 || count > 256) && atadev->param &&
+ atadev->param->support.command2 & ATA_SUPPORT_ADDRESS48) {
+
+ /* translate command into 48bit version */
+ switch (command) {
+ case ATA_READ:
+ command = ATA_READ48; break;
+ case ATA_READ_MUL:
+ command = ATA_READ_MUL48; break;
+ case ATA_READ_DMA:
+ command = ATA_READ_DMA48; break;
+ case ATA_READ_DMA_QUEUED:
+ command = ATA_READ_DMA_QUEUED48; break;
+ case ATA_WRITE:
+ command = ATA_WRITE48; break;
+ case ATA_WRITE_MUL:
+ command = ATA_WRITE_MUL48; break;
+ case ATA_WRITE_DMA:
+ command = ATA_WRITE_DMA48; break;
+ case ATA_WRITE_DMA_QUEUED:
+ command = ATA_WRITE_DMA_QUEUED48; break;
+ case ATA_FLUSHCACHE:
+ command = ATA_FLUSHCACHE48; break;
+ default:
+ ata_prtdev(atadev, "can't translate cmd to 48bit version\n");
+ return -1;
+ }
+ ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, (feature>>8) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_COUNT, (count>>8) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, (lba>>24) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>32) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>40) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_LBA | atadev->unit);
+ atadev->channel->flags |= ATA_48BIT_ACTIVE;
+ }
+ else {
+ ATA_IDX_OUTB(atadev->channel, ATA_FEATURE, feature);
+ ATA_IDX_OUTB(atadev->channel, ATA_COUNT, count);
+ ATA_IDX_OUTB(atadev->channel, ATA_SECTOR, lba & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_CYL_LSB, (lba>>8) & 0xff);
+ ATA_IDX_OUTB(atadev->channel, ATA_CYL_MSB, (lba>>16) & 0xff);
+ if (atadev->flags & ATA_D_USE_CHS)
+ ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
+ ATA_D_IBM | atadev->unit | ((lba>>24) & 0xf));
+ else
+ ATA_IDX_OUTB(atadev->channel, ATA_DRIVE,
+ ATA_D_IBM | ATA_D_LBA | atadev->unit|((lba>>24)&0xf));
+ atadev->channel->flags &= ~ATA_48BIT_ACTIVE;
+ }
+
+ /* issue command to controller */
+ ATA_IDX_OUTB(atadev->channel, ATA_CMD, command);
+
+ return 0;
+}
+
+static void
+ata_pio_read(struct ata_request *request, int length)
+{
+ int size = min(request->transfersize, length);
+ struct ata_channel *ch = request->device->channel;
+ int resid;
+
+ if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
+ ATA_IDX_INSW_STRM(ch, ATA_DATA,
+ (void*)((uintptr_t)request->data+request->donecount),
+ size / sizeof(int16_t));
+ else
+ ATA_IDX_INSL_STRM(ch, ATA_DATA,
+ (void*)((uintptr_t)request->data+request->donecount),
+ size / sizeof(int32_t));
+
+ if (request->transfersize < length) {
+ ata_prtdev(request->device, "WARNING - %s read data overrun %d/%d\n",
+ ata_cmd2str(request), length, request->transfersize);
+ for (resid = request->transfersize; resid < length;
+ resid += sizeof(int16_t))
+ ATA_IDX_INW(ch, ATA_DATA);
+ }
+}
+
+static void
+ata_pio_write(struct ata_request *request, int length)
+{
+ int size = min(request->transfersize, length);
+ struct ata_channel *ch = request->device->channel;
+ int resid;
+
+ if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
+ ATA_IDX_OUTSW_STRM(ch, ATA_DATA,
+ (void*)((uintptr_t)request->data+request->donecount),
+ size / sizeof(int16_t));
+ else
+ ATA_IDX_OUTSL_STRM(ch, ATA_DATA,
+ (void*)((uintptr_t)request->data+request->donecount),
+ size / sizeof(int32_t));
+
+ if (request->transfersize < length) {
+ ata_prtdev(request->device, "WARNING - %s write data underrun %d/%d\n",
+ ata_cmd2str(request), length, request->transfersize);
+ for (resid = request->transfersize; resid < length;
+ resid += sizeof(int16_t))
+ ATA_IDX_OUTW(ch, ATA_DATA, 0);
+ }
+}
diff --git a/sys/dev/ata/ata-pci.c b/sys/dev/ata/ata-pci.c
index 4a40ae2..efb8e6d 100644
--- a/sys/dev/ata/ata-pci.c
+++ b/sys/dev/ata/ata-pci.c
@@ -35,6 +35,7 @@
#include <sys/module.h>
#include <sys/bus.h>
#include <sys/malloc.h>
+#include <sys/taskqueue.h>
#include <machine/stdarg.h>
#include <machine/resource.h>
#include <machine/bus.h>
@@ -79,6 +80,8 @@ ata_pci_probe(device_t dev)
return ata_highpoint_ident(dev);
case ATA_INTEL_ID:
return ata_intel_ident(dev);
+ case ATA_NATIONAL_ID:
+ return ata_national_ident(dev);
case ATA_NVIDIA_ID:
return ata_nvidia_ident(dev);
case ATA_PROMISE_ID:
@@ -413,13 +416,11 @@ ata_pci_dmastart(struct ata_channel *ch, caddr_t data, int32_t count, int dir)
if ((error = ata_dmastart(ch, data, count, dir)))
return error;
-
- ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab);
- ATA_IDX_OUTB(ch, ATA_BMCMD_PORT, dir ? ATA_BMCMD_WRITE_READ : 0);
ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, (ATA_IDX_INB(ch, ATA_BMSTAT_PORT) |
(ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR)));
- ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
- ATA_IDX_INB(ch, ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP);
+ ATA_IDX_OUTL(ch, ATA_BMDTP_PORT, ch->dma->mdmatab);
+ ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
+ (dir ? ATA_BMCMD_WRITE_READ : 0) | ATA_BMCMD_START_STOP);
return 0;
}
@@ -432,10 +433,8 @@ ata_pci_dmastop(struct ata_channel *ch)
ATA_IDX_OUTB(ch, ATA_BMCMD_PORT,
ATA_IDX_INB(ch, ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP);
ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR);
-
ata_dmastop(ch);
-
- return (error & ATA_BMSTAT_MASK);
+ return error;
}
static int
@@ -505,8 +504,6 @@ ata_pcisub_probe(device_t dev)
if ((error = ctlr->allocate(dev, ch)))
return error;
- if (ctlr->chip)
- ch->chiptype = ctlr->chip->chipid;
ch->device[MASTER].setmode = ctlr->setmode;
ch->device[SLAVE].setmode = ctlr->setmode;
ch->locking = ctlr->locking;
diff --git a/sys/dev/ata/ata-pci.h b/sys/dev/ata/ata-pci.h
index 9cb19ca..aaab23c 100644
--- a/sys/dev/ata/ata-pci.h
+++ b/sys/dev/ata/ata-pci.h
@@ -35,7 +35,7 @@ struct ata_chip_id {
int cfg1;
int cfg2;
u_int8_t max_dma;
- char *text;
+ char *text;
};
/* structure describing a PCI ATA controller */
@@ -55,7 +55,7 @@ struct ata_pci_controller {
struct {
void (*function)(void *);
void *argument;
- } interrupt[4]; /* XXX SOS max ch# for now */
+ } interrupt[4]; /* SOS max ch# for now XXX */
};
#define ATA_MASTERDEV(dev) ((pci_get_progif(dev) & 0x80) && \
@@ -115,6 +115,9 @@ struct ata_pci_controller {
#define ATA_I82801EB 0x24db8086
#define ATA_I82801EB_1 0x24d18086
+#define ATA_NATIONAL_ID 0x100b
+#define ATA_SC1100 0x0502100b
+
#define ATA_NVIDIA_ID 0x10de
#define ATA_NFORCE1 0x01bc10de
#define ATA_NFORCE2 0x006510de
@@ -147,6 +150,7 @@ struct ata_pci_controller {
#define ATA_PDC20621 0x6621105a
#define ATA_SERVERWORKS_ID 0x1166
+#define ATA_ROSB4_ISA 0x02001166
#define ATA_ROSB4 0x02111166
#define ATA_CSB5 0x02121166
#define ATA_CSB6 0x02131166
@@ -279,6 +283,7 @@ int ata_cyrix_ident(device_t);
int ata_cypress_ident(device_t);
int ata_highpoint_ident(device_t);
int ata_intel_ident(device_t);
+int ata_national_ident(device_t);
int ata_nvidia_ident(device_t);
int ata_promise_ident(device_t);
int ata_serverworks_ident(device_t);
diff --git a/sys/dev/ata/ata-queue.c b/sys/dev/ata/ata-queue.c
new file mode 100644
index 0000000..8e0a31f
--- /dev/null
+++ b/sys/dev/ata/ata-queue.c
@@ -0,0 +1,471 @@
+/*-
+ * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "opt_ata.h"
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/ata.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/taskqueue.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <dev/ata/ata-all.h>
+
+/* prototypes */
+static void ata_completed(void *context, int pending);
+static void ata_timeout(struct ata_request *request);
+static char *ata_sensekey2str(u_int8_t skey);
+
+/* local vars */
+static MALLOC_DEFINE(M_ATA_REQ, "ATA request", "ATA request");
+static int atadebug = 0;
+
+/*
+ * ATA request related functions
+ */
+struct ata_request *
+ata_alloc_request(void)
+{
+ struct ata_request *request;
+
+ request = malloc(sizeof(struct ata_request), M_ATA_REQ, M_NOWAIT | M_ZERO);
+ if (!request)
+ printf("FAILURE - malloc ATA request failed\n");
+ return request;
+}
+
+void
+ata_free_request(struct ata_request *request)
+{
+ free(request, M_ATA_REQ);
+}
+
+void
+ata_queue_request(struct ata_request *request)
+{
+ /* mark request as virgin (it might be a reused one) */
+ request->result = request->status = request->error = 0;
+ request->flags &= ~ATA_R_DONE;
+
+ /* put request on the locked queue at the specified location */
+ mtx_lock(&request->device->channel->queue_mtx);
+ if (request->flags & ATA_R_AT_HEAD)
+ TAILQ_INSERT_HEAD(&request->device->channel->ata_queue, request, chain);
+ else
+ TAILQ_INSERT_TAIL(&request->device->channel->ata_queue, request, chain);
+ mtx_unlock(&request->device->channel->queue_mtx);
+
+ /* should we skip start ? */
+ if (!(request->flags & ATA_R_SKIPSTART))
+ ata_start(request->device->channel);
+
+ /* if this was a requeue op callback/sleep already setup */
+ if (request->flags & ATA_R_REQUEUE)
+ return;
+
+ /* if this is not a callback and we havn't seen DONE yet -> sleep */
+ if (!request->callback && !(request->flags & ATA_R_DONE)) {
+ while (tsleep(request, PRIBIO, "atareq", 60*10*hz)) ;
+ }
+}
+
+int
+ata_controlcmd(struct ata_device *atadev, u_int8_t command, u_int16_t feature,
+ u_int64_t lba, u_int16_t count)
+{
+ struct ata_request *request = ata_alloc_request();
+ int error = ENOMEM;
+
+ if (request) {
+ request->device = atadev;
+ request->u.ata.command = command;
+ request->u.ata.lba = lba;
+ request->u.ata.count = count;
+ request->u.ata.feature = feature;
+ request->flags = ATA_R_CONTROL;
+ request->timeout = 5;
+ ata_queue_request(request);
+ error = request->result;
+ ata_free_request(request);
+ }
+ return error;
+}
+
+int
+ata_atapicmd(struct ata_device *atadev, u_int8_t *ccb, caddr_t data,
+ int count, int flags, int timeout)
+{
+ struct ata_request *request = ata_alloc_request();
+ int packet_size, error = ENOMEM;
+
+ if ((atadev->param->config & ATA_PROTO_MASK) == ATA_PROTO_ATAPI_12)
+ packet_size = 12;
+ else
+ packet_size = 16;
+ if (request) {
+ request->device = atadev;
+ bcopy(ccb, request->u.atapi.ccb, packet_size);
+ request->data = data;
+ request->bytecount = count;
+ request->transfersize = min(request->bytecount, 65534);
+ request->flags = flags | ATA_R_ATAPI;
+ request->timeout = timeout;
+ ata_queue_request(request);
+ error = request->result;
+ ata_free_request(request);
+ }
+ return error;
+}
+
+void
+ata_start(struct ata_channel *ch)
+{
+ struct ata_request *request;
+
+ /* lock the ATA HW for this request */
+ ch->locking(ch, ATA_LF_LOCK);
+ if (!ATA_LOCK_CH(ch, ATA_ACTIVE)) {
+ return;
+ }
+
+if (atadebug && mtx_owned(&Giant)) printf("ata_start holds GIANT!!!\n");
+
+ /* if we dont have any work, ask the subdriver(s) */
+ mtx_lock(&ch->queue_mtx);
+ if (TAILQ_EMPTY(&ch->ata_queue)) {
+ mtx_unlock(&ch->queue_mtx);
+ if (ch->device[MASTER].start)
+ ch->device[MASTER].start(&ch->device[MASTER]);
+ if (ch->device[SLAVE].start)
+ ch->device[SLAVE].start(&ch->device[SLAVE]);
+ mtx_lock(&ch->queue_mtx);
+ }
+ if ((request = TAILQ_FIRST(&ch->ata_queue))) {
+ TAILQ_REMOVE(&ch->ata_queue, request, chain);
+ mtx_unlock(&ch->queue_mtx);
+
+ /* arm timeout */
+ if (!request->timeout_handle.callout && !dumping) {
+ request->timeout_handle =
+ timeout((timeout_t*)ata_timeout, request, request->timeout*hz);
+ }
+
+ /* kick HW into action */
+ if (ch->hw.transaction(request) == ATA_OP_CONTINUES)
+ return;
+
+ /* untimeout request */
+ untimeout((timeout_t *)ata_timeout, request, request->timeout_handle);
+ ata_finish(request);
+ }
+ else
+ mtx_unlock(&ch->queue_mtx);
+
+ ATA_UNLOCK_CH(ch);
+ ch->locking(ch, ATA_LF_UNLOCK);
+}
+
+void
+ata_finish(struct ata_request *request)
+{
+ /* request is done schedule it for completition */
+ TASK_INIT(&request->task, 0, ata_completed, request);
+ taskqueue_enqueue(taskqueue_swi, &request->task);
+}
+
+/* current command finished, clean up and return result */
+static void
+ata_completed(void *context, int pending)
+{
+ struct ata_request *request = (struct ata_request *)context;
+ struct ata_channel *channel = request->device->channel;
+
+ /* untimeout request now we have control back */
+ untimeout((timeout_t *)ata_timeout, request, request->timeout_handle);
+
+ /* do the all the magic for completition evt retry etc etc */
+ if (request->status & ATA_S_CORR)
+ ata_prtdev(request->device, "WARNING - %s soft error (ECC corrected)",
+ ata_cmd2str(request));
+
+ /* if this is a UDMA CRC error, retry request */
+ if (request->flags & ATA_R_DMA && request->error & ATA_E_ICRC) {
+ if (request->retries--) {
+ ata_prtdev(request->device,
+ "WARNING - %s UDMA ICRC error (retrying request)\n",
+ ata_cmd2str(request));
+ ata_queue_request(request);
+ return;
+ }
+ }
+
+ switch (request->flags & ATA_R_ATAPI) {
+ /* ATA errors */
+ default:
+ if (request->status & ATA_S_ERROR) {
+ if (!(request->flags & ATA_R_QUIET)) {
+ ata_prtdev(request->device,
+ "FAILURE - %s status=%b error=%b",
+ ata_cmd2str(request),
+ request->status, "\20\10BUSY\7READY\6DMA_READY"
+ "\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR",
+ request->error, "\20\10ICRC\7UNCORRECTABLE"
+ "\6MEDIA_CHANGED\5NID_NOT_FOUND\4MEDIA_CHANGE_REQEST"
+ "\3ABORTED\2NO_MEDIA\1ILLEGAL_LENGTH");
+ if (request->flags & ATA_R_DMA &&
+ request->dmastat & ATA_BMSTAT_ERROR)
+ printf(" dma=0x%02x\n", request->dmastat);
+ else
+ printf("\n");
+ }
+
+ /* SOS this could be more precise ? XXX*/
+ request->result = EIO;
+ }
+ break;
+
+ /* ATAPI errors */
+ case ATA_R_ATAPI:
+ /* is result already set return */
+ if (request->result)
+ break;
+
+ if (request->error & ATA_E_MASK) {
+ switch ((request->result & ATA_SK_MASK)) {
+ case ATA_SK_RECOVERED_ERROR:
+ ata_prtdev(request->device, "WARNING - %s recovered error\n",
+ ata_cmd2str(request));
+ /* FALLTHROUGH */
+
+ case ATA_SK_NO_SENSE:
+ request->result = 0;
+ break;
+
+ case ATA_SK_NOT_READY:
+ request->result = EBUSY;
+ break;
+
+ case ATA_SK_UNIT_ATTENTION:
+ request->device->flags |= ATA_D_MEDIA_CHANGED;
+ request->result = EIO;
+ break;
+
+ default:
+ request->result = EIO;
+ }
+ if (request->result && !(request->flags & ATA_R_QUIET))
+ ata_prtdev(request->device,
+ "FAILURE - %s status=%b sensekey=%s error=%b\n",
+ ata_cmd2str(request),
+ request->status, "\20\10BUSY\7READY\6DMA"
+ "\5DSC\4DRQ\3CORRECTABLE\2INDEX\1ERROR",
+ ata_sensekey2str((request->error & ATA_SK_MASK)>>4),
+ (request->error & ATA_E_MASK),
+ "\20\4MEDIA_CHANGE_REQUEST\3ABORTED"
+ "\2NO_MEDIA\1ILLEGAL_LENGTH");
+ }
+ break;
+ }
+
+ request->flags |= ATA_R_DONE;
+ if (request->callback)
+ (request->callback)(request);
+ else
+ wakeup(request);
+ ata_start(channel);
+}
+
+static void
+ata_timeout(struct ata_request *request)
+{
+ /* clear timeout etc */
+ request->timeout_handle.callout = NULL;
+
+ /* call interrupt to try finish up the command */
+ request->device->channel->hw.interrupt(request->device->channel);
+
+ if (request->device->channel->running == NULL) {
+ if (!(request->flags & ATA_R_QUIET))
+ ata_prtdev(request->device,
+ "WARNING - %s recovered from missing interrupt\n",
+ ata_cmd2str(request));
+ return;
+ }
+
+ /* if this was a DMA request stop the engine to be on the safe side */
+ if (request->flags & ATA_R_DMA) {
+ request->dmastat =
+ request->device->channel->dma->stop(request->device->channel);
+ }
+
+ /* try to adjust HW's attitude towards work */
+ ata_reinit(request->device->channel);
+
+ /* if retries still permit, reinject this request */
+ if (request->retries-- > 0) {
+ if (!(request->flags & ATA_R_QUIET))
+ ata_prtdev(request->device,
+ "TIMEOUT - %s retrying (%d retr%s left)\n",
+ ata_cmd2str(request), request->retries,
+ request->retries == 1 ? "y" : "ies");
+ request->flags |= (ATA_R_AT_HEAD | ATA_R_REQUEUE);
+ request->flags &= ~ATA_R_SKIPSTART;
+ ata_queue_request(request);
+ }
+ /* otherwise just schedule finish with error */
+ else {
+ request->status = ATA_S_ERROR;
+ TASK_INIT(&request->task, 0, ata_completed, request);
+ taskqueue_enqueue(taskqueue_swi, &request->task);
+ }
+}
+
+char *
+ata_cmd2str(struct ata_request *request)
+{
+ static char buffer[20];
+
+ if (request->flags & ATA_R_ATAPI) {
+ switch (request->u.atapi.ccb[0]) {
+ case 0x00: return ("TEST_UNIT_READY");
+ case 0x01: return ("REZERO");
+ case 0x03: return ("REQUEST_SENSE");
+ case 0x04: return ("FORMAT");
+ case 0x08: return ("READ");
+ case 0x0a: return ("WRITE");
+ case 0x10: return ("WEOF");
+ case 0x11: return ("SPACE");
+ case 0x15: return ("MODE_SELECT");
+ case 0x19: return ("ERASE");
+ case 0x1a: return ("MODE_SENSE");
+ case 0x1b: return ("START_STOP");
+ case 0x1e: return ("PREVENT_ALLOW");
+ case 0x23: return ("ATAPI_READ_FORMAT_CAPACITIES");
+ case 0x25: return ("READ_CAPACITY");
+ case 0x28: return ("READ_BIG");
+ case 0x2a: return ("WRITE_BIG");
+ case 0x2b: return ("LOCATE");
+ case 0x34: return ("READ_POSITION");
+ case 0x35: return ("SYNCHRONIZE_CACHE");
+ case 0x3b: return ("WRITE_BUFFER");
+ case 0x3c: return ("READ_BUFFER");
+ case 0x42: return ("READ_SUBCHANNEL");
+ case 0x43: return ("READ_TOC");
+ case 0x45: return ("PLAY_10");
+ case 0x47: return ("PLAY_MSF");
+ case 0x48: return ("PLAY_TRACK");
+ case 0x4b: return ("PAUSE");
+ case 0x51: return ("READ_DISK_INFO");
+ case 0x52: return ("READ_TRACK_INFO");
+ case 0x53: return ("RESERVE_TRACK");
+ case 0x54: return ("SEND_OPC_INFO");
+ case 0x55: return ("MODE_SELECT_BIG");
+ case 0x58: return ("REPAIR_TRACK");
+ case 0x59: return ("READ_MASTER_CUE");
+ case 0x5a: return ("MODE_SENSE_BIG");
+ case 0x5b: return ("CLOSE_TRACK/SESSION");
+ case 0x5c: return ("READ_BUFFER_CAPACITY");
+ case 0x5d: return ("SEND_CUE_SHEET");
+ case 0xa1: return ("BLANK_CMD");
+ case 0xa3: return ("SEND_KEY");
+ case 0xa4: return ("REPORT_KEY");
+ case 0xa5: return ("PLAY_12");
+ case 0xa6: return ("LOAD_UNLOAD");
+ case 0xad: return ("READ_DVD_STRUCTURE");
+ case 0xb4: return ("PLAY_CD");
+ case 0xbb: return ("SET_SPEED");
+ case 0xbd: return ("MECH_STATUS");
+ case 0xbe: return ("READ_CD");
+ case 0xff: return ("POLL_DSC");
+ }
+ }
+ else {
+ switch (request->u.ata.command) {
+ case 0x00: return ("NOP");
+ case 0x08: return ("ATAPI_RESET");
+ case 0x20: return ("READ");
+ case 0x24: return ("READ48");
+ case 0x25: return ("READ_DMA48");
+ case 0x26: return ("READ_DMA_QUEUED48");
+ case 0x29: return ("READ_MUL48");
+ case 0x30: return ("WRITE");
+ case 0x34: return ("WRITE48");
+ case 0x35: return ("WRITE_DMA48");
+ case 0x36: return ("WRITE_DMA_QUEUED48");
+ case 0x39: return ("WRITE_MUL48");
+ case 0xa0: return ("PACKET_CMD");
+ case 0xa1: return ("ATAPI_IDENTIFY");
+ case 0xa2: return ("SERVICE");
+ case 0xc4: return ("READ_MUL");
+ case 0xc5: return ("WRITE_MUL");
+ case 0xc6: return ("SET_MULTI");
+ case 0xc7: return ("READ_DMA_QUEUED");
+ case 0xc8: return ("READ_DMA");
+ case 0xca: return ("WRITE_DMA");
+ case 0xcc: return ("WRITE_DMA_QUEUED");
+ case 0xe6: return ("SLEEP");
+ case 0xe7: return ("FLUSHCACHE");
+ case 0xea: return ("FLUSHCACHE48");
+ case 0xec: return ("ATA_IDENTIFY");
+ case 0xef: return ("SETFEATURES");
+ }
+ }
+ sprintf(buffer, "unknown CMD (0x%02x)", request->u.ata.command);
+ return buffer;
+}
+
+static char *
+ata_sensekey2str(u_int8_t skey)
+{
+ switch (skey) {
+ case 0x00: return ("NO SENSE");
+ case 0x01: return ("RECOVERED ERROR");
+ case 0x02: return ("NOT READY");
+ case 0x03: return ("MEDIUM ERROR");
+ case 0x04: return ("HARDWARE ERROR");
+ case 0x05: return ("ILLEGAL REQUEST");
+ case 0x06: return ("UNIT ATTENTION");
+ case 0x07: return ("DATA PROTECT");
+ case 0x08: return ("BLANK CHECK");
+ case 0x09: return ("VENDOR SPECIFIC");
+ case 0x0a: return ("COPY ABORTED");
+ case 0x0b: return ("ABORTED COMMAND");
+ case 0x0c: return ("EQUAL");
+ case 0x0d: return ("VOLUME OVERFLOW");
+ case 0x0e: return ("MISCOMPARE");
+ case 0x0f: return ("RESERVED");
+ default: return("UNKNOWN");
+ }
+}
diff --git a/sys/dev/ata/ata-raid.c b/sys/dev/ata/ata-raid.c
index 8e13c63..26f2346 100644
--- a/sys/dev/ata/ata-raid.c
+++ b/sys/dev/ata/ata-raid.c
@@ -42,9 +42,12 @@
#include <sys/cons.h>
#include <sys/unistd.h>
#include <sys/kthread.h>
+#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <geom/geom_disk.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
#include <dev/ata/ata-all.h>
#include <dev/ata/ata-pci.h>
#include <dev/ata/ata-disk.h>
@@ -105,7 +108,7 @@ ata_raiddisk_attach(struct ad_softc *adp)
return 0;
}
- switch(adp->device->channel->chiptype & 0xffff) {
+ switch(pci_get_vendor(device_get_parent(adp->device->channel->dev))) {
case ATA_PROMISE_ID:
/* test RAID bit in PCI reg XXX */
return (ar_promise_read_conf(adp, ar_table, 0));
@@ -219,7 +222,7 @@ ar_attach_raid(struct ar_softc *rdp, int update)
printf(" disk%d SPARE ", disk);
else
printf(" disk%d FREE ", disk);
- printf("on %s at ata%d-%s\n", rdp->disks[disk].device->name,
+ printf("on %s at ata%d-%s\n", rdp->disks[disk].device->name,
device_get_unit(rdp->disks[disk].device->channel->dev),
(rdp->disks[disk].device->unit == ATA_MASTER) ?
"master" : "slave");
@@ -255,7 +258,7 @@ ata_raid_addspare(int array, int disk)
(AR_DF_PRESENT | AR_DF_ONLINE)) && rdp->disks[i].device)
continue;
if ((atadev = ar_locate_disk(disk))) {
- if (((struct ad_softc*)(atadev->driver))->flags & AD_F_RAID_SUBDISK)
+ if (((struct ad_softc*)(atadev->softc))->flags & AD_F_RAID_SUBDISK)
return EBUSY;
rdp->disks[i].device = atadev;
rdp->disks[i].flags |= (AR_DF_PRESENT|AR_DF_ASSIGNED|AR_DF_SPARE);
@@ -306,7 +309,8 @@ ata_raid_create(struct raid_setup *setup)
return EBUSY;
}
- switch (rdp->disks[disk].device->channel->chiptype & 0xffff) {
+ switch(pci_get_vendor(device_get_parent(
+ rdp->disks[disk].device->channel->dev))) {
case ATA_HIGHPOINT_ID:
ctlr |= AR_F_HIGHPOINT_RAID;
rdp->disks[disk].disk_sectors =
@@ -323,6 +327,7 @@ ata_raid_create(struct raid_setup *setup)
PR_LBA(AD_SOFTC(rdp->disks[disk]));
break;
}
+
if (rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID) &&
(rdp->flags & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID)) !=
(ctlr & (AR_F_PROMISE_RAID|AR_F_HIGHPOINT_RAID))) {
@@ -437,7 +442,9 @@ ata_raid_delete(int array)
for (disk = 0; disk < rdp->total_disks; disk++) {
if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
AD_SOFTC(rdp->disks[disk])->flags &= ~AD_F_RAID_SUBDISK;
+/* SOS
ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
+ XXX */
rdp->disks[disk].flags = 0;
}
}
@@ -556,15 +563,15 @@ ardump(void *arg, void *virtual, vm_offset_t physical,
chunk = blkno % rdp->interleave;
if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) *
(rdp->interleave * rdp->width) ) {
- lbs = (rdp->total_sectors -
+ lbs = (rdp->total_sectors -
((rdp->total_sectors / (rdp->interleave * rdp->width)) *
(rdp->interleave * rdp->width))) / rdp->width;
- drv = (blkno -
+ drv = (blkno -
((rdp->total_sectors / (rdp->interleave * rdp->width)) *
(rdp->interleave * rdp->width))) / lbs;
- lba = ((tmplba / rdp->width) * rdp->interleave) +
- (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs;
- chunk = min(count, lbs);
+ lba = ((tmplba / rdp->width) * rdp->interleave) +
+ (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs;
+ chunk = min(count, lbs);
}
else {
drv = tmplba % rdp->width;
@@ -670,15 +677,15 @@ arstrategy(struct bio *bp)
chunk = blkno % rdp->interleave;
if (blkno >= (rdp->total_sectors / (rdp->interleave * rdp->width)) *
(rdp->interleave * rdp->width) ) {
- lbs = (rdp->total_sectors -
+ lbs = (rdp->total_sectors -
((rdp->total_sectors / (rdp->interleave * rdp->width)) *
(rdp->interleave * rdp->width))) / rdp->width;
- drv = (blkno -
+ drv = (blkno -
((rdp->total_sectors / (rdp->interleave * rdp->width)) *
(rdp->interleave * rdp->width))) / lbs;
- lba = ((tmplba / rdp->width) * rdp->interleave) +
- (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs;
- chunk = min(count, lbs);
+ lba = ((tmplba / rdp->width) * rdp->interleave) +
+ (blkno - ((tmplba / rdp->width) * rdp->interleave)) % lbs;
+ chunk = min(count, lbs);
}
else {
drv = tmplba % rdp->width;
@@ -718,7 +725,7 @@ arstrategy(struct bio *bp)
case AR_F_RAID0:
if ((rdp->disks[buf1->drive].flags &
(AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
- !rdp->disks[buf1->drive].device->driver) {
+ !rdp->disks[buf1->drive].device->softc) {
rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
ar_config_changed(rdp, 1);
free(buf1, M_AR);
@@ -743,13 +750,13 @@ arstrategy(struct bio *bp)
}
if ((rdp->disks[buf1->drive].flags &
(AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
- !rdp->disks[buf1->drive].device->driver) {
+ !rdp->disks[buf1->drive].device->softc) {
rdp->disks[buf1->drive].flags &= ~AR_DF_ONLINE;
change = 1;
}
if ((rdp->disks[buf1->drive + rdp->width].flags &
(AR_DF_PRESENT|AR_DF_ONLINE))==(AR_DF_PRESENT|AR_DF_ONLINE) &&
- !rdp->disks[buf1->drive + rdp->width].device->driver) {
+ !rdp->disks[buf1->drive + rdp->width].device->softc) {
rdp->disks[buf1->drive + rdp->width].flags &= ~AR_DF_ONLINE;
change = 1;
}
@@ -948,10 +955,12 @@ ar_config_changed(struct ar_softc *rdp, int writeback)
break;
}
if ((rdp->disks[disk].flags&AR_DF_PRESENT) && rdp->disks[disk].device) {
+/* SOS
if (rdp->disks[disk].flags & AR_DF_ONLINE)
ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_GREEN);
else
ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_RED);
+ XXX */
}
}
if (writeback) {
@@ -986,7 +995,9 @@ ar_rebuild(void *arg)
#endif
continue;
}
+/* SOS
ata_enclosure_leds(rdp->disks[disk].device, ATA_LED_ORANGE);
+ XXX */
count++;
}
}
@@ -1278,7 +1289,7 @@ ar_highpoint_write_conf(struct ar_softc *rdp)
config->total_sectors = rdp->total_sectors;
config->rebuild_lba = rdp->lock_start;
- if (rdp->disks[disk].device && rdp->disks[disk].device->driver &&
+ if (rdp->disks[disk].device && rdp->disks[disk].device->softc &&
!(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
if (ar_rw(AD_SOFTC(rdp->disks[disk]), HPT_LBA,
sizeof(struct highpoint_raid_conf),
@@ -1356,7 +1367,8 @@ ar_promise_read_conf(struct ad_softc *adp, struct ar_softc **raidp, int local)
if (raid->flags & AR_F_HIGHPOINT_RAID)
continue;
- magic = (adp->device->channel->chiptype >> 16) |
+ magic = (pci_get_device(device_get_parent(
+ adp->device->channel->dev)) >> 16) |
(info->raid.array_number << 16);
if (raid->flags & AR_F_PROMISE_RAID && magic != raid->magic_0)
@@ -1486,7 +1498,7 @@ ar_promise_write_conf(struct ar_softc *rdp)
if (rdp->disks[disk].flags & AR_DF_PRESENT && rdp->disks[disk].device) {
config->raid.channel = rdp->disks[disk].device->channel->unit;
config->raid.device = (rdp->disks[disk].device->unit != 0);
- if (rdp->disks[disk].device->driver)
+ if (rdp->disks[disk].device->softc)
config->raid.disk_sectors = PR_LBA(AD_SOFTC(rdp->disks[disk]));
/*config->raid.disk_offset*/
}
@@ -1558,10 +1570,10 @@ ar_promise_write_conf(struct ar_softc *rdp)
PR_MAGIC0(rdp->disks[drive]) | timestamp.tv_sec;
}
- if (rdp->disks[disk].device && rdp->disks[disk].device->driver &&
+ if (rdp->disks[disk].device && rdp->disks[disk].device->softc &&
!(rdp->disks[disk].device->flags & ATA_D_DETACHING)) {
if ((rdp->disks[disk].flags & (AR_DF_PRESENT | AR_DF_ONLINE)) ==
- (AR_DF_PRESENT | AR_DF_ONLINE)) {
+ (AR_DF_PRESENT | AR_DF_ONLINE)) {
if (local)
bcopy(ATA_MAGIC, config->promise_id, sizeof(ATA_MAGIC));
else
@@ -1635,12 +1647,12 @@ ar_locate_disk(int diskno)
if (!(ch = devclass_get_softc(ata_devclass, ctlr)))
continue;
if (ch->devices & ATA_ATA_MASTER)
- if (ch->device[MASTER].driver &&
- ((struct ad_softc *)(ch->device[MASTER].driver))->lun == diskno)
+ if (ch->device[MASTER].softc &&
+ ((struct ad_softc *)(ch->device[MASTER].softc))->lun == diskno)
return &ch->device[MASTER];
if (ch->devices & ATA_ATA_SLAVE)
- if (ch->device[SLAVE].driver &&
- ((struct ad_softc *)(ch->device[SLAVE].driver))->lun == diskno)
+ if (ch->device[SLAVE].softc &&
+ ((struct ad_softc *)(ch->device[SLAVE].softc))->lun == diskno)
return &ch->device[SLAVE];
}
return NULL;
@@ -1656,7 +1668,7 @@ ar_print_conf(struct ar_softc *config)
printf("magic_1 0x%08x\n", config->magic_1);
printf("flags 0x%02x %b\n", config->flags, config->flags,
"\20\16HIGHPOINT\15PROMISE\13REBUILDING\12DEGRADED\11READY\3SPAN\2RAID1\1RAID0\n");
- printf("total_disks %d\n", config->total_disks);
+ printf("total_disks %d\n", config->total_disks);
printf("generation %d\n", config->generation);
printf("width %d\n", config->width);
printf("heads %d\n", config->heads);
@@ -1670,6 +1682,6 @@ ar_print_conf(struct ar_softc *config)
printf("disk %d: flags = 0x%02x %b\n", i, config->disks[i].flags, config->disks[i].flags, "\20\4ONLINE\3SPARE\2ASSIGNED\1PRESENT\n");
if (config->disks[i].device)
printf(" %s\n", config->disks[i].device->name);
- printf(" sectors %lld\n", (long long)config->disks[i].disk_sectors);
+ printf(" sectors %lld\n", (long long)config->disks[i].disk_sectors);
}
}
diff --git a/sys/dev/ata/ata-raid.h b/sys/dev/ata/ata-raid.h
index 2b6ba54..9af598e 100644
--- a/sys/dev/ata/ata-raid.h
+++ b/sys/dev/ata/ata-raid.h
@@ -36,7 +36,7 @@
#define AR_WRITE 0x02
#define AR_WAIT 0x04
#define AR_STRATEGY(x) (x)->bio_disk->d_strategy((x))
-#define AD_SOFTC(x) ((struct ad_softc *)(x.device->driver))
+#define AD_SOFTC(x) ((struct ad_softc *)(x.device->softc))
#define ATA_MAGIC "FreeBSD ATA driver RAID "
struct ar_disk {
diff --git a/sys/dev/ata/atapi-all.c b/sys/dev/ata/atapi-all.c
deleted file mode 100644
index 1b27ca4..0000000
--- a/sys/dev/ata/atapi-all.c
+++ /dev/null
@@ -1,699 +0,0 @@
-/*-
- * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#include "opt_ata.h"
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/ata.h>
-#include <sys/kernel.h>
-#include <sys/bus.h>
-#include <sys/malloc.h>
-#include <sys/bio.h>
-#include <sys/sysctl.h>
-#include <machine/bus.h>
-#include <sys/rman.h>
-#include <dev/ata/ata-all.h>
-#include <dev/ata/atapi-all.h>
-
-/* prototypes */
-static void atapi_read(struct atapi_request *, int);
-static void atapi_write(struct atapi_request *, int);
-static void atapi_finish(struct atapi_request *);
-static void atapi_timeout(struct atapi_request *);
-static char *atapi_cmd2str(u_int8_t);
-static char *atapi_skey2str(u_int8_t);
-
-/* misc defines */
-#define ATAPI_MAX_RETRIES 3
-
-/* internal vars */
-static int atapi_dma = 0;
-TUNABLE_INT("hw.ata.atapi_dma", &atapi_dma);
-static MALLOC_DEFINE(M_ATAPI, "ATAPI generic", "ATAPI driver generic layer");
-
-/* systcl vars */
-SYSCTL_DECL(_hw_ata);
-SYSCTL_INT(_hw_ata, OID_AUTO, atapi_dma, CTLFLAG_RD, &atapi_dma, 0,
- "ATAPI device DMA mode control");
-
-void
-atapi_attach(struct ata_device *atadev)
-{
- if (bootverbose)
- ata_prtdev(atadev, "piomode=%d dmamode=%d udmamode=%d dmaflag=%d\n",
- ata_pmode(atadev->param), ata_wmode(atadev->param),
- ata_umode(atadev->param), atadev->param->support_dma);
-
- /* use DMA if allowed and if drive/controller supports it */
- ATA_SLEEPLOCK_CH(atadev->channel, ATA_CONTROL);
- if (atapi_dma && atadev->channel->dma &&
- !(atadev->param->drq_type == ATAPI_DRQT_INTR))
- atadev->setmode(atadev, ATA_DMA_MAX);
- else
- atadev->setmode(atadev, ATA_PIO_MAX);
- ATA_UNLOCK_CH(atadev->channel);
-
- if (!(atadev->result = malloc(sizeof(struct atapi_reqsense), M_ATAPI,
- M_NOWAIT | M_ZERO)))
- ata_prtdev(atadev, "no memory for sense data\n");
-
- switch (atadev->param->type) {
-#ifdef DEV_ATAPICD
- case ATAPI_TYPE_CDROM:
- if (acdattach(atadev))
- return;
- break;
-#endif
-#ifdef DEV_ATAPIFD
- case ATAPI_TYPE_DIRECT:
- if (afdattach(atadev))
- return;
- break;
-#endif
-#ifdef DEV_ATAPIST
- case ATAPI_TYPE_TAPE:
- if (astattach(atadev))
- return;
- break;
-#endif
- }
-#ifndef DEV_ATAPICAM
- ata_prtdev(atadev, "<%.40s/%.8s> - NO DRIVER!\n",
- atadev->param->model, atadev->param->revision);
- free(atadev->result, M_ATAPI);
- atadev->driver = NULL;
-#endif
-}
-
-void
-atapi_detach(struct ata_device *atadev)
-{
- struct atapi_request *request;
-
- atadev->flags |= ATA_D_DETACHING;
- ata_prtdev(atadev, "removed from configuration\n");
- switch (atadev->param->type) {
-#ifdef DEV_ATAPICD
- case ATAPI_TYPE_CDROM:
- acddetach(atadev);
- break;
-#endif
-#ifdef DEV_ATAPIFD
- case ATAPI_TYPE_DIRECT:
- afddetach(atadev);
- break;
-#endif
-#ifdef DEV_ATAPIST
- case ATAPI_TYPE_TAPE:
- astdetach(atadev);
- break;
-#endif
- default:
- return;
- }
- TAILQ_FOREACH(request, &atadev->channel->atapi_queue, chain) {
- if (request->device != atadev)
- continue;
- TAILQ_REMOVE(&atadev->channel->atapi_queue, request, chain);
- if (request->driver) {
- struct bio *bp = (struct bio *) request->driver;
- biofinish(bp, NULL, ENXIO);
- }
- free(request, M_ATAPI);
- }
- free(atadev->result, M_ATAPI);
- atadev->driver = NULL;
- atadev->flags = 0;
-
-}
-
-int
-atapi_queue_cmd(struct ata_device *atadev, int8_t *ccb, caddr_t data,
- int count, int flags, int timeout,
- atapi_callback_t callback, void *driver)
-{
- struct atapi_request *request;
- int error, s;
-
- if (!(request = malloc(sizeof(struct atapi_request), M_ATAPI,
- M_NOWAIT | M_ZERO)))
- return ENOMEM;
-
- request->device = atadev;
- request->data = data;
- request->bytecount = count;
- request->flags = flags;
- request->error = EINPROGRESS;
- request->timeout = timeout * hz;
- request->ccbsize = atadev->param->packet_size ? 16 : 12;
- bcopy(ccb, request->ccb, request->ccbsize);
- if (callback) {
- request->callback = callback;
- request->driver = driver;
- }
- if (atadev->mode >= ATA_DMA && !atadev->channel->dma)
- atadev->mode = ATA_PIO;
-
-#ifdef ATAPI_DEBUG
- ata_prtdev(atadev, "queueing %s ", atapi_cmd2str(request->ccb[0]));
- atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb));
-#endif
- /* append onto controller queue and try to start controller */
- s = splbio();
- if (flags & ATPR_F_AT_HEAD)
- TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain);
- else
- TAILQ_INSERT_TAIL(&atadev->channel->atapi_queue, request, chain);
- ata_start(atadev->channel);
-
- /* if callback used, then just return, gets called from interrupt context */
- if (callback) {
- splx(s);
- return 0;
- }
-
- /* only sleep when command is in progress */
- if (request->error == EINPROGRESS)
- tsleep(request, PRIBIO, "atprq", 0);
- splx(s);
- error = request->error;
- if (error)
- bcopy(&request->sense, atadev->result, sizeof(struct atapi_reqsense));
- free(request, M_ATAPI);
- return error;
-}
-
-void
-atapi_start(struct ata_device *atadev)
-{
- switch (atadev->param->type) {
-#ifdef DEV_ATAPICD
- case ATAPI_TYPE_CDROM:
- acd_start(atadev);
- break;
-#endif
-#ifdef DEV_ATAPIFD
- case ATAPI_TYPE_DIRECT:
- afd_start(atadev);
- break;
-#endif
-#ifdef DEV_ATAPIST
- case ATAPI_TYPE_TAPE:
- ast_start(atadev);
- break;
-#endif
- default:
- return;
- }
-}
-
-int
-atapi_transfer(struct atapi_request *request)
-{
- struct ata_device *atadev = request->device;
- int timout;
- u_int8_t reason;
-
-#ifdef ATAPI_DEBUG
- ata_prtdev(atadev, "starting %s ", atapi_cmd2str(request->ccb[0]));
- atapi_dump("ccb = ", &request->ccb[0], sizeof(request->ccb));
-#endif
- /* is this just a POLL DSC command ? */
- if (request->ccb[0] == ATAPI_POLL_DSC) {
- ATA_IDX_OUTB(atadev->channel, ATA_DRIVE, ATA_D_IBM | atadev->unit);
- DELAY(10);
- if (ATA_IDX_INB(atadev->channel, ATA_ALTSTAT) & ATA_S_DSC)
- request->error = 0;
- else
- request->error = EBUSY;
- atapi_finish(request);
- return ATA_OP_FINISHED;
- }
-
- /* start timeout for this command */
- request->timeout_handle = timeout((timeout_t *)atapi_timeout,
- request, request->timeout);
-
- if (!(request->flags & ATPR_F_INTERNAL))
- atadev->cmd = request->ccb[0];
-
- /* if DMA enabled setup DMA hardware */
- request->flags &= ~ATPR_F_DMA_USED;
- if ((atadev->mode >= ATA_DMA) &&
- (request->ccb[0] == ATAPI_READ ||
- request->ccb[0] == ATAPI_READ_BIG ||
- request->ccb[0] == ATAPI_READ_CD ||
- ((request->ccb[0] == ATAPI_WRITE ||
- request->ccb[0] == ATAPI_WRITE_BIG) &&
- !(atadev->channel->flags & ATA_ATAPI_DMA_RO))) &&
- !atadev->channel->dma->setup(atadev, (void *)request->data, request->bytecount)) {
- request->flags |= ATPR_F_DMA_USED;
- }
-
- /* start ATAPI operation */
- if (ata_command(atadev, ATA_C_PACKET_CMD,
- min(request->bytecount, 65534) << 8, 0,
- (request->flags & ATPR_F_DMA_USED) ? ATA_F_DMA : 0,
- ATA_IMMEDIATE))
- ata_prtdev(atadev, "failure to send ATAPI packet command\n");
-
- if (request->flags & ATPR_F_DMA_USED)
- atadev->channel->dma->start(atadev->channel, request->data, request->bytecount,
- request->flags & ATPR_F_READ);
-
- /* command interrupt device ? just return */
- if (atadev->param->drq_type == ATAPI_DRQT_INTR)
- return ATA_OP_CONTINUES;
-
- /* ready to write ATAPI command */
- timout = 5000; /* might be less for fast devices */
- while (timout--) {
- reason = ATA_IDX_INB(atadev->channel, ATA_IREASON);
- atadev->channel->status = ATA_IDX_INB(atadev->channel, ATA_STATUS);
- if (((reason & (ATA_I_CMD | ATA_I_IN)) |
- (atadev->channel->status&(ATA_S_DRQ|ATA_S_BUSY)))==ATAPI_P_CMDOUT)
- break;
- DELAY(20);
- }
- if (timout <= 0) {
- ata_prtdev(atadev, "failure to execute ATAPI packet command\n");
- untimeout((timeout_t *)atapi_timeout, request, request->timeout_handle);
- request->error = EIO;
- atapi_finish(request);
- return ATA_OP_FINISHED;
- }
-
- /* this seems to be needed for some (slow) devices */
- DELAY(10);
-
- /* send actual command */
- ATA_IDX_OUTSW_STRM(atadev->channel, ATA_DATA, (int16_t *)request->ccb,
- request->ccbsize / sizeof(int16_t));
- return ATA_OP_CONTINUES;
-}
-
-int
-atapi_interrupt(struct atapi_request *request)
-{
- struct ata_device *atadev = request->device;
- int reason, dma_stat = 0;
-
- reason = (ATA_IDX_INB(atadev->channel, ATA_IREASON) & (ATA_I_CMD | ATA_I_IN)) |
- (atadev->channel->status & ATA_S_DRQ);
-
- if (reason == ATAPI_P_CMDOUT) {
- if (!(atadev->channel->status & ATA_S_DRQ)) {
- ata_prtdev(atadev, "command interrupt without DRQ\n");
- untimeout((timeout_t *)atapi_timeout,
- request, request->timeout_handle);
- request->error = EIO;
- atapi_finish(request);
- return ATA_OP_FINISHED;
- }
- ATA_IDX_OUTSW_STRM(atadev->channel, ATA_DATA, (int16_t *)request->ccb,
- request->ccbsize / sizeof(int16_t));
- return ATA_OP_CONTINUES;
- }
-
- if (request->flags & ATPR_F_DMA_USED) {
- dma_stat = atadev->channel->dma->stop(atadev->channel);
- if ((atadev->channel->status & (ATA_S_ERROR | ATA_S_DWF)) ||
- dma_stat & ATA_BMSTAT_ERROR) {
- request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR);
- }
- else {
- request->result = 0;
- request->donecount = request->bytecount;
- request->bytecount = 0;
- }
- }
- else {
- int length = ATA_IDX_INB(atadev->channel, ATA_CYL_LSB) |
- ATA_IDX_INB(atadev->channel, ATA_CYL_MSB) << 8;
-
- switch (reason) {
- case ATAPI_P_WRITE:
- if (request->flags & ATPR_F_READ) {
- request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR);
- ata_prtdev(atadev, "%s trying to write on read buffer\n",
- atapi_cmd2str(atadev->cmd));
- break;
- }
- atapi_write(request, length);
- return ATA_OP_CONTINUES;
-
- case ATAPI_P_READ:
- if (!(request->flags & ATPR_F_READ)) {
- request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR);
- ata_prtdev(atadev, "%s trying to read on write buffer\n",
- atapi_cmd2str(atadev->cmd));
- break;
- }
- atapi_read(request, length);
- return ATA_OP_CONTINUES;
-
- case ATAPI_P_DONEDRQ:
- ata_prtdev(atadev, "%s DONEDRQ\n", atapi_cmd2str(atadev->cmd));
- if (request->flags & ATPR_F_READ)
- atapi_read(request, length);
- else
- atapi_write(request, length);
- /* FALLTHROUGH */
-
- case ATAPI_P_ABORT:
- case ATAPI_P_DONE:
- if (atadev->channel->status & (ATA_S_ERROR | ATA_S_DWF))
- request->result = ATA_IDX_INB(atadev->channel, ATA_ERROR);
- else
- if (!(request->flags & ATPR_F_INTERNAL))
- request->result = 0;
- break;
-
- default:
- ata_prtdev(atadev, "unknown transfer phase %d\n", reason);
- }
- }
- untimeout((timeout_t *)atapi_timeout, request, request->timeout_handle);
-
- /* check for error, if valid sense key, queue a request sense cmd */
- if ((request->result & ATAPI_SK_MASK) &&
- request->ccb[0] != ATAPI_REQUEST_SENSE) {
- bzero(request->ccb, request->ccbsize);
- request->ccb[0] = ATAPI_REQUEST_SENSE;
- request->ccb[4] = sizeof(struct atapi_reqsense);
- request->bytecount = sizeof(struct atapi_reqsense);
- request->flags &= ATPR_F_QUIET;
- request->flags |= ATPR_F_READ | ATPR_F_INTERNAL;
- TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain);
- }
- else {
- if (request->result) {
- switch ((request->result & ATAPI_SK_MASK)) {
- case ATAPI_SK_NO_SENSE:
- request->error = 0;
- break;
-
- case ATAPI_SK_RECOVERED_ERROR:
- ata_prtdev(atadev, "%s - recovered error\n",
- atapi_cmd2str(atadev->cmd));
- request->error = 0;
- break;
-
- case ATAPI_SK_NOT_READY:
- request->error = EBUSY;
- break;
-
- case ATAPI_SK_UNIT_ATTENTION:
- atadev->flags |= ATA_D_MEDIA_CHANGED;
- request->error = EIO;
- break;
-
- default:
- request->error = EIO;
-
- if (request->flags & ATPR_F_QUIET)
- break;
-
- ata_prtdev(atadev, "%s - %s asc=0x%02x ascq=0x%02x ",
- atapi_cmd2str(atadev->cmd),
- atapi_skey2str(request->sense.sense_key),
- request->sense.asc, request->sense.ascq);
- if (request->sense.sksv)
- printf("sks=0x%02x 0x%02x 0x%02x ",
- request->sense.sk_specific,
- request->sense.sk_specific1,
- request->sense.sk_specific2);
- printf("error=0x%02x\n", request->result & ATAPI_E_MASK);
- }
- }
- else
- request->error = 0;
- atapi_finish(request);
- }
- return ATA_OP_FINISHED;
-}
-
-void
-atapi_reinit(struct ata_device *atadev)
-{
- /* reinit device parameters */
- atadev->setmode(atadev, atadev->mode);
-}
-
-int
-atapi_test_ready(struct ata_device *atadev)
-{
- int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- return atapi_queue_cmd(atadev, ccb, NULL, 0, 0, 30, NULL, NULL);
-}
-
-int
-atapi_wait_dsc(struct ata_device *atadev, int timeout)
-{
- int error = 0;
- int8_t ccb[16] = { ATAPI_POLL_DSC, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- timeout *= hz;
- while (timeout > 0) {
- error = atapi_queue_cmd(atadev, ccb, NULL, 0, 0, 0, NULL, NULL);
- if (error != EBUSY)
- break;
- tsleep(&error, PRIBIO, "atpwt", hz / 2);
- timeout -= (hz / 2);
- }
- return error;
-}
-
-void
-atapi_dump(char *label, void *data, int len)
-{
- u_int8_t *p = data;
-
- printf("%s %02x", label, *p++);
- while (--len > 0)
- printf ("-%02x", *p++);
- printf("\n");
-}
-
-static void
-atapi_read(struct atapi_request *request, int length)
-{
- int8_t **buffer = (int8_t **)&request->data;
- int size = min(request->bytecount, length);
- struct ata_channel *ch = request->device->channel;
- int resid;
-
- if (request->flags & ATPR_F_INTERNAL)
- *buffer = (int8_t *)&request->sense;
-
- if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
- ATA_IDX_INSW_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer),
- size / sizeof(int16_t));
- else
- ATA_IDX_INSL_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer),
- size / sizeof(int32_t));
-
- if (request->bytecount < length) {
- ata_prtdev(request->device, "read data overrun %d/%d\n",
- length, request->bytecount);
- for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t))
- ATA_IDX_INW(ch, ATA_DATA);
- }
- *buffer += size;
- request->bytecount -= size;
- request->donecount += size;
-}
-
-static void
-atapi_write(struct atapi_request *request, int length)
-{
- int8_t **buffer = (int8_t **)&request->data;
- int size = min(request->bytecount, length);
- struct ata_channel *ch = request->device->channel;
- int resid;
-
- if (request->flags & ATPR_F_INTERNAL)
- *buffer = (int8_t *)&request->sense;
-
- if (ch->flags & ATA_USE_16BIT || (size % sizeof(int32_t)))
- ATA_IDX_OUTSW_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer),
- size / sizeof(int16_t));
- else
- ATA_IDX_OUTSL_STRM(ch, ATA_DATA, (void *)((uintptr_t)*buffer),
- size / sizeof(int32_t));
-
- if (request->bytecount < length) {
- ata_prtdev(request->device, "write data underrun %d/%d\n",
- length, request->bytecount);
- for (resid=request->bytecount; resid<length; resid+=sizeof(int16_t))
- ATA_IDX_OUTW(ch, ATA_DATA, 0);
- }
- *buffer += size;
- request->bytecount -= size;
- request->donecount += size;
-}
-
-static void
-atapi_finish(struct atapi_request *request)
-{
-#ifdef ATAPI_DEBUG
- ata_prtdev(request->device, "finished %s%s\n",
- request->callback ? "callback " : "",
- atapi_cmd2str(request->ccb[0]));
-#endif
- if (request->callback) {
- if (!((request->callback)(request)))
- free(request, M_ATAPI);
- }
- else
- wakeup(request);
-}
-
-static void
-atapi_timeout(struct atapi_request *request)
-{
- struct ata_device *atadev = request->device;
-
- atadev->channel->running = NULL;
- ata_prtdev(atadev, "%s command timeout - resetting\n",
- atapi_cmd2str(request->ccb[0]));
-
- if (request->flags & ATPR_F_DMA_USED) {
- atadev->channel->dma->stop(atadev->channel);
- if (request->retries == ATAPI_MAX_RETRIES) {
- atadev->setmode(atadev, ATA_PIO_MAX);
- ata_prtdev(atadev, "trying fallback to PIO mode\n");
- request->retries = 0;
- }
- }
-
- /* if retries still permit, reinject this request */
- if (request->retries++ < ATAPI_MAX_RETRIES) {
- int s = splbio();
-
- TAILQ_INSERT_HEAD(&atadev->channel->atapi_queue, request, chain);
- splx(s);
- }
- else {
- /* retries all used up, return error */
- request->error = EIO;
- wakeup(request);
- }
- ata_reinit(atadev->channel);
-}
-
-static char *
-atapi_cmd2str(u_int8_t cmd)
-{
- switch (cmd) {
- case 0x00: return ("TEST_UNIT_READY");
- case 0x01: return ("REZERO");
- case 0x03: return ("REQUEST_SENSE");
- case 0x04: return ("FORMAT_UNIT");
- case 0x08: return ("READ");
- case 0x0a: return ("WRITE");
- case 0x10: return ("WEOF");
- case 0x11: return ("SPACE");
- case 0x15: return ("MODE_SELECT");
- case 0x19: return ("ERASE");
- case 0x1a: return ("MODE_SENSE");
- case 0x1b: return ("START_STOP");
- case 0x1e: return ("PREVENT_ALLOW");
- case 0x23: return ("ATAPI_READ_FORMAT_CAPACITIES");
- case 0x25: return ("READ_CAPACITY");
- case 0x28: return ("READ_BIG");
- case 0x2a: return ("WRITE_BIG");
- case 0x2b: return ("LOCATE");
- case 0x34: return ("READ_POSITION");
- case 0x35: return ("SYNCHRONIZE_CACHE");
- case 0x3b: return ("WRITE_BUFFER");
- case 0x3c: return ("READ_BUFFER");
- case 0x42: return ("READ_SUBCHANNEL");
- case 0x43: return ("READ_TOC");
- case 0x45: return ("PLAY_10");
- case 0x47: return ("PLAY_MSF");
- case 0x48: return ("PLAY_TRACK");
- case 0x4b: return ("PAUSE");
- case 0x51: return ("READ_DISK_INFO");
- case 0x52: return ("READ_TRACK_INFO");
- case 0x53: return ("RESERVE_TRACK");
- case 0x54: return ("SEND_OPC_INFO");
- case 0x55: return ("MODE_SELECT_BIG");
- case 0x58: return ("REPAIR_TRACK");
- case 0x59: return ("READ_MASTER_CUE");
- case 0x5a: return ("MODE_SENSE_BIG");
- case 0x5b: return ("CLOSE_TRACK/SESSION");
- case 0x5c: return ("READ_BUFFER_CAPACITY");
- case 0x5d: return ("SEND_CUE_SHEET");
- case 0xa1: return ("BLANK_CMD");
- case 0xa3: return ("SEND_KEY");
- case 0xa4: return ("REPORT_KEY");
- case 0xa5: return ("PLAY_12");
- case 0xa6: return ("LOAD_UNLOAD");
- case 0xad: return ("READ_DVD_STRUCTURE");
- case 0xb4: return ("PLAY_CD");
- case 0xbb: return ("SET_SPEED");
- case 0xbd: return ("MECH_STATUS");
- case 0xbe: return ("READ_CD");
- case 0xff: return ("POLL_DSC");
- default: {
- static char buffer[20];
- sprintf(buffer, "unknown CMD (0x%02x)", cmd);
- return buffer;
- }
- }
-}
-
-static char *
-atapi_skey2str(u_int8_t skey)
-{
- switch (skey) {
- case 0x00: return ("NO SENSE");
- case 0x01: return ("RECOVERED ERROR");
- case 0x02: return ("NOT READY");
- case 0x03: return ("MEDIUM ERROR");
- case 0x04: return ("HARDWARE ERROR");
- case 0x05: return ("ILLEGAL REQUEST");
- case 0x06: return ("UNIT ATTENTION");
- case 0x07: return ("DATA PROTECT");
- case 0x08: return ("BLANK CHECK");
- case 0x09: return ("VENDOR SPECIFIC");
- case 0x0a: return ("COPY ABORTED");
- case 0x0b: return ("ABORTED COMMAND");
- case 0x0c: return ("EQUAL");
- case 0x0d: return ("VOLUME OVERFLOW");
- case 0x0e: return ("MISCOMPARE");
- case 0x0f: return ("RESERVED");
- default: return("UNKNOWN");
- }
-}
diff --git a/sys/dev/ata/atapi-all.h b/sys/dev/ata/atapi-all.h
deleted file mode 100644
index d41b696..0000000
--- a/sys/dev/ata/atapi-all.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/*-
- * Copyright (c) 1998 - 2003 Søren Schmidt <sos@FreeBSD.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer,
- * without modification, immediately at the beginning of the file.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-/* ATAPI misc defines */
-#define ATAPI_MAGIC_LSB 0x14
-#define ATAPI_MAGIC_MSB 0xeb
-#define ATAPI_P_READ (ATA_S_DRQ | ATA_I_IN)
-#define ATAPI_P_WRITE (ATA_S_DRQ)
-#define ATAPI_P_CMDOUT (ATA_S_DRQ | ATA_I_CMD)
-#define ATAPI_P_DONEDRQ (ATA_S_DRQ | ATA_I_CMD | ATA_I_IN)
-#define ATAPI_P_DONE (ATA_I_CMD | ATA_I_IN)
-#define ATAPI_P_ABORT 0
-
-/* error register bits */
-#define ATAPI_E_MASK 0x0f /* error mask */
-#define ATAPI_E_ILI 0x01 /* illegal length indication */
-#define ATAPI_E_EOM 0x02 /* end of media detected */
-#define ATAPI_E_ABRT 0x04 /* command aborted */
-#define ATAPI_E_MCR 0x08 /* media change requested */
-#define ATAPI_SK_MASK 0xf0 /* sense key mask */
-#define ATAPI_SK_NO_SENSE 0x00 /* no specific sense key info */
-#define ATAPI_SK_RECOVERED_ERROR 0x10 /* command OK, data recovered */
-#define ATAPI_SK_NOT_READY 0x20 /* no access to drive */
-#define ATAPI_SK_MEDIUM_ERROR 0x30 /* non-recovered data error */
-#define ATAPI_SK_HARDWARE_ERROR 0x40 /* non-recoverable HW failure */
-#define ATAPI_SK_ILLEGAL_REQUEST 0x50 /* invalid command param(s) */
-#define ATAPI_SK_UNIT_ATTENTION 0x60 /* media changed */
-#define ATAPI_SK_DATA_PROTECT 0x70 /* write protect */
-#define ATAPI_SK_BLANK_CHECK 0x80 /* blank check */
-#define ATAPI_SK_VENDOR_SPECIFIC 0x90 /* vendor specific skey */
-#define ATAPI_SK_COPY_ABORTED 0xa0 /* copy aborted */
-#define ATAPI_SK_ABORTED_COMMAND 0xb0 /* command aborted, try again */
-#define ATAPI_SK_EQUAL 0xc0 /* equal */
-#define ATAPI_SK_VOLUME_OVERFLOW 0xd0 /* volume overflow */
-#define ATAPI_SK_MISCOMPARE 0xe0 /* data dont match the medium */
-#define ATAPI_SK_RESERVED 0xf0
-
-/* ATAPI commands */
-#define ATAPI_TEST_UNIT_READY 0x00 /* check if device is ready */
-#define ATAPI_REZERO 0x01 /* rewind */
-#define ATAPI_REQUEST_SENSE 0x03 /* get sense data */
-#define ATAPI_FORMAT 0x04 /* format unit */
-#define ATAPI_READ 0x08 /* read data */
-#define ATAPI_WRITE 0x0a /* write data */
-#define ATAPI_WEOF 0x10 /* write filemark */
-#define WF_WRITE 0x01
-#define ATAPI_SPACE 0x11 /* space command */
-#define SP_FM 0x01
-#define SP_EOD 0x03
-#define ATAPI_MODE_SELECT 0x15 /* mode select */
-#define ATAPI_ERASE 0x19 /* erase */
-#define ATAPI_MODE_SENSE 0x1a /* mode sense */
-#define ATAPI_START_STOP 0x1b /* start/stop unit */
-#define SS_LOAD 0x01
-#define SS_RETENSION 0x02
-#define SS_EJECT 0x04
-#define ATAPI_PREVENT_ALLOW 0x1e /* media removal */
-#define ATAPI_READ_FORMAT_CAPACITIES 0x23 /* get format capacities */
-#define ATAPI_READ_CAPACITY 0x25 /* get volume capacity */
-#define ATAPI_READ_BIG 0x28 /* read data */
-#define ATAPI_WRITE_BIG 0x2a /* write data */
-#define ATAPI_LOCATE 0x2b /* locate to position */
-#define ATAPI_READ_POSITION 0x34 /* read position */
-#define ATAPI_SYNCHRONIZE_CACHE 0x35 /* flush buf, close channel */
-#define ATAPI_WRITE_BUFFER 0x3b /* write device buffer */
-#define ATAPI_READ_BUFFER 0x3c /* read device buffer */
-#define ATAPI_READ_SUBCHANNEL 0x42 /* get subchannel info */
-#define ATAPI_READ_TOC 0x43 /* get table of contents */
-#define ATAPI_PLAY_10 0x45 /* play by lba */
-#define ATAPI_PLAY_MSF 0x47 /* play by MSF address */
-#define ATAPI_PLAY_TRACK 0x48 /* play by track number */
-#define ATAPI_PAUSE 0x4b /* pause audio operation */
-#define ATAPI_READ_DISK_INFO 0x51 /* get disk info structure */
-#define ATAPI_READ_TRACK_INFO 0x52 /* get track info structure */
-#define ATAPI_RESERVE_TRACK 0x53 /* reserve track */
-#define ATAPI_SEND_OPC_INFO 0x54 /* send OPC structurek */
-#define ATAPI_MODE_SELECT_BIG 0x55 /* set device parameters */
-#define ATAPI_REPAIR_TRACK 0x58 /* repair track */
-#define ATAPI_READ_MASTER_CUE 0x59 /* read master CUE info */
-#define ATAPI_MODE_SENSE_BIG 0x5a /* get device parameters */
-#define ATAPI_CLOSE_TRACK 0x5b /* close track/session */
-#define ATAPI_READ_BUFFER_CAPACITY 0x5c /* get buffer capicity */
-#define ATAPI_SEND_CUE_SHEET 0x5d /* send CUE sheet */
-#define ATAPI_BLANK 0xa1 /* blank the media */
-#define ATAPI_SEND_KEY 0xa3 /* send DVD key structure */
-#define ATAPI_REPORT_KEY 0xa4 /* get DVD key structure */
-#define ATAPI_PLAY_12 0xa5 /* play by lba */
-#define ATAPI_LOAD_UNLOAD 0xa6 /* changer control command */
-#define ATAPI_READ_STRUCTURE 0xad /* get DVD structure */
-#define ATAPI_PLAY_CD 0xb4 /* universal play command */
-#define ATAPI_SET_SPEED 0xbb /* set drive speed */
-#define ATAPI_MECH_STATUS 0xbd /* get changer status */
-#define ATAPI_READ_CD 0xbe /* read data */
-#define ATAPI_POLL_DSC 0xff /* poll DSC status bit */
-
-/* ATAPI request sense structure */
-struct atapi_reqsense {
- u_int8_t error_code :7; /* current or deferred errors */
- u_int8_t valid :1; /* follows ATAPI spec */
- u_int8_t segment; /* Segment number */
- u_int8_t sense_key :4; /* sense key */
- u_int8_t reserved2_4 :1; /* reserved */
- u_int8_t ili :1; /* incorrect length indicator */
- u_int8_t eom :1; /* end of medium */
- u_int8_t filemark :1; /* filemark */
- /* cmd information */
- u_int32_t cmd_info __packed;
- u_int8_t sense_length; /* additional sense len (n-7) */
- /* additional cmd spec info */
- u_int32_t cmd_specific_info __packed;
- u_int8_t asc; /* additional sense code */
- u_int8_t ascq; /* additional sense code qual */
- u_int8_t replaceable_unit_code; /* replaceable unit code */
- u_int8_t sk_specific :7; /* sense key specific */
- u_int8_t sksv :1; /* sense key specific info OK */
- u_int8_t sk_specific1; /* sense key specific */
- u_int8_t sk_specific2; /* sense key specific */
-};
-
-typedef int atapi_callback_t(struct atapi_request *);
-
-struct atapi_request {
- struct ata_device *device; /* ptr to parent softc */
- u_int8_t ccb[16]; /* command control block */
- int ccbsize; /* size of ccb (12 | 16) */
- u_int32_t bytecount; /* bytes to transfer */
- u_int32_t donecount; /* bytes transferred */
- int timeout; /* timeout for this cmd */
- struct callout_handle timeout_handle; /* handle for untimeout */
- int retries; /* retry count */
- int result; /* result of this cmd */
- int error; /* result translated to errno */
- struct atapi_reqsense sense; /* sense data if error */
- int flags;
-#define ATPR_F_READ 0x0001
-#define ATPR_F_DMA_USED 0x0002
-#define ATPR_F_AT_HEAD 0x0004
-#define ATPR_F_INTERNAL 0x0008
-#define ATPR_F_QUIET 0x0010
-
- caddr_t data; /* pointer to data buf */
- atapi_callback_t *callback; /* ptr to callback func */
- void *driver; /* driver specific */
- TAILQ_ENTRY(atapi_request) chain; /* list management */
-};
-
-void atapi_attach(struct ata_device *);
-void atapi_cam_attach_bus(struct ata_channel *);
-void atapi_detach(struct ata_device *);
-void atapi_cam_detach_bus(struct ata_channel *);
-void atapi_cam_reinit_bus(struct ata_channel *);
-void atapi_reinit(struct ata_device *);
-void atapi_start(struct ata_device *);
-int atapi_transfer(struct atapi_request *);
-int atapi_interrupt(struct atapi_request *);
-int atapi_queue_cmd(struct ata_device *, int8_t [], caddr_t, int, int, int, atapi_callback_t, void *);
-int atapi_test_ready(struct ata_device *);
-int atapi_wait_dsc(struct ata_device *, int);
-void atapi_request_sense(struct ata_device *, struct atapi_reqsense *);
-void atapi_dump(char *, void *, int);
-int acdattach(struct ata_device *);
-void acddetach(struct ata_device *);
-void acd_start(struct ata_device *);
-int afdattach(struct ata_device *);
-void afddetach(struct ata_device *);
-void afd_start(struct ata_device *);
-int astattach(struct ata_device *);
-void astdetach(struct ata_device *);
-void ast_start(struct ata_device *);
diff --git a/sys/dev/ata/atapi-cam.c b/sys/dev/ata/atapi-cam.c
index b694ac6..0aea83f 100644
--- a/sys/dev/ata/atapi-cam.c
+++ b/sys/dev/ata/atapi-cam.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2001,2002 Thomas Quinot <thomas@cuivre.fr.eu.org>
+ * Copyright (c) 2001-2003 Thomas Quinot <thomas@cuivre.fr.eu.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -34,6 +34,9 @@
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/ata.h>
+#include <sys/taskqueue.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <machine/bus.h>
#include <cam/cam.h>
@@ -45,7 +48,6 @@
#include <cam/scsi/scsi_all.h>
#include <dev/ata/ata-all.h>
-#include <dev/ata/atapi-all.h>
/* hardware command descriptor block */
struct atapi_hcb {
@@ -55,7 +57,6 @@ struct atapi_hcb {
int target;
int lun;
union ccb *ccb;
- u_int8_t cmd[CAM_MAX_CDBLEN];
int flags;
#define DOING_AUTOSENSE 1
@@ -78,6 +79,7 @@ struct atapi_xpt_softc {
enum reinit_reason { BOOT_ATTACH, ATTACH, RESET };
+static struct mtx atapicam_softc_mtx;
static LIST_HEAD(,atapi_xpt_softc) all_buses = LIST_HEAD_INITIALIZER(all_buses);
/* CAM XPT methods */
@@ -85,7 +87,7 @@ static void atapi_action(struct cam_sim *, union ccb *);
static void atapi_poll(struct cam_sim *);
static void atapi_async(void *, u_int32_t, struct cam_path *, void *);
static void atapi_async1(void *, u_int32_t, struct cam_path *, void *);
-static int atapi_cb(struct atapi_request *);
+static void atapi_cb(struct ata_request *);
/* internal functions */
static void reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason);
@@ -102,7 +104,7 @@ static struct ata_device *get_ata_device(struct atapi_xpt_softc *scp, int id);
static MALLOC_DEFINE(M_ATACAM, "ATA CAM transport", "ATA driver CAM-XPT layer");
-void
+void
atapi_cam_attach_bus(struct ata_channel *ata_ch)
{
struct atapi_xpt_softc *scp = NULL;
@@ -111,10 +113,21 @@ atapi_cam_attach_bus(struct ata_channel *ata_ch)
struct cam_path *path = NULL;
int unit;
+ GIANT_REQUIRED;
+
+ if (mtx_initialized(&atapicam_softc_mtx) == 0)
+ mtx_init(&atapicam_softc_mtx, "ATAPI/CAM softc mutex", NULL, MTX_DEF);
+
+ mtx_lock(&atapicam_softc_mtx);
+
LIST_FOREACH(scp, &all_buses, chain) {
if (scp->ata_ch == ata_ch)
- return;
+ break;
}
+ mtx_unlock(&atapicam_softc_mtx);
+
+ if (scp != NULL)
+ return;
if ((scp = malloc(sizeof(struct atapi_xpt_softc),
M_ATACAM, M_NOWAIT | M_ZERO)) == NULL)
@@ -157,11 +170,14 @@ error:
free_softc(scp);
}
-void
+void
atapi_cam_detach_bus(struct ata_channel *ata_ch)
{
struct atapi_xpt_softc *scp = get_softc(ata_ch);
+
+ mtx_lock(&Giant);
free_softc(scp);
+ mtx_unlock(&Giant);
}
void
@@ -173,12 +189,18 @@ atapi_cam_reinit_bus(struct ata_channel *ata_ch) {
* the boot-up sequence, before the ATAPI bus is registered.
*/
- if (scp != NULL)
+ if (scp != NULL) {
+ mtx_lock(&Giant);
reinit_bus(scp, RESET);
+ mtx_unlock(&Giant);
+ }
}
static void
reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason) {
+
+ GIANT_REQUIRED;
+
if (scp->ata_ch->devices & ATA_ATAPI_MASTER)
setup_dev(scp, &scp->ata_ch->device[MASTER]);
if (scp->ata_ch->devices & ATA_ATAPI_SLAVE)
@@ -199,11 +221,11 @@ reinit_bus(struct atapi_xpt_softc *scp, enum reinit_reason reason) {
static void
setup_dev(struct atapi_xpt_softc *scp, struct ata_device *atp)
{
- if (atp->driver == NULL) {
+ if (atp->softc == NULL) {
ata_set_name(atp, "atapicam",
2 * device_get_unit(atp->channel->dev) +
(atp->unit == ATA_MASTER) ? 0 : 1);
- atp->driver = (void *)scp;
+ atp->softc = (void *)scp;
}
}
@@ -212,6 +234,8 @@ setup_async_cb(struct atapi_xpt_softc *scp, uint32_t events)
{
struct ccb_setasync csa;
+ GIANT_REQUIRED;
+
xpt_setup_ccb(&csa.ccb_h, scp->path, /*priority*/ 5);
csa.ccb_h.func_code = XPT_SASYNC_CB;
csa.event_enable = events;
@@ -220,15 +244,16 @@ setup_async_cb(struct atapi_xpt_softc *scp, uint32_t events)
xpt_action((union ccb *) &csa);
}
-static void
+static void
atapi_action(struct cam_sim *sim, union ccb *ccb)
{
struct atapi_xpt_softc *softc = (struct atapi_xpt_softc*)cam_sim_softc(sim);
struct ccb_hdr *ccb_h = &ccb->ccb_h;
struct atapi_hcb *hcb = NULL;
+ struct ata_request *request = NULL;
int unit = cam_sim_unit(sim);
int bus = cam_sim_bus(sim);
- int len, s;
+ int len;
char *buf;
switch (ccb_h->func_code) {
@@ -292,7 +317,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
struct ata_device *dev = get_ata_device(softc, tid);
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_SUBTRACE, ("dev reset\n"));
- atapi_reinit(dev);
+ ata_controlcmd(dev, ATA_ATAPI_RESET, 0, 0, 0);
ccb->ccb_h.status = CAM_REQ_CMP;
xpt_done(ccb);
return;
@@ -352,37 +377,45 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
if (dev == NULL) {
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
("SCSI IO received for invalid device\n"));
- ccb_h->status = CAM_TID_INVALID;
- xpt_done(ccb);
- return;
+ goto action_invalid;
}
if (lid > 0) {
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
("SCSI IO received for invalid lun %d\n", lid));
- ccb_h->status = CAM_LUN_INVALID;
- xpt_done(ccb);
- return;
+ goto action_invalid;
+ }
+ if (csio->cdb_len > sizeof request->u.atapi.ccb) {
+ CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
+ ("CAM CCB too long for ATAPI"));
+ goto action_invalid;
}
if ((ccb_h->flags & CAM_SCATTER_VALID)) {
/* scatter-gather not supported */
xpt_print_path(ccb_h->path);
- printf("ATAPI-CAM does not support scatter-gather yet!\n");
+ printf("ATAPI/CAM does not support scatter-gather yet!\n");
break;
}
- if ((hcb = allocate_hcb(softc, unit, bus, ccb)) == NULL)
+
+ if ((hcb = allocate_hcb(softc, unit, bus, ccb)) == NULL) {
+ printf("cannot allocate ATAPI/CAM hcb\n");
goto action_oom;
+ }
+ if ((request = ata_alloc_request()) == NULL) {
+ printf("cannot allocate ATAPI/CAM request\n");
+ goto action_oom;
+ }
ccb_h->status |= CAM_SIM_QUEUED;
bcopy((ccb_h->flags & CAM_CDB_POINTER) ?
csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes,
- hcb->cmd, csio->cdb_len);
+ request->u.atapi.ccb, csio->cdb_len);
#ifdef CAMDEBUG
if (CAM_DEBUGGED(ccb_h->path, CAM_DEBUG_CDB)) {
char cdb_str[(SCSI_MAX_CDBLEN * 3) + 1];
printf("atapi_action: hcb@%p: %s\n", hcb,
- scsi_cdb_string(hcb->cmd, cdb_str, sizeof(cdb_str)));
+ scsi_cdb_string(request->u.atapi.ccb, cdb_str, sizeof(cdb_str)));
}
#endif
@@ -390,7 +423,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
buf = csio->data_ptr;
/* some SCSI commands require special processing */
- switch (hcb->cmd[0]) {
+ switch (request->u.atapi.ccb[0]) {
case INQUIRY: {
/*
* many ATAPI devices seem to report more than
@@ -399,7 +432,7 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
* when actually asked for it, so we are going to pretend
* that only SHORT_INQUIRY_LENGTH are expected, anyway.
*/
- struct scsi_inquiry *inq = (struct scsi_inquiry *) &hcb->cmd[0];
+ struct scsi_inquiry *inq = (struct scsi_inquiry *) &request->u.atapi.ccb[0];
if (inq->byte2 == 0 && inq->page_code == 0 &&
inq->length > SHORT_INQUIRY_LENGTH) {
@@ -412,19 +445,19 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
/* FALLTHROUGH */
case WRITE_6:
- CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
+ CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
("Translating %s into _10 equivalent\n",
- (hcb->cmd[0] == READ_6) ? "READ_6" : "WRITE_6"));
- hcb->cmd[0] |= 0x20;
- hcb->cmd[9] = hcb->cmd[5];
- hcb->cmd[8] = hcb->cmd[4];
- hcb->cmd[7] = 0;
- hcb->cmd[6] = 0;
- hcb->cmd[5] = hcb->cmd[3];
- hcb->cmd[4] = hcb->cmd[2];
- hcb->cmd[3] = hcb->cmd[1] & 0x1f;
- hcb->cmd[2] = 0;
- hcb->cmd[1] = 0;
+ (request->u.atapi.ccb[0] == READ_6) ? "READ_6" : "WRITE_6"));
+ request->u.atapi.ccb[0] |= 0x20;
+ request->u.atapi.ccb[9] = request->u.atapi.ccb[5];
+ request->u.atapi.ccb[8] = request->u.atapi.ccb[4];
+ request->u.atapi.ccb[7] = 0;
+ request->u.atapi.ccb[6] = 0;
+ request->u.atapi.ccb[5] = request->u.atapi.ccb[3];
+ request->u.atapi.ccb[4] = request->u.atapi.ccb[2];
+ request->u.atapi.ccb[3] = request->u.atapi.ccb[1] & 0x1f;
+ request->u.atapi.ccb[2] = 0;
+ request->u.atapi.ccb[1] = 0;
break;
}
@@ -432,28 +465,48 @@ atapi_action(struct cam_sim *sim, union ccb *ccb)
/* ATA always transfers an even number of bytes */
if (!(buf = hcb->dxfer_alloc = malloc(++len, M_ATACAM,
M_NOWAIT | M_ZERO)))
+ printf("cannot allocate ATAPI/CAM buffer\n");
goto action_oom;
}
- s = splbio();
+ request->device = dev;
+ request->driver = hcb;
+ request->data = buf;
+ request->bytecount = len;
+ request->transfersize = min(request->bytecount, 65534);
+ request->timeout = ccb_h->timeout;
+ request->retries = 2;
+ request->callback = &atapi_cb;
+ request->flags = (ATA_R_QUIET | ATA_R_ATAPI);
+ switch (ccb_h->flags & CAM_DIR_MASK) {
+ case CAM_DIR_IN:
+ request->flags |= ATA_R_READ;
+ break;
+ case CAM_DIR_OUT:
+ request->flags |= ATA_R_WRITE;
+ break;
+ case CAM_DIR_NONE:
+ request->flags |= ATA_R_CONTROL;
+ break;
+ default:
+ ata_prtdev(dev, "unknown IO operation\n");
+ goto action_invalid;
+ }
+
TAILQ_INSERT_TAIL(&softc->pending_hcbs, hcb, chain);
- splx(s);
- if (atapi_queue_cmd(dev, hcb->cmd, buf, len,
- (((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) ?
- ATPR_F_READ : 0) | ATPR_F_QUIET,
- ccb_h->timeout, atapi_cb, (void *)hcb) == 0)
- return;
- break;
+
+ ata_queue_request(request);
+ return;
}
default:
CAM_DEBUG(ccb_h->path, CAM_DEBUG_SUBTRACE,
("unsupported function code 0x%02x\n", ccb_h->func_code));
- ccb_h->status = CAM_REQ_INVALID;
- xpt_done(ccb);
- return;
+ goto action_invalid;
}
action_oom:
+ if (request != NULL)
+ ata_free_request(request);
if (hcb != NULL)
free_hcb(hcb);
xpt_print_path(ccb_h->path);
@@ -462,22 +515,29 @@ action_oom:
xpt_freeze_simq(sim, /*count*/ 1);
ccb_h->status = CAM_REQUEUE_REQ;
xpt_done(ccb);
+ return;
+
+action_invalid:
+ ccb_h->status = CAM_REQ_INVALID;
+ xpt_done(ccb);
+ return;
}
-static void
+static void
atapi_poll(struct cam_sim *sim)
{
/* do nothing - we do not actually service any interrupts */
printf("atapi_poll called!\n");
}
-static int
-atapi_cb(struct atapi_request *req)
+static void
+atapi_cb(struct ata_request *request)
{
- struct atapi_hcb *hcb = (struct atapi_hcb *) req->driver;
+ struct atapi_hcb *hcb = (struct atapi_hcb *) request->driver;
struct ccb_scsiio *csio = &hcb->ccb->csio;
- int hcb_status = req->result;
- int s = splbio();
+ int hcb_status = request->result;
+
+ mtx_lock(&Giant);
#ifdef CAMDEBUG
if (CAM_DEBUGGED(csio->ccb_h.path, CAM_DEBUG_CDB)) {
@@ -486,29 +546,35 @@ atapi_cb(struct atapi_request *req)
(hcb_status & 4) ? " ABRT" : "",
(hcb_status & 2) ? " EOM" : "",
(hcb_status & 1) ? " ILI" : "");
- printf(" %s: cmd %02x - sk=%02x asc=%02x ascq=%02x\n",
- req->device->name, req->ccb[0], req->sense.sense_key,
- req->sense.asc, req->sense.ascq);
+ printf(" %s: cmd %02x\n",
+ request->device->name, request->u.atapi.ccb[0]);
}
#endif
if (hcb_status != 0) {
csio->scsi_status = SCSI_STATUS_CHECK_COND;
if ((csio->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0) {
- csio->ccb_h.status |= CAM_AUTOSNS_VALID;
- bcopy((void *)&req->sense, (void *)&csio->sense_data,
- sizeof(struct atapi_reqsense));
+ int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0,
+ sizeof(struct atapi_sense), 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0 };
+
+ if (ata_atapicmd(request->device, ccb, (caddr_t)&csio->sense_data,
+ sizeof(struct atapi_sense), ATA_R_READ, 30) == 0)
+ {
+ csio->ccb_h.status |= CAM_AUTOSNS_VALID;
+ }
}
free_hcb_and_ccb_done(hcb, CAM_SCSI_STATUS_ERROR);
- }
+ }
else {
if (((csio->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) &&
hcb->dxfer_alloc != NULL)
+ {
bcopy(hcb->dxfer_alloc, csio->data_ptr, csio->dxfer_len);
+ }
csio->scsi_status = SCSI_STATUS_OK;
free_hcb_and_ccb_done(hcb, CAM_REQ_CMP);
}
- splx(s);
- return 0;
+ mtx_unlock(&Giant);
}
static void
@@ -517,6 +583,8 @@ free_hcb_and_ccb_done(struct atapi_hcb *hcb, u_int32_t status)
struct atapi_xpt_softc *softc = hcb->softc;
union ccb *ccb = hcb->ccb;
+ GIANT_REQUIRED;
+
if (hcb != NULL) {
/* we're about to free a hcb, so the shortage has ended */
if (softc->flags & RESOURCE_SHORTAGE) {
@@ -525,22 +593,21 @@ free_hcb_and_ccb_done(struct atapi_hcb *hcb, u_int32_t status)
}
free_hcb(hcb);
}
- ccb->ccb_h.status =
+ ccb->ccb_h.status =
status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED));
xpt_done(ccb);
}
-static void
+static void
atapi_async(void *callback_arg, u_int32_t code,
struct cam_path *path, void *arg)
{
- int s = splbio();
-
+ mtx_lock(&Giant);
atapi_async1(callback_arg, code, path, arg);
- splx(s);
+ mtx_unlock(&Giant);
}
-static void
+static void
atapi_async1(void *callback_arg, u_int32_t code,
struct cam_path* path, void *arg)
{
@@ -548,6 +615,8 @@ atapi_async1(void *callback_arg, u_int32_t code,
struct cam_sim *sim;
int targ;
+ GIANT_REQUIRED;
+
sim = (struct cam_sim *) callback_arg;
softc = (struct atapi_xpt_softc *) cam_sim_softc(sim);
switch (code) {
@@ -570,10 +639,10 @@ cam_rescan_callback(struct cam_periph *periph, union ccb *ccb)
{
if (ccb->ccb_h.status != CAM_REQ_CMP) {
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
- ("Rescan failed, 0x%04x\n", ccb->ccb_h.status));
+ ("Rescan failed, 0x%04x\n", ccb->ccb_h.status));
} else {
CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
- ("Rescan succeeded\n"));
+ ("Rescan succeeded\n"));
}
xpt_free_path(ccb->ccb_h.path);
free(ccb, M_ATACAM);
@@ -584,7 +653,7 @@ cam_rescan(struct cam_sim *sim)
{
struct cam_path *path;
union ccb *ccb = malloc(sizeof(union ccb), M_ATACAM, M_WAITOK | M_ZERO);
-
+
if (xpt_create_path(&path, xpt_periph, cam_sim_path(sim),
CAM_TARGET_WILDCARD, CAM_LUN_WILDCARD) != CAM_REQ_CMP)
return;
@@ -613,7 +682,7 @@ allocate_hcb(struct atapi_xpt_softc *softc, int unit, int bus, union ccb *ccb)
return hcb;
}
-static void
+static void
free_hcb(struct atapi_hcb *hcb)
{
TAILQ_REMOVE(&hcb->softc->pending_hcbs, hcb, chain);
@@ -627,6 +696,8 @@ free_softc(struct atapi_xpt_softc *scp)
{
struct atapi_hcb *hcb;
+ GIANT_REQUIRED;
+
if (scp != NULL) {
TAILQ_FOREACH(hcb, &scp->pending_hcbs, chain) {
free_hcb_and_ccb_done(hcb, CAM_UNREC_HBA_ERROR);
@@ -653,12 +724,15 @@ free_softc(struct atapi_xpt_softc *scp)
static struct atapi_xpt_softc *
get_softc(struct ata_channel *ata_ch) {
- struct atapi_xpt_softc *scp;
+ struct atapi_xpt_softc *scp = NULL;
+
+ mtx_lock(&atapicam_softc_mtx);
LIST_FOREACH(scp, &all_buses, chain) {
- if (scp->ata_ch == ata_ch)
- return scp;
+ if (scp->ata_ch == ata_ch)
+ break;
}
- return NULL;
+ mtx_unlock(&atapicam_softc_mtx);
+ return scp;
}
static struct ata_device *
diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c
index 751a2c4..9b7e865 100644
--- a/sys/dev/ata/atapi-cd.c
+++ b/sys/dev/ata/atapi-cd.c
@@ -44,36 +44,40 @@
#include <sys/fcntl.h>
#include <sys/conf.h>
#include <sys/ctype.h>
+#include <sys/taskqueue.h>
+#include <sys/mutex.h>
#include <machine/bus.h>
#include <dev/ata/ata-all.h>
-#include <dev/ata/atapi-all.h>
#include <dev/ata/atapi-cd.h>
/* device structures */
-static d_open_t acdopen;
-static d_close_t acdclose;
-static d_ioctl_t acdioctl;
-static d_strategy_t acdstrategy;
+static d_open_t acd_open;
+static d_close_t acd_close;
+static d_ioctl_t acd_ioctl;
+static d_strategy_t acd_strategy;
static struct cdevsw acd_cdevsw = {
- .d_open = acdopen,
- .d_close = acdclose,
+ .d_open = acd_open,
+ .d_close = acd_close,
.d_read = physread,
.d_write = physwrite,
- .d_ioctl = acdioctl,
- .d_strategy = acdstrategy,
+ .d_ioctl = acd_ioctl,
+ .d_strategy = acd_strategy,
.d_name = "acd",
.d_maj = 117,
- .d_flags = D_DISK | D_TRACKCLOSE,
+ .d_flags = D_DISK | D_TRACKCLOSE | D_NOGIANT,
};
/* prototypes */
+static void acd_detach(struct ata_device *atadev);
+static void acd_start(struct ata_device *atadev);
+
static struct acd_softc *acd_init_lun(struct ata_device *);
static void acd_make_dev(struct acd_softc *);
static void acd_set_ioparm(struct acd_softc *);
static void acd_describe(struct acd_softc *);
static void lba2msf(u_int32_t, u_int8_t *, u_int8_t *, u_int8_t *);
static u_int32_t msf2lba(u_int8_t, u_int8_t, u_int8_t);
-static int acd_done(struct atapi_request *);
+static void acd_done(struct ata_request *);
static void acd_read_toc(struct acd_softc *);
static int acd_play(struct acd_softc *, int, int);
static int acd_setchan(struct acd_softc *, u_int8_t, u_int8_t, u_int8_t, u_int8_t);
@@ -99,27 +103,29 @@ static int acd_set_speed(struct acd_softc *, int, int);
static void acd_get_cap(struct acd_softc *);
static int acd_read_format_caps(struct acd_softc *, struct cdr_format_capacities *);
static int acd_format(struct acd_softc *, struct cdr_format_params *);
+static int acd_test_ready(struct ata_device *atadev);
+static int acd_request_sense(struct ata_device *atadev, struct atapi_sense *sense);
/* internal vars */
static u_int32_t acd_lun_map = 0;
static MALLOC_DEFINE(M_ACD, "ACD driver", "ATAPI CD driver buffers");
-int
-acdattach(struct ata_device *atadev)
+void
+acd_attach(struct ata_device *atadev)
{
struct acd_softc *cdp;
struct changer *chp;
if ((cdp = acd_init_lun(atadev)) == NULL) {
- ata_prtdev(atadev, "acd: out of memory\n");
- return 0;
+ ata_prtdev(atadev, "out of memory\n");
+ return;
}
ata_set_name(atadev, "acd", cdp->lun);
acd_get_cap(cdp);
/* if this is a changer device, allocate the neeeded lun's */
- if (cdp->cap.mech == MST_MECH_CHANGER) {
+ if ((cdp->cap.mechanism & MST_MECH_MASK) == MST_MECH_CHANGER) {
int8_t ccb[16] = { ATAPI_MECH_STATUS, 0, 0, 0, 0, 0, 0, 0,
sizeof(struct changer)>>8, sizeof(struct changer),
0, 0, 0, 0, 0, 0 };
@@ -128,11 +134,10 @@ acdattach(struct ata_device *atadev)
if (chp == NULL) {
ata_prtdev(atadev, "out of memory\n");
free(cdp, M_ACD);
- return 0;
+ return;
}
- if (!atapi_queue_cmd(cdp->device, ccb, (caddr_t)chp,
- sizeof(struct changer),
- ATPR_F_READ, 60, NULL, NULL)) {
+ if (!ata_atapicmd(cdp->device, ccb, (caddr_t)chp,
+ sizeof(struct changer), ATA_R_READ, 60)) {
struct acd_softc *tmpcdp = cdp;
struct acd_softc **cdparr;
char *name;
@@ -144,7 +149,7 @@ acdattach(struct ata_device *atadev)
ata_prtdev(atadev, "out of memory\n");
free(chp, M_ACD);
free(cdp, M_ACD);
- return 0;
+ return;
}
for (count = 0; count < chp->slots; count++) {
if (count > 0) {
@@ -167,7 +172,7 @@ acdattach(struct ata_device *atadev)
if (!(name = malloc(strlen(atadev->name) + 2, M_ACD, M_NOWAIT))) {
ata_prtdev(atadev, "out of memory\n");
free(cdp, M_ACD);
- return 0;
+ return;
}
strcpy(name, atadev->name);
strcat(name, "-");
@@ -183,15 +188,27 @@ acdattach(struct ata_device *atadev)
DEVSTAT_TYPE_CDROM | DEVSTAT_TYPE_IF_IDE,
DEVSTAT_PRIORITY_CD);
}
+
+ /* use DMA if allowed and if drive/controller supports it */
+ if (atapi_dma && atadev->channel->dma &&
+ (atadev->param->config & ATA_DRQ_MASK) != ATA_DRQ_INTR)
+ atadev->setmode(atadev, ATA_DMA_MAX);
+ else
+ atadev->setmode(atadev, ATA_PIO_MAX);
+
+ /* setup the function ptrs */
+ atadev->detach = acd_detach;
+ atadev->start = acd_start;
+ atadev->softc = cdp;
+
+ /* announce we are here */
acd_describe(cdp);
- atadev->driver = cdp;
- return 1;
}
-void
-acddetach(struct ata_device *atadev)
+static void
+acd_detach(struct ata_device *atadev)
{
- struct acd_softc *cdp = atadev->driver;
+ struct acd_softc *cdp = atadev->softc;
struct acd_devlist *entry;
int subdev;
@@ -199,7 +216,9 @@ acddetach(struct ata_device *atadev)
for (subdev = 0; subdev < cdp->changer_info->slots; subdev++) {
if (cdp->driver[subdev] == cdp)
continue;
+ mtx_lock(&cdp->driver[subdev]->queue_mtx);
bioq_flush(&cdp->driver[subdev]->queue, NULL, ENXIO);
+ mtx_unlock(&cdp->driver[subdev]->queue_mtx);
destroy_dev(cdp->driver[subdev]->dev);
while ((entry = TAILQ_FIRST(&cdp->driver[subdev]->dev_list))) {
destroy_dev(entry->dev);
@@ -213,7 +232,9 @@ acddetach(struct ata_device *atadev)
free(cdp->driver, M_ACD);
free(cdp->changer_info, M_ACD);
}
+ mtx_lock(&cdp->queue_mtx);
bioq_flush(&cdp->queue, NULL, ENXIO);
+ mtx_unlock(&cdp->queue_mtx);
while ((entry = TAILQ_FIRST(&cdp->dev_list))) {
destroy_dev(entry->dev);
TAILQ_REMOVE(&cdp->dev_list, entry, chain);
@@ -222,10 +243,15 @@ acddetach(struct ata_device *atadev)
destroy_dev(cdp->dev);
EVENTHANDLER_DEREGISTER(dev_clone, cdp->clone_evh);
devstat_remove_entry(cdp->stats);
+ ata_prtdev(atadev, "WARNING - removed from configuration\n");
ata_free_name(atadev);
ata_free_lun(&acd_lun_map, cdp->lun);
+ atadev->attach = NULL;
+ atadev->detach = NULL;
+ atadev->start = NULL;
+ atadev->softc = NULL;
+ atadev->flags = 0;
free(cdp, M_ACD);
- atadev->driver = NULL;
}
static struct acd_softc *
@@ -237,6 +263,7 @@ acd_init_lun(struct ata_device *atadev)
return NULL;
TAILQ_INIT(&cdp->dev_list);
bioq_init(&cdp->queue);
+ mtx_init(&cdp->queue_mtx, "ATAPI CD bioqueue lock", MTX_DEF, 0);
cdp->device = atadev;
cdp->lun = ata_get_lun(&acd_lun_map);
cdp->block_size = 2048;
@@ -279,7 +306,12 @@ acd_make_dev(struct acd_softc *cdp)
static void
acd_set_ioparm(struct acd_softc *cdp)
{
- cdp->dev->si_iosize_max = ((256*DEV_BSIZE)/cdp->block_size)*cdp->block_size;
+ if (cdp->device->channel->dma)
+ cdp->dev->si_iosize_max = (min(cdp->device->channel->dma->max_iosize,
+ 65534)/cdp->block_size)*cdp->block_size;
+ else
+ cdp->dev->si_iosize_max = (min(DFLTPHYS,
+ 65534)/cdp->block_size)*cdp->block_size;
cdp->dev->si_bsize_phys = cdp->block_size;
}
@@ -292,11 +324,11 @@ acd_describe(struct acd_softc *cdp)
if (bootverbose) {
ata_prtdev(cdp->device, "<%.40s/%.8s> %s drive at ata%d as %s\n",
cdp->device->param->model, cdp->device->param->revision,
- (cdp->cap.write_dvdr) ? "DVD-R" :
- (cdp->cap.write_dvdram) ? "DVD-RAM" :
- (cdp->cap.write_cdrw) ? "CD-RW" :
- (cdp->cap.write_cdr) ? "CD-R" :
- (cdp->cap.read_dvdrom) ? "DVD-ROM" : "CDROM",
+ (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" :
+ (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" :
+ (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" :
+ (cdp->cap.media & MST_WRITE_CDR) ? "CDR" :
+ (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM" : "CDROM",
device_get_unit(cdp->device->channel->dev),
(cdp->device->unit == ATA_MASTER) ? "master" : "slave");
@@ -306,8 +338,8 @@ acd_describe(struct acd_softc *cdp)
if (cdp->cap.max_read_speed)
printf(" (%dKB/s)", cdp->cap.max_read_speed * 1000 / 1024);
if ((cdp->cap.cur_write_speed) &&
- (cdp->cap.write_cdr || cdp->cap.write_cdrw ||
- cdp->cap.write_dvdr || cdp->cap.write_dvdram)) {
+ (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW |
+ MST_WRITE_DVDR | MST_WRITE_DVDRAM))) {
printf(" write %dKB/s", cdp->cap.cur_write_speed * 1000 / 1024);
if (cdp->cap.max_write_speed)
printf(" (%dKB/s)", cdp->cap.max_write_speed * 1000 / 1024);
@@ -322,65 +354,65 @@ acd_describe(struct acd_softc *cdp)
ata_prtdev(cdp->device, "Reads:");
comma = 0;
- if (cdp->cap.read_cdr) {
- printf(" CD-R"); comma = 1;
+ if (cdp->cap.media & MST_READ_CDR) {
+ printf(" CDR"); comma = 1;
}
- if (cdp->cap.read_cdrw) {
- printf("%s CD-RW", comma ? "," : ""); comma = 1;
+ if (cdp->cap.media & MST_READ_CDRW) {
+ printf("%s CDRW", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.cd_da) {
- if (cdp->cap.cd_da_stream)
- printf("%s CD-DA stream", comma ? "," : "");
+ if (cdp->cap.capabilities & MST_READ_CDDA) {
+ if (cdp->cap.capabilities & MST_CDDA_STREAM)
+ printf("%s CDDA stream", comma ? "," : "");
else
- printf("%s CD-DA", comma ? "," : "");
+ printf("%s CDDA", comma ? "," : "");
comma = 1;
}
- if (cdp->cap.read_dvdrom) {
- printf("%s DVD-ROM", comma ? "," : ""); comma = 1;
+ if (cdp->cap.media & MST_READ_DVDROM) {
+ printf("%s DVDROM", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.read_dvdr) {
- printf("%s DVD-R", comma ? "," : ""); comma = 1;
+ if (cdp->cap.media & MST_READ_DVDR) {
+ printf("%s DVDR", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.read_dvdram) {
- printf("%s DVD-RAM", comma ? "," : ""); comma = 1;
+ if (cdp->cap.media & MST_READ_DVDRAM) {
+ printf("%s DVDRAM", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.read_packet)
+ if (cdp->cap.media & MST_READ_PACKET)
printf("%s packet", comma ? "," : "");
printf("\n");
ata_prtdev(cdp->device, "Writes:");
- if (cdp->cap.write_cdr || cdp->cap.write_cdrw ||
- cdp->cap.write_dvdr || cdp->cap.write_dvdram) {
+ if (cdp->cap.media & (MST_WRITE_CDR | MST_WRITE_CDRW |
+ MST_WRITE_DVDR | MST_WRITE_DVDRAM)) {
comma = 0;
- if (cdp->cap.write_cdr) {
- printf(" CD-R" ); comma = 1;
+ if (cdp->cap.media & MST_WRITE_CDR) {
+ printf(" CDR" ); comma = 1;
}
- if (cdp->cap.write_cdrw) {
- printf("%s CD-RW", comma ? "," : ""); comma = 1;
+ if (cdp->cap.media & MST_WRITE_CDRW) {
+ printf("%s CDRW", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.write_dvdr) {
- printf("%s DVD-R", comma ? "," : ""); comma = 1;
+ if (cdp->cap.media & MST_WRITE_DVDR) {
+ printf("%s DVDR", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.write_dvdram) {
- printf("%s DVD-RAM", comma ? "," : ""); comma = 1;
+ if (cdp->cap.media & MST_WRITE_DVDRAM) {
+ printf("%s DVDRAM", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.test_write) {
+ if (cdp->cap.media & MST_WRITE_TEST) {
printf("%s test write", comma ? "," : ""); comma = 1;
}
- if (cdp->cap.burnproof)
+ if (cdp->cap.capabilities & MST_BURNPROOF)
printf("%s burnproof", comma ? "," : "");
}
printf("\n");
- if (cdp->cap.audio_play) {
+ if (cdp->cap.capabilities & MST_AUDIO_PLAY) {
ata_prtdev(cdp->device, "Audio: ");
- if (cdp->cap.audio_play)
+ if (cdp->cap.capabilities & MST_AUDIO_PLAY)
printf("play");
if (cdp->cap.max_vol_levels)
printf(", %d volume levels", cdp->cap.max_vol_levels);
printf("\n");
}
ata_prtdev(cdp->device, "Mechanism: ");
- switch (cdp->cap.mech) {
+ switch (cdp->cap.mechanism & MST_MECH_MASK) {
case MST_MECH_CADDY:
mechanism = "caddy"; break;
case MST_MECH_TRAY:
@@ -395,17 +427,18 @@ acd_describe(struct acd_softc *cdp)
mechanism = 0; break;
}
if (mechanism)
- printf("%s%s", cdp->cap.eject ? "ejectable " : "", mechanism);
- else if (cdp->cap.eject)
+ printf("%s%s", (cdp->cap.mechanism & MST_EJECT) ?
+ "ejectable " : "", mechanism);
+ else if (cdp->cap.mechanism & MST_EJECT)
printf("ejectable");
- if (cdp->cap.lock)
- printf(cdp->cap.locked ? ", locked" : ", unlocked");
- if (cdp->cap.prevent)
+ if (cdp->cap.mechanism & MST_LOCKABLE)
+ printf((cdp->cap.mechanism & MST_LOCKED) ? ", locked":", unlocked");
+ if (cdp->cap.mechanism & MST_PREVENT)
printf(", lock protected");
printf("\n");
- if (cdp->cap.mech != MST_MECH_CHANGER) {
+ if ((cdp->cap.mechanism & MST_MECH_MASK) != MST_MECH_CHANGER) {
ata_prtdev(cdp->device, "Medium: ");
switch (cdp->cap.medium_type & MST_TYPE_MASK_HIGH) {
case MST_CDROM:
@@ -457,15 +490,13 @@ acd_describe(struct acd_softc *cdp)
}
else {
ata_prtdev(cdp->device, "%s ",
- (cdp->cap.write_dvdr) ? "DVD-R" :
- (cdp->cap.write_dvdram) ? "DVD-RAM" :
- (cdp->cap.write_cdrw) ? "CD-RW" :
- (cdp->cap.write_cdr) ? "CD-R" :
- (cdp->cap.read_dvdrom) ? "DVD-ROM" : "CDROM");
-
+ (cdp->cap.media & MST_WRITE_DVDR) ? "DVDR" :
+ (cdp->cap.media & MST_WRITE_DVDRAM) ? "DVDRAM" :
+ (cdp->cap.media & MST_WRITE_CDRW) ? "CDRW" :
+ (cdp->cap.media & MST_WRITE_CDR) ? "CDR" :
+ (cdp->cap.media & MST_READ_DVDROM) ? "DVDROM" : "CDROM");
if (cdp->changer_info)
printf("with %d CD changer ", cdp->changer_info->slots);
-
printf("<%.40s> at ata%d-%s %s\n", cdp->device->param->model,
device_get_unit(cdp->device->channel->dev),
(cdp->device->unit == ATA_MASTER) ? "master" : "slave",
@@ -491,26 +522,26 @@ msf2lba(u_int8_t m, u_int8_t s, u_int8_t f)
}
static int
-acdopen(dev_t dev, int flags, int fmt, struct thread *td)
+acd_open(dev_t dev, int flags, int fmt, struct thread *td)
{
struct acd_softc *cdp = dev->si_drv1;
int timeout = 60;
- if (!cdp)
+ if (!cdp || cdp->device->flags & ATA_D_DETACHING)
return ENXIO;
/* wait if drive is not finished loading the medium */
while (timeout--) {
- struct atapi_reqsense *sense = cdp->device->result;
+ struct atapi_sense sense;
- if (!atapi_test_ready(cdp->device))
+ if (!acd_test_ready(cdp->device))
break;
- if (sense->sense_key == 2 && sense->asc == 4 && sense->ascq == 1)
+ acd_request_sense(cdp->device, &sense);
+ if (sense.sense_key == 2 && sense.asc == 4 && sense.ascq == 1)
tsleep(&timeout, PRIBIO, "acdld", hz / 2);
else
break;
}
-
if (count_dev(dev) == 1) {
if (cdp->changer_info && cdp->slot != cdp->changer_info->current_slot) {
acd_select_slot(cdp);
@@ -524,7 +555,7 @@ acdopen(dev_t dev, int flags, int fmt, struct thread *td)
}
static int
-acdclose(dev_t dev, int flags, int fmt, struct thread *td)
+acd_close(dev_t dev, int flags, int fmt, struct thread *td)
{
struct acd_softc *cdp = dev->si_drv1;
@@ -543,7 +574,7 @@ acdclose(dev_t dev, int flags, int fmt, struct thread *td)
}
static int
-acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
+acd_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
{
struct acd_softc *cdp = dev->si_drv1;
int error = 0;
@@ -558,7 +589,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
if (cdp->device->flags & ATA_D_MEDIA_CHANGED)
switch (cmd) {
case CDIOCRESET:
- atapi_test_ready(cdp->device);
+ acd_test_ready(cdp->device);
break;
default:
@@ -599,7 +630,7 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
error = suser(td);
if (error)
break;
- error = atapi_test_ready(cdp->device);
+ error = acd_test_ready(cdp->device);
break;
case CDIOCEJECT:
@@ -749,9 +780,8 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
ccb[1] = args->address_format & CD_MSF_FORMAT;
- if ((error = atapi_queue_cmd(cdp->device,ccb,(caddr_t)&cdp->subchan,
- sizeof(cdp->subchan), ATPR_F_READ, 10,
- NULL, NULL)))
+ if ((error = ata_atapicmd(cdp->device,ccb,(caddr_t)&cdp->subchan,
+ sizeof(cdp->subchan), ATA_R_READ, 10)))
break;
if ((format == CD_MEDIA_CATALOG) || (format == CD_TRACK_INFO)) {
@@ -764,10 +794,9 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
if (format == CD_TRACK_INFO)
ccb[6] = args->track;
- if ((error = atapi_queue_cmd(cdp->device, ccb,
- (caddr_t)&cdp->subchan,
- sizeof(cdp->subchan), ATPR_F_READ,
- 10, NULL, NULL))) {
+ if ((error = ata_atapicmd(cdp->device, ccb,
+ (caddr_t)&cdp->subchan,
+ sizeof(cdp->subchan),ATA_R_READ,10))){
break;
}
}
@@ -819,79 +848,6 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
break;
}
- case CDIOCREADAUDIO:
- {
- struct ioc_read_audio *args = (struct ioc_read_audio *)addr;
- int32_t lba;
- caddr_t buffer, ubuf = args->buffer;
- int8_t ccb[16];
- int frames;
-
- if (!cdp->toc.hdr.ending_track) {
- error = EIO;
- break;
- }
-
- if ((frames = args->nframes) < 0) {
- error = EINVAL;
- break;
- }
-
- if (args->address_format == CD_LBA_FORMAT)
- lba = args->address.lba;
- else if (args->address_format == CD_MSF_FORMAT)
- lba = msf2lba(args->address.msf.minute,
- args->address.msf.second,
- args->address.msf.frame);
- else {
- error = EINVAL;
- break;
- }
-
-#ifndef CD_BUFFER_BLOCKS
-#define CD_BUFFER_BLOCKS 13
-#endif
- if (!(buffer = malloc(CD_BUFFER_BLOCKS * 2352, M_ACD, M_NOWAIT))){
- error = ENOMEM;
- break;
- }
- bzero(ccb, sizeof(ccb));
- while (frames > 0) {
- int8_t blocks;
- int size;
-
- blocks = (frames>CD_BUFFER_BLOCKS) ? CD_BUFFER_BLOCKS : frames;
- size = blocks * 2352;
-
- ccb[0] = ATAPI_READ_CD;
- ccb[1] = 4;
- ccb[2] = lba>>24;
- ccb[3] = lba>>16;
- ccb[4] = lba>>8;
- ccb[5] = lba;
- ccb[8] = blocks;
- ccb[9] = 0xf0;
- if ((error = atapi_queue_cmd(cdp->device, ccb, buffer, size,
- ATPR_F_READ, 30, NULL,NULL)))
- break;
-
- if ((error = copyout(buffer, ubuf, size)))
- break;
-
- ubuf += size;
- frames -= blocks;
- lba += blocks;
- }
- free(buffer, M_ACD);
- if (args->address_format == CD_LBA_FORMAT)
- args->address.lba = lba;
- else if (args->address_format == CD_MSF_FORMAT)
- lba2msf(lba, &args->address.msf.minute,
- &args->address.msf.second,
- &args->address.msf.frame);
- break;
- }
-
case CDIOCGETVOL:
{
struct ioc_vol *arg = (struct ioc_vol *)addr;
@@ -1047,24 +1003,24 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
break;
case DVDIOCREPORTKEY:
- if (!cdp->cap.read_dvdrom)
- error = EINVAL;
- else
+ if (cdp->cap.media & MST_READ_DVDROM)
error = acd_report_key(cdp, (struct dvd_authinfo *)addr);
+ else
+ error = EINVAL;
break;
case DVDIOCSENDKEY:
- if (!cdp->cap.read_dvdrom)
- error = EINVAL;
- else
+ if (cdp->cap.media & MST_READ_DVDROM)
error = acd_send_key(cdp, (struct dvd_authinfo *)addr);
+ else
+ error = EINVAL;
break;
case DVDIOCREADSTRUCTURE:
- if (!cdp->cap.read_dvdrom)
- error = EINVAL;
- else
+ if (cdp->cap.media & MST_READ_DVDROM)
error = acd_read_structure(cdp, (struct dvd_struct *)addr);
+ else
+ error = EINVAL;
break;
default:
@@ -1074,10 +1030,9 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
}
static void
-acdstrategy(struct bio *bp)
+acd_strategy(struct bio *bp)
{
struct acd_softc *cdp = bp->bio_dev->si_drv1;
- int s;
if (cdp->device->flags & ATA_D_DETACHING) {
biofinish(bp, NULL, ENXIO);
@@ -1094,17 +1049,18 @@ acdstrategy(struct bio *bp)
bp->bio_pblkno = bp->bio_blkno;
bp->bio_resid = bp->bio_bcount;
- s = splbio();
+ mtx_lock(&cdp->queue_mtx);
bioq_disksort(&cdp->queue, bp);
- splx(s);
+ mtx_unlock(&cdp->queue_mtx);
ata_start(cdp->device->channel);
}
-void
+static void
acd_start(struct ata_device *atadev)
{
- struct acd_softc *cdp = atadev->driver;
- struct bio *bp = bioq_first(&cdp->queue);
+ struct acd_softc *cdp = atadev->softc;
+ struct bio *bp;
+ struct ata_request *request;
u_int32_t lba, lastlba, count;
int8_t ccb[16];
int track, blocksize;
@@ -1113,23 +1069,34 @@ acd_start(struct ata_device *atadev)
int i;
cdp = cdp->driver[cdp->changer_info->current_slot];
+ mtx_lock(&cdp->queue_mtx);
bp = bioq_first(&cdp->queue);
+ mtx_unlock(&cdp->queue_mtx);
/* 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;
+ mtx_lock(&cdp->queue_mtx);
if (bioq_first(&(cdp->driver[i]->queue))) {
if (!bp || time_second > (cdp->timestamp + 10)) {
+ mtx_unlock(&cdp->queue_mtx);
acd_select_slot(cdp->driver[i]);
return;
}
}
+ mtx_unlock(&cdp->queue_mtx);
+
}
}
- if (!bp)
+ mtx_lock(&cdp->queue_mtx);
+ bp = bioq_first(&cdp->queue);
+ if (!bp) {
+ mtx_unlock(&cdp->queue_mtx);
return;
+ }
bioq_remove(&cdp->queue, bp);
+ mtx_unlock(&cdp->queue_mtx);
/* reject all queued entries if media changed */
if (cdp->device->flags & ATA_D_MEDIA_CHANGED) {
@@ -1197,27 +1164,54 @@ acd_start(struct ata_device *atadev)
ccb[7] = count>>8;
ccb[8] = count;
- devstat_start_transaction_bio(cdp->stats, bp);
bp->bio_caller1 = cdp;
- atapi_queue_cmd(cdp->device, ccb, bp->bio_data, count * blocksize,
- bp->bio_cmd == BIO_READ ? ATPR_F_READ : 0,
- (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30, acd_done, bp);
+ if (!(request = ata_alloc_request())) {
+ biofinish(bp, NULL, EIO);
+ return;
+ }
+ request->device = atadev;
+ request->driver = bp;
+ bcopy(ccb, request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 16 : 12);
+ request->data = bp->bio_data;
+ request->bytecount = count * blocksize;
+ request->transfersize = min(request->bytecount, 65534);
+ request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30;
+ request->retries = 2;
+ request->callback = acd_done;
+ request->flags = ATA_R_SKIPSTART | ATA_R_ATAPI;
+ if (request->device->mode >= ATA_DMA)
+ request->flags |= ATA_R_DMA;
+ switch (bp->bio_cmd) {
+ case BIO_READ:
+ request->flags |= ATA_R_READ;
+ break;
+ case BIO_WRITE:
+ request->flags |= ATA_R_WRITE;
+ break;
+ default:
+ ata_prtdev(atadev, "unknown BIO operation\n");
+ ata_free_request(request);
+ biofinish(bp, NULL, EIO);
+ return;
+ }
+ devstat_start_transaction_bio(cdp->stats, bp);
+ ata_queue_request(request);
}
-static int
-acd_done(struct atapi_request *request)
+static void
+acd_done(struct ata_request *request)
{
struct bio *bp = request->driver;
struct acd_softc *cdp = bp->bio_caller1;
- if (request->error) {
- bp->bio_error = request->error;
+ /* finish up transfer */
+ if ((bp->bio_error = request->result))
bp->bio_flags |= BIO_ERROR;
- }
- else
- bp->bio_resid = bp->bio_bcount - request->donecount;
+ bp->bio_resid = bp->bio_bcount - request->donecount;
biofinish(bp, cdp->stats, 0);
- return 0;
+ ata_free_request(request);
}
static void
@@ -1231,7 +1225,7 @@ acd_read_toc(struct acd_softc *cdp)
bzero(&cdp->toc, sizeof(cdp->toc));
bzero(ccb, sizeof(ccb));
- if (atapi_test_ready(cdp->device) != 0)
+ if (acd_test_ready(cdp->device) != 0)
return;
cdp->device->flags &= ~ATA_D_MEDIA_CHANGED;
@@ -1240,8 +1234,8 @@ acd_read_toc(struct acd_softc *cdp)
ccb[0] = ATAPI_READ_TOC;
ccb[7] = len>>8;
ccb[8] = len;
- if (atapi_queue_cmd(cdp->device, ccb, (caddr_t)&cdp->toc, len,
- ATPR_F_READ | ATPR_F_QUIET, 30, NULL, NULL)) {
+ if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len,
+ ATA_R_READ | ATA_R_QUIET, 30)) {
bzero(&cdp->toc, sizeof(cdp->toc));
return;
}
@@ -1256,8 +1250,8 @@ acd_read_toc(struct acd_softc *cdp)
ccb[0] = ATAPI_READ_TOC;
ccb[7] = len>>8;
ccb[8] = len;
- if (atapi_queue_cmd(cdp->device, ccb, (caddr_t)&cdp->toc, len,
- ATPR_F_READ | ATPR_F_QUIET, 30, NULL, NULL)) {
+ if (ata_atapicmd(cdp->device, ccb, (caddr_t)&cdp->toc, len,
+ ATA_R_READ | ATA_R_QUIET, 30)) {
bzero(&cdp->toc, sizeof(cdp->toc));
return;
}
@@ -1267,8 +1261,8 @@ acd_read_toc(struct acd_softc *cdp)
acd_set_ioparm(cdp);
bzero(ccb, sizeof(ccb));
ccb[0] = ATAPI_READ_CAPACITY;
- if (atapi_queue_cmd(cdp->device, ccb, (caddr_t)sizes, sizeof(sizes),
- ATPR_F_READ | ATPR_F_QUIET, 30, NULL, NULL)) {
+ if (ata_atapicmd(cdp->device, ccb, (caddr_t)sizes, sizeof(sizes),
+ ATA_R_READ | ATA_R_QUIET, 30)) {
bzero(&cdp->toc, sizeof(cdp->toc));
return;
}
@@ -1313,7 +1307,7 @@ acd_play(struct acd_softc *cdp, int start, int end)
ccb[0] = ATAPI_PLAY_MSF;
lba2msf(start, &ccb[3], &ccb[4], &ccb[5]);
lba2msf(end, &ccb[6], &ccb[7], &ccb[8]);
- return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 10);
}
static int
@@ -1335,39 +1329,52 @@ acd_setchan(struct acd_softc *cdp,
return acd_mode_select(cdp, (caddr_t)&cdp->au, sizeof(cdp->au));
}
-static int
-acd_select_done1(struct atapi_request *request)
+static void
+acd_load_done(struct ata_request *request)
{
struct acd_softc *cdp = request->driver;
+ /* finish the slot select and wakeup caller */
cdp->changer_info->current_slot = cdp->slot;
cdp->driver[cdp->changer_info->current_slot]->timestamp = time_second;
wakeup(&cdp->changer_info);
- return 0;
}
-static int
-acd_select_done(struct atapi_request *request)
+static void
+acd_unload_done(struct ata_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->device, ccb, NULL, 0, ATPR_F_AT_HEAD, 30,
- acd_select_done1, cdp);
- return 0;
+ bcopy(ccb, request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 16 : 12);
+ request->callback = acd_load_done;
+ ata_queue_request(request);
}
static void
acd_select_slot(struct acd_softc *cdp)
{
+ struct ata_request *request;
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->device, ccb, NULL, 0, ATPR_F_AT_HEAD, 30,
- acd_select_done, cdp);
+ if (!(request = ata_alloc_request())) {
+ return;
+ }
+ request->device = cdp->device;
+ request->driver = cdp;
+ bcopy(ccb, request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 16 : 12);
+ request->timeout = 30;
+ request->callback = acd_unload_done;
+ request->flags |= (ATA_R_ATAPI | ATA_R_AT_HEAD);
+ ata_queue_request(request);
}
static int
@@ -1377,10 +1384,10 @@ acd_init_writer(struct acd_softc *cdp, int test_write)
bzero(ccb, sizeof(ccb));
ccb[0] = ATAPI_REZERO;
- atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_QUIET, 60, NULL, NULL);
+ ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 60);
ccb[0] = ATAPI_SEND_OPC_INFO;
ccb[1] = 0x01;
- atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_QUIET, 30, NULL, NULL);
+ ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 30);
return 0;
}
@@ -1406,19 +1413,19 @@ acd_fixate(struct acd_softc *cdp, int multisession)
if ((error = acd_mode_select(cdp, (caddr_t)&param, param.page_length + 10)))
return error;
- error = atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ error = ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30);
if (error)
return error;
/* some drives just return ready, wait for the expected fixate time */
- if ((error = atapi_test_ready(cdp->device)) != EBUSY) {
+ if ((error = acd_test_ready(cdp->device)) != EBUSY) {
timeout = timeout / (cdp->cap.cur_write_speed / 177);
tsleep(&error, PRIBIO, "acdfix", timeout * hz / 2);
- return atapi_test_ready(cdp->device);
+ return acd_test_ready(cdp->device);
}
while (timeout-- > 0) {
- if ((error = atapi_test_ready(cdp->device)) != EBUSY)
+ if ((error = acd_test_ready(cdp->device)) != EBUSY)
return error;
tsleep(&error, PRIBIO, "acdcld", hz/2);
}
@@ -1444,7 +1451,7 @@ acd_init_track(struct acd_softc *cdp, struct cdr_track *track)
param.fp = 0;
param.packet_size = 0;
- if (cdp->cap.burnproof)
+ if (cdp->cap.capabilities & MST_BURNPROOF)
param.burnproof = 1;
switch (track->datablock_type) {
@@ -1511,8 +1518,7 @@ acd_flush(struct acd_softc *cdp)
int8_t ccb[16] = { ATAPI_SYNCHRONIZE_CACHE, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(cdp->device, ccb, NULL, 0, ATPR_F_QUIET, 60,
- NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, NULL, 0, ATA_R_QUIET, 60);
}
static int
@@ -1526,8 +1532,8 @@ acd_read_track_info(struct acd_softc *cdp,
0, 0, 0, 0, 0, 0, 0 };
int error;
- if ((error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)info, sizeof(*info),
- ATPR_F_READ, 30, NULL, NULL)))
+ if ((error = ata_atapicmd(cdp->device, ccb, (caddr_t)info, sizeof(*info),
+ ATA_R_READ, 30)))
return error;
info->track_start_addr = ntohl(info->track_start_addr);
info->next_writeable_addr = ntohl(info->next_writeable_addr);
@@ -1542,16 +1548,14 @@ acd_get_progress(struct acd_softc *cdp, int *finished)
{
int8_t ccb[16] = { ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
- struct atapi_reqsense *sense = cdp->device->result;
+ struct atapi_sense sense;
int8_t dummy[8];
- if (atapi_queue_cmd(cdp->device, ccb, dummy, sizeof(dummy),
- ATPR_F_READ, 30, NULL, NULL) != EBUSY) {
- *finished = 100;
- return 0;
- }
- if (sense->sksv)
- *finished = ((sense->sk_specific2|(sense->sk_specific1<<8))*100)/65535;
+ ata_atapicmd(cdp->device, ccb, dummy, sizeof(dummy), ATA_R_READ, 30);
+ acd_request_sense(cdp->device, &sense);
+
+ if (sense.sksv)
+ *finished = ((sense.sk_specific2|(sense.sk_specific1<<8))*100)/65535;
else
*finished = 0;
return 0;
@@ -1585,7 +1589,7 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet)
param.track_mode = CDR_TMODE_AUDIO;
param.datablock_type = CDR_DB_RAW;
param.session_format = cuesheet->session_format;
- if (cdp->cap.burnproof)
+ if (cdp->cap.capabilities & MST_BURNPROOF)
param.burnproof = 1;
if ((error = acd_mode_select(cdp, (caddr_t)&param, param.page_length + 10)))
@@ -1604,8 +1608,7 @@ acd_send_cue(struct acd_softc *cdp, struct cdr_cuesheet *cuesheet)
printf("\n%02x", buffer[i]);
printf("\n");
#endif
- error = atapi_queue_cmd(cdp->device, ccb, buffer, cuesheet->len, 0,
- 30, NULL, NULL);
+ error = ata_atapicmd(cdp->device, ccb, buffer, cuesheet->len, 0, 30);
}
free(buffer, M_ACD);
return error;
@@ -1656,9 +1659,8 @@ acd_report_key(struct acd_softc *cdp, struct dvd_authinfo *ai)
d = malloc(length, M_ACD, M_NOWAIT | M_ZERO);
d->length = htons(length - 2);
- error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)d, length,
- ai->format == DVD_INVALIDATE_AGID ? 0 : ATPR_F_READ,
- 10, NULL, NULL);
+ error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length,
+ ai->format == DVD_INVALIDATE_AGID ? 0 : ATA_R_READ,10);
if (error) {
free(d, M_ACD);
return error;
@@ -1743,8 +1745,7 @@ acd_send_key(struct acd_softc *cdp, struct dvd_authinfo *ai)
ccb[9] = length & 0xff;
ccb[10] = (ai->agid << 6) | ai->format;
d->length = htons(length - 2);
- error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)d, length, 0,
- 10, NULL, NULL);
+ error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, 0, 10);
free(d, M_ACD);
return error;
}
@@ -1802,8 +1803,7 @@ acd_read_structure(struct acd_softc *cdp, struct dvd_struct *s)
ccb[8] = (length >> 8) & 0xff;
ccb[9] = length & 0xff;
ccb[10] = s->agid << 6;
- error = atapi_queue_cmd(cdp->device, ccb, (caddr_t)d, length, ATPR_F_READ,
- 30, NULL, NULL);
+ error = ata_atapicmd(cdp->device, ccb, (caddr_t)d, length, ATA_R_READ, 30);
if (error) {
free(d, M_ACD);
return error;
@@ -1887,7 +1887,7 @@ acd_blank(struct acd_softc *cdp, int blanktype)
0, 0, 0, 0, 0, 0, 0, 0 };
cdp->device->flags |= ATA_D_MEDIA_CHANGED;
- return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30);
}
static int
@@ -1896,7 +1896,7 @@ acd_prevent_allow(struct acd_softc *cdp, int lock)
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30);
}
static int
@@ -1905,7 +1905,7 @@ acd_start_stop(struct acd_softc *cdp, int start)
int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30);
}
static int
@@ -1914,7 +1914,7 @@ acd_pause_resume(struct acd_softc *cdp, int pause)
int8_t ccb[16] = { ATAPI_PAUSE, 0, 0, 0, 0, 0, 0, 0, pause,
0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30);
}
static int
@@ -1924,8 +1924,7 @@ acd_mode_sense(struct acd_softc *cdp, int page, caddr_t pagebuf, int pagesize)
pagesize>>8, pagesize, 0, 0, 0, 0, 0, 0, 0 };
int error;
- error = atapi_queue_cmd(cdp->device, ccb, pagebuf, pagesize, ATPR_F_READ,
- 10, NULL, NULL);
+ error = ata_atapicmd(cdp->device, ccb, pagebuf, pagesize, ATA_R_READ, 10);
#ifdef ACD_DEBUG
atapi_dump("acd: mode sense ", pagebuf, pagesize);
#endif
@@ -1943,8 +1942,7 @@ acd_mode_select(struct acd_softc *cdp, caddr_t pagebuf, int pagesize)
"modeselect pagesize=%d\n", pagesize);
atapi_dump("mode select ", pagebuf, pagesize);
#endif
- return atapi_queue_cmd(cdp->device, ccb, pagebuf, pagesize, 0,
- 30, NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, pagebuf, pagesize, 0, 30);
}
static int
@@ -1954,7 +1952,7 @@ acd_set_speed(struct acd_softc *cdp, int rdspeed, int wrspeed)
wrspeed >> 8, wrspeed, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int error;
- error = atapi_queue_cmd(cdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ error = ata_atapicmd(cdp->device, ccb, NULL, 0, 0, 30);
if (!error)
acd_get_cap(cdp);
return error;
@@ -1963,18 +1961,21 @@ acd_set_speed(struct acd_softc *cdp, int rdspeed, int wrspeed)
static void
acd_get_cap(struct acd_softc *cdp)
{
- int retry = 5;
-
- /* get drive capabilities, some drives needs this repeated */
- while (retry-- && acd_mode_sense(cdp, ATAPI_CDROM_CAP_PAGE,
- (caddr_t)&cdp->cap, sizeof(cdp->cap)))
-
- cdp->cap.max_read_speed = ntohs(cdp->cap.max_read_speed);
- cdp->cap.cur_read_speed = ntohs(cdp->cap.cur_read_speed);
- cdp->cap.max_write_speed = ntohs(cdp->cap.max_write_speed);
- cdp->cap.cur_write_speed = max(ntohs(cdp->cap.cur_write_speed), 177);
- cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels);
- cdp->cap.buf_size = ntohs(cdp->cap.buf_size);
+ int count;
+
+ /* get drive capabilities, some bugridden drives needs this repeated */
+ for (count = 0 ; count < 5 ; count++) {
+ if (!acd_mode_sense(cdp, ATAPI_CDROM_CAP_PAGE,
+ (caddr_t)&cdp->cap, sizeof(cdp->cap)) &&
+ cdp->cap.page_code == ATAPI_CDROM_CAP_PAGE) {
+ cdp->cap.max_read_speed = ntohs(cdp->cap.max_read_speed);
+ cdp->cap.cur_read_speed = ntohs(cdp->cap.cur_read_speed);
+ cdp->cap.max_write_speed = ntohs(cdp->cap.max_write_speed);
+ cdp->cap.cur_write_speed = max(ntohs(cdp->cap.cur_write_speed),177);
+ cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels);
+ cdp->cap.buf_size = ntohs(cdp->cap.buf_size);
+ }
+ }
}
static int
@@ -1985,9 +1986,8 @@ acd_read_format_caps(struct acd_softc *cdp, struct cdr_format_capacities *caps)
sizeof(struct cdr_format_capacities) & 0xff,
0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(cdp->device, ccb, (caddr_t)caps,
- sizeof(struct cdr_format_capacities),
- ATPR_F_READ, 30, NULL, NULL);
+ return ata_atapicmd(cdp->device, ccb, (caddr_t)caps,
+ sizeof(struct cdr_format_capacities), ATA_R_READ, 30);
}
static int
@@ -1997,8 +1997,26 @@ acd_format(struct acd_softc *cdp, struct cdr_format_params* params)
int8_t ccb[16] = { ATAPI_FORMAT, 0x11, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0 };
- error = atapi_queue_cmd(cdp->device, ccb, (u_int8_t *)params,
- sizeof(struct cdr_format_params), 0, 30, NULL,NULL);
-
+ error = ata_atapicmd(cdp->device, ccb, (u_int8_t *)params,
+ sizeof(struct cdr_format_params), 0, 30);
return error;
}
+
+static int
+acd_test_ready(struct ata_device *atadev)
+{
+ int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
+}
+
+static int
+acd_request_sense(struct ata_device *atadev, struct atapi_sense *sense)
+{
+ int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0, sizeof(struct atapi_sense),
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ return ata_atapicmd(atadev, ccb, (caddr_t)sense,
+ sizeof(struct atapi_sense), ATA_R_READ, 30);
+}
diff --git a/sys/dev/ata/atapi-cd.h b/sys/dev/ata/atapi-cd.h
index 19d742c..71d1c03 100644
--- a/sys/dev/ata/atapi-cd.h
+++ b/sys/dev/ata/atapi-cd.h
@@ -76,6 +76,12 @@ struct audiopage {
} port[4];
};
+
+/* CDROM Capabilities and Mechanical Status Page */
+struct cappage {
+ /* mode page data header */
+ u_int16_t data_length;
+ u_int8_t medium_type;
#define MST_TYPE_MASK_LOW 0x0f
#define MST_FMT_NONE 0x00
#define MST_DATA_120 0x01
@@ -96,126 +102,61 @@ struct audiopage {
#define MST_DOOR_OPEN 0x71
#define MST_FMT_ERROR 0x72
-#define MST_MECH_CADDY 0
-#define MST_MECH_TRAY 1
-#define MST_MECH_POPUP 2
-#define MST_MECH_CHANGER 4
-#define MST_MECH_CARTRIDGE 5
-
-#define MST_DLEN_32 0
-#define MST_DLEN_16 1
-#define MST_DLEN_24 2
-#define MST_DLEN_24_I2S 3
-
-#define ATAPI_CDROM_CAP_PAGE 0x2a
-
-/* CDROM Capabilities and Mechanical Status Page */
-struct cappage {
- /* mode page data header */
- u_int16_t data_length;
- u_int8_t medium_type;
-
u_int8_t dev_spec;
- u_int8_t unused[2];
+ u_int16_t unused;
u_int16_t blk_desc_len;
/* capabilities page */
u_int8_t page_code;
+#define ATAPI_CDROM_CAP_PAGE 0x2a
u_int8_t param_len;
-#if BYTE_ORDER == LITTLE_ENDIAN
- u_int8_t read_cdr :1; /* supports CD-R read */
- u_int8_t read_cdrw :1; /* supports CD-RW read */
- u_int8_t read_packet :1; /* supports reading packet tracks */
- u_int8_t read_dvdrom :1; /* supports DVD-ROM read */
- u_int8_t read_dvdr :1; /* supports DVD-R read */
- u_int8_t read_dvdram :1; /* supports DVD-RAM read */
- u_int8_t reserved2_67 :2;
-
- u_int8_t write_cdr :1; /* supports CD-R write */
- u_int8_t write_cdrw :1; /* supports CD-RW write */
- u_int8_t test_write :1; /* supports test writing */
- u_int8_t reserved3_3 :1;
- u_int8_t write_dvdr :1; /* supports DVD-R write */
- u_int8_t write_dvdram :1; /* supports DVD-RAM write */
- u_int8_t reserved3_67 :2;
-
- u_int8_t audio_play :1; /* audio play supported */
- u_int8_t composite :1; /* composite audio/video supported */
- u_int8_t dport1 :1; /* digital audio on port 1 */
- u_int8_t dport2 :1; /* digital audio on port 2 */
- u_int8_t mode2_form1 :1; /* mode 2 form 1 (XA) read */
- u_int8_t mode2_form2 :1; /* mode 2 form 2 format */
- u_int8_t multisession :1; /* multi-session photo-CD */
- u_int8_t burnproof :1; /* supports burnproof */
-
- u_int8_t cd_da :1; /* audio-CD read supported */
- u_int8_t cd_da_stream :1; /* CD-DA streaming */
- u_int8_t rw :1; /* combined R-W subchannels */
- u_int8_t rw_corr :1; /* R-W subchannel data corrected */
- u_int8_t c2 :1; /* C2 error pointers supported */
- u_int8_t isrc :1; /* can return the ISRC info */
- u_int8_t upc :1; /* can return the catalog number UPC */
- u_int8_t :1;
-
- u_int8_t lock :1; /* can be locked */
- u_int8_t locked :1; /* current lock state */
- u_int8_t prevent :1; /* prevent jumper installed */
- u_int8_t eject :1; /* can eject */
- u_int8_t :1;
- u_int8_t mech :3; /* loading mechanism type */
-
- u_int8_t sep_vol :1; /* independent volume of channels */
- u_int8_t sep_mute :1; /* independent mute of channels */
- u_int8_t:6;
-#else
- /* This is read using 16-bit stream transfers */
- u_int8_t reserved2_67 :2;
- u_int8_t read_dvdram :1; /* supports DVD-RAM read */
- u_int8_t read_dvdr :1; /* supports DVD-R read */
- u_int8_t read_dvdrom :1; /* supports DVD-ROM read */
- u_int8_t read_packet :1; /* supports reading packet tracks */
- u_int8_t read_cdrw :1; /* supports CD-RW read */
- u_int8_t read_cdr :1; /* supports CD-R read */
-
- u_int8_t reserved3_67 :2;
- u_int8_t write_dvdram :1; /* supports DVD-RAM write */
- u_int8_t write_dvdr :1; /* supports DVD-R write */
- u_int8_t reserved3_3 :1;
- u_int8_t test_write :1; /* supports test writing */
- u_int8_t write_cdrw :1; /* supports CD-RW write */
- u_int8_t write_cdr :1; /* supports CD-R write */
-
- u_int8_t burnproof :1; /* supports burnproof */
- u_int8_t multisession :1; /* multi-session photo-CD */
- u_int8_t mode2_form2 :1; /* mode 2 form 2 format */
- u_int8_t mode2_form1 :1; /* mode 2 form 1 (XA) read */
- u_int8_t dport2 :1; /* digital audio on port 2 */
- u_int8_t dport1 :1; /* digital audio on port 1 */
- u_int8_t composite :1; /* composite audio/video supported */
- u_int8_t audio_play :1; /* audio play supported */
-
- u_int8_t :1;
- u_int8_t upc :1; /* can return the catalog number UPC */
- u_int8_t isrc :1; /* can return the ISRC info */
- u_int8_t c2 :1; /* C2 error pointers supported */
- u_int8_t rw_corr :1; /* R-W subchannel data corrected */
- u_int8_t rw :1; /* combined R-W subchannels */
- u_int8_t cd_da_stream :1; /* CD-DA streaming */
- u_int8_t cd_da :1; /* audio-CD read supported */
-
- u_int8_t mech :3; /* loading mechanism type */
- u_int8_t :1;
- u_int8_t eject :1; /* can eject */
- u_int8_t prevent :1; /* prevent jumper installed */
- u_int8_t locked :1; /* current lock state */
- u_int8_t lock :1; /* can be locked */
-
- u_int8_t:6;
- u_int8_t sep_mute :1; /* independent mute of channels */
- u_int8_t sep_vol :1; /* independent volume of channels */
-#endif
+ u_int16_t media;
+#define MST_READ_CDR 0x0001
+#define MST_READ_CDRW 0x0002
+#define MST_READ_PACKET 0x0004
+#define MST_READ_DVDROM 0x0008
+#define MST_READ_DVDR 0x0010
+#define MST_READ_DVDRAM 0x0020
+#define MST_WRITE_CDR 0x0100
+#define MST_WRITE_CDRW 0x0200
+#define MST_WRITE_TEST 0x0400
+#define MST_WRITE_DVDR 0x1000
+#define MST_WRITE_DVDRAM 0x2000
+
+ u_int16_t capabilities;
+#define MST_AUDIO_PLAY 0x0001
+#define MST_COMPOSITE 0x0002
+#define MST_AUDIO_P1 0x0004
+#define MST_AUDIO_P2 0x0008
+#define MST_MODE2_f1 0x0010
+#define MST_MODE2_f2 0x0020
+#define MST_MULTISESSION 0x0040
+#define MST_BURNPROOF 0x0080
+#define MST_READ_CDDA 0x0100
+#define MST_CDDA_STREAM 0x0200
+#define MST_COMBINED_RW 0x0400
+#define MST_CORRECTED_RW 0x0800
+#define MST_SUPPORT_C2 0x1000
+#define MST_ISRC 0x2000
+#define MST_UPC 0x4000
+
+ u_int8_t mechanism;
+#define MST_LOCKABLE 0x01
+#define MST_LOCKED 0x02
+#define MST_PREVENT 0x04
+#define MST_EJECT 0x08
+#define MST_MECH_MASK 0xe0
+#define MST_MECH_CADDY 0x00
+#define MST_MECH_TRAY 0x20
+#define MST_MECH_POPUP 0x40
+#define MST_MECH_CHANGER 0x80
+#define MST_MECH_CARTRIDGE 0xa0
+
+ uint8_t audio;
+#define MST_SEP_VOL 0x01
+#define MST_SEP_MUTE 0x02
u_int16_t max_read_speed; /* max raw data rate in bytes/1000 */
u_int16_t max_vol_levels; /* number of discrete volume levels */
@@ -223,21 +164,7 @@ struct cappage {
u_int16_t cur_read_speed; /* current data rate in bytes/1000 */
u_int8_t reserved3;
-#if BYTE_ORDER == LITTLE_ENDIAN
- u_int8_t bckf :1; /* data valid on failing edge of BCK */
- u_int8_t rch :1; /* high LRCK indicates left channel */
- u_int8_t lsbf :1; /* set if LSB first */
- u_int8_t dlen :2;
-
- u_int8_t :3;
-#else
- u_int8_t :3;
-
- u_int8_t dlen :2;
- u_int8_t lsbf :1; /* set if LSB first */
- u_int8_t rch :1; /* high LRCK indicates left channel */
- u_int8_t bckf :1; /* data valid on failing edge of BCK */
-#endif
+ u_int8_t misc;
u_int16_t max_write_speed; /* max raw data rate in bytes/1000 */
u_int16_t cur_write_speed; /* current data rate in bytes/1000 */
@@ -379,6 +306,7 @@ struct acd_softc {
int flags; /* device state flags */
#define F_LOCKED 0x0001 /* this unit is locked */
+ struct mtx queue_mtx; /* queue lock */
struct bio_queue_head queue; /* queue of i/o requests */
TAILQ_HEAD(, acd_devlist) dev_list; /* list of "track" devices */
struct toc toc; /* table of disc contents */
diff --git a/sys/dev/ata/atapi-fd.c b/sys/dev/ata/atapi-fd.c
index 5772242..91c2111 100644
--- a/sys/dev/ata/atapi-fd.c
+++ b/sys/dev/ata/atapi-fd.c
@@ -37,79 +37,105 @@
#include <sys/bus.h>
#include <sys/conf.h>
#include <sys/cdio.h>
+#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <geom/geom_disk.h>
#include <dev/ata/ata-all.h>
-#include <dev/ata/atapi-all.h>
#include <dev/ata/atapi-fd.h>
/* prototypes */
-static disk_open_t afdopen;
-static disk_close_t afdclose;
+static disk_open_t afd_open;
+static disk_close_t afd_close;
#ifdef notyet
-static disk_ioctl_t afdioctl;
+static disk_ioctl_t afd_ioctl;
#endif
-static disk_strategy_t afdstrategy;
+static disk_strategy_t afdstrategy;
+static void afd_detach(struct ata_device *atadev);
+static void afd_start(struct ata_device *atadev);
static int afd_sense(struct afd_softc *);
static void afd_describe(struct afd_softc *);
-static int afd_done(struct atapi_request *);
+static void afd_done(struct ata_request *);
static int afd_eject(struct afd_softc *, int);
static int afd_start_stop(struct afd_softc *, int);
static int afd_prevent_allow(struct afd_softc *, int);
+static int afd_test_ready(struct ata_device *atadev);
/* internal vars */
static u_int32_t afd_lun_map = 0;
static MALLOC_DEFINE(M_AFD, "AFD driver", "ATAPI floppy driver buffers");
-int
-afdattach(struct ata_device *atadev)
+void
+afd_attach(struct ata_device *atadev)
{
struct afd_softc *fdp;
fdp = malloc(sizeof(struct afd_softc), M_AFD, M_NOWAIT | M_ZERO);
if (!fdp) {
ata_prtdev(atadev, "out of memory\n");
- return 0;
+ return;
}
fdp->device = atadev;
fdp->lun = ata_get_lun(&afd_lun_map);
ata_set_name(atadev, "afd", fdp->lun);
bioq_init(&fdp->queue);
+ mtx_init(&fdp->queue_mtx, "ATAPI FD bioqueue lock", MTX_DEF, 0);
if (afd_sense(fdp)) {
free(fdp, M_AFD);
- return 0;
+ return;
}
- fdp->disk.d_open = afdopen;
- fdp->disk.d_close = afdclose;
+ /* use DMA if allowed and if drive/controller supports it */
+ if (atapi_dma && atadev->channel->dma &&
+ (atadev->param->config & ATA_DRQ_MASK) != ATA_DRQ_INTR)
+ atadev->setmode(atadev, ATA_DMA_MAX);
+ else
+ atadev->setmode(atadev, ATA_PIO_MAX);
+
+ /* setup the function ptrs */
+ atadev->detach = afd_detach;
+ atadev->start = afd_start;
+ atadev->softc = fdp;
+ atadev->flags |= ATA_D_MEDIA_CHANGED;
+
+ /* lets create the disk device */
+ fdp->disk.d_open = afd_open;
+ fdp->disk.d_close = afd_close;
#ifdef notyet
- fdp->disk.d_ioctl = afdioctl;
+ fdp->disk.d_ioctl = afd_ioctl;
#endif
fdp->disk.d_strategy = afdstrategy;
fdp->disk.d_name = "afd";
fdp->disk.d_drv1 = fdp;
- fdp->disk.d_maxsize = 256 * DEV_BSIZE;
- disk_create(fdp->lun, &fdp->disk, 0, NULL, NULL);
+ if (atadev->channel->dma)
+ fdp->disk.d_maxsize = atadev->channel->dma->max_iosize;
+ else
+ fdp->disk.d_maxsize = DFLTPHYS;
+ disk_create(fdp->lun, &fdp->disk, DISKFLAG_NOGIANT, NULL, NULL);
+ /* announce we are here */
afd_describe(fdp);
- atadev->flags |= ATA_D_MEDIA_CHANGED;
- atadev->driver = fdp;
- return 1;
}
-void
-afddetach(struct ata_device *atadev)
+static void
+afd_detach(struct ata_device *atadev)
{
- struct afd_softc *fdp = atadev->driver;
+ struct afd_softc *fdp = atadev->softc;
+ mtx_lock(&fdp->queue_mtx);
bioq_flush(&fdp->queue, NULL, ENXIO);
+ mtx_unlock(&fdp->queue_mtx);
disk_destroy(&fdp->disk);
+ ata_prtdev(atadev, "WARNING - removed from configuration\n");
ata_free_name(atadev);
ata_free_lun(&afd_lun_map, fdp->lun);
+ atadev->attach = NULL;
+ atadev->detach = NULL;
+ atadev->start = NULL;
+ atadev->softc = NULL;
+ atadev->flags = 0;
free(fdp, M_AFD);
- atadev->driver = NULL;
}
static int
@@ -118,7 +144,7 @@ afd_sense(struct afd_softc *fdp)
int8_t ccb[16] = { ATAPI_MODE_SENSE_BIG, 0, ATAPI_REWRITEABLE_CAP_PAGE,
0, 0, 0, 0, sizeof(struct afd_cappage) >> 8,
sizeof(struct afd_cappage) & 0xff, 0, 0, 0, 0, 0, 0, 0 };
- int count, error = 0;
+ int count;
/* The IOMEGA Clik! doesn't support reading the cap page, fake it */
if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12)) {
@@ -127,23 +153,22 @@ afd_sense(struct afd_softc *fdp)
fdp->cap.sectors = 2;
fdp->cap.cylinders = 39441;
fdp->cap.sector_size = 512;
- atapi_test_ready(fdp->device);
+ afd_test_ready(fdp->device);
return 0;
}
- /* get drive capabilities, some drives needs this repeated */
+ /* get drive capabilities, some bugridden drives needs this repeated */
for (count = 0 ; count < 5 ; count++) {
- if (!(error = atapi_queue_cmd(fdp->device, ccb, (caddr_t)&fdp->cap,
- sizeof(struct afd_cappage),
- ATPR_F_READ, 30, NULL, NULL)))
- break;
+ if (!ata_atapicmd(fdp->device, ccb, (caddr_t)&fdp->cap,
+ sizeof(struct afd_cappage), ATA_R_READ, 30) &&
+ fdp->cap.page_code == ATAPI_REWRITEABLE_CAP_PAGE) {
+ fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
+ fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
+ fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
+ return 0;
+ }
}
- if (error || fdp->cap.page_code != ATAPI_REWRITEABLE_CAP_PAGE)
- return 1;
- fdp->cap.cylinders = ntohs(fdp->cap.cylinders);
- fdp->cap.sector_size = ntohs(fdp->cap.sector_size);
- fdp->cap.transfer_rate = ntohs(fdp->cap.transfer_rate);
- return 0;
+ return 1;
}
static void
@@ -151,7 +176,7 @@ afd_describe(struct afd_softc *fdp)
{
if (bootverbose) {
ata_prtdev(fdp->device,
- "<%.40s/%.8s> rewriteable drive at ata%d as %s\n",
+ "<%.40s/%.8s> removable drive at ata%d as %s\n",
fdp->device->param->model, fdp->device->param->revision,
device_get_unit(fdp->device->channel->dev),
(fdp->device->unit == ATA_MASTER) ? "master" : "slave");
@@ -187,11 +212,8 @@ afd_describe(struct afd_softc *fdp)
}
}
else {
- ata_prtdev(fdp->device, "%luMB <%.40s> [%d/%d/%d] at ata%d-%s %s\n",
- (fdp->cap.cylinders * fdp->cap.heads * fdp->cap.sectors) /
- ((1024L * 1024L) / fdp->cap.sector_size),
+ ata_prtdev(fdp->device, "REMOVABLE <%.40s> at ata%d-%s %s\n",
fdp->device->param->model,
- fdp->cap.cylinders, fdp->cap.heads, fdp->cap.sectors,
device_get_unit(fdp->device->channel->dev),
(fdp->device->unit == ATA_MASTER) ? "master" : "slave",
ata_mode2str(fdp->device->mode));
@@ -199,15 +221,14 @@ afd_describe(struct afd_softc *fdp)
}
static int
-afdopen(struct disk *dp)
+afd_open(struct disk *dp)
{
struct afd_softc *fdp = dp->d_drv1;
- /* hold off access to we are fully attached */
- while (ata_delayed_attach)
- tsleep(&ata_delayed_attach, PRIBIO, "afdopn", 1);
+ if (fdp->device->flags & ATA_D_DETACHING)
+ return ENXIO;
- atapi_test_ready(fdp->device);
+ afd_test_ready(fdp->device);
afd_prevent_allow(fdp, 1);
@@ -226,7 +247,7 @@ afdopen(struct disk *dp)
}
static int
-afdclose(struct disk *dp)
+afd_close(struct disk *dp)
{
struct afd_softc *fdp = dp->d_drv1;
@@ -239,7 +260,7 @@ afdclose(struct disk *dp)
#ifdef notyet
static int
-afdioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
+afd_ioctl(struct disk *dp, u_long cmd, void *addr, int flag, struct thread *td)
{
struct afd_softc *fdp = dp->d_drv1;
@@ -264,7 +285,6 @@ static void
afdstrategy(struct bio *bp)
{
struct afd_softc *fdp = bp->bio_disk->d_drv1;
- int s;
if (fdp->device->flags & ATA_D_DETACHING) {
biofinish(bp, NULL, ENXIO);
@@ -278,26 +298,31 @@ afdstrategy(struct bio *bp)
return;
}
- s = splbio();
+ mtx_lock(&fdp->queue_mtx);
bioq_disksort(&fdp->queue, bp);
- splx(s);
+ mtx_unlock(&fdp->queue_mtx);
ata_start(fdp->device->channel);
}
-void
+static void
afd_start(struct ata_device *atadev)
{
- struct afd_softc *fdp = atadev->driver;
- struct bio *bp = bioq_first(&fdp->queue);
+ struct afd_softc *fdp = atadev->softc;
+ struct bio *bp;
+ struct ata_request *request;
u_int32_t lba;
u_int16_t count;
int8_t ccb[16];
- caddr_t data_ptr;
- if (!bp)
- return;
+ mtx_lock(&fdp->queue_mtx);
+ bp = bioq_first(&fdp->queue);
+ if (!bp) {
+ mtx_unlock(&fdp->queue_mtx);
+ return;
+ }
bioq_remove(&fdp->queue, bp);
+ mtx_unlock(&fdp->queue_mtx);
/* should reject all queued entries if media have changed. */
if (fdp->device->flags & ATA_D_MEDIA_CHANGED) {
@@ -307,7 +332,6 @@ afd_start(struct ata_device *atadev)
lba = bp->bio_pblkno;
count = bp->bio_bcount / fdp->cap.sector_size;
- data_ptr = bp->bio_data;
bp->bio_resid = bp->bio_bcount;
bzero(ccb, sizeof(ccb));
@@ -324,24 +348,49 @@ afd_start(struct ata_device *atadev)
ccb[7] = count>>8;
ccb[8] = count;
- atapi_queue_cmd(fdp->device, ccb, data_ptr, count * fdp->cap.sector_size,
- (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0, 30,
- afd_done, bp);
+ if (!(request = ata_alloc_request())) {
+ biofinish(bp, NULL, EIO);
+ return;
+ }
+ request->device = atadev;
+ request->driver = bp;
+ bcopy(ccb, request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 16 : 12);
+ request->data = bp->bio_data;
+ request->bytecount = count * fdp->cap.sector_size;
+ request->transfersize = min(request->bytecount, 65534);
+ request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 60 : 30;
+ request->retries = 2;
+ request->callback = afd_done;
+ switch (bp->bio_cmd) {
+ case BIO_READ:
+ request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_READ);
+ break;
+ case BIO_WRITE:
+ request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_WRITE);
+ break;
+ default:
+ ata_prtdev(atadev, "unknown BIO operation\n");
+ ata_free_request(request);
+ biofinish(bp, NULL, EIO);
+ return;
+ }
+ ata_queue_request(request);
+
}
-static int
-afd_done(struct atapi_request *request)
+static void
+afd_done(struct ata_request *request)
{
struct bio *bp = request->driver;
- if (request->error || (bp->bio_flags & BIO_ERROR)) {
- bp->bio_error = request->error;
+ /* finish up transfer */
+ if ((bp->bio_error = request->result))
bp->bio_flags |= BIO_ERROR;
- }
- else
- bp->bio_resid = bp->bio_bcount - request->donecount;
+ bp->bio_resid = bp->bio_bcount - request->donecount;
biodone(bp);
- return 0;
+ ata_free_request(request);
}
static int
@@ -372,7 +421,7 @@ afd_start_stop(struct afd_softc *fdp, int start)
int8_t ccb[16] = { ATAPI_START_STOP, 0, 0, 0, start,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30);
}
static int
@@ -383,5 +432,14 @@ afd_prevent_allow(struct afd_softc *fdp, int lock)
if (!strncmp(fdp->device->param->model, "IOMEGA Clik!", 12))
return 0;
- return atapi_queue_cmd(fdp->device, ccb, NULL, 0, 0, 30, NULL, NULL);
+ return ata_atapicmd(fdp->device, ccb, NULL, 0, 0, 30);
+}
+
+static int
+afd_test_ready(struct ata_device *atadev)
+{
+ int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
}
diff --git a/sys/dev/ata/atapi-fd.h b/sys/dev/ata/atapi-fd.h
index 8979409..90223f4 100644
--- a/sys/dev/ata/atapi-fd.h
+++ b/sys/dev/ata/atapi-fd.h
@@ -71,6 +71,7 @@ struct afd_cappage {
struct afd_softc {
struct ata_device *device; /* device softc */
int lun; /* logical device unit */
+ struct mtx queue_mtx; /* queue lock */
struct bio_queue_head queue; /* queue of i/o requests */
struct afd_cappage cap; /* capabilities page info */
struct disk disk; /* virtual drives */
diff --git a/sys/dev/ata/atapi-tape.c b/sys/dev/ata/atapi-tape.c
index cfd0b28..f9f7e82 100644
--- a/sys/dev/ata/atapi-tape.c
+++ b/sys/dev/ata/atapi-tape.c
@@ -39,32 +39,34 @@
#include <sys/bus.h>
#include <sys/mtio.h>
#include <sys/devicestat.h>
+#include <sys/taskqueue.h>
#include <machine/bus.h>
#include <dev/ata/ata-all.h>
-#include <dev/ata/atapi-all.h>
#include <dev/ata/atapi-tape.h>
/* device structures */
-static d_open_t astopen;
-static d_close_t astclose;
-static d_ioctl_t astioctl;
-static d_strategy_t aststrategy;
+static d_open_t ast_open;
+static d_close_t ast_close;
+static d_ioctl_t ast_ioctl;
+static d_strategy_t ast_strategy;
static struct cdevsw ast_cdevsw = {
- .d_open = astopen,
- .d_close = astclose,
+ .d_open = ast_open,
+ .d_close = ast_close,
.d_read = physread,
.d_write = physwrite,
- .d_ioctl = astioctl,
- .d_strategy = aststrategy,
+ .d_ioctl = ast_ioctl,
+ .d_strategy = ast_strategy,
.d_name = "ast",
.d_maj = 119,
- .d_flags = D_TAPE | D_TRACKCLOSE,
+ .d_flags = D_TAPE | D_TRACKCLOSE | D_NOGIANT,
};
/* prototypes */
+static void ast_detach(struct ata_device *atadev);
+static void ast_start(struct ata_device *atadev);
static int ast_sense(struct ast_softc *);
static void ast_describe(struct ast_softc *);
-static int ast_done(struct atapi_request *);
+static void ast_done(struct ata_request *);
static int ast_mode_sense(struct ast_softc *, int, void *, int);
static int ast_mode_select(struct ast_softc *, void *, int);
static int ast_write_filemark(struct ast_softc *, u_int8_t);
@@ -75,14 +77,16 @@ static int ast_prevent_allow(struct ast_softc *stp, int);
static int ast_load_unload(struct ast_softc *, u_int8_t);
static int ast_rewind(struct ast_softc *);
static int ast_erase(struct ast_softc *);
+static int ast_test_ready(struct ata_device *atadev);
+static int ast_wait_dsc(struct ata_device *atadev, int timeout);
/* internal vars */
static u_int32_t ast_lun_map = 0;
static u_int64_t ast_total = 0;
static MALLOC_DEFINE(M_AST, "AST driver", "ATAPI tape driver buffers");
-int
-astattach(struct ata_device *atadev)
+void
+ast_attach(struct ata_device *atadev)
{
struct ast_softc *stp;
struct ast_readposition position;
@@ -91,17 +95,18 @@ astattach(struct ata_device *atadev)
stp = malloc(sizeof(struct ast_softc), M_AST, M_NOWAIT | M_ZERO);
if (!stp) {
ata_prtdev(atadev, "out of memory\n");
- return 0;
+ return;
}
stp->device = atadev;
stp->lun = ata_get_lun(&ast_lun_map);
ata_set_name(atadev, "ast", stp->lun);
bioq_init(&stp->queue);
+ mtx_init(&stp->queue_mtx, "ATAPI TAPE bioqueue lock", MTX_DEF, 0);
if (ast_sense(stp)) {
free(stp, M_AST);
- return 0;
+ return;
}
if (!strcmp(atadev->param->model, "OnStream DI-30")) {
@@ -127,43 +132,70 @@ astattach(struct ata_device *atadev)
dev = make_dev(&ast_cdevsw, 2 * stp->lun,
UID_ROOT, GID_OPERATOR, 0640, "ast%d", stp->lun);
dev->si_drv1 = stp;
- dev->si_iosize_max = 256 * DEV_BSIZE;
+ if (atadev->channel->dma)
+ dev->si_iosize_max = atadev->channel->dma->max_iosize;
+ else
+ dev->si_iosize_max = DFLTPHYS;
stp->dev1 = dev;
dev = make_dev(&ast_cdevsw, 2 * stp->lun + 1,
UID_ROOT, GID_OPERATOR, 0640, "nast%d", stp->lun);
+
dev->si_drv1 = stp;
- dev->si_iosize_max = 256 * DEV_BSIZE;
+ if (atadev->channel->dma)
+ dev->si_iosize_max = atadev->channel->dma->max_iosize;
+ else
+ dev->si_iosize_max = DFLTPHYS;
stp->dev2 = dev;
- stp->device->flags |= ATA_D_MEDIA_CHANGED;
+
+ /* use DMA if allowed and if drive/controller supports it */
+ if (atapi_dma && atadev->channel->dma &&
+ (atadev->param->config & ATA_DRQ_MASK) != ATA_DRQ_INTR)
+ atadev->setmode(atadev, ATA_DMA_MAX);
+ else
+ atadev->setmode(atadev, ATA_PIO_MAX);
+
+ /* setup the function ptrs */
+ atadev->detach = ast_detach;
+ atadev->start = ast_start;
+ atadev->softc = stp;
+ atadev->flags |= ATA_D_MEDIA_CHANGED;
+
+ /* announce we are here */
ast_describe(stp);
- atadev->driver = stp;
- return 1;
}
-void
-astdetach(struct ata_device *atadev)
+static void
+ast_detach(struct ata_device *atadev)
{
- struct ast_softc *stp = atadev->driver;
+ struct ast_softc *stp = atadev->softc;
+ mtx_lock(&stp->queue_mtx);
bioq_flush(&stp->queue, NULL, ENXIO);
+ mtx_unlock(&stp->queue_mtx);
destroy_dev(stp->dev1);
destroy_dev(stp->dev2);
devstat_remove_entry(stp->stats);
+ ata_prtdev(atadev, "WARNING - removed from configuration\n");
ata_free_name(atadev);
ata_free_lun(&ast_lun_map, stp->lun);
+ atadev->attach = NULL;
+ atadev->detach = NULL;
+ atadev->start = NULL;
+ atadev->softc = NULL;
+ atadev->flags = 0;
free(stp, M_AST);
- atadev->driver = NULL;
}
static int
ast_sense(struct ast_softc *stp)
{
- int count, error = 0;
+ int count;
- /* get drive capabilities, some drives needs this repeated */
+ /* get drive capabilities, some bugridden drives needs this repeated */
for (count = 0 ; count < 5 ; count++) {
- if (!(error = ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE,
- &stp->cap, sizeof(stp->cap)))) {
+ if (!ast_mode_sense(stp, ATAPI_TAPE_CAP_PAGE,
+ &stp->cap, sizeof(stp->cap)) &&
+ stp->cap.page_code == ATAPI_TAPE_CAP_PAGE) {
if (stp->cap.blk32k)
stp->blksize = 32768;
if (stp->cap.blk1024)
@@ -235,17 +267,17 @@ ast_describe(struct ast_softc *stp)
}
static int
-astopen(dev_t dev, int flags, int fmt, struct thread *td)
+ast_open(dev_t dev, int flags, int fmt, struct thread *td)
{
struct ast_softc *stp = dev->si_drv1;
- if (!stp)
+ if (!stp || stp->device->flags & ATA_D_DETACHING)
return ENXIO;
if (count_dev(dev) > 1)
return EBUSY;
- atapi_test_ready(stp->device);
+ ast_test_ready(stp->device);
if (stp->cap.lock)
ast_prevent_allow(stp, 1);
@@ -260,7 +292,7 @@ astopen(dev_t dev, int flags, int fmt, struct thread *td)
}
static int
-astclose(dev_t dev, int flags, int fmt, struct thread *td)
+ast_close(dev_t dev, int flags, int fmt, struct thread *td)
{
struct ast_softc *stp = dev->si_drv1;
@@ -271,7 +303,7 @@ astclose(dev_t dev, int flags, int fmt, struct thread *td)
/* write filemark if data written to tape */
if (!(stp->flags & F_ONSTREAM) &&
(stp->flags & (F_DATA_WRITTEN | F_FM_WRITTEN)) == F_DATA_WRITTEN)
- ast_write_filemark(stp, WF_WRITE);
+ ast_write_filemark(stp, ATAPI_WF_WRITE);
/* if minor is even rewind on close */
if (!(minor(dev) & 0x01))
@@ -283,13 +315,13 @@ astclose(dev_t dev, int flags, int fmt, struct thread *td)
stp->flags &= ~F_CTL_WARN;
#ifdef AST_DEBUG
ata_prtdev(stp->device, "%ju total bytes transferred\n",
- (uintmax_t)ast_total);
+ (uintmax_t)ast_total);
#endif
return 0;
}
static int
-astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
+ast_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
{
struct ast_softc *stp = dev->si_drv1;
int error = 0;
@@ -321,17 +353,17 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
case MTWEOF:
for (i=0; i < mt->mt_count && !error; i++)
- error = ast_write_filemark(stp, WF_WRITE);
+ error = ast_write_filemark(stp, ATAPI_WF_WRITE);
break;
case MTFSF:
if (mt->mt_count)
- error = ast_space(stp, SP_FM, mt->mt_count);
+ error = ast_space(stp, ATAPI_SP_FM, mt->mt_count);
break;
case MTBSF:
if (mt->mt_count)
- error = ast_space(stp, SP_FM, -(mt->mt_count));
+ error = ast_space(stp, ATAPI_SP_FM, -(mt->mt_count));
break;
case MTREW:
@@ -339,7 +371,7 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
break;
case MTOFFL:
- error = ast_load_unload(stp, SS_EJECT);
+ error = ast_load_unload(stp, ATAPI_SS_EJECT);
break;
case MTNOP:
@@ -351,11 +383,11 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
break;
case MTEOD:
- error = ast_space(stp, SP_EOD, 0);
+ error = ast_space(stp, ATAPI_SP_EOD, 0);
break;
case MTRETENS:
- error = ast_load_unload(stp, SS_RETENSION | SS_LOAD);
+ error = ast_load_unload(stp, ATAPI_SS_RETENSION|ATAPI_SS_LOAD);
break;
case MTFSR:
@@ -401,10 +433,9 @@ astioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
}
static void
-aststrategy(struct bio *bp)
+ast_strategy(struct bio *bp)
{
struct ast_softc *stp = bp->bio_dev->si_drv1;
- int s;
if (stp->device->flags & ATA_D_DETACHING) {
biofinish(bp, NULL, ENXIO);
@@ -439,22 +470,29 @@ aststrategy(struct bio *bp)
}
}
- s = splbio();
+ mtx_lock(&stp->queue_mtx);
bioq_insert_tail(&stp->queue, bp);
- splx(s);
+ mtx_unlock(&stp->queue_mtx);
ata_start(stp->device->channel);
}
-void
+static void
ast_start(struct ata_device *atadev)
{
- struct ast_softc *stp = atadev->driver;
- struct bio *bp = bioq_first(&stp->queue);
+ struct ast_softc *stp = atadev->softc;
+ struct bio *bp;
+ struct ata_request *request;
u_int32_t blkcount;
int8_t ccb[16];
- if (!bp)
+ mtx_lock(&stp->queue_mtx);
+ bp = bioq_first(&stp->queue);
+ if (!bp) {
+ mtx_unlock(&stp->queue_mtx);
return;
+ }
+ bioq_remove(&stp->queue, bp);
+ mtx_unlock(&stp->queue_mtx);
bzero(ccb, sizeof(ccb));
@@ -463,7 +501,6 @@ ast_start(struct ata_device *atadev)
else
ccb[0] = ATAPI_WRITE;
- bioq_remove(&stp->queue, bp);
blkcount = bp->bio_bcount / stp->blksize;
ccb[1] = 1;
@@ -471,31 +508,53 @@ ast_start(struct ata_device *atadev)
ccb[3] = blkcount>>8;
ccb[4] = blkcount;
+ if (!(request = ata_alloc_request())) {
+ biofinish(bp, NULL, EIO);
+ return;
+ }
+ request->device = atadev;
+ request->driver = bp;
+ bcopy(ccb, request->u.atapi.ccb,
+ (request->device->param->config & ATA_PROTO_MASK) ==
+ ATA_PROTO_ATAPI_12 ? 16 : 12);
+ request->data = bp->bio_data;
+ request->bytecount = blkcount * stp->blksize;
+ request->transfersize = min(request->bytecount, 65534);
+ request->timeout = (ccb[0] == ATAPI_WRITE_BIG) ? 180 : 120;
+ request->retries = 2;
+ request->callback = ast_done;
+ switch (bp->bio_cmd) {
+ case BIO_READ:
+ request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_READ);
+ break;
+ case BIO_WRITE:
+ request->flags |= (ATA_R_SKIPSTART | ATA_R_ATAPI | ATA_R_WRITE);
+ break;
+ default:
+ ata_prtdev(atadev, "unknown BIO operation\n");
+ ata_free_request(request);
+ biofinish(bp, NULL, EIO);
+ return;
+ }
devstat_start_transaction_bio(stp->stats, bp);
-
- atapi_queue_cmd(stp->device, ccb, bp->bio_data, blkcount * stp->blksize,
- (bp->bio_cmd == BIO_READ) ? ATPR_F_READ : 0,
- 120, ast_done, bp);
+ ata_queue_request(request);
}
-static int
-ast_done(struct atapi_request *request)
+static void
+ast_done(struct ata_request *request)
{
struct bio *bp = request->driver;
- struct ast_softc *stp = request->device->driver;
+ struct ast_softc *stp = request->device->softc;
- if (request->error) {
- bp->bio_error = request->error;
+ /* finish up transfer */
+ if ((bp->bio_error = request->result))
bp->bio_flags |= BIO_ERROR;
- }
- else {
- if (!(bp->bio_cmd == BIO_READ))
- stp->flags |= F_DATA_WRITTEN;
- bp->bio_resid = bp->bio_bcount - request->donecount;
- ast_total += (bp->bio_bcount - bp->bio_resid);
- }
+ if (bp->bio_cmd == BIO_WRITE)
+ stp->flags |= F_DATA_WRITTEN;
+ bp->bio_resid = bp->bio_bcount - request->donecount;
+ ast_total += (bp->bio_bcount - bp->bio_resid);
biofinish(bp, stp->stats, 0);
- return 0;
+ ata_free_request(request);
}
static int
@@ -505,8 +564,7 @@ ast_mode_sense(struct ast_softc *stp, int page, void *pagebuf, int pagesize)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int error;
- error = atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, ATPR_F_READ,
- 10, NULL, NULL);
+ error = ata_atapicmd(stp->device, ccb, pagebuf, pagesize, ATA_R_READ, 10);
#ifdef AST_DEBUG
atapi_dump("ast: mode sense ", pagebuf, pagesize);
#endif
@@ -523,8 +581,7 @@ ast_mode_select(struct ast_softc *stp, void *pagebuf, int pagesize)
ata_prtdev(stp->device, "modeselect pagesize=%d\n", pagesize);
atapi_dump("mode select ", pagebuf, pagesize);
#endif
- return atapi_queue_cmd(stp->device, ccb, pagebuf, pagesize, 0,
- 10, NULL, NULL);
+ return ata_atapicmd(stp->device, ccb, pagebuf, pagesize, 0, 10);
}
static int
@@ -544,10 +601,10 @@ ast_write_filemark(struct ast_softc *stp, u_int8_t function)
stp->flags |= F_FM_WRITTEN;
}
}
- error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
+ error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
if (error)
return error;
- return atapi_wait_dsc(stp->device, 10*60);
+ return ast_wait_dsc(stp->device, 10*60);
}
static int
@@ -558,9 +615,8 @@ ast_read_position(struct ast_softc *stp, int hard,
0, 0, 0, 0, 0, 0, 0, 0 };
int error;
- error = atapi_queue_cmd(stp->device, ccb, (caddr_t)position,
- sizeof(struct ast_readposition), ATPR_F_READ, 10,
- NULL, NULL);
+ error = ata_atapicmd(stp->device, ccb, (caddr_t)position,
+ sizeof(struct ast_readposition), ATA_R_READ, 10);
position->tape = ntohl(position->tape);
position->host = ntohl(position->host);
return error;
@@ -572,7 +628,7 @@ ast_space(struct ast_softc *stp, u_int8_t function, int32_t count)
int8_t ccb[16] = { ATAPI_SPACE, function, count>>16, count>>8, count,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL);
+ return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60);
}
static int
@@ -583,10 +639,10 @@ ast_locate(struct ast_softc *stp, int hard, u_int32_t pos)
0, 0, 0, 0, 0, 0, 0, 0, 0 };
int error;
- error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
+ error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
if (error)
return error;
- return atapi_wait_dsc(stp->device, 60*60);
+ return ast_wait_dsc(stp->device, 60*60);
}
static int
@@ -595,7 +651,7 @@ ast_prevent_allow(struct ast_softc *stp, int lock)
int8_t ccb[16] = { ATAPI_PREVENT_ALLOW, 0, 0, 0, lock,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0,30, NULL, NULL);
+ return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 30);
}
static int
@@ -605,15 +661,15 @@ ast_load_unload(struct ast_softc *stp, u_int8_t function)
0, 0, 0, 0, 0, 0, 0, 0 };
int error;
- if ((function & SS_EJECT) && !stp->cap.eject)
+ if ((function & ATAPI_SS_EJECT) && !stp->cap.eject)
return 0;
- error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
+ error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
if (error)
return error;
tsleep((caddr_t)&error, PRIBIO, "astlu", 1 * hz);
- if (function == SS_EJECT)
+ if (function == ATAPI_SS_EJECT)
return 0;
- return atapi_wait_dsc(stp->device, 60*60);
+ return ast_wait_dsc(stp->device, 60*60);
}
static int
@@ -623,10 +679,10 @@ ast_rewind(struct ast_softc *stp)
0, 0, 0, 0, 0, 0, 0, 0 };
int error;
- error = atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 10, NULL, NULL);
+ error = ata_atapicmd(stp->device, ccb, NULL, 0, 0, 10);
if (error)
return error;
- return atapi_wait_dsc(stp->device, 60*60);
+ return ast_wait_dsc(stp->device, 60*60);
}
static int
@@ -639,5 +695,32 @@ ast_erase(struct ast_softc *stp)
if ((error = ast_rewind(stp)))
return error;
- return atapi_queue_cmd(stp->device, ccb, NULL, 0, 0, 60*60, NULL, NULL);
+ return ata_atapicmd(stp->device, ccb, NULL, 0, 0, 60*60);
+}
+
+static int
+ast_test_ready(struct ata_device *atadev)
+{
+ int8_t ccb[16] = { ATAPI_TEST_UNIT_READY, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ return ata_atapicmd(atadev, ccb, NULL, 0, 0, 30);
+}
+
+static int
+ast_wait_dsc(struct ata_device *atadev, int timeout)
+{
+ int error = 0;
+ int8_t ccb[16] = { ATAPI_POLL_DSC, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ timeout *= hz;
+ while (timeout > 0) {
+ error = ata_atapicmd(atadev, ccb, NULL, 0, 0, 0);
+ if (error != EBUSY)
+ break;
+ tsleep(&error, PRIBIO, "atpwt", hz / 2);
+ timeout -= (hz / 2);
+ }
+ return error;
}
diff --git a/sys/dev/ata/atapi-tape.h b/sys/dev/ata/atapi-tape.h
index 18b4449..77c9076 100644
--- a/sys/dev/ata/atapi-tape.h
+++ b/sys/dev/ata/atapi-tape.h
@@ -154,6 +154,7 @@ struct ast_softc {
#define F_ONSTREAM 0x0100 /* OnStream ADR device */
int blksize; /* block size (512 | 1024) */
+ struct mtx queue_mtx; /* queue lock */
struct bio_queue_head queue; /* queue of i/o requests */
struct atapi_params *param; /* drive parameters table */
struct ast_cappage cap; /* capabilities page info */
OpenPOWER on IntegriCloud