This patch enables support for ATA bus master dma transfers. It should work with any SFF 8038 compatible PCI device. Currently, only ATA transfers (not ATAPI packet) are supported.
This patch significantly improves performance on some real hardware controllers.
This patch does not enable UDMA or set controller timings - that is left for a future patch.
-Kevin
diff --git a/src/ata.c b/src/ata.c index d87072d..2d9e0b1 100644 --- a/src/ata.c +++ b/src/ata.c @@ -130,6 +130,7 @@ done: dprintf(6, "ata_reset exit status=%x\n", status); }
+// Check for drive RDY for 16bit interface command. static int isready(struct drive_s *drive_g) { @@ -143,6 +144,7 @@ isready(struct drive_s *drive_g) return DISK_RET_ENOTREADY; }
+// Default 16bit command demuxer for ATA and ATAPI devices. static int process_ata_misc_op(struct disk_op_s *op) { @@ -179,6 +181,7 @@ struct ata_pio_command { u8 device; u8 command;
+ u8 feature2; u8 sector_count2; u8 lba_low2; u8 lba_mid2; @@ -209,9 +212,9 @@ send_cmd(struct drive_s *drive_g, struct ata_pio_command *cmd) return status; }
- if (cmd->command == ATA_CMD_READ_SECTORS_EXT - || cmd->command == ATA_CMD_WRITE_SECTORS_EXT) { - outb(0x00, iobase1 + ATA_CB_FR); + // Check for ATA_CMD_(READ|WRITE)_(SECTORS|DMA)_EXT commands. + if ((cmd->command & ~0x11) == ATA_CMD_READ_SECTORS_EXT) { + outb(cmd->feature2, iobase1 + ATA_CB_FR); outb(cmd->sector_count2, iobase1 + ATA_CB_SC); outb(cmd->lba_low2, iobase1 + ATA_CB_SN); outb(cmd->lba_mid2, iobase1 + ATA_CB_CL); @@ -224,7 +227,14 @@ send_cmd(struct drive_s *drive_g, struct ata_pio_command *cmd) outb(cmd->lba_high, iobase1 + ATA_CB_CH); outb(cmd->command, iobase1 + ATA_CB_CMD);
- status = ndelay_await_not_bsy(iobase1); + return 0; +} + +// Wait for data after calling 'send_cmd'. +static int +ata_wait_data(u16 iobase1) +{ + int status = ndelay_await_not_bsy(iobase1); if (status < 0) return status;
@@ -241,17 +251,55 @@ send_cmd(struct drive_s *drive_g, struct ata_pio_command *cmd) return 0; }
+// Send an ata command that does not transfer any further data. +int +ata_cmd_nondata(struct drive_s *drive_g, struct ata_pio_command *cmd) +{ + u8 ataid = GET_GLOBAL(drive_g->cntl_id); + u8 channel = ataid / 2; + u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1); + u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2); + + // Disable interrupts + outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); + + int ret = send_cmd(drive_g, cmd); + if (ret) + goto fail; + ret = ndelay_await_not_bsy(iobase1); + if (ret < 0) + goto fail; + + if (ret & ATA_CB_STAT_ERR) { + dprintf(6, "nondata cmd : read error (status=%02x err=%02x)\n" + , ret, inb(iobase1 + ATA_CB_ERR)); + ret = -4; + goto fail; + } + if (ret & ATA_CB_STAT_DRQ) { + dprintf(6, "nondata cmd : DRQ set (status %02x)\n", ret); + ret = -5; + goto fail; + } + +fail: + // Enable interrupts + outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); + + return ret; +} +
/**************************************************************** - * ATA transfers + * ATA PIO transfers ****************************************************************/
// Transfer 'op->count' blocks (of 'blocksize' bytes) to/from drive // 'op->drive_g'. static int -ata_transfer(struct disk_op_s *op, int iswrite, int blocksize) +ata_pio_transfer(struct disk_op_s *op, int iswrite, int blocksize) { - dprintf(16, "ata_transfer id=%p write=%d count=%d bs=%d buf=%p\n" + dprintf(16, "ata_pio_transfer id=%p write=%d count=%d bs=%d buf=%p\n" , op->drive_g, iswrite, op->count, blocksize, op->buf_fl);
u8 ataid = GET_GLOBAL(op->drive_g->cntl_id); @@ -291,7 +339,7 @@ ata_transfer(struct disk_op_s *op, int iswrite, int blocksize) break; status &= (ATA_CB_STAT_BSY | ATA_CB_STAT_DRQ | ATA_CB_STAT_ERR); if (status != ATA_CB_STAT_DRQ) { - dprintf(6, "ata_transfer : more sectors left (status %02x)\n" + dprintf(6, "ata_pio_transfer : more sectors left (status %02x)\n" , status); op->count -= count; return -6; @@ -303,7 +351,7 @@ ata_transfer(struct disk_op_s *op, int iswrite, int blocksize) if (!iswrite) status &= ~ATA_CB_STAT_DF; if (status != 0) { - dprintf(6, "ata_transfer : no sectors left (status %02x)\n", status); + dprintf(6, "ata_pio_transfer : no sectors left (status %02x)\n", status); return -7; }
@@ -312,73 +360,230 @@ ata_transfer(struct disk_op_s *op, int iswrite, int blocksize)
/**************************************************************** + * ATA DMA transfers + ****************************************************************/ + +#define BM_CMD 0 +#define BM_CMD_MEMWRITE 0x08 +#define BM_CMD_START 0x01 +#define BM_STATUS 2 +#define BM_STATUS_IRQ 0x04 +#define BM_STATUS_ERROR 0x02 +#define BM_STATUS_ACTIVE 0x01 +#define BM_TABLE 4 + +struct sff_dma_prd { + u32 buf_fl; + u32 count; +}; + +// Check if DMA available and setup transfer if so. +static int +ata_try_dma(struct disk_op_s *op, int iswrite, int blocksize) +{ + u32 dest = (u32)op->buf_fl; + if (dest & 1) + // Need minimum alignment of 1. + return -1; + u8 ataid = GET_GLOBAL(op->drive_g->cntl_id); + u8 channel = ataid / 2; + u16 iomaster = GET_GLOBAL(ATA_channels[channel].iomaster); + if (! iomaster) + return -1; + u32 bytes = op->count * blocksize; + if (! bytes) + return -1; + + // Build PRD dma structure. + struct sff_dma_prd *dma = MAKE_FLATPTR( + get_ebda_seg() + , (void*)offsetof(struct extended_bios_data_area_s, extra_stack)); + struct sff_dma_prd *origdma = dma; + while (bytes) { + if (dma >= &origdma[16]) + // Too many descriptors.. + return -1; + u32 count = bytes; + if (count > 0x10000) + count = 0x10000; + u32 max = 0x10000 - (dest & 0xffff); + if (count > max) + count = max; + + SET_FLATPTR(dma->buf_fl, dest); + bytes -= count; + if (!bytes) + // Last descriptor. + count |= 1<<31; + dprintf(16, "dma@%p: %08x %08x\n", dma, dest, count); + dest += count; + SET_FLATPTR(dma->count, count); + dma++; + } + + // Program bus-master controller. + outl((u32)origdma, iomaster + BM_TABLE); + u8 oldcmd = inb(iomaster + BM_CMD) & ~(BM_CMD_MEMWRITE|BM_CMD_START); + outb(oldcmd | (iswrite ? 0x00 : BM_CMD_MEMWRITE), iomaster + BM_CMD); + outb(BM_STATUS_ERROR|BM_STATUS_IRQ, iomaster + BM_STATUS); + + return 0; +} + +// Transfer data using DMA. +static int +ata_dma_transfer(struct disk_op_s *op) +{ + dprintf(16, "ata_dma_transfer id=%p buf=%p\n" + , op->drive_g, op->buf_fl); + + u8 ataid = GET_GLOBAL(op->drive_g->cntl_id); + u8 channel = ataid / 2; + u16 iomaster = GET_GLOBAL(ATA_channels[channel].iomaster); + + // Start bus-master controller. + u8 oldcmd = inb(iomaster + BM_CMD); + outb(oldcmd | BM_CMD_START, iomaster + BM_CMD); + + u64 end = calc_future_tsc(IDE_TIMEOUT); + u8 status; + for (;;) { + status = inb(iomaster + BM_STATUS); + if (status & BM_STATUS_IRQ) + break; + // Transfer in progress + if (check_time(end)) { + // Timeout. + dprintf(1, "IDE DMA timeout\n"); + break; + } + yield(); + } + outb(oldcmd & ~BM_CMD_START, iomaster + BM_CMD); + + u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1); + u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2); + int idestatus = pause_await_not_bsy(iobase1, iobase2); + + if ((status & (BM_STATUS_IRQ|BM_STATUS_ACTIVE)) == BM_STATUS_IRQ + && idestatus >= 0x00 + && (idestatus & (ATA_CB_STAT_BSY | ATA_CB_STAT_DF | ATA_CB_STAT_DRQ + | ATA_CB_STAT_ERR)) == 0x00) + // Success. + return 0; + + dprintf(6, "IDE DMA error (dma=%x ide=%x/%x/%x)\n", status, idestatus + , inb(iobase2 + ATA_CB_ASTAT), inb(iobase1 + ATA_CB_ERR)); + op->count = 0; + return -1; +} + + +/**************************************************************** * ATA hard drive functions ****************************************************************/
-// Read/write count blocks from a harddrive. +// Transfer data to harddrive using PIO protocol. static int -ata_cmd_data(struct disk_op_s *op, int iswrite, int command) +ata_pio_cmd_data(struct disk_op_s *op, int iswrite, struct ata_pio_command *cmd) { u8 ataid = GET_GLOBAL(op->drive_g->cntl_id); u8 channel = ataid / 2; + u16 iobase1 = GET_GLOBAL(ATA_channels[channel].iobase1); u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2); + + // Disable interrupts + outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); + + int ret = send_cmd(op->drive_g, cmd); + if (ret) + goto fail; + ret = ata_wait_data(iobase1); + if (ret) + goto fail; + ret = ata_pio_transfer(op, iswrite, DISK_SECTOR_SIZE); + +fail: + // Enable interrupts + outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); + return ret; +} + +// Transfer data to harddrive using DMA protocol. +static int +ata_dma_cmd_data(struct disk_op_s *op, struct ata_pio_command *cmd) +{ + int ret = send_cmd(op->drive_g, cmd); + if (ret) + return ret; + return ata_dma_transfer(op); +} + +// Read/write count blocks from a harddrive. +static int +ata_readwrite(struct disk_op_s *op, int iswrite) +{ u64 lba = op->lba;
+ int usepio = ata_try_dma(op, iswrite, DISK_SECTOR_SIZE); + struct ata_pio_command cmd; memset(&cmd, 0, sizeof(cmd));
- cmd.command = command; + cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS : ATA_CMD_READ_SECTORS); if (op->count >= (1<<8) || lba + op->count >= (1<<28)) { cmd.sector_count2 = op->count >> 8; cmd.lba_low2 = lba >> 24; cmd.lba_mid2 = lba >> 32; cmd.lba_high2 = lba >> 40; - - cmd.command |= 0x04; lba &= 0xffffff; + + if (usepio) + cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS_EXT + : ATA_CMD_READ_SECTORS_EXT); + else + cmd.command = (iswrite ? ATA_CMD_WRITE_DMA_EXT + : ATA_CMD_READ_DMA_EXT); + } else { + if (usepio) + cmd.command = (iswrite ? ATA_CMD_WRITE_SECTORS + : ATA_CMD_READ_SECTORS); + else + cmd.command = (iswrite ? ATA_CMD_WRITE_DMA + : ATA_CMD_READ_DMA); }
- cmd.feature = 0; cmd.sector_count = op->count; cmd.lba_low = lba; cmd.lba_mid = lba >> 8; cmd.lba_high = lba >> 16; cmd.device = ((lba >> 24) & 0xf) | ATA_CB_DH_LBA;
- // Disable interrupts - outb(ATA_CB_DC_HD15 | ATA_CB_DC_NIEN, iobase2 + ATA_CB_DC); - - int ret = send_cmd(op->drive_g, &cmd); + int ret; + if (usepio) + ret = ata_pio_cmd_data(op, iswrite, &cmd); + else + ret = ata_dma_cmd_data(op, &cmd); if (ret) - goto fail; - ret = ata_transfer(op, iswrite, DISK_SECTOR_SIZE); - -fail: - // Enable interrupts - outb(ATA_CB_DC_HD15, iobase2+ATA_CB_DC); - return ret; + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; }
+// 16bit command demuxer for ATA harddrives. int process_ata_op(struct disk_op_s *op) { if (!CONFIG_ATA) return 0;
- int ret; switch (op->command) { case CMD_READ: - ret = ata_cmd_data(op, 0, ATA_CMD_READ_SECTORS); - break; + return ata_readwrite(op, 0); case CMD_WRITE: - ret = ata_cmd_data(op, 1, ATA_CMD_WRITE_SECTORS); - break; + return ata_readwrite(op, 1); default: return process_ata_misc_op(op); } - if (ret) - return DISK_RET_EBADTRACK; - return DISK_RET_SUCCESS; }
@@ -396,12 +601,9 @@ atapi_cmd_data(struct disk_op_s *op, u8 *cmdbuf, u8 cmdlen, u16 blocksize) u16 iobase2 = GET_GLOBAL(ATA_channels[channel].iobase2);
struct ata_pio_command cmd; - cmd.sector_count = 0; - cmd.feature = 0; - cmd.lba_low = 0; + memset(&cmd, 0, sizeof(cmd)); cmd.lba_mid = blocksize; cmd.lba_high = blocksize >> 8; - cmd.device = 0; cmd.command = ATA_CMD_PACKET;
// Disable interrupts @@ -410,6 +612,9 @@ atapi_cmd_data(struct disk_op_s *op, u8 *cmdbuf, u8 cmdlen, u16 blocksize) int ret = send_cmd(op->drive_g, &cmd); if (ret) goto fail; + ret = ata_wait_data(iobase1); + if (ret) + goto fail;
// Send command to device outsw_fl(iobase1, MAKE_FLATPTR(GET_SEG(SS), cmdbuf), cmdlen / 2); @@ -435,7 +640,7 @@ atapi_cmd_data(struct disk_op_s *op, u8 *cmdbuf, u8 cmdlen, u16 blocksize) goto fail; }
- ret = ata_transfer(op, 0, blocksize); + ret = ata_pio_transfer(op, 0, blocksize);
fail: // Enable interrupts @@ -460,6 +665,7 @@ cdrom_read(struct disk_op_s *op) return atapi_cmd_data(op, atacmd, sizeof(atacmd), CDROM_SECTOR_SIZE); }
+// 16bit command demuxer for ATAPI cdroms. int process_atapi_op(struct disk_op_s *op) { @@ -467,16 +673,15 @@ process_atapi_op(struct disk_op_s *op) switch (op->command) { case CMD_READ: ret = cdrom_read(op); - break; + if (ret) + return DISK_RET_EBADTRACK; + return DISK_RET_SUCCESS; case CMD_FORMAT: case CMD_WRITE: return DISK_RET_EWRITEPROTECT; default: return process_ata_misc_op(op); } - if (ret) - return DISK_RET_EBADTRACK; - return DISK_RET_SUCCESS; }
// Send a simple atapi command to a drive. @@ -498,6 +703,26 @@ ata_cmd_packet(struct drive_s *drive_g, u8 *cmdbuf, u8 cmdlen * ATA detect and init ****************************************************************/
+// Send an identify device or identify device packet command. +static int +send_ata_identity(struct drive_s *drive_g, u16 *buffer, int command) +{ + memset(buffer, 0, DISK_SECTOR_SIZE); + + struct disk_op_s dop; + memset(&dop, 0, sizeof(dop)); + dop.drive_g = drive_g; + dop.count = 1; + dop.lba = 1; + dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer); + + struct ata_pio_command cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.command = command; + + return ata_pio_cmd_data(&dop, 0, &cmd); +} + // Extract the ATA/ATAPI version info. static int extract_version(u16 *buffer) @@ -537,6 +762,7 @@ extract_identify(struct drive_s *drive_g, u16 *buffer) SET_GLOBAL(drive_g->cntl_info, extract_version(buffer)); }
+// Print out a description of the given atapi drive. void describe_atapi(struct drive_s *drive_g) { @@ -550,18 +776,12 @@ describe_atapi(struct drive_s *drive_g) , (iscd ? "CD-Rom/DVD-Rom" : "Device")); }
+// Detect if the given drive is an atapi - initialize it if so. static struct drive_s * init_drive_atapi(struct drive_s *dummy, u16 *buffer) { // Send an IDENTIFY_DEVICE_PACKET command to device - memset(buffer, 0, DISK_SECTOR_SIZE); - struct disk_op_s dop; - memset(&dop, 0, sizeof(dop)); - dop.drive_g = dummy; - dop.count = 1; - dop.lba = 1; - dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer); - int ret = ata_cmd_data(&dop, 0, ATA_CMD_IDENTIFY_DEVICE_PACKET); + int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_PACKET_DEVICE); if (ret) return NULL;
@@ -584,6 +804,7 @@ init_drive_atapi(struct drive_s *dummy, u16 *buffer) return drive_g; }
+// Print out a description of the given ata drive. void describe_ata(struct drive_s *drive_g) { @@ -601,18 +822,12 @@ describe_ata(struct drive_s *drive_g) printf(" (%u GiBytes)", (u32)(sizeinmb >> 10)); }
+// Detect if the given drive is a regular ata drive - initialize it if so. static struct drive_s * init_drive_ata(struct drive_s *dummy, u16 *buffer) { // Send an IDENTIFY_DEVICE command to device - memset(buffer, 0, DISK_SECTOR_SIZE); - struct disk_op_s dop; - memset(&dop, 0, sizeof(dop)); - dop.drive_g = dummy; - dop.count = 1; - dop.lba = 1; - dop.buf_fl = MAKE_FLATPTR(GET_SEG(SS), buffer); - int ret = ata_cmd_data(&dop, 0, ATA_CMD_IDENTIFY_DEVICE); + int ret = send_ata_identity(dummy, buffer, ATA_CMD_IDENTIFY_DEVICE); if (ret) return NULL;
@@ -647,6 +862,7 @@ init_drive_ata(struct drive_s *dummy, u16 *buffer)
static u64 SpinupEnd;
+// Wait for non-busy status and check for "floating bus" condition. static int powerup_await_non_bsy(u16 base) { @@ -671,6 +887,7 @@ powerup_await_non_bsy(u16 base) return status; }
+// Detect any drives attached to a given controller. static void ata_detect(void *data) { @@ -754,22 +971,25 @@ ata_detect(void *data) } }
+// Initialize an ata controller and detect its drives. static void init_controller(struct ata_channel_s *atachannel - , int bdf, int irq, u32 port1, u32 port2) + , int bdf, int irq, u32 port1, u32 port2, u32 master) { SET_GLOBAL(atachannel->irq, irq); SET_GLOBAL(atachannel->pci_bdf, bdf); SET_GLOBAL(atachannel->iobase1, port1); SET_GLOBAL(atachannel->iobase2, port2); - dprintf(1, "ATA controller %d at %x/%x (irq %d dev %x)\n" - , atachannel - ATA_channels, port1, port2, irq, bdf); + SET_GLOBAL(atachannel->iomaster, master); + dprintf(1, "ATA controller %d at %x/%x/%x (irq %d dev %x)\n" + , atachannel - ATA_channels, port1, port2, master, irq, bdf); run_thread(ata_detect, atachannel); }
#define IRQ_ATA1 14 #define IRQ_ATA2 15
+// Locate and init ata controllers. static void ata_init() { @@ -785,6 +1005,16 @@ ata_init()
u8 pciirq = pci_config_readb(bdf, PCI_INTERRUPT_LINE); u8 prog_if = pci_config_readb(bdf, PCI_CLASS_PROG); + int master = 0; + if (prog_if & 0x80) { + // Check for bus-mastering. + u32 bar = pci_config_readl(bdf, PCI_BASE_ADDRESS_4); + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + master = bar & PCI_BASE_ADDRESS_IO_MASK; + pci_config_maskw(bdf, PCI_COMMAND, 0, PCI_COMMAND_MASTER); + } + } + u32 port1, port2, irq; if (prog_if & 1) { port1 = pci_config_readl(bdf, PCI_BASE_ADDRESS_0) & ~3; @@ -795,7 +1025,7 @@ ata_init() port2 = PORT_ATA1_CTRL_BASE; irq = IRQ_ATA1; } - init_controller(&ATA_channels[count], bdf, irq, port1, port2); + init_controller(&ATA_channels[count], bdf, irq, port1, port2, master); count++;
if (prog_if & 4) { @@ -807,17 +1037,18 @@ ata_init() port2 = PORT_ATA2_CTRL_BASE; irq = IRQ_ATA2; } - init_controller(&ATA_channels[count], bdf, irq, port1, port2); + init_controller(&ATA_channels[count], bdf, irq, port1, port2 + , master ? master + 8 : 0); count++; }
if (!CONFIG_COREBOOT && !pcicount && ARRAY_SIZE(ATA_channels) >= 2) { // No PCI devices found - probably a QEMU "-M isapc" machine. // Try using ISA ports for ATA controllers. - init_controller(&ATA_channels[0] - , -1, IRQ_ATA1, PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE); - init_controller(&ATA_channels[1] - , -1, IRQ_ATA2, PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE); + init_controller(&ATA_channels[0], -1, IRQ_ATA1 + , PORT_ATA1_CMD_BASE, PORT_ATA1_CTRL_BASE, 0); + init_controller(&ATA_channels[1], -1, IRQ_ATA2 + , PORT_ATA2_CMD_BASE, PORT_ATA2_CTRL_BASE, 0); } }
diff --git a/src/ata.h b/src/ata.h index d0a2f8b..149bacf 100644 --- a/src/ata.h +++ b/src/ata.h @@ -7,6 +7,7 @@ struct ata_channel_s { u16 iobase1; u16 iobase2; + u16 iomaster; u8 irq; int pci_bdf; }; @@ -97,7 +98,6 @@ void describe_atapi(struct drive_s *drive_g); #define ATA_CMD_FLUSH_CACHE 0xE7 #define ATA_CMD_FORMAT_TRACK 0x50 #define ATA_CMD_IDENTIFY_DEVICE 0xEC -#define ATA_CMD_IDENTIFY_DEVICE_PACKET 0xA1 #define ATA_CMD_IDENTIFY_PACKET_DEVICE 0xA1 #define ATA_CMD_IDLE1 0xE3 #define ATA_CMD_IDLE2 0x97 @@ -109,15 +109,24 @@ void describe_atapi(struct drive_s *drive_g); #define ATA_CMD_PACKET 0xA0 #define ATA_CMD_READ_BUFFER 0xE4 #define ATA_CMD_READ_DMA 0xC8 +#define ATA_CMD_READ_DMA_EXT 0x25 #define ATA_CMD_READ_DMA_QUEUED 0xC7 +#define ATA_CMD_READ_DMA_QUEUED_EXT 0x26 +#define ATA_CMD_READ_LOG_EXT 0x2F #define ATA_CMD_READ_MULTIPLE 0xC4 +#define ATA_CMD_READ_MULTIPLE_EXT 0x29 +#define ATA_CMD_READ_NATIVE_MAX_ADDRESS 0xF8 +#define ATA_CMD_READ_NATIVE_MAX_ADDRESS_EXT 0x27 #define ATA_CMD_READ_SECTORS 0x20 #define ATA_CMD_READ_SECTORS_EXT 0x24 #define ATA_CMD_READ_VERIFY_SECTORS 0x40 +#define ATA_CMD_READ_VERIFY_SECTORS_EXT 0x42 #define ATA_CMD_RECALIBRATE 0x10 #define ATA_CMD_REQUEST_SENSE 0x03 #define ATA_CMD_SEEK 0x70 #define ATA_CMD_SET_FEATURES 0xEF +#define ATA_CMD_SET_MAX 0xF9 +#define ATA_CMD_SET_MAX_ADDRESS_EXT 0x37 #define ATA_CMD_SET_MULTIPLE_MODE 0xC6 #define ATA_CMD_SLEEP1 0xE6 #define ATA_CMD_SLEEP2 0x99 @@ -127,8 +136,12 @@ void describe_atapi(struct drive_s *drive_g); #define ATA_CMD_STANDBY_IMMEDIATE2 0x94 #define ATA_CMD_WRITE_BUFFER 0xE8 #define ATA_CMD_WRITE_DMA 0xCA +#define ATA_CMD_WRITE_DMA_EXT 0x35 #define ATA_CMD_WRITE_DMA_QUEUED 0xCC +#define ATA_CMD_WRITE_DMA_QUEUED_EXT 0x36 +#define ATA_CMD_WRITE_LOG_EXT 0x3F #define ATA_CMD_WRITE_MULTIPLE 0xC5 +#define ATA_CMD_WRITE_MULTIPLE_EXT 0x39 #define ATA_CMD_WRITE_SECTORS 0x30 #define ATA_CMD_WRITE_SECTORS_EXT 0x34 #define ATA_CMD_WRITE_VERIFY 0x3C
Kevin O'Connor wrote:
This patch enables support for ATA bus master dma transfers.
Looks good at a glance! Is is committed already?
//Peter
On Thu, Dec 24, 2009 at 03:06:04PM +0100, Peter Stuge wrote:
Kevin O'Connor wrote:
This patch enables support for ATA bus master dma transfers.
Looks good at a glance! Is is committed already?
Thanks. I have not yet committed it - I'll wait a couple days in case there is any further feedback.
-Kevin