mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-24 11:29:10 +00:00
Add support for using DMA on dump, greatly speeds up the dump process.
Add dump support in ataraid.
This commit is contained in:
parent
9238d0aff6
commit
f5f55db308
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=154507
@ -63,7 +63,6 @@ static struct cdevsw ata_cdevsw = {
|
||||
};
|
||||
|
||||
/* prototypes */
|
||||
static void ata_interrupt(void *);
|
||||
static void ata_boot_attach(void);
|
||||
static device_t ata_add_child(device_t, struct ata_device *, int);
|
||||
static int ata_getparam(struct ata_device *, int);
|
||||
@ -139,7 +138,7 @@ ata_attach(device_t dev)
|
||||
return ENXIO;
|
||||
}
|
||||
if ((error = bus_setup_intr(dev, ch->r_irq, ATA_INTR_FLAGS,
|
||||
ata_interrupt, ch, &ch->ih))) {
|
||||
(driver_intr_t *)ata_interrupt, ch, &ch->ih))) {
|
||||
device_printf(dev, "unable to setup interrupt\n");
|
||||
return error;
|
||||
}
|
||||
@ -317,7 +316,7 @@ ata_resume(device_t dev)
|
||||
return error;
|
||||
}
|
||||
|
||||
static void
|
||||
int
|
||||
ata_interrupt(void *data)
|
||||
{
|
||||
struct ata_channel *ch = (struct ata_channel *)data;
|
||||
@ -325,20 +324,17 @@ ata_interrupt(void *data)
|
||||
|
||||
mtx_lock(&ch->state_mtx);
|
||||
do {
|
||||
/* ignore interrupt if its not for us */
|
||||
if (ch->hw.status && !ch->hw.status(ch->dev))
|
||||
break;
|
||||
|
||||
/* do we have a running request */
|
||||
if (!(request = ch->running))
|
||||
break;
|
||||
|
||||
ATA_DEBUG_RQ(request, "interrupt");
|
||||
|
||||
/* ignore interrupt if device is busy */
|
||||
if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
|
||||
DELAY(100);
|
||||
if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY)
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for the right state */
|
||||
/* safetycheck for the right state */
|
||||
if (ch->state != ATA_ACTIVE && ch->state != ATA_STALL_QUEUE) {
|
||||
device_printf(request->dev, "interrupt on idle channel ignored\n");
|
||||
break;
|
||||
@ -355,10 +351,11 @@ ata_interrupt(void *data)
|
||||
mtx_unlock(&ch->state_mtx);
|
||||
ATA_LOCKING(ch->dev, ATA_LF_UNLOCK);
|
||||
ata_finish(request);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
} while (0);
|
||||
mtx_unlock(&ch->state_mtx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -470,6 +470,7 @@ struct ata_dma {
|
||||
|
||||
/* structure holding lowlevel functions */
|
||||
struct ata_lowlevel {
|
||||
int (*status)(device_t dev);
|
||||
int (*begin_transaction)(struct ata_request *request);
|
||||
int (*end_transaction)(struct ata_request *request);
|
||||
int (*command)(struct ata_request *request);
|
||||
@ -495,6 +496,7 @@ struct ata_channel {
|
||||
#define ATA_USE_16BIT 0x02
|
||||
#define ATA_ATAPI_DMA_RO 0x04
|
||||
#define ATA_NO_48BIT_DMA 0x08
|
||||
#define ATA_ALWAYS_DMASTAT 0x10
|
||||
|
||||
int devices; /* what is present */
|
||||
#define ATA_ATA_MASTER 0x01
|
||||
@ -534,6 +536,7 @@ int ata_detach(device_t dev);
|
||||
int ata_reinit(device_t dev);
|
||||
int ata_suspend(device_t dev);
|
||||
int ata_resume(device_t dev);
|
||||
int ata_interrupt(void *data);
|
||||
int ata_device_ioctl(device_t dev, u_long cmd, caddr_t data);
|
||||
int ata_identify(device_t dev);
|
||||
void ata_default_registers(device_t dev);
|
||||
@ -558,6 +561,8 @@ char *ata_cmd2str(struct ata_request *request);
|
||||
|
||||
/* ata-lowlevel.c: */
|
||||
void ata_generic_hw(device_t dev);
|
||||
int ata_begin_transaction(struct ata_request *);
|
||||
int ata_end_transaction(struct ata_request *);
|
||||
void ata_generic_reset(device_t dev);
|
||||
int ata_generic_command(struct ata_request *request);
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -289,45 +289,23 @@ ad_ioctl(struct disk *disk, u_long cmd, void *data, int flag, struct thread *td)
|
||||
|
||||
static int
|
||||
ad_dump(void *arg, void *virtual, vm_offset_t physical,
|
||||
off_t offset, size_t length)
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
struct disk *dp = arg;
|
||||
device_t dev = dp->d_drv1;
|
||||
struct ata_device *atadev = device_get_softc(dev);
|
||||
struct ad_softc *adp = device_get_ivars(dev);
|
||||
struct ata_channel *ch = device_get_softc(device_get_parent(dev));
|
||||
struct ata_request request;
|
||||
struct bio bp;
|
||||
|
||||
if (!adp)
|
||||
return ENXIO;
|
||||
/* length zero is special and really means flush buffers to media */
|
||||
if (!length)
|
||||
return ata_controlcmd(dp->d_drv1, ATA_FLUSHCACHE, 0, 0, 0);
|
||||
|
||||
bzero(&request, sizeof(struct ata_request));
|
||||
request.dev = dev;
|
||||
|
||||
if (length) {
|
||||
request.data = virtual;
|
||||
request.bytecount = length;
|
||||
request.transfersize = min(length, atadev->max_iosize);
|
||||
request.flags = ATA_R_WRITE;
|
||||
if (atadev->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;
|
||||
}
|
||||
else {
|
||||
request.u.ata.command = ATA_FLUSHCACHE;
|
||||
request.flags = ATA_R_CONTROL;
|
||||
}
|
||||
if (ch->hw.begin_transaction(&request) == ATA_OP_CONTINUES) {
|
||||
do {
|
||||
DELAY(20);
|
||||
} while (ch->hw.end_transaction(&request) == ATA_OP_CONTINUES);
|
||||
}
|
||||
if (request.status & ATA_S_ERROR)
|
||||
return EIO;
|
||||
return 0;
|
||||
bzero(&bp, sizeof(struct bio));
|
||||
bp.bio_disk = dp;
|
||||
bp.bio_pblkno = offset / DEV_BSIZE;
|
||||
bp.bio_bcount = length;
|
||||
bp.bio_data = virtual;
|
||||
bp.bio_cmd = BIO_WRITE;
|
||||
ad_strategy(&bp);
|
||||
return bp.bio_error;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -46,8 +46,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <ata_if.h>
|
||||
|
||||
/* prototypes */
|
||||
static int ata_begin_transaction(struct ata_request *);
|
||||
static int ata_end_transaction(struct ata_request *);
|
||||
static int ata_generic_status(device_t dev);
|
||||
static int ata_wait(struct ata_channel *ch, struct ata_device *, u_int8_t);
|
||||
static void ata_pio_read(struct ata_request *, int);
|
||||
static void ata_pio_write(struct ata_request *, int);
|
||||
@ -62,11 +61,12 @@ ata_generic_hw(device_t dev)
|
||||
|
||||
ch->hw.begin_transaction = ata_begin_transaction;
|
||||
ch->hw.end_transaction = ata_end_transaction;
|
||||
ch->hw.status = ata_generic_status;
|
||||
ch->hw.command = ata_generic_command;
|
||||
}
|
||||
|
||||
/* must be called with ATA channel locked and state_mtx held */
|
||||
static int
|
||||
int
|
||||
ata_begin_transaction(struct ata_request *request)
|
||||
{
|
||||
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
|
||||
@ -220,7 +220,7 @@ ata_begin_transaction(struct ata_request *request)
|
||||
}
|
||||
|
||||
/* must be called with ATA channel locked and state_mtx held */
|
||||
static int
|
||||
int
|
||||
ata_end_transaction(struct ata_request *request)
|
||||
{
|
||||
struct ata_channel *ch = device_get_softc(device_get_parent(request->dev));
|
||||
@ -470,7 +470,7 @@ ata_end_transaction(struct ata_request *request)
|
||||
return ATA_OP_CONTINUES;
|
||||
}
|
||||
|
||||
/* must be called with ATA channel locked */
|
||||
/* must be called with ATA channel locked and state_mtx held */
|
||||
void
|
||||
ata_generic_reset(device_t dev)
|
||||
{
|
||||
@ -605,6 +605,20 @@ ata_generic_reset(device_t dev)
|
||||
"\20\4ATAPI_SLAVE\3ATAPI_MASTER\2ATA_SLAVE\1ATA_MASTER");
|
||||
}
|
||||
|
||||
/* must be called with ATA channel locked and state_mtx held */
|
||||
int
|
||||
ata_generic_status(device_t dev)
|
||||
{
|
||||
struct ata_channel *ch = device_get_softc(dev);
|
||||
|
||||
if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
|
||||
DELAY(100);
|
||||
if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ata_wait(struct ata_channel *ch, struct ata_device *atadev, u_int8_t mask)
|
||||
{
|
||||
|
@ -203,7 +203,8 @@ ata_pci_attach(device_t dev)
|
||||
RF_ACTIVE);
|
||||
}
|
||||
|
||||
ctlr->chipinit(dev);
|
||||
if (ctlr->chipinit(dev))
|
||||
return ENXIO;
|
||||
|
||||
/* attach all channels on this controller */
|
||||
for (unit = 0; unit < ctlr->channels; unit++) {
|
||||
@ -420,10 +421,42 @@ ata_pci_allocate(device_t dev)
|
||||
}
|
||||
}
|
||||
|
||||
ata_generic_hw(dev);
|
||||
ata_pci_hw(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ata_pci_hw(device_t dev)
|
||||
{
|
||||
struct ata_channel *ch = device_get_softc(dev);
|
||||
|
||||
ata_generic_hw(dev);
|
||||
ch->hw.status = ata_pci_status;
|
||||
}
|
||||
|
||||
int
|
||||
ata_pci_status(device_t dev)
|
||||
{
|
||||
struct ata_channel *ch = device_get_softc(dev);
|
||||
|
||||
if (ch->dma && ((ch->flags & ATA_ALWAYS_DMASTAT) ||
|
||||
(ch->dma->flags & ATA_DMA_ACTIVE))) {
|
||||
int bmstat = ATA_IDX_INB(ch, ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK;
|
||||
|
||||
if ((bmstat & (ATA_BMSTAT_ACTIVE | ATA_BMSTAT_INTERRUPT)) !=
|
||||
ATA_BMSTAT_INTERRUPT)
|
||||
return 0;
|
||||
ATA_IDX_OUTB(ch, ATA_BMSTAT_PORT, bmstat & ~ATA_BMSTAT_ERROR);
|
||||
DELAY(1);
|
||||
}
|
||||
if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY) {
|
||||
DELAY(100);
|
||||
if (ATA_IDX_INB(ch, ATA_ALTSTAT) & ATA_S_BUSY)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ata_pci_dmastart(device_t dev)
|
||||
{
|
||||
|
@ -392,6 +392,9 @@ int ata_pci_release_resource(device_t dev, device_t child, int type, int rid, st
|
||||
int ata_pci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, driver_intr_t *function, void *argument, void **cookiep);
|
||||
int ata_pci_teardown_intr(device_t dev, device_t child, struct resource *irq, void *cookie);
|
||||
int ata_pci_allocate(device_t dev);
|
||||
void ata_pci_hw(device_t dev);
|
||||
int ata_pci_status(device_t dev);
|
||||
|
||||
|
||||
/* global prototypes ata-chipset.c */
|
||||
int ata_generic_ident(device_t);
|
||||
@ -413,7 +416,6 @@ int ata_sii_ident(device_t);
|
||||
int ata_sis_ident(device_t);
|
||||
int ata_via_ident(device_t);
|
||||
int ata_legacy(device_t);
|
||||
struct ata_chip_id *ata_match_chip(device_t, struct ata_chip_id *);
|
||||
|
||||
/* global prototypes ata-dma.c */
|
||||
void ata_dmainit(device_t);
|
||||
|
@ -94,7 +94,8 @@ ata_queue_request(struct ata_request *request)
|
||||
/* if this is not a callback wait until request is completed */
|
||||
if (!request->callback) {
|
||||
ATA_DEBUG_RQ(request, "wait for completition");
|
||||
while (sema_timedwait(&request->done, request->timeout * hz * 4)) {
|
||||
while (!dumping &&
|
||||
sema_timedwait(&request->done, request->timeout * hz * 4)) {
|
||||
device_printf(request->dev,
|
||||
"req=%p %s semaphore timeout !! DANGER Will Robinson !!\n",
|
||||
request, ata_cmd2str(request));
|
||||
@ -200,6 +201,13 @@ ata_start(device_t dev)
|
||||
ata_finish(request);
|
||||
return;
|
||||
}
|
||||
if (dumping) {
|
||||
mtx_unlock(&ch->state_mtx);
|
||||
mtx_unlock(&ch->queue_mtx);
|
||||
while (!ata_interrupt(ch))
|
||||
DELAY(10);
|
||||
return;
|
||||
}
|
||||
}
|
||||
mtx_unlock(&ch->state_mtx);
|
||||
}
|
||||
@ -216,7 +224,8 @@ ata_finish(struct ata_request *request)
|
||||
* if in ATA_STALL_QUEUE state or request has ATA_R_DIRECT flags set
|
||||
* we need to call ata_complete() directly here (no taskqueue involvement)
|
||||
*/
|
||||
if ((ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) {
|
||||
if (dumping ||
|
||||
(ch->state & ATA_STALL_QUEUE) || (request->flags & ATA_R_DIRECT)) {
|
||||
ATA_DEBUG_RQ(request, "finish directly");
|
||||
ata_completed(request, 0);
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ static int testing = 0;
|
||||
|
||||
/* device structures */
|
||||
static disk_strategy_t ata_raid_strategy;
|
||||
//static dumper_t ata_raid_dump;
|
||||
static dumper_t ata_raid_dump;
|
||||
|
||||
static void
|
||||
ata_raid_attach(struct ar_softc *rdp, int writeback)
|
||||
@ -134,7 +134,7 @@ ata_raid_attach(struct ar_softc *rdp, int writeback)
|
||||
buffer[0] = '\0';
|
||||
rdp->disk = disk_alloc();
|
||||
rdp->disk->d_strategy = ata_raid_strategy;
|
||||
//rdp->disk->d_dump = ata_raid_dump;
|
||||
rdp->disk->d_dump = ata_raid_dump;
|
||||
rdp->disk->d_name = "ar";
|
||||
rdp->disk->d_sectorsize = DEV_BSIZE;
|
||||
rdp->disk->d_mediasize = (off_t)rdp->total_sectors * DEV_BSIZE;
|
||||
@ -751,6 +751,35 @@ ata_raid_done(struct ata_request *request)
|
||||
ata_free_request(request);
|
||||
}
|
||||
|
||||
static int
|
||||
ata_raid_dump(void *arg, void *virtual, vm_offset_t physical,
|
||||
off_t offset, size_t length)
|
||||
{
|
||||
struct disk *dp = arg;
|
||||
struct ar_softc *rdp = dp->d_drv1;
|
||||
struct bio bp;
|
||||
|
||||
/* length zero is special and really means flush buffers to media */
|
||||
if (!length) {
|
||||
int disk, error;
|
||||
|
||||
for (disk = 0, error = 0; disk < rdp->total_disks; disk++)
|
||||
if (rdp->disks[disk].dev)
|
||||
error |= ata_controlcmd(rdp->disks[disk].dev,
|
||||
ATA_FLUSHCACHE, 0, 0, 0);
|
||||
return (error ? EIO : 0);
|
||||
}
|
||||
|
||||
bzero(&bp, sizeof(struct bio));
|
||||
bp.bio_disk = dp;
|
||||
bp.bio_pblkno = offset / DEV_BSIZE;
|
||||
bp.bio_bcount = length;
|
||||
bp.bio_data = virtual;
|
||||
bp.bio_cmd = BIO_WRITE;
|
||||
ata_raid_strategy(&bp);
|
||||
return bp.bio_error;
|
||||
}
|
||||
|
||||
static void
|
||||
ata_raid_config_changed(struct ar_softc *rdp, int writeback)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user