summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorsos <sos@FreeBSD.org>2003-08-24 09:22:26 +0000
committersos <sos@FreeBSD.org>2003-08-24 09:22:26 +0000
commitacd43345e5181bc90912ee1da2b67fd9c3d9c7f6 (patch)
treefc8660c3fbead647641e9e7a6968b5a490dfd90f /sys
parent2b41ad87c9729efcb95d20102fb76ef2684cb633 (diff)
downloadFreeBSD-src-acd43345e5181bc90912ee1da2b67fd9c3d9c7f6.zip
FreeBSD-src-acd43345e5181bc90912ee1da2b67fd9c3d9c7f6.tar.gz
This is a major rework of the ATA driver (ATAng)
Restructure the way ATA/ATAPI commands are processed, use a common ata_request structure for both. This centralises the way requests are handled so locking is much easier to handle. The driver is now layered much more cleanly to seperate the lowlevel HW access so it can be tailored to specific controllers without touching the upper layers. This is needed to support some of the newer semi-intelligent ATA controllers showing up. The top level drivers (disk, ATAPI devices) are more or less still the same with just corrections to use the new interface. Pull ATA out from under Gaint now that locking can be done in a sane way. Add support for a the National Geode SC1100. Thanks to Soekris engineering for sponsoring a Soekris 4801 to make this support. Fixed alot of small bugs in the chipset code for various chips now we are around in that corner anyways.
Diffstat (limited to 'sys')
-rw-r--r--sys/conf/NOTES4
-rw-r--r--sys/conf/files8
-rw-r--r--sys/conf/options5
-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
-rw-r--r--sys/sys/ata.h483
29 files changed, 3563 insertions, 3934 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES
index 6ab5036..05fcfe9 100644
--- a/sys/conf/NOTES
+++ b/sys/conf/NOTES
@@ -2352,14 +2352,10 @@ options KSTACK_MAX_PAGES=32 # Maximum pages to give the kernel stack
# Yet more undocumented options for linting.
options AAC_DEBUG
-options ACD_DEBUG
options ACPI_MAX_THREADS=1
#!options ACPI_NO_SEMAPHORES
# Broken:
##options ASR_MEASURE_PERFORMANCE
-options AST_DEBUG
-options ATAPI_DEBUG
-options ATA_DEBUG
# BKTR_ALLOC_PAGES has no effect except to cause warnings, and
# BROOKTREE_ALLOC_PAGES hasn't actually been superseded by it, since the
# driver still mostly spells this option BROOKTREE_ALLOC_PAGES.
diff --git a/sys/conf/files b/sys/conf/files
index abda8dc..ab7788d 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -302,6 +302,8 @@ dev/an/if_an_pccard.c optional an pccard
dev/an/if_an_pci.c optional an pci
dev/asr/asr.c optional asr pci
dev/ata/ata-all.c optional ata
+dev/ata/ata-queue.c optional ata
+dev/ata/ata-lowlevel.c optional ata
dev/ata/ata-isa.c optional ata isa
dev/ata/ata-cbus.c optional ata pc98
dev/ata/ata-card.c optional ata card
@@ -310,11 +312,7 @@ dev/ata/ata-pci.c optional ata pci
dev/ata/ata-chipset.c optional ata pci
dev/ata/ata-dma.c optional ata pci
dev/ata/ata-disk.c optional atadisk
-dev/ata/ata-raid.c optional atadisk
-dev/ata/atapi-all.c optional atapicd
-dev/ata/atapi-all.c optional atapifd
-dev/ata/atapi-all.c optional atapist
-dev/ata/atapi-all.c optional atapicam
+dev/ata/ata-raid.c optional ataraid
dev/ata/atapi-cd.c optional atapicd
dev/ata/atapi-fd.c optional atapifd
dev/ata/atapi-tape.c optional atapist
diff --git a/sys/conf/options b/sys/conf/options
index 3a1ed5e..29fc475 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -297,13 +297,10 @@ ISP_TARGET_MODE opt_isp.h
ISP_FW_CRASH_DUMP opt_isp.h
# Options used in the 'ata' ATA/ATAPI driver
-ACD_DEBUG opt_ata.h
-AST_DEBUG opt_ata.h
-ATAPI_DEBUG opt_ata.h
-ATA_DEBUG opt_ata.h
ATA_STATIC_ID opt_ata.h
ATA_NOPCI opt_ata.h
DEV_ATADISK opt_ata.h
+DEV_ATARAID opt_ata.h
DEV_ATAPICD opt_ata.h
DEV_ATAPIST opt_ata.h
DEV_ATAPIFD opt_ata.h
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 */
diff --git a/sys/sys/ata.h b/sys/sys/ata.h
index f40d8be..e10b8b4 100644
--- a/sys/sys/ata.h
+++ b/sys/sys/ata.h
@@ -33,57 +33,22 @@
#include <sys/ioccom.h>
-#define ATAPI_PSIZE_12 0 /* 12 bytes */
-#define ATAPI_PSIZE_16 1 /* 16 bytes */
-
-#define ATAPI_DRQT_MPROC 0 /* cpu 3 ms delay */
-#define ATAPI_DRQT_INTR 1 /* intr 10 ms delay */
-#define ATAPI_DRQT_ACCEL 2 /* accel 50 us delay */
-
-#define ATAPI_TYPE_DIRECT 0 /* disk/floppy */
-#define ATAPI_TYPE_TAPE 1 /* streaming tape */
-#define ATAPI_TYPE_CDROM 5 /* CD-ROM device */
-#define ATAPI_TYPE_OPTICAL 7 /* optical disk */
-
-#define ATA_PROTO_ATA 0
-#define ATA_PROTO_ATAPI 1
-
-#define ATA_BT_SINGLEPORTSECTOR 1 /* 1 port, 1 sector buffer */
-#define ATA_BT_DUALPORTMULTI 2 /* 2 port, mult sector buffer */
-#define ATA_BT_DUALPORTMULTICACHE 3 /* above plus track cache */
-
-#define ATA_FLAG_54_58 1 /* words 54-58 valid */
-#define ATA_FLAG_64_70 2 /* words 64-70 valid */
-#define ATA_FLAG_88 4 /* word 88 valid */
-
-/* ATA/ATAPI device parameter information */
+/* ATA/ATAPI device parameters */
struct ata_params {
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-/*000*/ u_int16_t packet_size :2; /* packet command size */
-
- u_int16_t incomplete :1;
- u_int16_t :2;
- u_int16_t drq_type :2; /* DRQ type */
-
- u_int16_t removable :1; /* device is removable */
- u_int16_t type :5; /* device type */
-
- u_int16_t :2;
- u_int16_t cmd_protocol :1; /* command protocol */
-#else
- u_int16_t cmd_protocol :1; /* command protocol */
- u_int16_t :2;
-
- u_int16_t type :5; /* device type */
- u_int16_t removable :1; /* device is removable */
-
- u_int16_t drq_type :2; /* DRQ type */
- u_int16_t :2;
- u_int16_t incomplete :1;
-
- u_int16_t packet_size :2; /* packet command size */
-#endif
+/*000*/ u_int16_t config; /* configuration info */
+#define ATA_PROTO_MASK 0x8003
+#define ATA_PROTO_ATA 0x0002
+#define ATA_PROTO_ATAPI_12 0x8000
+#define ATA_PROTO_ATAPI_16 0x8001
+#define ATA_ATAPI_TYPE_MASK 0x1f00
+#define ATA_ATAPI_TYPE_DIRECT 0x0000 /* disk/floppy */
+#define ATA_ATAPI_TYPE_TAPE 0x0100 /* streaming tape */
+#define ATA_ATAPI_TYPE_CDROM 0x0500 /* CD-ROM device */
+#define ATA_ATAPI_TYPE_OPTICAL 0x0700 /* optical disk */
+#define ATA_DRQ_MASK 0x0060
+#define ATA_DRQ_SLOW 0x0000 /* cpu 3 ms delay */
+#define ATA_DRQ_INTR 0x0020 /* interrupt 10 ms delay */
+#define ATA_DRQ_FAST 0x0040 /* accel 50 us delay */
/*001*/ u_int16_t cylinders; /* # of cylinders */
u_int16_t reserved2;
@@ -93,77 +58,33 @@ struct ata_params {
/*006*/ u_int16_t sectors; /* # sectors/track */
/*007*/ u_int16_t vendor7[3];
/*010*/ u_int8_t serial[20]; /* serial number */
- u_int16_t retired20;
+/*020*/ u_int16_t retired20;
u_int16_t retired21;
u_int16_t obsolete22;
/*023*/ u_int8_t revision[8]; /* firmware revision */
/*027*/ u_int8_t model[40]; /* model name */
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-/*047*/ u_int16_t sectors_intr:8; /* sectors per interrupt */
- u_int16_t :8;
-#else
- u_int16_t :8;
- u_int16_t sectors_intr:8; /* sectors per interrupt */
-#endif
-
+/*047*/ u_int16_t sectors_intr; /* sectors per interrupt */
/*048*/ u_int16_t usedmovsd; /* double word read/write? */
+/*049*/ u_int16_t capabilities1;
+#define ATA_SUPPORT_DMA 0x0100
+#define ATA_SUPPORT_LBA 0x0200
+#define ATA_SUPPORT_OVERLAP 0x4000
-#if BYTE_ORDER == LITTLE_ENDIAN
-/*049*/ u_int16_t retired49:8;
- u_int16_t support_dma :1; /* DMA supported */
- u_int16_t support_lba :1; /* LBA supported */
- u_int16_t disable_iordy :1; /* IORDY may be disabled */
- u_int16_t support_iordy :1; /* IORDY supported */
- u_int16_t softreset :1; /* needs softreset when busy */
- u_int16_t stdby_ovlap :1; /* standby/overlap supported */
- u_int16_t support_queueing:1; /* supports queuing overlap */
- u_int16_t support_idma :1; /* interleaved DMA supported */
-
-/*050*/ u_int16_t device_stdby_min:1;
- u_int16_t :13;
- u_int16_t capability_one:1;
- u_int16_t capability_zero:1;
-
-/*051*/ u_int16_t vendor51:8;
- u_int16_t retired_piomode:8; /* PIO modes 0-2 */
-/*052*/ u_int16_t vendor52:8;
- u_int16_t retired_dmamode:8; /* DMA modes, not ATA-3 */
-#else
- u_int16_t support_idma :1; /* interleaved DMA supported */
- u_int16_t support_queueing:1; /* supports queuing overlap */
- u_int16_t stdby_ovlap :1; /* standby/overlap supported */
- u_int16_t softreset :1; /* needs softreset when busy */
- u_int16_t support_iordy :1; /* IORDY supported */
- u_int16_t disable_iordy :1; /* IORDY may be disabled */
- u_int16_t support_lba :1; /* LBA supported */
- u_int16_t support_dma :1; /* DMA supported */
- u_int16_t retired49:8;
-
- u_int16_t capability_zero:1;
- u_int16_t capability_one:1;
- u_int16_t :13;
- u_int16_t device_stdby_min:1;
-
- u_int16_t retired_piomode:8; /* PIO modes 0-2 */
- u_int16_t vendor51:8;
- u_int16_t retired_dmamode:8; /* DMA modes, not ATA-3 */
- u_int16_t vendor52:8;
-#endif
+/*050*/ u_int16_t capabilities2;
+/*051*/ u_int16_t retired_piomode; /* PIO modes 0-2 */
+#define ATA_RETIRED_PIO_MASK 0x0003
-/*053*/ u_int16_t atavalid; /* fields valid */
+/*052*/ u_int16_t retired_dmamode; /* DMA modes */
+#define ATA_RETIRED_DMA_MASK 0x0003
- u_int16_t obsolete54[5];
+/*053*/ u_int16_t atavalid; /* fields valid */
+#define ATA_FLAG_54_58 0x0001 /* words 54-58 valid */
+#define ATA_FLAG_64_70 0x0002 /* words 64-70 valid */
+#define ATA_FLAG_88 0x0004 /* word 88 valid */
-#if BYTE_ORDER == LITTLE_ENDIAN
-/*059*/ u_int16_t multi_count:8;
- u_int16_t multi_valid:1;
- u_int16_t :7;
-#else
- u_int16_t :7;
- u_int16_t multi_valid:1;
- u_int16_t multi_count:8;
-#endif
+/*054*/ u_int16_t obsolete54[5];
+/*059*/ u_int16_t multi;
+#define ATA_MULTI_VALID 0x0100
/*060*/ u_int16_t lba_size_1;
u_int16_t lba_size_2;
@@ -181,14 +102,8 @@ struct ata_params {
/*072*/ u_int16_t rlsservice; /* rel time (us) for service */
u_int16_t reserved73;
u_int16_t reserved74;
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-/*075*/ u_int16_t queuelen:5;
- u_int16_t :11;
-#else
- u_int16_t :11;
- u_int16_t queuelen:5;
-#endif
+/*075*/ u_int16_t queue;
+#define ATA_QUEUE_LEN(x) ((x) & 0x001f)
u_int16_t reserved76;
u_int16_t reserved77;
@@ -196,96 +111,40 @@ struct ata_params {
u_int16_t reserved79;
/*080*/ u_int16_t version_major;
/*081*/ u_int16_t version_minor;
+
struct {
-#if BYTE_ORDER == LITTLE_ENDIAN
-/*082/085*/ u_int16_t smart:1;
- u_int16_t security:1;
- u_int16_t removable:1;
- u_int16_t power_mngt:1;
- u_int16_t packet:1;
- u_int16_t write_cache:1;
- u_int16_t look_ahead:1;
- u_int16_t release_irq:1;
- u_int16_t service_irq:1;
- u_int16_t reset:1;
- u_int16_t protected:1;
- u_int16_t :1;
- u_int16_t write_buffer:1;
- u_int16_t read_buffer:1;
- u_int16_t nop:1;
- u_int16_t :1;
-
-/*083/086*/ u_int16_t microcode:1;
- u_int16_t queued:1;
- u_int16_t cfa:1;
- u_int16_t apm:1;
- u_int16_t notify:1;
- u_int16_t standby:1;
- u_int16_t spinup:1;
- u_int16_t :1;
- u_int16_t max_security:1;
- u_int16_t auto_acoustic:1;
- u_int16_t address48:1;
- u_int16_t config_overlay:1;
- u_int16_t flush_cache:1;
- u_int16_t flush_cache48:1;
- u_int16_t support_one:1;
- u_int16_t support_zero:1;
-
-/*084/087*/ u_int16_t smart_error_log:1;
- u_int16_t smart_self_test:1;
- u_int16_t media_serial_no:1;
- u_int16_t media_card_pass:1;
- u_int16_t streaming:1;
- u_int16_t logging:1;
- u_int16_t :8;
- u_int16_t extended_one:1;
- u_int16_t extended_zero:1;
-#else
- u_int16_t :1;
- u_int16_t nop:1;
- u_int16_t read_buffer:1;
- u_int16_t write_buffer:1;
- u_int16_t :1;
- u_int16_t protected:1;
- u_int16_t reset:1;
- u_int16_t service_irq:1;
- u_int16_t release_irq:1;
- u_int16_t look_ahead:1;
- u_int16_t write_cache:1;
- u_int16_t packet:1;
- u_int16_t power_mngt:1;
- u_int16_t removable:1;
- u_int16_t security:1;
- u_int16_t smart:1;
-
- u_int16_t support_zero:1;
- u_int16_t support_one:1;
- u_int16_t flush_cache48:1;
- u_int16_t flush_cache:1;
- u_int16_t config_overlay:1;
- u_int16_t address48:1;
- u_int16_t auto_acoustic:1;
- u_int16_t max_security:1;
- u_int16_t :1;
- u_int16_t spinup:1;
- u_int16_t standby:1;
- u_int16_t notify:1;
- u_int16_t apm:1;
- u_int16_t cfa:1;
- u_int16_t queued:1;
- u_int16_t microcode:1;
-
- u_int16_t extended_zero:1;
- u_int16_t extended_one:1;
- u_int16_t :8;
- u_int16_t logging:1;
- u_int16_t streaming:1;
- u_int16_t media_card_pass:1;
- u_int16_t media_serial_no:1;
- u_int16_t smart_self_test:1;
- u_int16_t smart_error_log:1;
-#endif
+/*082/085*/ u_int16_t command1;
+#define ATA_SUPPORT_SMART 0x0001
+#define ATA_SUPPORT_SECURITY 0x0002
+#define ATA_SUPPORT_REMOVABLE 0x0004
+#define ATA_SUPPORT_POWERMGT 0x0008
+#define ATA_SUPPORT_PACKET 0x0010
+#define ATA_SUPPORT_WRITECACHE 0x0020
+#define ATA_SUPPORT_LOOKAHEAD 0x0040
+#define ATA_SUPPORT_RELEASEIRQ 0x0080
+#define ATA_SUPPORT_SERVICEIRQ 0x0100
+#define ATA_SUPPORT_RESET 0x0200
+#define ATA_SUPPORT_PROTECTED 0x0400
+#define ATA_SUPPORT_WRITEBUFFER 0x1000
+#define ATA_SUPPORT_READBUFFER 0x2000
+#define ATA_SUPPORT_NOP 0x4000
+
+/*083/086*/ u_int16_t command2;
+#define ATA_SUPPORT_MICROCODE 0x0001
+#define ATA_SUPPORT_QUEUED 0x0002
+#define ATA_SUPPORT_CFA 0x0004
+#define ATA_SUPPORT_APM 0x0008
+#define ATA_SUPPORT_NOTIFY 0x0010
+#define ATA_SUPPORT_STANDBY 0x0020
+#define ATA_SUPPORT_SPINUP 0x0040
+#define ATA_SUPPORT_MAXSECURITY 0x0100
+#define ATA_SUPPORT_AUTOACOUSTIC 0x0200
+#define ATA_SUPPORT_ADDRESS48 0x0400
+#define ATA_SUPPORT_OVERLAY 0x0800
+#define ATA_SUPPORT_FLUSHCACHE 0x1000
+#define ATA_SUPPORT_FLUSHCACHE48 0x2000
+
+/*084/087*/ u_int16_t extension;
} support, enabled;
/*088*/ u_int16_t udmamodes; /* UltraDMA modes */
@@ -293,24 +152,12 @@ struct ata_params {
/*090*/ u_int16_t enhanced_erase_time;
/*091*/ u_int16_t apm_value;
/*092*/ u_int16_t master_passwd_revision;
+/*093*/ u_int16_t hwres;
+#define ATA_CABLE_ID 0x2000
-#if BYTE_ORDER == LITTLE_ENDIAN
-/*093*/ u_int16_t hwres_master :8;
- u_int16_t hwres_slave :5;
- u_int16_t hwres_cblid :1;
- u_int16_t hwres_valid:2;
-
-/*094*/ u_int16_t current_acoustic:8;
- u_int16_t vendor_acoustic:8;
-#else
- u_int16_t hwres_valid:2;
- u_int16_t hwres_cblid :1;
- u_int16_t hwres_slave :5;
- u_int16_t hwres_master :8;
-
- u_int16_t vendor_acoustic:8;
- u_int16_t current_acoustic:8;
-#endif
+/*094*/ u_int16_t acoustic;
+#define ATA_ACOUSTIC_CURRENT(x) ((x) & 0x00ff)
+#define ATA_ACOUSTIC_VENDOR(x) (((x) & 0xff00) >> 8)
/*095*/ u_int16_t stream_min_req_size;
/*096*/ u_int16_t stream_transfer_time;
@@ -331,6 +178,7 @@ struct ata_params {
/*255*/ u_int16_t integrity;
};
+/* ATA transfer modes */
#define ATA_MODE_MASK 0x0f
#define ATA_DMA_MASK 0xf0
#define ATA_PIO 0x00
@@ -354,34 +202,160 @@ struct ata_params {
#define ATA_SA150 0x47
#define ATA_DMA_MAX 0x4f
+/* 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 */
+
struct ata_cmd {
int channel;
int device;
int cmd;
-#define ATAGPARM 1
-#define ATAGMODE 2
-#define ATASMODE 3
-#define ATAREINIT 4
-#define ATAATTACH 5
-#define ATADETACH 6
-#define ATAPICMD 7
-#define ATARAIDREBUILD 8
-#define ATARAIDCREATE 9
-#define ATARAIDDELETE 10
-#define ATARAIDSTATUS 11
-#define ATAENCSTAT 12
-#define ATAGMAXCHANNEL 13
-#define ATARAIDADDSPARE 14
+#define ATAGMAXCHANNEL 0x0101
+#define ATAGPARM 0x0102
+#define ATAGMODE 0x0103
+#define ATASMODE 0x0104
+#define ATAREQUEST 0x0108
+#define ATAREINIT 0x0110
+#define ATAATTACH 0x0111
+#define ATADETACH 0x0112
+#define ATARAIDCREATE 0x0120
+#define ATARAIDDELETE 0x0121
+#define ATARAIDSTATUS 0x0122
+#define ATARAIDADDSPARE 0x0123
+#define ATARAIDREBUILD 0x0124
+#define ATAENCSTAT 0x0130
union {
- struct {
- int mode[2];
- } mode;
+ int maxchan;
+
struct {
int type[2];
char name[2][32];
struct ata_params params[2];
} param;
+
+ struct {
+ int mode[2];
+ } mode;
+
+ struct {
+ union {
+ struct {
+ u_int8_t command;
+ u_int8_t feature;
+ u_int64_t lba;
+ u_int16_t count;
+ } ata;
+ struct {
+ char ccb[16];
+ } atapi;
+ } u;
+ caddr_t data;
+ int count;
+ int flags;
+#define ATA_CMD_CONTROL 0x01
+#define ATA_CMD_READ 0x02
+#define ATA_CMD_WRITE 0x04
+#define ATA_CMD_ATAPI 0x08
+
+ int timeout;
+ int error;
+ } request;
+
struct raid_setup {
int type;
#define AR_RAID0 1
@@ -393,9 +367,7 @@ struct ata_cmd {
int interleave;
int unit;
} raid_setup;
- struct {
- int disk;
- } raid_spare;
+
struct raid_status {
int type;
int total_disks;
@@ -408,26 +380,17 @@ struct ata_cmd {
int progress;
} raid_status;
+
+ struct {
+ int disk;
+ } raid_spare;
+
struct {
int fan;
int temp;
int v05;
int v12;
} enclosure;
- struct {
- char ccb[16];
- caddr_t data;
- int count;
- int flags;
-#define ATAPI_CMD_CTRL 0x00
-#define ATAPI_CMD_READ 0x01
-#define ATAPI_CMD_WRITE 0x02
-
- int timeout;
- int error;
- char sense_data[18];
- } atapi;
- int maxchan;
} u;
};
OpenPOWER on IntegriCloud