]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[ata] Use data-transfer buffers for data-in and data-out master 1811/head
authorMichael Brown <mcb30@ipxe.org>
Mon, 10 Aug 2026 10:51:46 +0000 (11:51 +0100)
committerMichael Brown <mcb30@ipxe.org>
Mon, 10 Aug 2026 10:51:46 +0000 (11:51 +0100)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/drivers/block/ata.c
src/include/ipxe/ata.h
src/net/aoe.c

index ee2acdebb62c11005749d336f3bba9fd7077db2f..1f549dcff0c951aa43c423fde3edd2c584f2eb00 100644 (file)
@@ -140,30 +140,27 @@ struct ata_command_type {
        /** Command for LBA48-capable devices */
        uint8_t cmd_lba48;
        /**
-        * Calculate data-in buffer
+        * Initialise data-in buffer
         *
         * @v atacmd            ATA command
+        * @v xferbuf           Data transfer buffer
         * @v buffer            Available buffer
         * @v len               Available buffer length
-        * @ret data_in         Data-in buffer
-        * @ret data_in_len     Data-in buffer length
         */
-       void ( * data_in ) ( struct ata_command *atacmd, void *buffer,
-                            size_t len, void **data_in,
-                            size_t *data_in_len );
+       void ( * data_in ) ( struct ata_command *atacmd,
+                            struct xfer_buffer *xferbuf,
+                            void *buffer, size_t len );
        /**
-        * Calculate data-out buffer
-        *
+        * Initialise data-out buffer
         *
         * @v atacmd            ATA command
+        * @v xferbuf           Data transfer buffer
         * @v buffer            Available buffer
         * @v len               Available buffer length
-        * @ret data_out        Data-out buffer
-        * @ret data_out_len    Data-out buffer length
         */
-       void ( * data_out ) ( struct ata_command *atacmd, void *buffer,
-                             size_t len, void **data_out,
-                             size_t *data_out_len );
+       void ( * data_out ) ( struct ata_command *atacmd,
+                             struct xfer_buffer *xferbuf,
+                             void *buffer, size_t len );
        /**
         * Handle ATA command completion
         *
@@ -280,48 +277,44 @@ static void atacmd_done ( struct ata_command *atacmd, int rc ) {
  * Use provided data buffer for ATA command
  *
  * @v atacmd           ATA command
+ * @v xferbuf          Data transfer buffer
  * @v buffer           Available buffer
  * @v len              Available buffer length
- * @ret data           Data buffer
- * @ret data_len       Data buffer length
  */
 static void atacmd_data_buffer ( struct ata_command *atacmd __unused,
-                                void *buffer, size_t len,
-                                void **data, size_t *data_len ) {
-       *data = buffer;
-       *data_len = len;
+                                struct xfer_buffer *xferbuf,
+                                void *buffer, size_t len ) {
+       xferbuf_fixed_init ( xferbuf, buffer, len );
 }
 
 /**
  * Use no data buffer for ATA command
  *
  * @v atacmd           ATA command
+ * @v xferbuf          Data transfer buffer
  * @v buffer           Available buffer
  * @v len              Available buffer length
- * @ret data           Data buffer
- * @ret data_len       Data buffer length
  */
 static void atacmd_data_none ( struct ata_command *atacmd __unused,
-                              void *buffer __unused, size_t len __unused,
-                              void **data __unused,
-                              size_t *data_len __unused ) {
-       /* Nothing to do */
+                              struct xfer_buffer *xferbuf,
+                              void *buffer __unused, size_t len __unused ) {
+       xferbuf_void_init ( xferbuf );
 }
 
 /**
  * Use private data buffer for ATA command
  *
  * @v atacmd           ATA command
+ * @v xferbuf          Data transfer buffer
  * @v buffer           Available buffer
  * @v len              Available buffer length
- * @ret data           Data buffer
- * @ret data_len       Data buffer length
  */
 static void atacmd_data_priv ( struct ata_command *atacmd,
-                              void *buffer __unused, size_t len __unused,
-                              void **data, size_t *data_len ) {
-       *data = atacmd_priv ( atacmd );
-       *data_len = atacmd->type->priv_len;
+                              struct xfer_buffer *xferbuf,
+                              void *buffer __unused, size_t len __unused ) {
+
+       xferbuf_fixed_init ( xferbuf, atacmd_priv ( atacmd ),
+                            atacmd->type->priv_len );
 }
 
 /** ATA READ command type */
@@ -494,10 +487,8 @@ static int atadev_command ( struct ata_device *atadev,
                command.cb.device |= command.cb.lba.bytes.low_prev;
        command.cb.cmd_stat =
                ( atadev->lba48 ? type->cmd_lba48 : type->cmd_lba );
-       type->data_in ( atacmd, buffer, len,
-                       &command.data_in, &command.data_in_len );
-       type->data_out ( atacmd, buffer, len,
-                        &command.data_out, &command.data_out_len );
+       type->data_in ( atacmd, &command.data_in, buffer, len );
+       type->data_out ( atacmd, &command.data_out, buffer, len );
 
        /* Issue command */
        if ( ( tag = ata_command ( &atadev->ata, &atacmd->ata,
index eea086c13e22a95fcff7354c3ac566b55340c04e..1dedc7ffee6348ca9b5a33dd7017eacbb28723af 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <stdint.h>
 #include <ipxe/interface.h>
+#include <ipxe/xferbuf.h>
 
 /** @file
  *
@@ -168,28 +169,10 @@ struct ata_identity {
 struct ata_cmd {
        /** ATA command block */
        struct ata_cb cb;
-       /** Data-out buffer (may be NULL)
-        *
-        * If non-NULL, this buffer must be ata_command::cb::count
-        * sectors in size.
-        */
-       void *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)
-        *
-        * If non-NULL, this buffer must be ata_command::cb::count
-        * sectors in size.
-        */
-       void *data_in;
-       /** Data-in buffer length
-        *
-        * Must be zero if @c data_in is NULL
-        */
-       size_t data_in_len;
+       /** Data-out buffer */
+       struct xfer_buffer data_out;
+       /** Data-in buffer */
+       struct xfer_buffer data_in;
 };
 
 extern int ata_command ( struct interface *control, struct interface *data,
index 86911ab67cd84b4f6f0c39009a09f7d22c744d6e..2a1b55769c3fa7d87cc464407cf1a7c5b40af594 100644 (file)
@@ -107,8 +107,9 @@ struct aoe_command_type {
         * @v aoecmd            AoE command
         * @v data              Command IU
         * @v len               Length of command IU
+        * @ret rc              Return status code
         */
-       void ( * cmd ) ( struct aoe_command *aoecmd, void *data, size_t len );
+       int ( * cmd ) ( struct aoe_command *aoecmd, void *data, size_t len );
        /**
         * Handle AoE response IU
         *
@@ -249,8 +250,10 @@ static int aoecmd_tx ( struct aoe_command *aoecmd ) {
        /* Create outgoing I/O buffer */
        cmd_len = aoecmd->type->cmd_len ( aoecmd );
        iobuf = alloc_iob ( MAX_LL_HEADER_LEN + cmd_len );
-       if ( ! iobuf )
-               return -ENOMEM;
+       if ( ! iobuf ) {
+               rc = -ENOMEM;
+               goto err_alloc;
+       }
        iob_reserve ( iobuf, MAX_LL_HEADER_LEN );
        aoehdr = iob_put ( iobuf, cmd_len );
 
@@ -260,18 +263,27 @@ static int aoecmd_tx ( struct aoe_command *aoecmd ) {
        aoehdr->major = htons ( aoedev->major );
        aoehdr->minor = aoedev->minor;
        aoehdr->tag = htonl ( aoecmd->tag );
-       aoecmd->type->cmd ( aoecmd, iobuf->data, iob_len ( iobuf ) );
+       if ( ( rc = aoecmd->type->cmd ( aoecmd, iobuf->data,
+                                       iob_len ( iobuf ) ) ) != 0 ) {
+               goto err_cmd;
+       }
 
        /* Send packet */
-       if ( ( rc = net_tx ( iobuf, netdev, &aoe_protocol, aoedev->target,
-                            netdev->ll_addr ) ) != 0 ) {
+       if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &aoe_protocol,
+                            aoedev->target, netdev->ll_addr ) ) != 0 ) {
                DBGC ( aoedev, "AoE %s/%08x could not transmit: %s\n",
                       aoedev_name ( aoedev ), aoecmd->tag,
                       strerror ( rc ) );
-               return rc;
+               goto err_tx;
        }
 
        return 0;
+
+ err_tx:
+ err_cmd:
+       free_iob ( iobuf );
+ err_alloc:
+       return rc;
 }
 
 /**
@@ -357,7 +369,7 @@ static size_t aoecmd_ata_cmd_len ( struct aoe_command *aoecmd ) {
        struct ata_cmd *command = &aoecmd->command;
 
        return ( sizeof ( struct aoehdr ) + sizeof ( struct aoeata ) +
-                command->data_out_len );
+                command->data_out.len );
 }
 
 /**
@@ -366,25 +378,27 @@ static size_t aoecmd_ata_cmd_len ( struct aoe_command *aoecmd ) {
  * @v aoecmd           AoE command
  * @v data             Command IU
  * @v len              Length of command IU
+ * @ret rc             Return status code
  */
-static void aoecmd_ata_cmd ( struct aoe_command *aoecmd,
-                            void *data, size_t len ) {
+static int aoecmd_ata_cmd ( struct aoe_command *aoecmd,
+                           void *data, size_t len ) {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct ata_cmd *command = &aoecmd->command;
        struct aoehdr *aoehdr = data;
        struct aoeata *aoeata = &aoehdr->payload[0].ata;
+       int rc;
 
        /* Sanity check */
        static_assert ( AOE_FL_DEV_HEAD == ATA_DEV_SLAVE );
        assert ( len == ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) +
-                         command->data_out_len ) );
+                         command->data_out.len ) );
 
        /* Build IU */
        aoehdr->command = AOE_CMD_ATA;
        memset ( aoeata, 0, sizeof ( *aoeata ) );
        aoeata->aflags = ( ( command->cb.lba48 ? AOE_FL_EXTENDED : 0 ) |
                           ( command->cb.device & ATA_DEV_SLAVE ) |
-                          ( command->data_out_len ? AOE_FL_WRITE : 0 ) );
+                          ( command->data_out.len ? AOE_FL_WRITE : 0 ) );
        aoeata->err_feat = command->cb.err_feat.bytes.cur;
        aoeata->count = command->cb.count.native;
        aoeata->cmd_stat = command->cb.cmd_stat;
@@ -392,17 +406,25 @@ static void aoecmd_ata_cmd ( struct aoe_command *aoecmd,
        if ( ! command->cb.lba48 )
                aoeata->lba.bytes[3] |=
                        ( command->cb.device & ATA_DEV_MASK );
-       memcpy ( aoeata->data, command->data_out, command->data_out_len );
-
        DBGC2 ( aoedev, "AoE %s/%08x ATA cmd %02x:%02x:%02x:%02x:%08llx",
                aoedev_name ( aoedev ), aoecmd->tag, aoeata->aflags,
                aoeata->err_feat, aoeata->count, aoeata->cmd_stat,
                aoeata->lba.u64 );
-       if ( command->data_out_len )
-               DBGC2 ( aoedev, " out %04zx", command->data_out_len );
-       if ( command->data_in_len )
-               DBGC2 ( aoedev, " in %04zx", command->data_in_len );
+       if ( command->data_out.len )
+               DBGC2 ( aoedev, " out %04zx", command->data_out.len );
+       if ( command->data_in.len )
+               DBGC2 ( aoedev, " in %04zx", command->data_in.len );
        DBGC2 ( aoedev, "\n" );
+
+       /* Copy data-out (if any) to command IU */
+       if ( ( rc = xferbuf_read ( &command->data_out, 0, aoeata->data,
+                                  command->data_out.len ) ) != 0 ) {
+               DBGC ( aoedev, "AoE %s/%08x could not read data-out: %s\n",
+                      aoedev_name ( aoedev ), aoecmd->tag, strerror ( rc ) );
+               return rc;
+       }
+
+       return 0;
 }
 
 /**
@@ -421,6 +443,7 @@ static int aoecmd_ata_rsp ( struct aoe_command *aoecmd, const void *data,
        const struct aoehdr *aoehdr = data;
        const struct aoeata *aoeata = &aoehdr->payload[0].ata;
        size_t data_len;
+       int rc;
 
        /* Sanity check */
        if ( len < ( sizeof ( *aoehdr ) + sizeof ( *aoeata ) ) ) {
@@ -444,15 +467,20 @@ static int aoecmd_ata_rsp ( struct aoe_command *aoecmd, const void *data,
        /* Check data-in length is sufficient.  (There may be trailing
         * garbage due to Ethernet minimum-frame-size padding.)
         */
-       if ( data_len < command->data_in_len ) {
+       if ( data_len < command->data_in.len ) {
                DBGC ( aoedev, "AoE %s/%08x data-in underrun (received %zd, "
                       "expected %zd)\n", aoedev_name ( aoedev ), aoecmd->tag,
-                      data_len, command->data_in_len );
+                      data_len, command->data_in.len );
                return -ERANGE;
        }
 
        /* Copy out data payload */
-       memcpy ( command->data_in, aoeata->data, command->data_in_len );
+       if ( ( rc = xferbuf_write ( &command->data_in, 0, aoeata->data,
+                                   command->data_in.len ) ) != 0 ) {
+               DBGC ( aoedev, "AoE %s/%08x could not write data-in: %s\n",
+                      aoedev_name ( aoedev ), aoecmd->tag, strerror ( rc ) );
+               return rc;
+       }
 
        return 0;
 }
@@ -480,9 +508,10 @@ static size_t aoecmd_cfg_cmd_len ( struct aoe_command *aoecmd __unused ) {
  * @v aoecmd           AoE command
  * @v data             Command IU
  * @v len              Length of command IU
+ * @ret rc             Return status code
  */
-static void aoecmd_cfg_cmd ( struct aoe_command *aoecmd,
-                            void *data, size_t len ) {
+static int aoecmd_cfg_cmd ( struct aoe_command *aoecmd,
+                           void *data, size_t len ) {
        struct aoe_device *aoedev = aoecmd->aoedev;
        struct aoehdr *aoehdr = data;
        struct aoecfg *aoecfg = &aoehdr->payload[0].cfg;
@@ -493,9 +522,10 @@ static void aoecmd_cfg_cmd ( struct aoe_command *aoecmd,
        /* Build IU */
        aoehdr->command = AOE_CMD_CONFIG;
        memset ( aoecfg, 0, sizeof ( *aoecfg ) );
-
        DBGC ( aoedev, "AoE %s/%08x CONFIG cmd\n",
               aoedev_name ( aoedev ), aoecmd->tag );
+
+       return 0;
 }
 
 /**