Handle multi-sector reads by splitting them into subcommands.
authorMichael Brown <mcb30@etherboot.org>
Mon, 29 May 2006 08:25:31 +0000 (08:25 +0000)
committerMichael Brown <mcb30@etherboot.org>
Mon, 29 May 2006 08:25:31 +0000 (08:25 +0000)
src/drivers/ata/aoedev.c
src/include/gpxe/aoe.h
src/include/gpxe/ata.h
src/net/aoe.c

index 8db484b..0350bc0 100644 (file)
@@ -37,7 +37,7 @@ static int aoe_command ( struct ata_device *ata,
        struct aoe_device *aoedev
                = container_of ( ata, struct aoe_device, ata );
 
-       return aoe_issue ( &aoedev->aoe, command );
+       return aoe_issue_split ( &aoedev->aoe, command );
 }
 
 /**
index 094feb5..2e13d7a 100644 (file)
@@ -110,6 +110,8 @@ struct aoe_session {
 extern void aoe_open ( struct aoe_session *aoe );
 extern void aoe_close ( struct aoe_session *aoe );
 extern int aoe_issue ( struct aoe_session *aoe, struct ata_command *command );
+extern int aoe_issue_split ( struct aoe_session *aoe,
+                            struct ata_command *command );
 
 /** An AoE device */
 struct aoe_device {
index ecc9c5b..195e361 100644 (file)
@@ -117,6 +117,9 @@ struct ata_cb {
 /** Master ("device 0") flag in the ATA device register */
 #define ATA_DEV_MASTER 0x00
 
+/** Mask of non-LBA portion of device register */
+#define ATA_DEV_MASK 0xf0
+
 /** "Read sectors" command */
 #define ATA_CMD_READ 0x20
 
index e1c9393..7267cf0 100644 (file)
@@ -84,7 +84,7 @@ static int aoe_send_command ( struct aoe_session *aoe ) {
        aoecmd->cmd_stat = command->cb.cmd_stat;
        aoecmd->lba.u64 = cpu_to_le64 ( command->cb.lba.native );
        if ( ! command->cb.lba48 )
-               aoecmd->lba.bytes[3] |= command->cb.device;
+               aoecmd->lba.bytes[3] |= ( command->cb.device & ATA_DEV_MASK );
 
        /* Fill data payload */
        copy_from_user ( pkb_put ( pkb, command->data_out_len ),
@@ -244,8 +244,11 @@ void aoe_kick ( struct aoe_session *aoe ) {
  * Issue ATA command via an open AoE session
  *
  * @v aoe              AoE session
- * @v command          AoE command
+ * @v command          ATA command
  * @ret rc             Return status code
+ *
+ * The ATA command must fit within a single AoE frame (i.e. the sector
+ * count must not exceed AOE_MAX_COUNT).
  */
 int aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
        aoe->command = command;
@@ -259,3 +262,46 @@ int aoe_issue ( struct aoe_session *aoe, struct ata_command *command ) {
 
        return ( ( aoe->status & AOE_STATUS_ERR_MASK ) ? -EIO : 0 );
 }
+
+/**
+ * Issue ATA command via an open AoE session
+ *
+ * @v aoe              AoE session
+ * @v command          ATA command
+ * @ret rc             Return status code
+ *
+ * The ATA command will be split into several smaller ATA commands,
+ * each with a sector count no larger than AOE_MAX_COUNT.
+ */
+int aoe_issue_split ( struct aoe_session *aoe, struct ata_command *command ) {
+       struct ata_command subcommand;
+       unsigned int offset;
+       unsigned int count;
+       unsigned int data_len;
+       unsigned int status = 0;
+       int rc = 0;
+
+       /* Split ATA command into AoE-sized subcommands */
+       for ( offset = 0; offset < command->cb.count.native; offset += count ){
+               memcpy ( &subcommand, command, sizeof ( subcommand ) );
+               count = ( command->cb.count.native - offset );
+               if ( count > AOE_MAX_COUNT )
+                       count = AOE_MAX_COUNT;
+               data_len = count * ATA_SECTOR_SIZE;
+               if ( subcommand.data_in_len )
+                       subcommand.data_in_len = data_len;
+               if ( subcommand.data_out_len )
+                       subcommand.data_out_len = data_len;
+               aoe->command_offset = ( offset * ATA_SECTOR_SIZE );
+               subcommand.cb.lba.native += offset;
+               subcommand.cb.count.native = count;
+               if ( ( rc = aoe_issue ( aoe, &subcommand ) ) != 0 )
+                       goto done;
+               status |= subcommand.cb.cmd_stat;
+       }
+       command->cb.cmd_stat = status;
+
+ done:
+       aoe->command_offset = 0;
+       return rc;
+}