[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [tyndur-devel] [PATCH] ata: Unterstuetzung fuer DMA
Am Sonntag, 17. Mai 2009 21:03 schrieb Antoine Kaufmann:
> + ata: Unterstuetzung fuer PCI-DMA
> ---
> build/config/grub_hd.cfg | 1 +
> src/modules/cdi/ata/ata.c | 67 ++++++++++++++-------
> src/modules/cdi/ata/device.c | 37 +++++++-----
> src/modules/cdi/ata/device.h | 53 +++++++++++++++--
> src/modules/cdi/ata/main.c | 47 ++++++++++++++-
> src/modules/cdi/ata/request.c | 132
> +++++++++++++++++++++++++++++++++++++++-- 6 files changed, 287
> insertions(+), 50 deletions(-)
>
> diff --git a/build/config/grub_hd.cfg b/build/config/grub_hd.cfg
> index f29cd6a..cd0f4f2 100644
> --- a/build/config/grub_hd.cfg
> +++ b/build/config/grub_hd.cfg
> @@ -1,6 +1,7 @@
> title tyndur
> kernel /boot/tyndur debug=s
> module /modules/init boot=file:/
> +module /modules/pci
> module /modules/ata
> module /modules/ext2
> module /modules/console servmgr:/term servmgr:/term
> diff --git a/src/modules/cdi/ata/ata.c b/src/modules/cdi/ata/ata.c
> index 14e777b..7710e9a 100644
> --- a/src/modules/cdi/ata/ata.c
> +++ b/src/modules/cdi/ata/ata.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2007 The tyndur Project. All rights reserved.
> + * Copyright (c) 2007-2009 The tyndur Project. All rights reserved.
> *
> * This code is derived from software contributed to the tyndur Project
> * by Antoine Kaufmann.
> @@ -86,6 +86,11 @@ int ata_drv_identify(struct ata_device* dev)
> dev->dev.storage.block_count = id.lba_sector_count;
> }
>
> + // Pruefen ob DMA unterstuetzt wird
> + if (id.capabilities.dma) {
> + dev->dma = 1;
> + }
> +
> // Wenn keiner der LBA-Modi unterstuetzt wird, muss abgebrochen
> werden, da // CHS noch nicht implementiert ist.
> if (!dev->lba48 && !dev->lba28) {
> @@ -122,38 +127,56 @@ static int ata_drv_rw_sectors(struct ata_device* dev,
> int direction, uint16_t current_count;
> void* current_buffer = buffer;
> uint64_t lba = start;
> -
> + int max_count;
> // Anzahl der Sektoren die noch uebrig sind
> size_t count_left = count;
>
> +
> +
> + // Request vorbereiten
> + request.dev = dev;
> + request.flags.poll = 0;
> + request.flags.ata = 0;
> + request.flags.lba = 1;
> +
> + // Richtung festlegen
> + if (direction == 0) {
> + request.flags.direction = READ;
> + } else {
> + request.flags.direction = WRITE;
> + }
> +
> +
> + if (dev->dma && dev->controller->dma_use) {
> + // DMA
> + max_count = ATA_DMA_MAXSIZE / ATA_SECTOR_SIZE;
> + if (direction) {
> + request.registers.ata.command = WRITE_SECTORS_DMA;
> + } else {
> + request.registers.ata.command = READ_SECTORS_DMA;
> + }
> + request.protocol = DMA;
> + } else {
> + // PIO
> + max_count = 256;
> + if (direction) {
> + request.registers.ata.command = WRITE_SECTORS;
> + } else {
> + request.registers.ata.command = READ_SECTORS;
> + }
> + request.protocol = PIO;
> + }
> +
> // Solange wie noch Sektoren uebrig sind, wird gelesen
> while (count_left > 0) {
> // Entscheiden wieviele Sektoren im aktuellen Durchlauf gelesen
> werden - if (count_left > 256) {
> - current_count = 256;
> + if (count_left > max_count) {
> + current_count = max_count;
> } else {
> current_count = count_left;
> }
>
> - // Request vorbereiten
> - request.dev = dev;
> - // TODO: DMA, UltraDMA...
> - request.protocol = PIO;
>
> - // FIXME
> - request.flags.poll = 1;
> - request.flags.ata = 0;
> - request.flags.lba = 1;
> -
> - // Richtung festlegen
> - if (direction == 0) {
> - request.flags.direction = READ;
> - request.registers.ata.command = READ_SECTORS;
> - } else {
> - request.flags.direction = WRITE;
> - request.registers.ata.command = WRITE_SECTORS;
> - }
> -
> // Achtung: Beim casten nach uint8_t wird bei 256 Sektoren eine 0.
> // Das macht aber nichts, da in der Spezifikation festgelegt ist,
> // dass 256 Sektoren gelesen werden sollen, wenn im count-Register
> diff --git a/src/modules/cdi/ata/device.c b/src/modules/cdi/ata/device.c
> index 4bf4a14..dfe144f 100644
> --- a/src/modules/cdi/ata/device.c
> +++ b/src/modules/cdi/ata/device.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2007 The tyndur Project. All rights reserved.
> + * Copyright (c) 2007-2009 The tyndur Project. All rights reserved.
> *
> * This code is derived from software contributed to the tyndur Project
> * by Antoine Kaufmann.
> @@ -142,10 +142,6 @@ static int ata_bus_responsive_drv(struct
> ata_controller* controller) */
> static void ata_controller_irq(struct cdi_device* dev)
> {
> - struct ata_device* ata_dev = (struct ata_device*) dev;
> - struct ata_controller* ctrl = ata_dev->controller;
> -
> - ctrl->irq_cnt++;
> }
Brauchen wir das wirklich als leere Funktion? Wenn ja, gehört da ein Kommentar
rein, der sagt, wieso.
>
> /**
> @@ -157,18 +153,9 @@ static void ata_controller_irq(struct cdi_device* dev)
> */
> int ata_wait_irq(struct ata_controller* controller, uint32_t timeout)
> {
> - uint32_t time = 0;
> -
> - // Warten bis der IRQ-Zaehler vom Handler erhoeht wird
> - while (controller->irq_cnt == 0) {
> - cdi_sleep_ms(20);
> - time += 20;
> -
> - if (timeout <= time) {
> - return 0;
> - }
> + if (cdi_wait_irq(controller->irq, timeout)) {
> + return 0;
> }
> -
> return 1;
> }
>
> @@ -242,6 +229,14 @@ void ata_init_controller(struct ata_controller*
> controller) cdi_ioports_free(controller->port_cmd_base, 8);
> return;
> }
> + if (controller->port_bmr_base &&
> + (cdi_ioports_alloc(controller->port_bmr_base, 8) != 0))
> + {
> + DEBUG("ata: Fehler beim allozieren der I/O-Ports\n");
> + cdi_ioports_free(controller->port_ctl_base, 1);
> + cdi_ioports_free(controller->port_cmd_base, 8);
> + return;
> + }
Die Fehlerbehandlung würde hier aber mit einem goto schöner gehen.
>
> // Da NIEN nicht ueberall sauber funktioniert, muss jetzt trotzdem
> schon // ein IRQ-Handler registriert werden. Und dafuer brauchen wir nun
> mal ein @@ -323,6 +318,16 @@ void ata_init_controller(struct
> ata_controller* controller) free(dev);
> }
> }
> +
> + // Abschliessend wird noch DMA vorbereitet, wenn moeglich
> + if (controller->port_bmr_base) {
> + cdi_alloc_phys_mem(sizeof(uint64_t), (void**)
> &controller->prdt_virt, + (void**) &controller->prdt_phys);
> + cdi_alloc_phys_mem(ATA_DMA_MAXSIZE, (void**)
> &controller->dma_buf_virt, + (void**)
> &controller->dma_buf_phys);
> +
> + controller->dma_use = 1;
> + }
> }
>
> void ata_remove_controller(struct ata_controller* controller)
> diff --git a/src/modules/cdi/ata/device.h b/src/modules/cdi/ata/device.h
> index 54dfb80..36a86d1 100644
> --- a/src/modules/cdi/ata/device.h
> +++ b/src/modules/cdi/ata/device.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2007 The tyndur Project. All rights reserved.
> + * Copyright (c) 2007-2009 The tyndur Project. All rights reserved.
> *
> * This code is derived from software contributed to the tyndur Project
> * by Antoine Kaufmann.
> @@ -48,6 +48,10 @@
>
> #define ATAPI_ENABLE
>
> +#define PCI_CLASS_ATA 0x01
> +#define PCI_SUBCLASS_ATA 0x01
> +#define PCI_VENDOR_VIA 0x1106
> +
> #define ATA_PRIMARY_CMD_BASE 0x1F0
> #define ATA_PRIMARY_CTL_BASE 0x3F6
> #define ATA_PRIMARY_IRQ 14
> @@ -76,6 +80,7 @@
> // Diese Register werden ueber die port_cmd_base angesprochen
> #define REG_DATA 0x0
> #define REG_ERROR 0x1
> +#define REG_FEATURES 0x1
> #define REG_SEC_CNT 0x2
> #define REG_LBA_LOW 0x3
> #define REG_LBA_MID 0x4
> @@ -110,6 +115,24 @@
> #define CONTROL_SRST (1 << 2)
> #define CONTROL_NIEN (1 << 1)
>
> +
> +// Busmaster-Register (in port_bmr_base)
> +#define BMR_COMMAND 0x0
> +#define BMR_STATUS 0x2
> +#define BMR_PRDT 0x4
> +
> +// Bits im Busmaster Command Register
> +#define BMR_CMD_START (1 << 0)
> +#define BMR_CMD_WRITE (1 << 3)
> +
> +// Bits im Busmaster Status Register
> +#define BMR_STATUS_ERROR (1 << 1)
> +#define BMR_STATUS_IRQ (1 << 2)
> +
> +/// Maximale Groesse eines DMA-Transfers
> +#define ATA_DMA_MAXSIZE (64 * 1024)
> +
> +
> // Debug
> #ifdef DEBUG_ENABLE
> #define DEBUG(fmt, ...) printf("ata: " fmt, __VA_ARGS__)
> @@ -320,7 +343,10 @@ struct ata_device {
>
> // 1 Wenn das Geraet lba28 unterstuetzt
> uint8_t lba28;
> -
> +
> + /// 1 wenn das Geraet DMA unterstuetzt
> + uint8_t dma;
> +
> // Funktionen fuer den Zugriff auf dieses Geraet
> int (*read_sectors) (struct ata_device* dev, uint64_t start, size_t
> count, void* dest);
> @@ -335,14 +361,26 @@ struct ata_controller {
> uint8_t id;
> uint16_t port_cmd_base;
> uint16_t port_ctl_base;
> + uint16_t port_bmr_base;
> uint16_t irq;
> - uint16_t irq_cnt;
>
> // Wird auf 1 gesetzt wenn IRQs benutzt werden sollen, also das
> NIEN-Bit im // Control register nicht aktiviert ist.
> int irq_use;
> + /// Wird auf 1 gesetzt wenn DMA benutzt werden darf
> + int dma_use;
> // HACKKK ;-)
> struct ata_device irq_dev;
> +
> +
> + /// Physische Adresse der Physical Region Descriptor Table (fuer DMA)
> + uint64_t* prdt_phys;
> + /// Virtuelle Adresse der Physical Region Descriptor Table (fuer DMA)
> + uint64_t* prdt_virt;
> + /// Physische Adresse des DMA-Puffers
> + void* dma_buf_phys;
> + /// Virtuelle Adresse des DMA-Puffers
> + void* dma_buf_virt;
> };
>
> struct ata_request {
> @@ -350,7 +388,8 @@ struct ata_request {
>
> enum {
> NON_DATA,
> - PIO
> + PIO,
> + DMA,
> } protocol;
>
> // Flags fuer die Uebertragung
> @@ -378,10 +417,14 @@ struct ata_request {
> IDENTIFY_PACKET_DEVICE = 0xA1,
> PACKET = 0xA0,
> READ_SECTORS = 0x20,
> - WRITE_SECTORS = 0x30
> + READ_SECTORS_DMA = 0xC8,
> + SET_FEATURES = 0xEF,
> + WRITE_SECTORS = 0x30,
> + WRITE_SECTORS_DMA = 0xCA,
> } command;
> uint8_t count;
> uint64_t lba;
> + uint8_t features;
> } ata;
> } registers;
>
> diff --git a/src/modules/cdi/ata/main.c b/src/modules/cdi/ata/main.c
> index 750f7b2..7ea07bd 100644
> --- a/src/modules/cdi/ata/main.c
> +++ b/src/modules/cdi/ata/main.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2007 The tyndur Project. All rights reserved.
> + * Copyright (c) 2007-2009 The tyndur Project. All rights reserved.
> *
> * This code is derived from software contributed to the tyndur Project
> * by Antoine Kaufmann.
> @@ -39,6 +39,7 @@
>
> #include "cdi/storage.h"
> #include "cdi/lists.h"
> +#include "cdi/pci.h"
>
> #include "device.h"
>
> @@ -76,6 +77,11 @@ int init_ata(void)
> static void ata_driver_init()
> {
> struct ata_controller* controller;
> + uint16_t busmaster_regbase = 0;
> + struct cdi_pci_device* pci_dev;
> + cdi_list_t pci_devices;
> + int i;
> + int j;
>
> // Konstruktor der Vaterklasse
> cdi_storage_driver_init((struct cdi_storage_driver*) &driver_storage);
> @@ -99,11 +105,46 @@ static void ata_driver_init()
>
> // Liste mit Controllern initialisieren
> controller_list = cdi_list_create();
> -
> +
> +
> + // PCI-Geraet fuer Controller finden
> + pci_devices = cdi_list_create();
> + cdi_pci_get_all_devices(pci_devices);
> + for (i = 0; (pci_dev = cdi_list_get(pci_devices, i)) &&
> !busmaster_regbase; + i++)
> + {
> + struct cdi_pci_resource* res;
> +
> + if ((pci_dev->class_id != PCI_CLASS_ATA) ||
> + (pci_dev->subclass_id != PCI_SUBCLASS_ATA))
> + {
> + continue;
> + }
> +
> + // Jetzt noch die Ressource finden mit den Busmaster-Registern
> + // TODO: Das funktioniert so vermutlich nicht ueberall, da es
> + // warscheinlich auch Kontroller mit nur einem Kanal gibt und
> solche bei + // denen die BM-Register im Speicher gemappt sind
> + for (j = 0; (res = cdi_list_get(pci_dev->resources, j)); j++) {
> + if ((res->type == CDI_PCI_IOPORTS) && (res->length == 16)) {
> + busmaster_regbase = res->start;
> + break;
> + }
> + }
> + }
> +
> + // Kaputte VIA-Kontroller sollten nur PIO benutzen, da es bei DMA zu
> + // haengern kommt.
> + if (pci_dev && (pci_dev->vendor_id == PCI_VENDOR_VIA)) {
> + busmaster_regbase = 0;
> + }
VIA baut nur kaputte Sachen?
Und es sind die einzigen, die kaputte Sachen bauen? Sonst wäre vielleicht eine
Möglichkeit, DMA manuell abzuschalten, nicht schlecht.
> +
> // Primaeren Controller vorbereiten
> controller = malloc(sizeof(*controller));
> + memset(controller, 0, sizeof(*controller));
calloc
> controller->port_cmd_base = ATA_PRIMARY_CMD_BASE;
> controller->port_ctl_base = ATA_PRIMARY_CTL_BASE;
> + controller->port_bmr_base = busmaster_regbase;
> controller->irq = ATA_PRIMARY_IRQ;
> controller->id = 0;
> controller->storage = (struct cdi_storage_driver*) &driver_storage;
> @@ -113,8 +154,10 @@ static void ata_driver_init()
>
> // Sekundaeren Controller vorbereiten
> controller = malloc(sizeof(*controller));
> + memset(controller, 0, sizeof(*controller));
> controller->port_cmd_base = ATA_SECONDARY_CMD_BASE;
> controller->port_ctl_base = ATA_SECONDARY_CTL_BASE;
> + controller->port_bmr_base = (busmaster_regbase ? busmaster_regbase :
> 0); controller->irq = ATA_SECONDARY_IRQ;
> controller->id = 1;
> controller->storage = (struct cdi_storage_driver*) &driver_storage;
> diff --git a/src/modules/cdi/ata/request.c b/src/modules/cdi/ata/request.c
> index 6e470d4..133d199 100644
> --- a/src/modules/cdi/ata/request.c
> +++ b/src/modules/cdi/ata/request.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2007 The tyndur Project. All rights reserved.
> + * Copyright (c) 2007-2009 The tyndur Project. All rights reserved.
> *
> * This code is derived from software contributed to the tyndur Project
> * by Antoine Kaufmann.
> @@ -96,7 +96,7 @@ static int ata_request_command(struct ata_request*
> request)
>
> // IRQ-Zaehler zuruecksetzen, egal ob er gebraucht wird oder nicht,
> stoert // ja niemanden
> - ctrl->irq_cnt = 0;
> + cdi_reset_wait_irq(ctrl->irq);
>
> ata_drv_select(dev);
>
> @@ -120,6 +120,9 @@ static int ata_request_command(struct ata_request*
> request) // TODO: HOB
> ata_reg_outb(ctrl, REG_CONTROL, control);
>
> + // Features-Register schreiben
> + ata_reg_outb(ctrl, REG_FEATURES, request->registers.ata.features);
> +
> // Count-Register schrieben
> ata_reg_outb(ctrl, REG_SEC_CNT, request->registers.ata.count);
>
> @@ -160,7 +163,7 @@ static int ata_protocol_non_data(struct ata_request*
> request) switch (state) {
> case IRQ_WAIT:
> // Auf IRQ warten
> - if (ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
> + if (!ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
Hm? Unabhängiger Bugfix oder hast du da den Rückgabewert geändert? Falls
letzteres, warum?
> request->error = IRQ_TIMEOUT;
> DEBUG("non_data IRQ-Timeout\n");
> return 0;
> @@ -216,7 +219,7 @@ int ata_protocol_pio_in(struct ata_request* request)
> switch (state) {
> case IRQ_WAIT:
> // Auf IRQ warten
> - if (ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
> + if (!ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
> request->error = IRQ_TIMEOUT;
> DEBUG("pio_in IRQ-Timeout\n");
> return 0;
> @@ -313,7 +316,7 @@ int ata_protocol_pio_out(struct ata_request* request)
> switch (state) {
> case IRQ_WAIT:
> // Auf IRQ warten
> - if (ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
> + if (!ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
> request->error = IRQ_TIMEOUT;
> DEBUG("pio_out IRQ-Timeout\n");
> return 0;
> @@ -395,6 +398,109 @@ int ata_protocol_pio_out(struct ata_request* request)
> }
>
> /**
> + * Initialisiert DMA fuer einen Transfer
> + */
> +static int ata_request_dma_init(struct ata_request* request)
> +{
> + struct ata_device* dev = request->dev;
> + struct ata_controller* ctrl = dev->controller;
> + uint64_t size = request->block_size * request->block_count;
> +
> + *ctrl->prdt_virt = (uint32_t) ctrl->dma_buf_phys;
> + // Groesse nicht ueber 64K, 0 == 64K
> + *ctrl->prdt_virt |= (size & (ATA_DMA_MAXSIZE - 1)) << 32L;
> + // Letzter Eintrag in PRDT
> + *ctrl->prdt_virt |= (uint64_t) 1L << 63L;
> +
> + // Die laufenden Transfers anhalten
> + cdi_outb(ctrl->port_bmr_base + BMR_COMMAND, 0);
> + cdi_outb(ctrl->port_bmr_base + BMR_STATUS,
> + cdi_inb(ctrl->port_bmr_base + BMR_STATUS) | BMR_STATUS_ERROR |
> + BMR_STATUS_IRQ);
> +
> + // Adresse der PRDT eintragen
> + cdi_outl(ctrl->port_bmr_base + BMR_PRDT, (uint32_t) ctrl->prdt_phys);
> +
> + if (request->flags.direction != READ) {
> + memcpy(ctrl->dma_buf_virt, request->buffer, size);
> + }
> + return 1;
> +}
> +
> +/**
> + * Verarbeitet einen ATA-Request bei dem Daten ueber DMA uebertragen
> werden + * sollen
> + */
> +static int ata_protocol_dma(struct ata_request* request)
> +{
> + struct ata_device* dev = request->dev;
> + struct ata_controller* ctrl = dev->controller;
> +
> + // Aktueller Status im Protokol
Protokoll.
(Merkt man, daß ich keine Ahnung habe und mich auf irgendwelche
Belanglosigkeiten konzentriere? *g*)
> + enum {
> + IRQ_WAIT,
> + CHECK_STATUS,
> + } state;
> +
> + // Wozu das lesen und dieser Register gut ist, weiss ich nicht, doch
> ich + // habe es so in verschiedenen Treibern gesehen, deshalb gehe ich
> mal davon + // aus, dass es notwendig ist.
> + cdi_inb(ctrl->port_bmr_base + BMR_COMMAND);
> + cdi_inb(ctrl->port_bmr_base + BMR_STATUS);
> + // Busmastering starten
> + if (request->flags.direction != READ) {
> + cdi_outb(ctrl->port_bmr_base + BMR_COMMAND, BMR_CMD_START |
> + BMR_CMD_WRITE);
> + } else {
> + cdi_outb(ctrl->port_bmr_base + BMR_COMMAND, BMR_CMD_START);
> + }
> + cdi_inb(ctrl->port_bmr_base + BMR_COMMAND);
> + cdi_inb(ctrl->port_bmr_base + BMR_STATUS);
> +
> +
> + if (request->flags.poll) {
> + state = CHECK_STATUS;
> + } else {
> + state = IRQ_WAIT;
> + }
> +
> + while (1) {
> + switch (state) {
> + case IRQ_WAIT:
> + // Auf IRQ warten
> + if (!ata_wait_irq(ctrl, ATA_IRQ_TIMEOUT)) {
> + request->error = IRQ_TIMEOUT;
> + DEBUG("pio_out IRQ-Timeout\n");
> + return 0;
> + }
> +
> + state = CHECK_STATUS;
> + break;
> +
> + case CHECK_STATUS: {
> + uint8_t status = ata_reg_inb(ctrl, REG_STATUS);
> +
> + // Sicherstellen dass der Transfer abgeschlossen ist. Bei
> + // polling ist das hier noch nicht umbedingt der Fall.
> + if ((status & (STATUS_BSY | STATUS_DRQ)) == 0) {
> + cdi_inb(ctrl->port_bmr_base + BMR_STATUS);
> + cdi_outb(ctrl->port_bmr_base + BMR_COMMAND, 0);
> + goto out_success;
> + }
> + break;
> + }
> + }
> + }
> +
> +out_success:
> + if (request->flags.direction == READ) {
> + memcpy(request->buffer, ctrl->dma_buf_virt,
> + request->block_size * request->block_count);
> + }
> + return 1;
> +}
> +
> +/**
> * Fuehrt einen ATA-Request aus.
> *
> * @return 1 Wenn der Request erfolgreich bearbeitet wurde, 0 sonst
> @@ -402,6 +508,13 @@ int ata_protocol_pio_out(struct ata_request* request)
> int ata_request(struct ata_request* request)
> {
> // printf("ata: [%d:%d] Request command=%x count=%x lba=%llx
> protocol=%x\n", request->dev->controller->id, request->dev->id,
> request->registers.ata.command, request->registers.ata.count,
> request->registers.ata.lba, request->protocol); +
> + // Bei einem DMA-Request muss der DMA-Controller erst vorbereitet
> werden + if ((request->protocol == DMA) &&
> !ata_request_dma_init(request)) { + DEBUG("ata: Fehler beim
> Initialisieren des DMA-Controllers\n"); + return 0;
> + }
> +
> // Befehl ausfuehren
> if (!ata_request_command(request)) {
> DEBUG("Fehler bei der Befehlsausfuehrung\n");
> @@ -427,6 +540,15 @@ int ata_request(struct ata_request* request)
> return 0;
> }
> break;
> +
> + case DMA:
> + if (!ata_protocol_dma(request)) {
> + return 0;
> + }
> + break;
> +
> + default:
> + return 0;
> }
> return 1;
> }
Also wenn du sagst, das funktioniert, glaube ich dir einfach mal. ;-) Gegen
die Spec habe ich das jetzt allerdings auch nicht geprüft, nur mal grob
überflogen.