Use separate data-in and data-out buffers.
authorMichael Brown <mcb30@etherboot.org>
Sun, 28 May 2006 23:26:42 +0000 (23:26 +0000)
committerMichael Brown <mcb30@etherboot.org>
Sun, 28 May 2006 23:26:42 +0000 (23:26 +0000)
Increase code simplicity at the expense of around 64 bytes.

src/drivers/block/ata.c
src/include/gpxe/ata.h

index 8bd88fe..3fcfa71 100644 (file)
@@ -51,55 +51,32 @@ ata_command ( struct ata_device *ata, struct ata_command *command ) {
 }
 
 /**
- * Read block from / write block to ATA device
+ * Read block from ATA device
  *
- * @v write            Write flag (ATA_FL_WRITE or 0)
  * @v blockdev         Block device
  * @v block            LBA block number
  * @v count            Block count
  * @v buffer           Data buffer
  * @ret rc             Return status code
  */
-static __attribute__ (( regparm ( 1 ) )) int
-ata_rw ( int write, struct block_device *blockdev, uint64_t block,
-        unsigned long count, userptr_t buffer ) {
+static int ata_read ( struct block_device *blockdev, uint64_t block,
+                     unsigned long count, userptr_t buffer ) {
        struct ata_device *ata = block_to_ata ( blockdev );
        struct ata_command command;
-       int lba48 = ( ata->flags & ATA_FL_LBA48 );
 
        memset ( &command, 0, sizeof ( command ) );
        command.cb.lba.native = block;
        command.cb.count.native = count;
-       command.cb.device = ( ata->flags | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
-       command.cb.flags = ( ata->flags | write );
-       command.cb.cmd_stat = ( write ? ATA_CMD_WRITE : ATA_CMD_READ );
-       if ( lba48 ) {
-               command.cb.cmd_stat |= ATA_CMD_EXT;
-       } else {
+       command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
+       command.cb.lba48 = ata->lba48;
+       if ( ! ata->lba48 )
                command.cb.device |= command.cb.lba.bytes.low_prev;
-       }
-       command.data = buffer;
-       command.data_len = ( count * blockdev->blksize );
+       command.cb.cmd_stat = ( ata->lba48 ? ATA_CMD_READ_EXT : ATA_CMD_READ );
+       command.data_in = buffer;
+       command.data_in_len = ( count * blockdev->blksize );
        return ata_command ( ata, &command );
 }
 
-/**
- * Read block from ATA device
- *
- * @v blockdev         Block device
- * @v block            LBA block number
- * @v count            Block count
- * @v buffer           Data buffer
- * @ret rc             Return status code
- */
-static int ata_read ( struct block_device *blockdev, uint64_t block,
-                     unsigned long count, userptr_t buffer ) {
-       /* Pass through to ata_rw().  Since ata_rw is regparm(1), this
-        * is extremely efficient; just a mov and a jmp.
-        */
-       return ata_rw ( 0, blockdev, block, count, buffer );
-}
-
 /**
  * Write block to ATA device
  *
@@ -111,10 +88,21 @@ static int ata_read ( struct block_device *blockdev, uint64_t block,
  */
 static int ata_write ( struct block_device *blockdev, uint64_t block,
                       unsigned long count, userptr_t buffer ) {
-       /* Pass through to ata_rw().  Since ata_rw is regparm(1), this
-        * is extremely efficient; just a mov and a jmp.
-        */
-       return ata_rw ( ATA_FL_WRITE, blockdev, block, count, buffer );
+       struct ata_device *ata = block_to_ata ( blockdev );
+       struct ata_command command;
+       
+       memset ( &command, 0, sizeof ( command ) );
+       command.cb.lba.native = block;
+       command.cb.count.native = count;
+       command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
+       command.cb.lba48 = ata->lba48;
+       if ( ! ata->lba48 )
+               command.cb.device |= command.cb.lba.bytes.low_prev;
+       command.cb.cmd_stat = ( ata->lba48 ?
+                               ATA_CMD_WRITE_EXT : ATA_CMD_WRITE );
+       command.data_out = buffer;
+       command.data_out_len = ( count * blockdev->blksize );
+       return ata_command ( ata, &command );
 }
 
 /**
@@ -131,17 +119,19 @@ static int ata_identify ( struct block_device *blockdev ) {
 
        /* Issue IDENTIFY */
        memset ( &command, 0, sizeof ( command ) );
-       command.cb.device = ( ata->flags | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
+       command.cb.count.native = 1; /* n/a according to spec, but at least
+                                     * AoE vblade devices require it. */
+       command.cb.device = ( ata->device | ATA_DEV_OBSOLETE | ATA_DEV_LBA );
        command.cb.cmd_stat = ATA_CMD_IDENTIFY;
-       command.data = virt_to_user ( &identity );
-       command.data_len = sizeof ( identity );
+       command.data_in = virt_to_user ( &identity );
+       command.data_in_len = sizeof ( identity );
        if ( ( rc = ata_command ( ata, &command ) ) != 0 )
                return rc;
 
        /* Fill in block device parameters */
        blockdev->blksize = ATA_SECTOR_SIZE;
        if ( identity.supports_lba48 & cpu_to_le16 ( ATA_SUPPORTS_LBA48 ) ) {
-               ata->flags |= ATA_FL_LBA48;
+               ata->lba48 = 1;
                blockdev->blocks = le64_to_cpu ( identity.lba48_sectors );
        } else {
                blockdev->blocks = le32_to_cpu ( identity.lba_sectors );
index 5aeb82e..ecc9c5b 100644 (file)
@@ -56,9 +56,9 @@ union ata_lba {
                uint8_t low_prev;
                uint8_t mid_prev;
                uint8_t high_prev;
-               uint8_t pad[2];
+               uint16_t pad;
 #elif __BYTE_ORDER == __BIG_ENDIAN
-               uint8_t pad[2];
+               uint16_t pad;
                uint8_t high_prev;
                uint8_t mid_prev;
                uint8_t low_prev;
@@ -101,52 +101,55 @@ struct ata_cb {
        uint8_t device;
        /** Command/status register */
        uint8_t cmd_stat;
-       /** Flags
-        *
-        * This field does not correspond to any ATA register.
-        */
-       uint8_t flags;
+       /** LBA48 addressing flag */
+       int lba48;
 };
 
-/** LBA48 extended addressing */
-#define ATA_FL_LBA48 0x40
-
-/** Device 1 ("slave") */
-#define ATA_FL_SLAVE 0x10
-
-/** Write command */
-#define ATA_FL_WRITE 0x01
-
 /** Obsolete bits in the ATA device register */
 #define ATA_DEV_OBSOLETE 0xa0
 
 /** LBA flag in the ATA device register */
 #define ATA_DEV_LBA 0x40
 
+/** Slave ("device 1") flag in the ATA device register */
+#define ATA_DEV_SLAVE 0x10
+
+/** Master ("device 0") flag in the ATA device register */
+#define ATA_DEV_MASTER 0x00
+
 /** "Read sectors" command */
 #define ATA_CMD_READ 0x20
 
+/** "Read sectors (ext)" command */
+#define ATA_CMD_READ_EXT 0x24
+
 /** "Write sectors" command */
 #define ATA_CMD_WRITE 0x30
 
+/** "Write sectors (ext)" command */
+#define ATA_CMD_WRITE_EXT 0x34
+
 /** "Identify" command */
 #define ATA_CMD_IDENTIFY 0xec
 
-/** "Extended (LBA48)" command modifier
- *
- * This doesn't apply to all ATA commands, but it does for @c
- * ATA_CMD_READ and @c ATA_CMD_WRITE.
- */
-#define ATA_CMD_EXT 0x04
-
 /** An ATA command */
 struct ata_command {
        /** ATA command block */
        struct ata_cb cb;
-       /** Data buffer */
-       userptr_t data;
-       /** Data buffer length */
-       size_t data_len;
+       /** Data-out buffer (may be NULL) */
+       userptr_t data_out;
+       /** Data-out buffer length
+        *
+        * Must be zero if @c data_out is NULL
+        */
+       size_t data_out_len;
+       /** Data-in buffer (may be NULL) */
+       userptr_t data_in;
+       /** Data-in buffer length
+        *
+        * Must be zero if @c data_in is NULL
+        */
+       size_t data_in_len;
 };
 
 /**
@@ -175,8 +178,13 @@ struct ata_identity {
 struct ata_device {
        /** Block device interface */
        struct block_device blockdev;
-       /** Flags */
-       int flags;
+       /** Device number
+        *
+        * Must be ATA_DEV_MASTER or ATA_DEV_SLAVE.
+        */
+       int device;
+       /** LBA48 extended addressing */
+       int lba48;
        /**
         * Issue ATA command
         *